Comments 71
Можно уточнить — это точно авторский материал? Меня не покидало ощущение, что эта статья перевод, но ссылка на оригинал потерялась.
Если я ошибся, то поздравляю — это ещё раз говорит о качестве фактуры материала (с хорошей стороны)
Они мне снятся иногда и я замерзаю, стараясь не шевелиться, чтобы не привлечь их внимание.
Всё же это явно перевод, хотя допускаю что вы автор английского оригинала. «Я замерзаю» — это явно «I freeze» («я замираю»).
Но чеклист понравился, спасибо.
Я уточнил, точно я. :D Вообще сам чек-лист у меня по-английски хранится, возможно это ощущается. Остальной текст написан сразу по-русски.
А можете на английском хабре опубликовать. Прям вот очень нужно!
Так себе объяснение, почему явно английская фраза присутствует в статье.
Если, на самом деле, это компиляция из разных источников, то так и стоит указать.
все так и есть на самом деле.
Еще одна рекомендация:
не пихать в контейнеры все подряд «потому что это модно»! Только тогда, когда это нужно.
А ещё есть service mesh networks и так далее. Стоит только начать…
Я думаю это вполне можно расширить и на другие типы проектов, без микросервисов — почти ничего не изменится.
В крупноблочных или монолитных приложениях легче отслеживаются проблемы, если всё выполняется в одном потоке. Конечно всё это выжимка опыта работы, включающая и до-докерную эру, однако с множеством мелких программ в одном проекте приходят новые сложности. Зоопарк технологий, фреймворков, всё это очень усложняет понимание сути происходящего.
Так что ваша статья прекрасно подходит для монолитов и сервисной архитектуры.
На заре развития Докера, когда я его не любил, я тоже так делал. Чистый докер тяжело управляется, стыковать контейнеры друг с другом сложно и долго, поэтому Supervisor был спасением и получался эдакий «быстрый Vagrant».
Большинство пунктов применимо к приложениям других архитектур.
Все будет хорошо до первого исключения на 100 строк с другим логом внутри
Оповещения настроены
И эскалации, чтобы никто не проспал оповещения. Для этого нужен Incident Management, например:
www.pagerduty.com
victorops.com
www.opsgenie.com
amixr.io (Да, я советую свой сервис, но он правда хороший)
Вы совершенно правы, но это уже сильно индивидуальный выбор, да и стоит денег.
в бункере в 2000 метрах под землёй с подогревом половя бы лучше подумал над охлождением на такой глубине
</зануда>
Все логи пишутся в STDOUT/STDERR
А дальше куда? Где их искать, чтобы почитать?
journald, кстати, тоже прекрасно хватает с legacy приложений, обернутых в systemd юниты, stdout & stderr
примерно так
Если приложение пишет логи самостоятельно в стороннюю систему, например в Logstash — это создаёт бесполезную избыточность.и
Загрузите в любую подходящую систему (правильно настроенный ElasticSearch, например)не противоречат друг другу или я не правильно понял?
На целевой системе — шлем логи в stdout/stderr
Далее лог-коллектор их собирает, аггрегирует, обогащает и шлёт…
В централизованный ELK, например, где пользователь уже может с логами делать поиск, фильтрацию, статистику собирать и пр
— Логи «снимаются» с докера (rsyslog, fluentd, ...). Способы реализации разные. Можно изнутри Kubernetes это делать, а можно снаружи, собирая просто логи докера на каждой ноде прямо на хосте, настраивая это всё через оркестратор типа Chef/Salt/whatever.
— собранные логи «умно» пересылаются в какой-либо аггрегатор, с учётом его производительности. Здесь тоже сетап может сильно отличаться. Если логов мало и они качественные (согласованный json), то можно прямо в ElasticSearch слать в нужный индекс. Если их много, можно сначала в какую-то промежуточную точку сбора вроде Kafka, а затем уже в конечную (это может быть какой-то SAAS, не обязательно ElasticSearch).
— потом выводятся в каких-нибудь вьюхах. Kibana/Graphana, тут кому что ближе к телу. Сильно зависит от знания технологии и наличия свободного времени. Можно наворотить нереально красивые и полезные графики. Но большинство просто использует поиск и фильтрацию.
— а поверх настраиваются оповещения о событиях.
Если приложение пишет логи самостоятельно в стороннюю систему, например в Logstash — это создаёт бесполезную избыточность. Соседний сервис не умеет этого делать, т.к. у него другой фреймворк? Вы получаете зоопарк.
Сбивчивый абзац. Можно поподробнее что не так с Logstash?
Автор — вы молодец!
Ещё можно добавить использование сервисов типа Crazy Monkey для раннего обнаружения проблем с архитектурой и реализацией
Вашим бы списком да по нашим ребятам из dev'а…
Я просто тут как раз занимался процессом принятия кучи микросервисов из dev-окружения в production Kubernetes, и прямо вот из ваших 22 кажется пунктов были на месте от силы 4, и это боль, да. Кину им английскую версию почитать :)
Вот про «Все логи пишутся в STDOUT/STDERR» еще добавлю: оно еще важно не только с точки зрения однообразия и удобства, но и использования места на диске — у нас так один микросервис со «случайно» включенным DEBUG режимом за короткое время заполнил всю файловую систему /var/lib/docker, просто потому что писал логи в файл внутри контейнера. И главное в такой ситуации log rotation самого докера не поможет никак.
у нас так один микросервис со «случайно» включенным DEBUG режимом за короткое время заполнил всю файловую систему /var/lib/docker, просто потому что писал логи в файл внутри контейнера.
он заполнил эфемерную файловую систему самого себя (там лимит кажется по умолчанию 10 ГиБ)? Или заполнил файловую систему, на которой был каталог /var/lib/docker? Ну, вообще-то можно заставить по умолчанию docker писать в journald, а не в json-file и там сразу автоматически куча плюшек (включая лимит по размеру логов и ротация). И как человек, который тащил это в прод, Вы должны были это знать…
Ну во-первых это был один из staging'ов. Во-вторых как я сказал, проблема не в ротации логов, а в том что контейнер заполнил файловую систему которую ему выделили. 10G лимит распространяется только на devicemapper
, в случае overlay2
лимитов нет.
Еще точнее так, из документации:
For the overlay2 storage driver, the size option is only available if the backing fs is xfs and mounted with the pquota mount option. Under these conditions, user can pass any size less than the backing fs size.
Вообще я ожидаю от разработчика, что его приложение вообще не пишет ничего в свою контейнерную файловую систему. Если уж нужно что-то писать, то для этого подключаются волюмы.
Если уж нужно что-то писать, то для этого подключаются волюмы.
есть еще временные файлы, которые на вольюм не нужно класть. От слова совсем. И может быть ошибка в приложении, которая не позволяет очищать эти временные файлы. Почему я знаю об этом? Да с gitlab'ом в докере в определенный момент времени такая история произошла и пришлось заняться расследованием инцидента. Решилось изменением параметров gitlab pages.
И еще — как временный костыль могло помочь увеличение базового размера образа. Примерно как в ответе stackoverflow.com/questions/30994760/how-to-increase-docker-container-default-size
но учитывая, что была ошибка в прикладе, то это все равно не помогло надолго.
p.s. судя по всему действительно там изначально был devicemapper…
P.S. и, да, большое спасибо за Ваш опыт. Это навело меня на мысли, где еще может сломаться кубернетес и как правильно его приготовить… И так уже целая коллекция, а тут еще один ценный экспонат (кейс).
Вдруг в вашей коллекции ещё есть место :D
Up: перепутал ссылку, обновил
Все логи пишутся в STDOUT/STDERR
А ещё лучше — в старый добрый syslog или новый модный systemd-journal. Их API использует локальный DGRAM сокет, а значит в приложении не потребуется синхронизация между тредами перед записью в общий FIFO буфер пайпа.
Прочитал комментарий ниже и до меня дошло, что вы наверное имеете ввиду писать куда-то вовне из самого контейнера. С этим я не могу согласиться.
Вот еще пример: LogLevel. Когда я пишу библиотеку аутентификации и пароль не совпадает — это ошибка. Тот-же самый вызов со стороны клиентского приложения может быть как нормальной ситуацией (ну ошибся при вводе и что?), фатальной ситуацией (сервис не может аутентифицироваться), предупреждением (много ошибок — может подбор?). Что тут делать? А ничего. Ставить тот LogLevel, какой считаешь нужным на данном уровне. После систему логирования можно сконфигурировать понижать/повышать уровень сообщений от конкретного компонента.
Пример с уровнем можно расширить на весь лог — компонент логирует как считает нужным (он может быть вообще 3rd party), а потом его лог обрабатывается как надо.
Понятно, что если Вам нужно смотреть логи прямо на продакшене, то да — json становится человеком не читабельным… Но нужно ли это?
Аналогия — никто же не обламывается от бинарных протоколов типа grpc, protobuf!?
Вот принято у вас в Json писать — пишите, но не надо говорить, что это вселенское добро и всем так надо. Не надо. Безопаснее (и в конечном итоге проще) сразу предполагать, что постпроцессинг логов потребуется и не накладывать жестких ограничений. А точнее надо давать рекомендации. Но скоуп у рекомендаций все равно ограничен вашей системой. А что если в другой системе жестко запрещен Json и все должно идти через logd?
Пример из жизни: поскольку у саппорта Geneos настроен на LogLevel=ERROR в программе нельзя вообще использовать этот уровень — иначе есть вероятность, что тебя поднимут ночью из-за «Temporary file already exists. Using another name.». В данном (воображаемом) примере программа не ожидала, что временный файл с таким именем будет существовать (т.е. с ее точки зрения это ошибка), но все равно попыталась исправить ситуацию и успешно это сделала. Однако звонок в 3 ночи обеспечен. Разумеется можно (и нужно) поменять сообщение, его уровень, настройки Geneos, runbook и т.д. Но звонок уже был и кто-то прийдет на работу сонный.
> Вот принято у вас в Json писать — пишите, но не надо говорить, что это вселенское добро и всем так надо.
Если вы нашли иной способ, используя другой формат, получать гарантированный парсинг всех требуемых полей, начиная (но не ограничиваясь) с точной метки времени — то конечно. Но из всего, что я знаю, только json поддерживается в любом языке и парсится чем угодно. Следовательно, я буду продолжать утверждать, что это и есть единственный оптимальный формат для подавляющего большинства проектов. А редкие исключения требуют редких специалистов.
По-поводу LogLevel, конечно же разработчик сам определяет что критично, а что нет. Но у администратора системы должна быть возможность выключить всё некритичное и включить когда требуется единым способом.
Я согласен, что приложение должно выводить логи на stdout/stderr, но меня сильно напрягает список исправленных достаточно критичных ошибок (включающих потерю строк, дублирование строк, и блокирование при записи в лог) в области обработки логов докером в почти каждом релизе докера. Поэтому я предпочитаю запускать внутри контейнера не только приложение, но и лог-процессор, который будет забирать логи с stdout/stderr приложения и надёжно куда-то их писать/отправлять.
Что до вывода логов в json, то здесь всё зависит от масштабов: пока проект небольшой и серьёзной инфраструктуры для обработки логов вроде ELK нет — удобнее выводить логи текстом. Но если/когда проект вырастет, то логи нужно будет перевести в json. Поэтому крайне желательно, чтобы используемая библиотека для логирования изначально принимала от приложения структурированные данные для вывода в лог и позволяла переключать вывод между текстом и json.
Я согласен, что приложение должно выводить логи на stdout/stderr, но меня сильно напрягает список исправленных достаточно критичных ошибок (включающих потерю строк, дублирование строк, и блокирование при записи в лог) в области обработки логов докером в почти каждом релизе докера. Поэтому я предпочитаю запускать внутри контейнера не только приложение, но и лог-процессор, который будет забирать логи с stdout/stderr приложения и надёжно куда-то их писать/отправлять.
Тогда может лучше кубернетес и писать логи в файл? А лог процессор — сайдкартом?
Чек-лист: что нужно было делать до того, как запускать микросервисы в prod