Русский
Русский
English
Статистика
Реклама

Devops

PVS-Studio, Blender цикл заметок о пользе регулярного использования статического анализа

03.03.2021 20:06:54 | Автор: admin

PVS-Studio мониторит код Blender
В статьях мы регулярно повторяем важную мысль: статический анализатор должен использоваться регулярно. В этом случае многие ошибки выявляются на самом раннем этапе, а их исправление максимально дёшево. Однако теория это одно, но намного лучше подкреплять слова практическими примерами. Рассмотрим несколько свежих ошибок, появившихся в новом коде проекта Blender.


Недавно мы настроили регулярную проверку проекта Blender, о чём мой коллега рассказал в статье "Just for fun: команда PVS-Studio придумала мониторить качество некоторых открытых проектов". В дальнейшем планируем начать мониторить ещё некоторые интересные проекты.


Сразу скажу, что мы не ставим перед собой задачу найти как можно больше ошибок. Целью является периодическое написание небольших заметок (таких как эта), в которых мы будем на практике показывать достоинства регулярного анализа кода. Другими словами, мы иногда будем описывать некоторые интересные ошибки в новом коде, найденные при очередном ночном запуске PVS-Studio, и тем самым популяризировать правильное использование методологии статического анализа кода.


Итак, давайте посмотрим, что найдено в свежем коде проекта Blender.


Фрагмент первый: double-checked locking


typedef struct bNodeTree {  ....  struct NodeTreeUIStorage *ui_storage;} bNodeTree;static void ui_storage_ensure(bNodeTree &ntree){  /* As an optimization, only acquire a lock if the UI storage doesn't exist,   * because it only needs to be allocated once for every node tree. */  if (ntree.ui_storage == nullptr) {    std::lock_guard<std::mutex> lock(global_ui_storage_mutex);    /* Check again-- another thread may have allocated the storage       while this one waited. */    if (ntree.ui_storage == nullptr) {      ntree.ui_storage = new NodeTreeUIStorage();    }  }}

Предупреждение PVS-Studio. V1036: Potentially unsafe double-checked locking. node_ui_storage.cc 46


Перед нами неправильная реализация блокировки с двойной проверкой. Для пояснения проблемы процитирую фрагмент статьи "C++ and the Perils of Double-Checked Locking", написанной Scott Meyers и Andrei Alexandrescu ещё в 2004 году. Как видите, проблема давно известна, но это не защищает разработчиков от того, чтобы наступать на одни и те же грабли. Хорошо, что анализатор PVS-Studio помогает выявлять подобные проблемы :). Итак, фрагмент из статьи:


Consider again the line that initializes pInstance: pInstance = newSingleton;

This statement causes three things to happen:

Step 1: Allocate memory to hold a Singleton object.

Step 2: Construct a Singleton object in the allocated memory.

Step 3: Make pInstance point to the allocated memory.

Of critical importance is the observation that compilers are not constrainedto perform these steps in this order! In particular, compilers are sometimes allowed to swap steps 2 and 3. Why they might want to do that is a question we'll address in a moment. For now, let's focus on what happens if they do.

Consider the following code, where we've expanded pInstance's initialization line into the three constituent tasks we mentioned above and where we've merged steps 1 (memory allocation) and 3 (pInstance assignment) into a single statement that precedes step 2 (Singleton construction). The idea is not that a human would write this code. Rather, it's that a compiler might generate code equivalent to this in response to the conventional DCLP source code (shown earlier) that a human would write.

Если вы хотите подробнее разобраться с написанием блокировки с двойной проверкой, то отсылаю вас к описанию диагностики и статьи, ссылки на которые были даны выше. Для нас важно другое.


Подобные ошибки очень коварны! Они могут очень редко проявлять себя. Программа вроде как работает, проходит все тесты и так далее. Но время от времени она неожиданно падает у пользователей, и понять причину может быть крайне проблематично. Воспроизвести такую ошибку может быть очень сложно. Другим словами, исправление этой ошибки по жалобе от пользователей может обойтись в 1000 раз дороже, чем правка кода, сделанная по результату анализа кода с помощью PVS-Studio или аналогичного инструмента.


Примечание. Ошибка может и не существовать сейчас в двоичном коде, и всё зависит от компилятора, и ключей оптимизации. Однако, даже если сейчас всё работает хорошо, это не значит, что так будет всегда. Ошибка может проявить себя при смене компилятора/ключей оптимизации.


Фрагмент второй: realloc


static void icon_merge_context_register_icon(struct IconMergeContext *context,                                             const char *file_name,                                             struct IconHead *icon_head){  context->read_icons = realloc(context->read_icons,    sizeof(struct IconInfo) * (context->num_read_icons + 1));  struct IconInfo *icon_info = &context->read_icons[context->num_read_icons];  icon_info->head = *icon_head;  icon_info->file_name = strdup(path_basename(file_name));  context->num_read_icons++;}

Анализатор PVS-Studio выдаёт здесь два предупреждения, и это правильно. Здесь действительно допущено сразу две ошибки различного плана.


Первая: V701: realloc() possible leak: when realloc() fails in allocating memory, original pointer 'context->read_icons' is lost. Consider assigning realloc() to a temporary pointer. datatoc_icon.c 252


Если память не удастся выделить, функция realloc вернёт значение NULL. Нулевой указатель будет записан в переменную context->read_icons, а её предыдущее значение будет потеряно. Раз предыдущее значение указателя потеряно, то и невозможно освободить ранее выделенный блок памяти, на который ссылался этот указатель. Произойдёт утечка памяти.


Вторая: V522: There might be dereferencing of a potential null pointer 'context->read_icons'. Check lines: 255, 252. datatoc_icon.c


Описанная выше ошибка в каком-то смысле и не ошибка с точки зрения автора кода. Он и не собирался писать код, который будет продолжать работу в случае невозможности увеличения блока выделенной памяти. Такой случай просто не рассматривается. Автор предполагает, что, если память выделить не удалось, программа просто аварийно завершится при разыменовании нулевого указателя. И поэтому смело работает с указателем, не выполняя его предварительную проверку. Оставим в стороне вопрос, насколько красивым является такое поведение программы. На мой взгляд, такое поведение библиотек недопустимо.


Интереснее другое. На самом-то деле падение может и не произойти. Запись производится вовсе не по нулевому указателю, а куда-то дальше. Теоретически возможна ситуация, когда этот адрес уже не находится в странице памяти, защищенной от записи, и никакого падения не будет. Будут испорчены какие-то случайные данные в памяти, и программа продолжит своё выполнение. Последствия работы с испорченными данными непредсказуемы. Подробнее всё это разобрано в статье "Почему важно проверять, что вернула функция malloc".


Фрагмент третий: разыменование указателя для проверки


static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event){  ....  bNodeLinkDrag *nldrag = node_link_init(bmain, snode, cursor, detach);  nldrag->last_picked_multi_input_socket_link = NULL;  if (nldrag) {    op->customdata = nldrag;  ....}

Предупреждение PVS-Studio: V595: The 'nldrag' pointer was utilized before it was verified against nullptr. Check lines: 1037, 1039. node_relationships.c


Один из самых частых паттернов ошибок (proof). В начале указатель nldrag разыменовывается. Но из следующего условного оператора становится видно, что на самом деле этот указатель может быть нулевым.


Всё просто и понятно. Но, согласитесь, намного лучше поправить такую ошибку сразу, ещё на этапе написания кода, а не после того, когда на неё наткнётся тестировщик или пользователь.


Кстати, нашлась ещё одна такая-же ошибка, но описывать её неинтересно. Приведу только сообщение: V595: The 'seq' pointer was utilized before it was verified against nullptr. Check lines: 373, 385. strip_add.c


Заключение


Используйте статические анализаторы кода регулярно. От этого выиграют как разработчики, так и пользователи. Вы можете скачать и попробовать PVS-Studio здесь. Спасибо за внимание.


Если хотите поделиться этой статьей с англоязычной аудиторией, то прошу использовать ссылку на перевод: Andrey Karpov. PVS-Studio, Blender: Series of Notes on Advantages of Regular Static Analysis of Code.

Подробнее..

Перевод CICD обещания и реальность

24.02.2021 14:21:40 | Автор: admin


Мы говорим CI/CD и подразумеваем непрерывную интеграцию. Никто не имеет в виду (и не практикует) непрерывный деплоймент. Вообще никогда. О нем все забыли. Пора это изменить.


Поучительная история


Один большой и страшный пиратский корабль наводил ужас на всю округу, хоть и подтекал немножко. После шторма или битвы пиратам нередко приходилось откачивать воду с нижних палуб.


Однажды в особо яростном бою пушечные ядра пробили борт под ватерлинией. Ни инструментов, ни плотников, чтобы заделать пробоины, у них не было, так что они просто откачивали воду без остановки. Сначала все получалось, но потом пришлось купить в два раза больше насосов и расширить экипаж.


Скоро они обнаружили, что насосами занимается больше людей, чем кораблем и грабежами. Это было как-то не по-пиратски и очень раздражало. Они стали первоклассными экспертами по откачиванию воды из трюма, зато навыки мореплавания и абордажей применять было некогда. Их лучшие люди заметно заскучали. И года не прошло, как корабль затонул.


Мораль истории такова: устраняйте не симптомы, а причину.


Что подводит нас к разговору о CI/CD?


CI/CD (непрерывная интеграция и доставка, или деплоймент) это часть нашей жизни. Мы ходим на конференции по CI/CD, пишем статьи о CI/CD, ведем блоги о CI/CD, указываем CI/CD на странице LinkedIn. Никто даже не спорит, надо оно нам или нет. Мы все одинаково обожаем CI/CD. Так ведь?


Вот только мы говорим CI/CD и подразумеваем непрерывную интеграцию. Никто не имеет в виду (и не практикует) непрерывный деплоймент. О нем все забыли.


Нет, это замечательно, что мы так поднаторели в непрерывной интеграции за последние лет десять. Но этого же мало. Это даже не половина. Можно подумать, цель непрерывной интеграции наслаждаться своим красивым синтаксисом и логикой. Хотя это приятный бонус, кто же спорит. По факту же CI это просто подготовка к следующему этапу непрерывной доставке. Потому что вообще-то в этом вся суть.


Как пираты на этом злосчастном корабле, мы должны лечить причины, а не заниматься симптомами. А что делает дыры в нашем продакшен-корабле? Да все что угодно. Все, что происходит между моментом написания кода и его релизом, пока он проходит по этой затянутой, подтекающей, раздутой, комковатой и нестабильной системе переваривания программного обеспечения.


Что это вообще такое CI/CD?


Отличный вопрос. Отвечу с удовольствием. CI/CD это процесс и методология, цель которой убедиться, что весь код, вливаемый в главную ветку, можно в любое время протестировать и задеплоить. Автоматически. После каждого дифа.


Цель конвейера CI/CD ускорить внедрение изменений в программах настолько, чтобы мы не успевали выпасть из контекста и забыть, что это были за изменения.


Если любой в вашей команде может отправить изменения в главную ветвь, точно зная, что через 15 минут они будут протестированы и развернуты в продакшене без человеческого вмешательства, наши поздравления! Вы используете CI/CD.


Жаль, что редкая команда может похвастаться этим. Хотя это основы гигиены разработки.


Гибельный водоворот разработки


Представьте, что между разработкой и доставкой ваш код лежит в чашке Петри при комнатной температуре и обрастает вредными бактериями. Чем дольше лежит, тем крупнее дифы и медленнее ревью. Приходится ковыряться в этих монстрах и всматриваться в контекст при переходе с написания кода на ревью и обратно.


Цикл обратной связи растягивается в сторону бесконечности, люди на каждом этапе все дольше ждут друг друга (ревью, комменты, деплои, реализация изменений), и каждый раз приходится заново во все вникать и запоминать, на чем ты остановился и что вообще пытался сделать.


И даже это еще не все. Обычно мы деплоим код вручную через сто лет после его написания. Причем делает это не автор кода. В худшем случае мы выкатываем изменения от нескольких разработчиков за раз. В итоге люди не видят результаты своей работы сразу и не могут нести всю ответственность за жизненный цикл кода.


Если изменения деплоятся пакетом, невозможно отследить эффект каждого фрагмента кода по отдельности. Мы не знаем, когда выйдет код, кто отвечает за изменения в продакшене, поэтому у нас нет ни прав, ни обязанностей в отношении собственного кода. В результате инженеры большую часть времени ждут, суетятся или разбираются с техническим долгом. Никакой пользы бизнесу это не приносит.


Раз все имеющиеся разработчики заняты, нужно нанять много новых и потратить еще больше усилий на их координацию. Скоро вам понадобятся отдельные должности SRE, Ops, QA, билд-инженер, чтобы героически бороться с каждым симптомом по отдельности. Для этой оравы нужно будет больше менеджеров и так далее. Вуаля! Получаем огромную, дорогую и неповоротливую компанию.


Все становится еще медленнее, еще труднее, еще запутаннее. Нужно больше ресурсов, чтобы управлять этой навороченной системой и бороться с побочными эффектами, которые только усугубляют ситуацию. Нас затягивает в гибельный водоворот разработки. Есть и другой путь! Мы можем изначально делать все возможное, чтобы сократить интервал между написанием строки кода и ее полноценным деплойментом в продакшене. Это должно стать нашей навязчивой идеей. Давайте автоматизируем этот интервал, будем отслеживать его, потратим драгоценные ресурсы на его сокращение.


Пока у нас не будет рабочего цикла обратной связи, мы будем снова и снова бороться с симптомами. Чем дольше задержка, тем заметнее симптомы и тем больше времени мы тратим на откачку воды из трюма.


Каким должен быть интервал? В идеале 15 минут. Максимум час. Предсказуемость важна не меньше продолжительности, поэтому человек тут будет только мешать. Если сейчас вам требуется 15 дней, а не минут, не отчаивайтесь. Любые усилия по сокращению интервала обязательно окупятся. Любые!


Вижу, вы сомневаетесь. Моя команда, мол, такое не осилит, здесь вам не Facebook и не Google.


Вы идете сложным путем


Вы, наверное, удивитесь, но непрерывный деплоймент это самый простой способ писать, поставлять и выполнять код в продакшене. Звучит нелогично: делать много маленьких изменений быстро бесконечно проще, чем несколько больших изменений медленно.


Смотрите сами. Какой баг легче найти, понять, воспроизвести и исправить: баг в коде, который вы сами написали буквально только что, или баг в коде, который кто-то другой написал в прошлом году?


Как это вообще можно сравнивать? Пока код еще свеж в памяти, мы четко видим проблему и ее решение.


В процессе написания кода позаботьтесь о своем будущем я, которому через полчаса придется разбираться, получилось задуманное или нет. Итак, вы пишете код, отправляете его в главную ветку, ждете несколько минут и смотрите в продакшен. Все идет как надо? Или тут что-то не то?


В таком ритме разработчики обычно находят больше 80% всех багов сразу пока ничего еще не забылось и знаешь, на что смотреть. Если что-то пошло не так, можно тут же слепить еще один диф.


Команды, которые не практикуют такой рабочий процесс и не привыкли сразу оценивать изменения в продакшене, не находят эти баги. За них это делают клиенты.


Сложно, конечно, просто взять и начать по десять раз в день выпускать обновления для приложения, которое раньше обновлялось ежемесячно. Но вы удивитесь, как просто запустить приложение, в котором изначально предусмотрена непрерывная доставка, и сохранять этот темп, не выбиваясь из 15 минут. Скоро это войдет у вас в привычку и не будет отнимать много сил.


Если наладить CD для существующих приложений слишком сложно, попробуйте создать новые репозитории, сервисы и приложения, в которые уже заложен принцип CD. Любой CD лучше, чем его отсутствие. Если хотя бы часть кода будет деплоиться автоматически, команда освоит много полезных новых навыков. Например, сохранять обратную совместимость между версиями.


Задача номер 1 для технических руководителей в 2021 году


Почему мало кто пытается наладить непрерывную доставку? Для меня это загадка. Ведь у быстрого исполнения и короткого цикла обратной связи очень много преимуществ, о которых все прекрасно знают. Но, кажется, я начинаю понимать.


Создается впечатление, что это не техническая задача, а вопрос персонала, проблема управленцев. Руководители привыкли решать такие проблемы своими инструментами нанимая больше сотрудников.


А высшее руководство и вовсе сложно убедить в пользе такого подхода. Мы же просим их отложить план выпуска в краткосрочном периоде и согласиться на снижение надежности на неопределенное время, чтобы реализовать нечто противоречащее логике, которая подсказывает: чем медленнее, тем безопаснее.


В целом разработчики понимают ценность непрерывной доставки. Многие из них мечтают работать в таком режиме. Если у вас уже налажен CI/CD, это повысит вашу привлекательность как работодателя. Но главное ваша команда сможет эффективнее использовать существующий процесс разработки.


В конце хочу упомянуть плюсы для технических руководителей и директоров. Вам бы понравилось, если бы ваши разработчики работали с энтузиазмом и выкладывались на полную, а не тратили время на тушение пожаров, бесконечные технические долги и ожидания ревью от коллег?


Вам бы понравилось, если бы ваши специалисты всегда вспоминали вас как человека, который изменил их мышление и подход к разработке, и были благодарны вам за то, что помогли им выйти на новый уровень? Все зависит от вас.


Не надо быть гением, чтобы раскрыть весь потенциал CI/CD. Честное слово. Надо просто приложить чуть больше усилий к тому, чтобы наладить этот процесс. Хорошие специалисты вырастают в хороших командах.


При использовании непрерывной доставки разработчики несут всю ответственность за свой код в продакшене. Но это не единственное преимущество. У вас появляются полезные привычки писать маленькие дифы, быстро ревьюить код, воплощать свои изначальные намерения, использовать переключатели функций, разделять деплои и релизы и т. д.


Можно целыми днями цепляться к разработчикам и требовать, чтобы они подчищали код и следовали лучшим методам по отдельности, а можно приложить все усилия, чтобы сократить цикл обратной связи, и тогда все встанет на свои места само по себе.


Сложно ли это? Еще как. Надеюсь, мне удалось вас убедить, что оно того стоит. Это изменит вашу жизнь. Это шаг к социотехническим системам будущего. Чем больше команд его сделают, тем лучше. А какой у вас план по CI/CD на 2021 год?


Узнать больше о CI/CD и получить практику создания пайплайнов можно на курсе Слёрма CI/CD на примере Gitlab CI.
Подробнее..

Свидетели DevOps мифы и байки про девопсов и тех, кто их нанимает

25.02.2021 10:21:06 | Автор: admin

Те, кто решил стать девопсом, видят в этой профессии заманчивые перспективы. Это новый уровень мышления, это творчество и возможность создавать, это безграничные просторы для самосовершенствования. Не секрет также, что девопсам хорошо платят. Вместе с тем, вокруг понятия DevOps сформировался некий культ, овеянный мифами и легендами.

Вот уже несколько лет я набираю на работу девопсов. Путеводная звезда приводила к нам в компанию разных соискателей, в том числе весьма курьезных: от программистов микроконтроллеров до арт-директора, который после 40 вдруг узрел новое призвание. Был даже студент-африканец, который едва говорил по-русски, но уже сделал головокружительную карьеру ростовой куклы, распугивающей пассажиров у выхода из метро. Но за анекдотическими ситуациями кроется главная проблема: по-настоящему квалифицированные люди это крупицы и большая редкость

На эту тему было уже немало публикаций, но острота темы не отпускает. Под катом я поделюсь своими наблюдениями о том, какие типовые ошибки совершают и кандидаты, и практикующие девопсы, а также расскажу, что следует делать их по-разному везучим работодателям. Не обошлось и без злобных баек.

Трудности перевода

Справедливости ради оговорюсь, что DevOps это не название профессии, а методология. Она описывает набор подходов и практик, которые помогают командной разработке. Но штампы преследуют нас повсюду. И вот уже не режет слух, когда уважаемый заказчик, представляя свою команду на установочном звонке, говорит: А это Антон, наш девопс. Знакомьтесь, DevOps. Человек и пароход.

Помню, как в институтские годы мой школьный друг, поселившись в общаге, отгонял соседа по комнате от компа, кидаясь в него консервированной килькой и негромко приговаривая, что программистов нельзя подпускать к технике, так как они ее неизбежно ломают. В этой очаровательной бытовой зарисовке отражен давний конфликт, когда разработчик во всем винит окружение, а эксплуатация кривой код.

Поэтому девопс в классической интерпретации это либо программист, который стал админить, либо админ, который начал программировать. Это если уж совсем просто. Его задача выступить связующим звеном между двумя лагерями, привнести в их работу синергию и тем самым сберечь запасы кильки и других ценных промысловых пород.

Однако, девопс девопсу рознь. И кажется, что девопс стал эдаким расхожим понятием, которое подменило нынче массу остальных профессий.

Байка про хромого девопса

Недавно нас позвали на помощь в один проект, где стояла, на первый взгляд, простая задача. Web-приложение работало через web-сокеты, но было развернуто внутри периметра, а на фронте стоял ISPManager, который в качестве reverse proxy использовал apache. Юный девопс, работавший в этом проекте, перепробовал все примеры конфига апача, которые нашел в Гугле, и вконец разочаровавшись в его поисковых способностях, перешел уже было к Яндексу, но тут менеджер проекта забил тревогу. На задачу к тому моменту было потрачено 72 часа. 72 часа, Карл! Кто вам сказал, что методология DevOps ускоряет разработку и сокращает time-to-market? ;)

К сожалению, я и мои коллеги все чаще замечаем, что новоиспеченные девопсы имеют довольно туманные представления об устройстве операционной системы, а навыки ее администрирования и траблшутинга оставляют желать лучшего. Не зная как следует матчасть, такой специалист, оказавшись в нештатной ситуации, быстро превращается в вареную морковку и разводит руками, пораженный чувством беспомощности. Клянет неизвестные баги, ссылается на мистику и чудовищное стечение обстоятельств.

Согласитесь, чтобы говорить на иностранном языке, недостаточно изучить только слова. В любом языке есть еще и правила грамматические, лексические, стилистические. Более того, основу языка составляют уважаемые буквы. Практики DevOps своего рода тоже язык, где работает та же логика. Недостаточно просто освоить модные инструменты. Без технической и концептуальной подготовки они рискуют просто оказаться микроскопом, которым колют орехи.

Но я не хочу возлагать всю вину только на ребят, так как у любой проблемы, как водится, причин много. Это и обилие технологий, и скорость, которая требуется в их освоении и применении, и тот самый кадровый дефицит. Многие осознают белые пятна в своих знаниях, но не находят времени и сил их целенаправленно закрывать. Для таких мы, кстати,запустили целый курс будет полезно и тем, кто только грезит о новой профессии, и тем, кто уже попробовал свои силы, но чувствует, что нехватка основ мешает развиваться уверенно.

Про технологии

DevOps это про культуру и философию совместной работы, но с этим понятием также сопряжен определенный технологический стек. Скорее всего я не ошибусь, если скажу, что какие-нибудь NetApp, Cisco, AIX или MS SQL воспринимаются как старый добрый олдскул (хотя это не совсем так, и классические вендоры делают гигантские шаги в новом направлении), а вот, скажем, Docker, Ansible, Jenkins и Prometheus в нашем сознании прочно ассоциируются с DevOps, SRE и новыми веяниями.

Но каким бы ни был стек, каждым инструментарием нужно владеть, разбираясь в его сути и основах. Делая настройку, нужно знать не только, что надо сделать, но и почему надо сделать так, и что будет, если сделать не так, а иначе.

Найти в гугле пример и скопипастить его к себе еще один легкий путь отхватить проблем. Типичный пример тюнинг и оптимизация сети и ядра через параметры sysctl. Конфиг, который удачно сработал для кого-то в интернете, не является волшебной пилюлей для любой другой системы. Как минимум, надо разобраться, что каждая директива значит. Может в вашей версии ядра она вообще deprecated.

И отдельная боль это сеть. В сети надо разбираться, владеть инструментами диагностики. Сеть не зависит от платформы, она есть везде и напрямую (а порой больно) влияет на работоспособность и производительность всего остального. Когда человек, грезящий себя девопсом, наивно полагает, что надо установить свежую версию Kibana, потому что она умеет конвертировать адреса IPv6 в IPv4 это звучит как анекдот. Но потом он, например, берет и орудует с сетью вот так:

или вот так:

Дальше хочу немного заострить внимание на двух технологиях, которые почти стали синонимами DevOps.

А давайте-ка все распилим на микросервисы, засунем в Docker и запустим в Kubernetes

Идея микросервисов прекрасна и выражается в том, чтобы программа перестала быть неповоротливым монстром, а превратилась в набор слабосвязанных компонентов, каждый из которых можно развивать отдельно. А вместе они взаимодействуют посредством унифицированных вызовов. Людей, изможденных поддержкой и обновлением монолита, микросервисная архитектура вдохновляет тревожной надеждой, что вот наконец-то судьба поспешила им на выручку.

Но не все следует доводить до маразма, даже если это увлекательно. Недавно моей команде на попечение был передан проект разработки мобильного приложения, в котором до нас один одаренный девопс настроил деплой бэкэнда на тестинг и продакшн, а затем от греха подальше уволился. Бэкэнд, по сути, представлял собой приложение на python, упакованное в один единственный контейнер. И этот одинокий контейнер исполнятся на одном физическом хосте. Мы читали путанный многоэтажный Dockerfile и искренне недоумевали, зачем все это надо было вообще совать в контейнер. Точнее, в контейнере ему и место, но не в этом.

Пока мы переваривали увиденное, в соседнем проекте разворачивалась новая драма. Этот же товарищ оставил после себя несколько обреченных проектов, но в этом размах был самым масштабным. Почерк автора угадывался повсюду среди двух десятков виртуалок: все в контейнерах, контейнеры случайным образом раскиданы по хостам, где-то живут в одиночку, но даже там, где они как-то совмещены, особой логики не просматривалось. Ребилд контейнера представляет собой варварскую бойню, когда затирается все, что установлено локально, а в конце с нуля воссоздается все окружение и празднично приезжает образ версии latest.

Вот, кстати, символичный фрагмент одного из скриптов по деплою:

Хорошо, что мы не дали запустить это в прод, так как не нашли в этой малопонятной архитектуре ни одного сервиса, который можно было бы безболезненно передернуть, не положив весь конечный функционал.

Хочу также на полях заметить, что микросервисная архитектура совсем не обязательно означает контейнеры. Просто контейнеры оказались удобной портативной упаковкой для этих модулей.

А про кубер вспоминается недавно гулявший ролик, где старый фильм озвучили новыми словами:

- А у вас есть kubernetes?

- Да, конечно, ну как у всех! Как полагается.

- А зачем?

- Ну как это зачем? Это же

Дальше следует немая сцена, гримаса ужаса и спустя некоторое время человек, вероятно, идет топиться.

Я считаю себя евангелистом подхода Infrastructure as Code (IaC). Мне спокойно только тогда, когда продукт не просто освоен, а когда его развертывание и настройка автоматизированы. Специально не добавляю слово документированы, потому что декларативный характер инструментов IaC что приятно во много порождает автодокументируемый код.

Кубер в этом смысле апофеоз описательного подхода к управлению сервисами. Но надо понимать, что закатить свой приклад в кубер потребует немало усилий и времени, которые кратно превышают трудозатраты для развертывания в классическом окружении. И для кубера должны быть веские причины.

Для иллюстрации пример, который подвернулся на скорую руку это варианты, как можно запустить телеграм-бот для Alertmanager (взято отсюда).

Просто через docker run:

docker run

docker run -d \

-e 'ALERTMANAGER_URL=http://alertmanager:9093' \

-e 'BOLT_PATH=/data/bot.db' \

-e 'STORE=bolt' \

-e 'TELEGRAM_ADMIN=1234567' \

-e 'TELEGRAM_TOKEN=XXX' \

-v '/srv/monitoring/alertmanager-bot:/data' \

--name alertmanager-bot \

metalmatze/alertmanager-bot:0.4.3

С помощью docker-compose

docker-compose

networks:

alertmanager-bot: {}

services:

alertmanager-bot:

command:

- --alertmanager.url=http://localhost:9093

- --log.level=info

- --store=bolt

- --bolt.path=/data/bot.db

environment:

TELEGRAM_ADMIN: "1234"

TELEGRAM_TOKEN: XXXXXXX

image: metalmatze/alertmanager-bot:0.4.3

networks:

- alertmanager-bot

ports:

- 8080:8080

restart: always

volumes:

- ./data:/data

version: "3"

А вот тот же сервис в Kubernetes

кубер

apiVersion: v1

items:

- apiVersion: v1

data:

admin: MTIzNA==

token: WFhYWFhYWA==

kind: Secret

metadata:

labels:

app.kubernetes.io/name: alertmanager-bot

name: alertmanager-bot

namespace: monitoring

type: Opaque

- apiVersion: v1

kind: Service

metadata:

labels:

app.kubernetes.io/name: alertmanager-bot

name: alertmanager-bot

namespace: monitoring

spec:

ports:

- name: http

port: 8080

targetPort: 8080

selector:

app.kubernetes.io/name: alertmanager-bot

- apiVersion: apps/v1

kind: StatefulSet

metadata:

labels:

app.kubernetes.io/name: alertmanager-bot

name: alertmanager-bot

namespace: monitoring

spec:

podManagementPolicy: OrderedReady

replicas: 1

selector:

matchLabels:

app.kubernetes.io/name: alertmanager-bot

serviceName: alertmanager-bot

template:

metadata:

labels:

app.kubernetes.io/name: alertmanager-bot

name: alertmanager-bot

namespace: monitoring

spec:

containers:

- args:

- --alertmanager.url=http://localhost:9093

- --log.level=info

- --store=bolt

- --bolt.path=/data/bot.db

env:

- name: TELEGRAM_ADMIN

valueFrom:

secretKeyRef:

key: admin

name: alertmanager-bot

- name: TELEGRAM_TOKEN

valueFrom:

secretKeyRef:

key: token

name: alertmanager-bot

image: metalmatze/alertmanager-bot:0.4.3

imagePullPolicy: IfNotPresent

name: alertmanager-bot

ports:

- containerPort: 8080

name: http

resources:

limits:

cpu: 100m

memory: 128Mi

requests:

cpu: 25m

memory: 64Mi

volumeMounts:

- mountPath: /data

name: data

restartPolicy: Always

volumes:

- name: data

persistentVolumeClaim:

claimName: data

volumeClaimTemplates:

- apiVersion: v1

kind: PersistentVolumeClaim

metadata:

labels:

app.kubernetes.io/name: alertmanager-bot

name: alertmanager-bot

namespace: monitoring

spec:

accessModes:

- ReadWriteOnce

resources:

requests:

storage: 1Gi

storageClassName: standard

kind: List

Если решение все же принято, вам предстоит перелопатить горы документации, написать тонны yaml-a, мучительно искать, где пропущен отступ, по 10 раз пересобирать контейнеры. И в этом момент вы еще и не знаете, что через пару недель пройдете новый круг ада, подстраивая ваш деплоймент под Pod Security Policy и разные энтерпрайзные фичи. Конечно, когда вы это дотащите до конца, вы получите красивый сервис, который легко скейлится, автоматически перезапускается при сбоях, который можно обновлять, используя, например, канареечные релизы или какой-нибудь blue-green deployment.

Но все же я хочу подчеркнуть - это нужно не везде и не всегда. Вместо того, чтобы слепо идти за зовом моды, нужно трезво оценивать баланс усилий и пользы. Девопсы, в том числе трушные, нередко имеют свойство увлекаться технологическом изяществом, благодаря чему постоянно создают на своем пути искусственные трудности, которые потом же мужественно преодолевают.

Автоматизация как истинный путь джедая

Наши бэкапшики помнят один случай, как сотрудник заказчика собирался в консоли что-то удалить то ли ненужный симлинк, то ли копию конфига. А его то и дело дергали. По воле случая в один момент так сошлось, что товарищ успел набрать rm -rf /oradata, работая от рута, потом чихнул, что в свою очередь пробудило в его организме рута позывы на исход жидкости, а по дороге обратно он зацепился языками с товарищами. Когда он вернулся на рабочее месте, его экран спал. Не будучи в силах терпеть проделки этого вечно дремлющего устройства и дабы преподнести ему урок бодрости, товарищ решительно разбудил его точным ударом в Enter. В общем, когда все делаешь руками, нелепые вещи случаются сплошь и рядом.

Автоматизацию я считаю главной чертой современных подходов к управлению ИТ. Только автоматизация помогает действительно сократить время, которое обычно тратится на рутинные, повторяющиеся задачи, и только она может минимизировать влияние человеческого фактора.

Самое плохое в автоматизации это время, которое надо на нее потратить. И самое хорошее в ней тоже время, которое она впоследствие высвобождает. Например, пару лет назад нам потребовалось в нашем облаке IaaS развернуть инфраструктуру под нового e-commerce заказчика. Архитектура проекта: кластер БД, пул серверов приложений, распределенное хранилище, слой кэширования, сетевые балансировщики, WAF, ну и стандартная обвязка в виде телеметрии, СРК и сбора логов с визуализацией. Конечно, виртуальные машины мы давно создавали при помощи terraform, благо под наше облако можно использовать AWS-провайдер, так как мы по API совместимы. Программные компоненты и раньше ставили через ansible, и опыт настройки всего по отдельности, в общем, был. Но мы задались целью описать инфраструктуру проекта в виде единого пайплайна. На это ушло время, ну и до сих пор части этой автоматизации совершенствуются, так как еще много где были нами после переиспользованы.

Когда нам позже подвернулся аналогичный проект, различия описывались на уровне файла ответов. Мы развернули проект за 2 дня, причем большую часть времени занял перенос данных. В Gitlab CI запускался pipeline, который заполнял переменные для terraform, который затем запускался runner-ом. Тот создавал в облаке сети, диски и ВМ. ВМ запускались с cloud-init, который ставил внутрь puppet agent, который после старта связывался с foreman, забирал настройки для своей роли и деплоил все ПО. Через service discovery подключался мониторинг всех служб, везде встал и настроился filebeat, а бакап полился в S3. Voila! Все быстро и четко, без ошибок и ручных тестов на каждом шаге.

По нашим многолетним наблюдениям основные беды уже развернутых систем в основном сводятся к небольшому, довольно банальному списку причин. На борьбу с этими бедами расходуется много ресурсов, оттягивая их от куда более важных дел. Мы даже стали замечать, что крупный бизнес, пытаясь отгородить своих ценных гиков-девопсов от этого скучного труда, стал передавать такие задачи на аутсорс.

Вместе с тем, выполнение следующих правил способно практически нивелировать эффект самозагнивания (когда ломается само по себе с течением времени). Для этого нужно:

  • осмысленный сайзинг ресурсов;

  • отдельные точки монтирования (отдельный диск/раздел) под данные приложений и все, что может быстро пухнуть;

  • синхронизацию времени по ntp;

  • переход на использование ключей вместо паролей в ssh;

  • настроить ротацию всех логов;

  • иметь автоматический механизм обновления протухающих SSL-сертификатов

  • покрыть мониторингом все ключевые показатели жизнеспособности системы и не забыть про алерты;

  • если в системе есть данные, иметь автоматический бэкап по расписанию, и не хранить его рядом с данными.

Если система работает на физическом оборудования, сюда надо добавить дублирование дисков и агрегацию сетевых интерфейсов.

Эти простые меры по принципу Парето составляют не более 20% действий по первичной настройке, но дают 80% вклада в стабильную и автономную их работу в будущем.

Если у вас уже есть provision-система, то следом можно подключить инструмент IaC, и накатывать все эти настройки всегда по умолчанию, через какой-нибудь базовый профиль. Я в такой профиль еще включаю набор обязательных утилит, чтобы, к примеру, в экстренной ситуации не оказалось, что в системе нет lsof, tcpdump и т. п.

Время и внимание хорошего девопса такие проблемы не отнимают, потому что он их еще в самом начале решил.

Как не стать героем баек

В игре, которую мы ведем в жизни, многое зависит не только от того, что мы знаем и умеем, как и от того, насколько в себя верим. Между состояниями, когда ты еще просто админ, и когда ты уже причислен к сословию девопсов граница весьма призрачная. И по упомянутым выше причинам люди стараются быстрее ее пересечь. Поучился по видосикам на ютубе девопс. Запустил хром в докере у себя на компе девопс. Засунул в гит всю свою папку с котиками ну, тоже девопс.

Но на самом деле с изобретением DevOps наш мир радикально не поменялся. Он по-прежнему подчиняется законам физики, логики и здравого смысла. Просто невозможно стать качественным специалистом за несколько месяцев, пройдя курсы в онлайн-школе, обещающей сделать из вас гика. Настоящая квалификация куется годами, настоящий опыт мы получаем в основном на ошибках.

Нанимая ребят на позиции linux-инженеров/devops, мы в первую очередь смотрим на их способность мыслить, рассуждать, выстраивать цепочку связей. Немаловажен широкий технический кругозор и реальный практический опыт. И мы совершенно точно отдаем предпочтение тому кандидату, который лучше знает матчасть, так как больше уверены, что и с модными технологиями ему не составит труда разобраться.

И напоследок завет работодателям

Порой из-за хайпа кажется, что эти космические люди, творящие чудеса в консоли, всемогущи но один девопс, даже самый талантливый, не может знать всего. ИТ давно уже превратилась в обширную отрасль, и в ней, как в медицине, два человека в белых халатах могут совсем друг друга не понимать. Когда стоматолог рассказывает проктологу про зубы, то вяло улыбается, потому что крыть нечем.

Если вам понадобился девопс, у вас вероятно уже есть разработка. Задачи, которые выполняет девопс это та же разработка, только инфраструктуры и процессов, поэтому к ней в целом применимы те же правила. Над девопсом должен быть senior или тимлид, который через систему контроля версий делает code review, проверяет и одобряет PR/MR. И совершенно точно не стоит доверять архитектурные вопросы человеку без подтвержденного архитектурного опыта. Лучше поищите стороннюю экспертизу для подстраховки.

Мне также нравится концепция, когда отдельно от специалистов DevOps позиционируется еще одна команда - платформенных инженеров (Platform engineer). Она не работает непосредственно с девелоперами, но именно она снабжает девопса готовыми, отлаженными рычагами к этой платформе и уже настроенному инструментарию. Именно такой подход позволяет снизить планку требований к девопсу, позволяя ему спокойнее учиться и снижая риск его ошибок.

В этом месте ставлю не точку, а многоточие, так как тема неисчерпаемая и весьма холиварная. Комментарии, как говорится, покажут :)

Подробнее..

Перевод Вам (вероятно) нужны liveness и readiness probes

26.02.2021 10:11:26 | Автор: admin

Один из самых частых вопросов, которые мне задают как консультанту это: В чем разница между liveness и readiness пробами?. Следующий самый частый вопрос: Какие из них нужны моему приложению?.

Любой, кто пробовал за Duck Duck Go-ить этот вопрос знает, что на него непросто найти ответ в интернете. В этой статье, надеюсь, я смогу помочь вам ответить на эти вопросы самостоятельно. Я поделюсь своим мнением о том, каким образом лучше использовать liveness и readiness пробы в приложениях развернутых в Red Hat OpenShift. И я предлагаю не строгий алгоритм, а, скорее, общую схему, которую вы можете использовать для принятия своих собственных архитектурных решений.

Чтобы сделать абстракции более конкретными я предлагаю рассмотреть четыре общих примера приложений. Для каждого из них мы выясним нужно ли нам настраивать liveness и readiness probes, и если нужно, то как. Прежде чем перейти к примерам, давайте ближе посмотрим на эти два разных типа проб.

Примечание: Kubernetes недавно внедрили новую startup probe, доступную в OpenShift 4.5 clusters. Вы быстро разберетесь со startup probe, когда поймете liveness и readiness probes. Здесь я не буду рассказывать о startup probes.

Liveness и readiness probes

Liveness (работоспособности) и readiness (готовности) пробы это два основных типа проверок, доступных в OpenShift. Они имеют схожий интерфейс настройки, но разные значения для платформы.

Когда liveness проверка не проходит, то это сигнализирует OpenShiftу, что контейнер мертв и должен быть перезагружен. Когда readiness проверка не проходит, то это опознается OpenShiftом как то, что проверяемый контейнер не готов к принятию входящего сетевого трафика. В будущем это приложение может прийти в готовность, но сейчас оно не должно принимать трафик.

Если liveness проверка успешна, и в то же время readiness проверка не прошла, OpenShift знает, что контейнер не готов принимать сетевой трафик, но он работает над тем, чтобы прийти в готовность. Например, часто приложениям нужно длительное время для инициализации или для синхронной обработки длительных запросов. (Синхронная обработка длительных запросов - это анти-паттерн, но, к несчастью, мы сталкиваемся с этим в некоторых legacy-приложениях.)

Далее мы подробнее рассмотрим специфику использования каждой из этих проверок. Как только мы поймем как работает каждая из них, я покажу примеры того, как они работают вместе в OpenShift.

Для чего нужны liveness проверки?

Liveness проверка отправляет сигнал OpenShiftу, что контейнер либо жив (прошел проверку), либо мертв (не прошел). Если контейнер жив, тогда OpenShift не делает ничего, потому что текущее состояние контейнера в порядке. Если контейнер мертв, то OpenShift пытается починить приложение через его перезапуск.

Название liveness проверки (проверка живучести) имеет семантическое значение. По сути проверка отвечает Да или Нет на вопрос: Жив ли этот контейнер?.

Что если я не установил liveness проверку?

Если вы не задали liveness проверку, тогда OpenShift будет принимать решение о перезапуске вашего контейнера на основе статуса процесса в контейнере с PID 1. Процесс с PID 1 это родительский процесс для всех других процессов, которые запущены внутри контейнера. Так как каждый контейнер начинает жить внутри его собственного пространства имен процессов, первый процесс в контейнере берет на себя особенные обязательства процесса с PID 1.

Если процесс с PID 1 завершается и liveness пробы не заданы, OpenShift предполагает (обычно безопасно), что контейнер умер. Перезапуск процесса - это единственное не зависящее от приложения универсально эффективное корректирующее действие. Пока PID 1 жив, не зависимо от того, живы ли дочерние процессы, OpenShift оставит контейнер работать дальше.

Если ваше приложение это один процесс, и он имеет PID 1, то это поведение по умолчанию может быть именно тем, что вам нужно, и тогда нет необходимости в liveness пробах. Если вы используйте init инструменты, такие как tini или dumb-init, тогда это может быть не то, что вы хотите. Решение о том, задавать ли свои liveness вместо того, чтобы использовать поведение по умолчанию, зависит от специфики каждого приложения.

Для чего нужны readiness пробы?

Сервисы OpenShift используют readiness проверки (проверки готовности) для того, чтобы узнать когда проверяемый контейнер будет готов принимать сетевой трафик. Если ваш контейнер вошел в состояние, когда он все ещё жив, но не может обрабатывать входящий трафик (частый сценарий во время запуска), вам нужно, чтобы readiness проверка не проходила. В этом случае OpenShift не будет отправлять сетевой трафик в контейнер, который к этому не готов. Если OpenShift преждевременно отправит трафик в контейнер, это может привести к тому, что балансировщик (или роутер) вернет 502 ошибку клиенту и завершит запрос, либо клиент получит сообщение с ошибкой connection refused.

Как и liveness проверки, название readiness проба (проба готовности) передает семантическое значение. Фактически это проверка отвечает на вопрос: Готов ли этот контейнер принимать сетевой трафик?.

Что если я не задам readiness пробу?

Если вы не зададите readiness проверку, OpenShift решит, что контейнер готов к принятию трафика как только процесс с PID 1 запустился. Это никогда не является желаемым поведением.

Принятие готовности без проверки приведет к ошибкам (таким, как 502 от роутера OpenShift) каждый раз при запуске нового контейнера, при масштабировании или развертывании. Без readiness проб вы будете получать пакет ошибок при каждом развертывании, когда старые контейнеры выключаются и запускаются новые. Ели вы используете автоматическое масштабирование, тогда в зависимости от установленного порога метрик новые инстансы могут запускаться и останавливаться в любое время, особенно во время колебаний нагрузки. Когда приложение будет масштабироваться вверх или вниз, вы будете получать пачки ошибок, так как контейнеры, которые не совсем готовы получать сетевой трафик включаются в распределение балансировщиком.

Вы можете легко исправить эти проблемы через задание readiness проверки. Проверка дает OpenShift'у возможность спросить ваш контейнер, готов ли он принимать трафик.

Теперь давайте взглянем на конкретные примеры, которые помогут нам понять разницу между двумя типами проб и то, как важно задать их правильно.

Примечание: Из-за того, что у этих двух разных типов проверок одинаковый интерфейс часто возникает путаница. Но наличие двух или более типов проб - это хорошее решение: это делает OpenShift гибче для разных типов приложений. Доступность обеих liveness и readiness проб критична для репутации OpenShift как Container-as-a-Service, который подходит для широкого спектра приложений.

Пример 1: Сервер для отдачи статического контента (Nginx)

Рис. 1: Пример реализации сервера для отдачи статики NginxРис. 1: Пример реализации сервера для отдачи статики Nginx

В примере приложение, изображенное на рисунке 1 - это простой сервер для отдачи статики, который использует Nginx, чтобы отдавать файлы. Сервер запускается быстро и проверить, обрабатывает ли сервер трафик легко: вы можете запросить определенную страницу и проверить, что вернулся 200 код HTTP ответа.

Нужны ли liveness пробы?

Приложение запускается быстро и завершается, если обнаружит ошибку, которая не позволит ему отдавать страницы. Поэтому, в данном случае, нам не нужны liveness пробы. Завершенный процесс Nginx означает, что приложение умерло и его нужно перезапустить (отметим, что неполадки, такие как проблемы с SELinux или неправильно настроенные права в файловой системе могут быть причиной выключений Nginx, но перезапуск не исправит их в любом случае).

Нужны ли readiness пробы?

Nginx обрабатывает входящий трафик поэтому нам нужны readiness пробы. Всегда, когда вы обрабатываете сетевой трафик вам нужны readiness пробы для предотвращения возникновения ошибок во время запуска контейнеров, при развертывании или масштабировании. Nginx запускается быстро, поэтому может вам повезет и вы не успеете увидеть ошибку, но мы все ещё хотим предотвратить передачу трафика до тех пор, пока контейнер не придет в готовность, в соответствии с best practice.

Добавление readiness проб для сервера

Нам нужно будет сделать определенные изменения для каждого примера, но сначала, приведем здесь первую часть Deployment. Мы изменим этот файл по ходу статьи, но верхняя часть останется той же. В следующих примерах, нам нужно будет изменять только секцию template.

apiVersion: apps/v1kind: Deploymentmetadata:  labels:    app: application-nginx  name: application-nginxspec:  replicas: 1  selector:    matchLabels:      app: application-nginx  template:    metadata:      labels:        app: application-nginx    spec:      #  Will appear below as it changes

Здесь настройка проверки для первого примера:

    spec:      containers:      - image: quay.io/<username>/nginx:latest        name: application-nginx        imagePullPolicy: Always        ports:        - containerPort: 8443          protocol: TCP        readinessProbe:          httpGet:            scheme: HTTPS            path: /index.html            port: 8443          initialDelaySeconds: 10          periodSeconds: 5
Рис. 2: Реализация сервера Nginx для отдачи статики с настроенными readiness проверкамиРис. 2: Реализация сервера Nginx для отдачи статики с настроенными readiness проверками

Пример 2: Сервер заданий (без REST API)

Многие приложения имеют HTTP веб-компонент, а так же компонент выполняющий асинхронные задания. Серверу с заданиями не нужны readiness проверки, так как он не обрабатывает входящий трафик. Однако, ему в любом случае нужны liveness проверки. Если процесс, выполняющий задания умирает, то контейнер становится бесполезным, и задания будут накапливаться в очереди. Обычно, перезапуск контейнера является правильным решением, поэтому liveness пробы идеальны для такого случая.

Пример с приложением на рис. 3 это простой сервер заданий который забирает и запускает задания из очереди . Он не обслуживает напрямую входящий трафик.

Рис. 3: Реализация сервера заданий без liveness проверок.Рис. 3: Реализация сервера заданий без liveness проверок.

Я уже упоминал, что этот тип приложений выигрывает от наличия liveness проб, но более детальное пояснение не повредит в любом случае.

Нужны ли нам liveness пробы?

Когда сервер заданий запущен корректно, это будет живой процесс. Если контейнер сервера заданий перестает работать, это скорее всего означает сбой, необработанное исключение или что-то в этом духе. В этом случае настройка проверки будет зависеть от того, запущен ли процесс нашего задания с PID 1.

Если наш процесс задания запущен с PID 1, то он завершится, когда поймает исключение. Без настроенных liveness проверок OpenShift распознает завершение процесса с PID 1 как смерть и перезапустит контейнер. Для простого сервера заданий перезапуск может быть нежелательным поведением.

Однако, в реальной жизни ситуации могут быть сложнее. Например, если наш процесс с заданием получил deadlock, он может все ещё считаться живым, так как процесс запущен, но он определенно в нерабочем состоянии и должен быть перезапущен.

Чтобы помочь вычислить deadlock, наше приложение будет писать текущее системное время в миллисекундах в файл/tmp/jobs.updateкогда выполняет задание. Это время потом будет проверяться через shell команду (через exec liveness пробы) для того, чтобы убедиться, что текущее задание не запущено дольше определенного значения таймаута. Тогда приложение само сможет проверять себя на liveness выполняя/usr/bin/my-application-jobs --alive.

Мы можем настроить liveness так (опять же, я пропускаю первую часть YAML-файла Deploymenta, который я показывал ранее):

    spec:      containers:      - image: quay.io/<username>/my-application-jobs:latest        name: my-application-jobs        imagePullPolicy: Always        livenessProbe:          exec:            command:            - /bin/sh            - -c            - "/usr/bin/my-application-jobs --alive"          initialDelaySeconds: 10          periodSeconds: 5

Нужны ли readiness проверки?

В это случае readiness не нужны. Помним, что readiness пробы отправляют OpenShift сигнал о том, что контейнер готов принимать трафик и поэтому может быть добавлен в конфигурацию балансировщика. Так как это приложение не обрабатывает входящий трафик, оно не нуждается в проверке на готовность. Мы можем отключить readiness пробу. Рис. 4 показывает реализацию сервиса заданий с настроенными liveness проверками.

Рис. 4: Реализация сервера заданий с liveness проверкамиРис. 4: Реализация сервера заданий с liveness проверками

Пример 3: Приложение с рендерингом на стороне сервера с API

Рис. 5: SSR приложение без каких-либо проверокРис. 5: SSR приложение без каких-либо проверок

Это пример стандартного приложение рендеринга на стороне сервера SSR: оно отрисовывает HTML-страницы на сервере по востребованию, и отправляет его клиенту. Мы можем собрать такое приложение используя Spring Boot, PHP, Ruby on Rails, Django, Node.js, или любой другой похожий фреймворк.

Нужны ли нам liveness проверки?

Если приложение запускается за несколько секунд или меньше, то liveness проверки, скорее всего, не обязательны. Если запуск занимает больше нескольких секунд, мы должны настроить liveness проверки, чтобы понять, что контейнер инициализировался без ошибок и не произошел сбой.

В этом случае мы могли бы использовать liveness пробы типа exec, которые запускает команду в shell, чтобы убедиться, что приложение по-прежнему работает. Эта команда будет отличаться в зависимости от приложения. Например, если приложение создает PID файл, мы можем проверить, что он все еще жив:

        livenessProbe:          exec:            command:            - /bin/sh            - -c            - "[ -f /run/my-application-web.pid ] && ps -A | grep my-application-web"          initialDelaySeconds: 10          periodSeconds: 5

Нужны ли readiness пробы?

Так как данное приложение обрабатывает входящий трафик нам определенно нужны readiness пробы. Без readiness OpenShift немедленно отправит сетевой трафик в наш контейнер после его запуска, независимо от того, готово приложение или нет. Если контейнер начинает отбрасывать запросы, но не завершает работу аварийно, он продолжит получать трафик бесконечно, что, конечно же, не то, что нам нужно.

Мы хотим, чтобы OpenShift удалил контейнер из балансировщика, если приложение перестанет возвращать правильные ответы. Мы можем использовать readiness пробы, подобные этой, чтобы сообщить OpenShift, что контейнер готов к приему сетевого трафика:

        readinessProbe:          httpGet:            scheme: HTTPS            path: /healthz            port: 8443          initialDelaySeconds: 10          periodSeconds: 5

Для удобства, вот полный YAML для этого приложения из этого примера:

apiVersion: apps/v1kind: Deploymentmetadata:  labels:    app: backend-service  name: backend-servicespec:  replicas: 1  selector:    matchLabels:      app: backend-service  template:    metadata:      labels:        app: backend-service    spec:      containers:      - image: quay.io/<username>/backend-service:latest        name: backend-service        imagePullPolicy: Always        ports:        - containerPort: 8443          protocol: TCP        readinessProbe:          httpGet:            scheme: HTTPS            path: /healthz            port: 8443          initialDelaySeconds: 10          periodSeconds: 5

На рисунке 6 показана схема приложения SSR с настроенными liveness и readiness пробами.

Рис. 6. Приложение SSR с настроенными liveness и readiness пробами.Рис. 6. Приложение SSR с настроенными liveness и readiness пробами.

Пример 4: Собираем все вместе

В конечном, сложном и реалистичном приложении у вас могут быть элементы из всех трех предыдущих примеров. Рассмотрение их по отдельности полезно при анализе работы проб, но также полезно увидеть, как они могут работать вместе для обслуживания большого приложения с миллионами запросов. Этот последний пример объединяет остальные три.

Рис. 7: Реалистичный пример приложения в OpenShift для изучения использования проб.Рис. 7: Реалистичный пример приложения в OpenShift для изучения использования проб.

В примере приложение состоит из трех частей, это контейнеры:

  • Сервер приложений: Этот сервер предоставляет REST API и выполняет рендеринг на стороне сервера для некоторых страниц. Эта конфигурация широко распространена, поскольку приложения, которые создаются в качестве простых серверов для отрисовки, позже расширяются для обеспечения конечных точек REST API.

  • Сервер для отдачи статики Nginx: У этого контейнера есть две задачи: он отображает статические ресурсы для приложения (например, ресурсы JavaScript и CSS). И также он реализует завершение TLS-соединений (Transport Layer Security) для сервера приложений, действуя как обратный прокси для определенных URL. Это также широко используемая настройка.

  • Сервер заданий: этот контейнер не обрабатывает входящий сетевой трафик самостоятельно, но обрабатывает задания. Сервер приложений помещает каждое задание в очередь, где сервер заданий берет его и выполняет. Сервер заданий разгружает сервер приложений, чтобы он мог сосредоточиться на обработке сетевых запросов, а не на обработке длинных заданий.

Приложение также включает в себя несколько сервисов хранения данных:

  • Реляционная база данных: реляционная база данных будет хранить состояние для нашего приложения. Почти каждое приложение нуждается в какой-либо базе данных, и реляционные являются наиболее предпочтительным выбором.

  • Очередь. Очередь предоставляет серверу приложений путь первым пришел - первым вышел (FIFO) для передачи задач серверу заданий. Сервер приложений всегда будет пушить задания в очередь, а сервер заданий извлекать.

Наши контейнеры разделены на два пода:

  • Первый под состоит из нашего сервера приложений и Nginx TLS-прокси или сервера для статики. Это упрощает работу сервера приложений, позволяя ему взаимодействовать напрямую через HTTP. Благодаря расположению в одном поде эти контейнеры могут безопасно и напрямую связываться с минимальной задержкой. Они также могут получить доступ к общему volume space. Эти контейнеры также нужно масштабировать вместе и рассматривать как единое целое, поэтому под является идеальным решением.

  • Второй под состоит из сервера заданий. Этот сервер необходимо масштабировать независимо от других контейнеров, поэтому он должен находиться в собственном поде. Поскольку весь стейт хранится в базе данных и очереди, сервер заданий может легко получить доступ к необходимым ему ресурсам.

Если вы читали предыдущие примеры, решению здесь вы не удивитесь. Для интеграции мы переключаем сервер приложений на использование HTTP и порта 8080 вместо HTTPS и 8443 для readiness проб. Мы также добавляем liveness пробы на сервер приложений, чтобы прикрыть нас, если сервер приложений не завершает работу в случае ошибки. Таким образом, наш контейнер будет перезапущен Kubelet'ом, когда он мертв:

# Pod One - Application Server and NginxapiVersion: apps/v1kind: Deploymentmetadata:  labels:    app: my-application-web  name: my-application-webspec:  replicas: 1  selector:    matchLabels:      app: my-application-web  template:    metadata:      labels:        app: my-application-web    spec:      containers:      - image: quay.io/<username>/my-application-nginx:latest        name: my-application-nginx        imagePullPolicy: Always        ports:        - containerPort: 8443          protocol: TCP        livenessProbe:          exec:            command:            - /bin/sh            - -c            - "[ -f /run/nginx.pid ] && ps -A | grep nginx"          initialDelaySeconds: 10          periodSeconds: 5        readinessProbe:          httpGet:            scheme: HTTPS            path: /index.html            port: 8443          initialDelaySeconds: 10          periodSeconds: 5      - image: quay.io/<username>/my-application-app-server:latest        name: my-application-app-server        imagePullPolicy: Always        ports:        - containerPort: 8080          protocol: TCP        livenessProbe:          exec:            command:            - /bin/sh            - -c            - "/usr/bin/my-application-web --alive"          initialDelaySeconds: 10          periodSeconds: 5        readinessProbe:          httpGet:            scheme: HTTP            path: /healthz            port: 8080          initialDelaySeconds: 10          periodSeconds: 5# Pod Two - Jobs ServerapiVersion: apps/v1kind: Deploymentmetadata:  labels:    app: my-application-jobs  name: my-application-jobsspec:  replicas: 1  selector:    matchLabels:      app: my-application-jobs  template:    metadata:      labels:        app: my-application-jobs    spec:      containers:      - image: quay.io/<username>/my-application-jobs:latest        name: my-application-jobs        imagePullPolicy: Always        livenessProbe:          exec:            command:            - /bin/sh            - -c            - "/usr/bin/my-application-jobs --alive"          initialDelaySeconds: 10          periodSeconds: 5

На рисунке 8 показаны полные примеры приложений с обеими настроенными пробами.

Рис. 8: Полный пример приложений с обеими настроенными пробами.Рис. 8: Полный пример приложений с обеими настроенными пробами.

Что насчет одинаковых liveness и readiness проб?

На мой взгляд, хотя этот шаблон используется чересчур часто, в некоторых случаях он имеет смысл. Если приложение начинает некорректно отвечать на HTTP-запросы и, вероятно, никогда не восстановит свою работу без перезапуска, то вы, вероятно, захотите, чтобы OpenShift перезапустил под. Было бы лучше, если бы ваше приложение восстанавливалось само по себе, но это бывает нецелесообразно в реальном мире.

Если у вас есть HTTP endpoint, который может быть исчерпывающим индикатором, вы можете настроить и liveness и readiness пробы на работу с этим endpoint. Используя один и тот же endpoint убедитесь, что ваш под будет перезапущен, если этот endpoint не сможет вернуть корректный ответ.

Финальные мысли

Liveness и readiness пробы отправляют разные сигналы в OpenShift.Каждый имеет свое определенное значение и они не взаимозаменяемы. Не пройденная liveness проверка говорит OpenShift, что контейнер должен быть перезапущен. Не пройденная readiness проба говорит OpenShift придержать трафик от отправки в этот контейнер.

Нет универсального рецепта для проб, потому что правильный выбор будет зависеть от того, как написано приложение. Приложению, которое умеет самовосстанавливаться нужна иная настройка от того, которое просто дает сбой и умирает.

Выбирая корректные проверки для приложения я обращаюсь к семантическому смыслу в сочетании с поведением приложения. Зная, что проваленная liveness проба перезапустит контейнер, а проваленная readiness проба удалит его из балансировщика. Обычно это не сложно, определить какие пробы нужны приложению.

Мы рассмотрели реалистичные примеры, но вы можете увидеть значительно более сложные случаи в реальных системах. Для инстанса в сервис-ориентированной архитектуре (SOA), сервис может зависеть от другого сервиса при обработке соединений. Если нисходящий сервис не готов, должен ли проходить readiness проверку восходящий сервис или нет? Ответ зависит от приложения. Вам нужно провести анализ стоимости/преимуществ решения, чтобы определить, что добавочная сложность того стоит.

Хотя концептуально пробы очень просты, они могут быть сложны на практике. Лучший подход для нахождения оптимального решения - это итеративный! Проведите тестирование производительности и хаотичное тестирование для наблюдения за поведением вашей конфигурации и улучшайте её в процессе. Мы редко делаем все правильно с первого раза.

Подробнее..

Стоит ли переходить с Powershell DSC на Ansible и как это сделать

03.03.2021 14:04:54 | Автор: admin
Об IaC под Windows пишут мало, потому что DevOps/SRE ассоциируется в основном c Linux и Kubernetes. Мы решили исправить эту ситуацию и сравнить инструменты, которыми можно управлять IaC на базе Windows. Статья будет полезна разработчикам, которые работают с Windows-инфраструктурой и выбирают способы управления, и тем, кто уже внедрил Powershell DSC или Ansible, но сомневается в своем решении. Ниже поделимся опытом и расскажем:
  • как устроен Powershell DSC и чем он отличается от Ansible при управлении инфраструктурой на Windows;
  • почему мы перешли на Ansible;
  • с какими проблемами столкнулись и как их решали;
  • как соотносятся ожидания и реальность после перехода на Ansible;
  • кому стоит выбрать Powershell DSC, а кому Ansible.

Почему изначально выбрали PowerShell DSC


В Mindbox развита культура DevOps/SRE, несмотря на преимущественно Windows-инфраструктуру: Hyper-V, IIS, MS SQL Server. И хотя компания постепенно переходит на Linux и Open Source, Windows пока превалирует.

Чтобы управлять этой инфраструктурой, планировали использовать инфраструктурный код: писать его, сохранять в репозиторий, а затем с помощью какого-то инструмента превращать код в реальную инфраструктуру. В то время как Ansible самый популярный инструмент управления инфраструктурой через код, он все-таки традиционно ассоциируется с Linux-миром. Нам хотелось что-то нативное и заточенное под Windows, поэтому выбрали PowerShell DSC.

Как работает Powershell DSC


PowerShell Desired State Configuration (DSC) это сервис, который уже есть в Windows из коробки и помогает управлять инфраструктурой через конфигурационные файлы. На вход он принимает инфраструктурный код на PowerShell, а внутри преобразует его в команды, которые конфигурируют систему. Кроме тривиальных операций, например установки Windows-компонентов, изменения ключей реестра, создания файлов или конфигурирования служб, он умеет многое из того, что обычно выполняется PowerShell-скриптами. Например, полный цикл настройки DNS или высокодоступный инстанс MS SQL Server.



Полезные ссылки к схеме:
Пример простой конфигурации для документов по DSC
Как использовать датафайлы
Как использовать SQL Server-базу в качестве бэкэнда для Windows Server 2019
Как настроить DSC pull server для работы с базой данных SQL для версий раньше Windows Server 2019

Чем DSC отличается от Ansible


Критерий DSC Ansible
Архитектура Служба на каждом управляемом хосте. В случае pull-модели, отдельный управляющий хост и база данных, пререквизиты в виде .NET Framework 4.0 и WMF 5.1 Несколько исполняемых файлов, например ansible, ansible-playbook и ansible-inventory. Запускается с любого Linux-хоста, пререквизит у управляемых хостов один python
Хранение состояния хостов Можно хранить в базе данных Нет
Кроссплатформенность Да Да, включая управление сетевыми устройствами
Pull/push-режимы Pull и push Только push
Устранение дрифта конфигурации Есть в pull-режиме Нет
Декларативность Декларативно-процедурный: важна последовательность выполнения тасков, можно писать недекларативные конструкции в любом месте, а значит, больше шансов написать запутанный код Декларативно-процедурный: важна последовательность выполнения тасков, при этом невозможно написать скриптовый код, не обернув в таск
Аудитория ~1300 ресурсов в Gallery ~20000 ролей в Ansible Galaxy
Используемый язык PowerShell YAML
Инвентаризация Да, по удобству проигрывает Ansible Да
Единица распространения Ресурс (модуль) Роль

Проблемы, которые возникли с DSC


Ожидания от DSC оправдались не во всём. Кроме этого, во время работы возникли новые потребности, которые не могли удовлетворить с помощью DSC.

Разработчики не могут использовать инструмент самостоятельно без помощи SRE. Хотя почти в каждой команде есть SRE, инструмент IaC должен быть достаточно простым, чтобы разработчик мог им пользоваться и тратить на это не больше получаса. DSC позволяет использовать не только декларативный код, но и любые конструкции на Powershell. Это значит, что высок шанс сделать код, который будет сложно сопровождать или который приведет к инфраструктурной аварии. Например, развертывание приложения с некорректными параметрами не в той среде.

Невозможно пропустить конфигурацию в режиме dry run перед прокаткой, чтобы увидеть, какие именно изменения будут применены, а какие нет.

Для DSC трудно организовать синтаксические проверки и проверки стиля кода. Инструментов для проверки мало, и они не обновляются. Для Ansible мы это уже сделали.

В push-режиме DSC нет удобного способа отслеживать состояние тасков. В случае если конфигурация применилась с ошибкой, для диагностики следует совершать дополнительные действия: выполнять команды, чтобы получить статус применения конфигурации, смотреть журналы событий. Если ошибка произошла на нескольких серверах, то это отнимает много времени.

Pull-режим так и не стал преимуществом. В нем конфигурация применяется асинхронно узнать, когда точно закончено применение новой конфигурации, невозможно без обвязок и костылей.

Избыточное использование двух отличных друг от друга инструментов IaC, которые конфигурируют серверы. Ansible может делать то же, что и DSC, а ведь мы уже используем Ansible для конфигурирования Linux-хостов и сетевого оборудования.

Как планировали перейти с DSC на Ansible


Сначала задача казалась простой, приблизительно на месяц. Мы выделили три этапа работ:
  • научиться подключаться к Windows-хостам с помощью Ansible;
  • переписать конфигурации DSC с помощью Ansible-модулей;
  • удалить DSC pull server, его базу данных и прочие артефакты.

Вот какой рабочий процесс был на DSC, и как планировали организовать в Ansible:




Стандартная структура ролей в Ansible

На Ansible мы планировали отделить сложный код, который что-то конфигурирует и устанавливает, в код ролей и разнести роли по отдельным репозиториям. В главном репозитории Ansible должны были остаться только вызовы ролей, переопределения параметров ролей и списки серверов по группам. Так не только SRE, но и любой разработчик мог бы развернуть роль на нужные серверы или подправить параметр, не углубляясь в логику инфраструктурного кода. Исправить же код роли разработчик сможет только после ревью SRE.

С какими сложностями столкнулись при переходе на Ansible и как их решали


Когда работа началась, мы поняли, что ошиблись: задача оказалась непростой. Проблем не возникло только с репозиторием, а в других вопросах пришлось много исследовать и улучшать наработки.

WinRM или SSH


Первый сюрприз состоял в выборе типа подключения. В случае Windows их два WinRM и SSH. Оказалось, что Ansible медленно работает через WinRM. При этом Ansible не рекомендует использовать OpenSSH из коробки для Windows Server 2019. И мы нашли новое решение:
  1. Форкнули и переделали под себя роль из Galaxy.
  2. Написали плейбук, в котором есть только вызов этой роли. Это единственный плейбук, при котором идет подключение к хостам по WinRM.
  3. Стандартными средствами Prometheus Blackbox Exporter сделали мониторинг порта 22/tcp и версии OpenSSH:

    - alert: SSHPortDown
    expr: probe_success{job=~".*-servers-ssh",instance!~".*domain..ru"} == 0
    for: 1d
    annotations:
    summary: "Cannot reach {{`{{ $labels.instance }}`}} with SSH"
  4. Выбрали и настроили LDAP-плагин для инвентаризации, чтобы не вписывать вручную все Windows-серверы из домена в статическую инвентаризацию:

    plugin: ldap_inventory
    domain: 'ldaps://domain:636'
    search_ou: "DC=domain,DC=ru"
    ldap_filter: "(&(objectCategory=computer)(operatingSystem=*server*)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))"
    validate_certs: False
    exclude_hosts:
    - db-
    account_age: 15
    fqdn_format: True
  5. Развернули везде OpenSSH с нужными ключами и убедились, что ни одного алерта о недоступности Windows-серверов по SSH больше нет.
  6. Чуть позже интегрировали установку OpenSSH в стандартный образ. Наши образы готовятся с помощью Packer, который также умеет вызывать Ansible:

    "type": "shell-local",
    "tempfile_extension": ".ps1",
    "execute_command": ["powershell.exe", "{{.Vars}} {{.Script}}"],
    "env_var_format": "$env:%s=\"%s\"; ",
    "environment_vars": [
    "packer_directory={{ pwd }}",
    "ldap_machine_name={{user `ldap_machine_name`}}",
    "ldap_username={{user `ldap_username`}}",
    "ldap_password={{user `ldap_password`}}",
    "ansible_playbooks={{user `ansible_playbooks`}}",
    "github_token={{user `github_token`}}"
    ],
    "script": "./scripts/run-ansiblewithdocker.ps1"


Рефакторинг


Когда мы переписывали код под Ansible, то периодически натыкались на дублирование кода. Например, почти все конфигурации DSC содержали установку windows_exporter. Единственное, что отличалось это коллекторы, которые экспортер должен был использовать:



Чтобы избавиться от дублированного кода, вынесли windows_exporter в отдельную Ansible-роль, а параметры этой установки в переменные групп хостов.

Second hop authentication


Наверное, second hop authentication самая распространенная проблема, с которой сталкиваются те, кто начал использовать Ansible под Windows:

- name: Custom modules loaded into module directory
win_copy:
src: '\\share\dsc\modules'
dest: 'C:\Program Files\WindowsPowerShell\Modules'
remote_src: yes


Такая конструкция вызывает ошибку Access Denied из-за того, что по умолчанию делегировать учетные данные для авторизации на удаленном ресурсе невозможно без дополнительных настроек. Обойти ошибку помогает, например, new_credentials. Но мы предпочли воспользоваться тем, что Ansible умеет вызывать ресурсы DSC через модуль win_dsc. Вызываем DSC-ресурс File, который по умолчанию выполняется под учетной записью компьютера. Делегация Kerberos в этом случае не нужна:

- name: Custom modules loaded into module directory
win_dsc:
resource_name: File
SourcePath: '\\share\dsc\modules'
DestinationPath: 'C:\Program Files\WindowsPowerShell\Modules'
Type: Directory
Recurse: true
Force: true
MatchSource: true


При этом нет противоречия в том, чтобы отказываться от DSC, но использовать его ресурсы, если они лучше решают задачу, чем модуль Ansible. Главная цель прекратить использовать DSC-конфигурации, потому что нас не устраивала именно экосистема DSC, а не сами ресурсы. Например, если нужно создать виртуальный свитч Hyper-V, то придется использовать ресурс DSC в Ansible пока нет средств по управлению конфигурацией Hyper-V.

Сетевой дисконнект


Некоторые задачи вызывают отключение сети (дисконнект) на конфигурируемых серверах. Например, создание виртуального свитча Hyper-V из примера выше:

- name: External switch present
win_dsc:
resource_name: xVMSwitch
Ensure: 'Present'
Name: 'Virtual Network'
Type: 'External'
NetAdapterName: 'TEAM_LAN'
AllowManagementOS: True


Проблема в том, что в DSC такой вызов работает, а в Ansible завершается с ошибкой, так как управляемый хост дисконнектнул. Это происходит потому, что Windows всегда дисконнектит при создании виртуального экстернал-свитча. Решение добавить к таску аргумент async:

async: 10

Так Ansible отправляет таск на хост, ждет заданное время и только потом запрашивает состояние.

Дрифт инфраструктуры


Когда мы стали переносить код, обнаружили дрифт конфигураций. Это фактические различия между тем, что описано в коде, и реальной конфигурацией сервера или ПО. Причина в том, что в некоторых случаях DSC выполнял только часть работы, а остальное делали либо скриптами, либо вручную по инструкции.

Чтобы облегчить работу с IaC, мы собрали все скрипты и документы и сделали единые однозначные инструкции. Кроме этого, организовали процесс так, чтобы никто не внес случайные изменения в Ansible. Мы храним весь инфраструктурный код в GitHub, а задачи инженерам ставим через GitHub Projects, поэтому у нас есть возможность связывать изменения инфраструктурного кода (pull requests) с задачами. Так мы можем посмотреть изменения по каждой выполненной задаче. Если у задачи не будет изменений, то её не примут и вернут на доработку.

Баги сбора фактов


В отличие от DSC, Ansible при запуске собирает факты об управляемых хостах, чтобы у разработчика была возможность определить поведение тасков в зависимости от состояния хоста. При сборе фактов с Windows-хостов Ansible может выдавать ошибку, из-за некорректного кода модуля. Чтобы её исправить, нужно подключить коллекцию ansible.windows.

[WARNING]: Error when collecting bios facts: New-Object : Exception calling ".ctor" with "0" argument(s): "Index was out of range. Must be non-negative and less than the size of the collection. Parameter name: index" At line:2
char:21 + ... $bios = New-Object -TypeName


Пайплайн для Ansible перед запуском каждого плейбука проверяет наличие файлов requirements.yml со списком необходимых ролей и коллекций, а затем устанавливает их. Туда мы и добавили коллекцию ansible.windows.

Коллекции это новый концепт развития Ansible. Если раньше в Galaxy распространялись только роли, то теперь там можно найти подборки различных плагинов и модулей, плейбуков и ролей.

Тесты


Прежде чем передать IaC-инструментарий разработчикам, мы хотели быть уверенными, что Ansible-код будет надежным и ничего не сломает. В случае с DSC никаких специальных тестов не было, хотя существует специальный фреймворк для этой задачи. Конфигурации обычно валидировались на стейджинг-серверах, поломка которых не приводила к дефектам.

Для тестирования Ansible обычно используют инструмент molecule как обертку для запуска тестов. Это удобный инструмент для Linux-ролей, но в случае с Windows есть проблема. Раньше molecule умела поднимать инфраструктуру сама, но сейчас разработчики убрали такую возможность. Теперь инфраструктура поднимается либо с помощью molecule в Docker, либо вне molecule. Протестировать Windows-роли в Docker чаще всего невозможно: Hyper-V и большинство других Windows-фич в Docker-контейнере не установятся. Придется разворачивать инфраструктуру под тесты вне molecule и использовать delegated driver в molecule.

Эту задачу мы еще не решили, но нашли инструменты, которые обнаружат самые очевидные ошибки:

Проверка Функционал Комментарий
Синтаксическая проверка Проверяет синтаксис и возможность запуска кода Используем синтаксическую проверку и линтинг локально и в репозитории. Например, встраиваем в pre-commit check и настраиваем GitHub Action, который будет запускаться при каждом pull request
Линтинг Проверяет код на логические ошибки
Dry run Позволяет до запуска плейбука узнать, что он сделает Используем в пайплайне раскатки кода: запускаем ansible-playbook с флагами check и diff, затем оцениваем изменения и подтверждаем раскатку. Когда пишем роли, учитываем, что для некоторых тасков необходимо явно указывать, что именно они должны поменять. Например, win_command и win_shell

Как устроена работа с Ansible


После того как мы внедрили Ansible и преодолели все сложности, сформировался процесс действий инженеров и автоматических запусков:
  1. Инженер пишет код роли и тесты к ней, если это роль для Linux-серверов. Как только инженер решит, что роль готова, он делает pull request в отдельный бранч в GitHub-репозитории, созданном специально для роли.
  2. При создании pull request автоматически запускается воркфлоу GitHub Actions, который выполняет синтаксическую проверку и линтинг роли. Если это Linux-роль, то запускаются еще и тесты. Инженер проверяет, что всё хорошо, и при необходимости исправляет.
  3. Другой инженер делает ревью кода из pull request. После того как автор роли исправляет все замечания, код вливается в мастер-бранч, а версия роли автоматически повышается.
  4. Теперь нужно развернуть новую версию роли. Версии перечислены в специальных файлах requirements.yml, которые лежат в GitHub-репозитории с плейбуками. Для каждого плейбука отдельный такой файл. Автор роли изменяет версию в таком файле. Если нужно развернуть роль на серверы, которых нет в инвентаризации Ansible, автор дополняет инвентаризацию. Потом автор снова создает pull request, но уже в репозиторий с плейбуками.
  5. После подтверждения pull request снова запускается GitHub Actions, который создает новый релиз в Octopus Deploy. Роль готова к развертыванию.
  6. Инженер заходит в Octopus Deploy и запускает развертывание. Процесс развертывания позволяет инженеру ограничить теги и хосты, а также переопределить переменные аналогично опциям команды ansible-playbook: --tags, --limit и --extra-vars.
  7. Процесс развертывания сначала запускает режим проверки, который показывает, какие изменения будут сделаны. Инженер оценивает результат проверки и либо подтверждает развертывание кода на целевую инфраструктуру, либо сначала устраняет обнаруженные недостатки.

Организация работы с Ansible




Что выбрать: DSC или Ansible


Перейти с DSC на Ansible Если важно:
  • отслеживать состояние тасков;
  • иметь возможность пропустить конфигурацию в режиме dry run перед прокаткой;
  • модифицировать инфраструктурный код;
  • делать синтаксические и логические проверки.


Если Linux-хосты или сетевое оборудование уже управляются с помощью Ansible.

Если не боитесь работать с Linux, потому что Ansible нужно централизованно запускать на Linux, будь то агент CI/CD системы или Docker-контейнер.
Внедрить с нуля или остаться на DSC Если инфраструктура только на Windows и вы не хотите работать с Linux.

Если готовы дописывать свои ресурсы для DSC.

Нужно хранить состояние инфраструктуры, а также исправлять её дрифт.
Внедрить с нуля Ansible Если управляете смешанной Windows/Linux средой и хотите переделать существующие скрипты в инфраструктурный код и разворачивать его с помощью CI/CD систем.


Евгений Берендяев, SRE-инженер
Подробнее..

Изучаем ELK. Часть III Безопасность

03.03.2021 20:06:54 | Автор: admin

Вступительное слово

В первой и второй частях данной серии статей была описана процедура установки и настройки кластера Elasticsearch, Kibana и Logstash, но не был освящен вопрос безопасности.

В этой статье я расскажу, как настроить шифрование трафика между узлами кластера Elasticsearch и его клиентам, шифрование трафика между Kibana и клиентами, покажу, как создавать роли и пользователей, а так же выдавать API ключи для доступа к кластеру Elasticsearch.

План действий

  1. "Включаем" безопасность.

  2. Настраиваем шифрование между узлами Elasticsearch.

  3. Настраиваем аутентификацию.

  4. Настраиваем шифрование клиентского трафика Elasticsearch.

  5. Подключаем Kibana к Elasticsearch.

  6. Настраиваем шифрование трафика между Kibana и клиентами.

  7. Создаем пользователей и роли.

  8. Настраиваем пользовательские сессии в Kibana.

  9. Настраиваем Logstash.

  10. Создаем API ключи.

"Включаем" безопасность

Чтобы использовать функции безопасности в Elasticsearch, их необходимо активировать. Для этого на каждом узле в файле конфигурации указывается следующая настройка:

xpack.security.enabled: true

Настраиваем шифрование между узлами Elasticsearch

Следующим шагом необходимо настроить шифрование трафика между узлами Elasticsearch. Для этого выполняем несколько шагов:

  • Создаем CA (Certificate Authority) для кластера Elasticsearch:

./bin/elasticsearch-certutil ca

Для установки из пакетов Deb и RPM исполняемые файлы Elasticsearch лежат в каталоге /usr/share/elasticsearch/bin/. Для установки из архива - в каталоге $ES_HOME/bin/.

В примерах все команды выполнены из каталога /usr/share/elasticsearch/.

Во время генерации корневого сертификата можно задать имя PKCS#12 файла, по умолчанию это elastic-stack-ca.p12 и пароль к нему.

Для получения сертификата и ключа в PEM формате укажите ключ --pem. На выходе будет ZIP архив с .crt и .key файлами.

С помощью ключа --out можно указать каталог для создаваемого файла.

Полученный корневой сертификат (для PEM формата еще и ключ) надо переместить на все узлы кластера для генерации сертификата узла.

  • Генерируем на каждом узле кластера сертификат и ключ:

./bin/elasticsearch-certutil cert --ca elastic-stack-ca.p12 --ip 10.0.3.11 --dns es-node01

Ключ --ca указывает путь к корневому сертификату CA в формате PKCS#12. Если сертификат и ключ были получены в PEM формате, то необходимо использовать ключи --ca-cert и --ca-key соответственно.

Ключи --dns и --ip добавляют проверку по имени узла и IP адресу и являются опциональными. Если вы указываете их, то укажите эти параметры для каждого узла.

Ключ --pass позволяет установить passphrase для ключа.

  • Включаем TLS в файле конфигурации Elasticsearch:

xpack.security.transport.ssl.enabled: truexpack.security.transport.ssl.verification_mode: fullxpack.security.transport.ssl.keystore.path: es-node01-cert.p12xpack.security.transport.ssl.truststore.path: elastic-stack-ca.p12

Где:

xpack.security.transport.ssl.enabled - включаем TLS/SSL

xpack.security.transport.ssl.verification_mode - режим проверки сертификатов. none - проверка не выполняется, certificate - выполняется проверка сертификата без проверки имени узла и IP адреса, full - проверка сертификата, а также имени узла и адреса указанных в сертификате.

xpack.security.transport.ssl.keystore.path - путь к файлу с сертификатом и ключем узла.

xpack.security.transport.ssl.truststore.path - путь к доверенному сертификату (CA).

Если сертификаты CA и/или узла в формате PEM, то необходимо изменить последние два параметра на следующие:

xpack.security.transport.ssl.key - путь к закрытому ключу узла

xpack.security.transport.ssl.certificate - путь к сертификату узла

xpack.security.transport.ssl.certificate_authorities - список путей к сертифкатам CA.

  • Cоздаем keystore и добавляем пароли от сертификатов(если они были заданы):

./bin/elasticsearch-keystore create -p

Ключ -p требуется для установки пароля keystone во время создания

Для PKCS#12 формата:

./bin/elasticsearch-keystore add xpack.security.transport.ssl.keystore.secure_password./bin/elasticsearch-keystore add xpack.security.transport.ssl.truststore.secure_password

Для PEM сертификата:

./bin/elasticsearch-keystore add xpack.security.transport.ssl.securekeypassphrase

Чтобы запустить Elasticsearch с keystore, на который установлен пароль, необходимо передать этот пароль Elasticsearch. Это делается с помощью файла на который будет ссылаться переменная ES_KEYSTORE_PASSPHRASE_FILE. После запуска файл можно удалить, но при каждом последующим запуске файл необходимо создавать.

echo "password" > /etc/elasticsearch/ks_secret.tmpchmod 600 /etc/elasticsearch/ks_secret.tmpsudo systemctl set-environment ES_KEYSTORE_PASSPHRASE_FILE=/etc/elasticsearch/ks_secret.tmp
  • Перезапускаем Elasticsearch

В логах Elasticsearch должны появится записи о создании кластера:

[INFO ][o.e.c.s.ClusterApplierService] [es-node01] master node changed {previous [], current [{es-node02}{L1KdSSwCT9uBFhq0QlxpGw}{ujCcXRmOSn-EbqioSeDNXA}{10.0.3.12}{10.0.3.12:9300}...

Если обратиться к API, то будет ошибка "missing authentication credentials for REST request". С момента включения функций безопасности для обращения к кластер необходимо пройти аутентификацию.

Настраиваем аутентификацию

Elasticsearch имеет несколько встроенных пользователей:

Пользователь

Описание

elastic

Суперпользователь

kibana_system

Используется для коммуникации между Kibana и Elasticsearch

logstash_system

Пользователь, которого использует Logstash сервер, когда сохраняет информацию в Elasticsearch

beats_system

Пользователь, которого использует агент Beats, когда сохраняет информацию в Elasticsearch

apm_system

Пользователь, которого использует APM сервер, когда сохраняет информацию в Elasticsearch

remote_monitoring_user

Пользователь Metricbeat, который используется при сборе и хранении информации мониторинга в Elasticsearch

Прежде чем воспользоваться перечисленными пользователями, необходимо установить для них пароль. Для этого используется утилита elasticsearch-setup-passwords. В режиме interactive для каждого пользователя необходимо ввести пароли самостоятельно, в режиме auto Elasticsearch создаст пароли автоматически:

./bin/elasticsearch-setup-passwords autoInitiating the setup of passwords for reserved users elastic,apm_system,kibana,kibana_system,logstash_system,beats_system,remote_monitoring_user.The passwords will be randomly generated and printed to the console.Please confirm that you would like to continue [y/N]yChanged password for user apm_systemPASSWORD apm_system = NtvuRYhwbKpIEVUmHsZBChanged password for user kibana_systemPASSWORD kibana_system = ycXvzXglaLnrFMdAFsvyChanged password for user kibanaPASSWORD kibana = ycXvzXglaLnrFMdAFsvyChanged password for user logstash_systemPASSWORD logstash_system = vU3CuRbjBpax1RrsCCLFChanged password for user beats_systemPASSWORD beats_system = c9GQ85qhNL59H2AXUvcAChanged password for user remote_monitoring_userPASSWORD remote_monitoring_user = wB320seihljmGsjc29W5Changed password for user elasticPASSWORD elastic = iOrMTBbfHOAkm5CPeOj7

Второй раз elasticsearch-setup-passwords запустить не получится, так как bootstrap password изменился. Чтобы изменить пароль пользователям можно воспользоваться API.

Попробуем сделатьAPI запрос к любому узлу Elasticsearch с использованием учетной записи elastic и пароля к от неё:

curl -u 'elastic' -X GET "http://10.0.3.1:9200/_cluster/health?pretty"Enter host password for user 'elastic':{  "cluster_name" : "es_cluster",  "status" : "green",  "timed_out" : false,  "number_of_nodes" : 4,  "number_of_data_nodes" : 3,  "active_primary_shards" : 9,  "active_shards" : 18,  "relocating_shards" : 0,  "initializing_shards" : 0,  "unassigned_shards" : 0,  "delayed_unassigned_shards" : 0,  "number_of_pending_tasks" : 0,  "number_of_in_flight_fetch" : 0,  "task_max_waiting_in_queue_millis" : 0,  "active_shards_percent_as_number" : 100.0}

Как видно из примера все работает, но мы обращались через http, значит трафик между клиентом и кластером Elasticsearch не шифрованный.

Настраиваем шифрование клиентского трафика Elasticsearch

Для шифрования клиентского трафика необходимо выпустить сертификат, который будет использоваться для шифрования трафика между узлом Elasticsearch и клиентом. При этом для Kibana будет сформирован отдельный сертификат, чтобы настроить соединение с Elasticsearch. Для этого делаем следующее:

  • Генерируем сертификат:

./bin/elasticsearch-certutil http

В процессе генерации необходимо определить:

1) Необходимо ли сгенерировать Certificate Signing Request (CSR). Потребуется, если сертификат будет выпускаться сторонним CA (Certificate Authority).

2) Использовать ли собственный CA (Certificate Authority). Если да, то указываем путь до ключа, которым будет подписаны будущие сертификаты.

3) Срок действия сертификата. По умолчанию 5 лет. Можно определить дни(D), месяцы (M), года (Y).

4) Как выпустить сертификат, на каждый узел или общий. Если все узлы имеют общий домен, то можно выпустить wildcard сертификат (например *.domain.local). Если общего домена нет и в будущем возможно добавление узлов, то необходимо генерировать на каждый узел, указав имя узла и его адрес. В будущем можно выпустить отдельный сертификат для нового узла.

На выходе получаем архив сертификатами, в моём случае со всеми сертификатам для каждого узла Elasticsearch, а так же сертификат для подключения Kibana к Elasticsearch:

. elasticsearch    es-nlb01       README.txt       http.p12       sample-elasticsearch.yml    es-node01       README.txt       http.p12       sample-elasticsearch.yml    es-node02       README.txt       http.p12       sample-elasticsearch.yml    es-node03        README.txt        http.p12        sample-elasticsearch.yml kibana     README.txt     elasticsearch-ca.pem     sample-kibana.yml

В архиве также лежит инструкция по дальнейшим действиям с сертификатом (README.txt) и пример конфигурационного файла (sample-...yml).

Сертификат elasticsearch-ca.pem из директории kibana потребуется в следующем шаге.

  • Размещаем сертификаты на узлах и добавляем необходимые настройки в файле конфигурации:

    xpack.security.http.ssl.enabled: truexpack.security.http.ssl.keystore.path: "http.p12"
    
  • Добавляем пароль от сгенерированного сертификата в keystore:

./bin/elasticsearch-keystore add xpack.security.http.ssl.keystore.secure_password
  • Проверяем, что все работает по https:

curl -u 'elastic' -k -X GET "https://10.0.3.1:9200/_cluster/health?pretty"Enter host password for user 'elastic':{  "cluster_name" : "es_cluster",  "status" : "green",  "timed_out" : false,  "number_of_nodes" : 4,  "number_of_data_nodes" : 3,  "active_primary_shards" : 9,  "active_shards" : 18,  "relocating_shards" : 0,  "initializing_shards" : 0,  "unassigned_shards" : 0,  "delayed_unassigned_shards" : 0,  "number_of_pending_tasks" : 0,  "number_of_in_flight_fetch" : 0,  "task_max_waiting_in_queue_millis" : 0,  "active_shards_percent_as_number" : 100.0}

Подключаем Kibana к Elasticsearch

Если сейчас обратиться к Kibana, то ответом будет "Kibana server is not ready yet".

Это связанно с тем, что сейчас Kibana не может получить доступ к Elasticsearch по http, для этого необходим сертификат Kibana, который был получен в предыдущем шаге, а также требуется пройти аутентификацию. Чтобы настроить работу Kibana:

  • В конфигурационном файле Kibana указываем ключ к сертификату elasticsearch-ca.pem(из предыдущего шага) и меняем протокол http на https:

elasticsearch.hosts: ['https://10.0.3.1:9200']elasticsearch.ssl.certificateAuthorities: [ "/etc/kibana/elasticsearch-ca.pem" ]

В примере выше я использую адрес Coordinating only узла для балансировки нагрузки между Kibana и Elasticsearch, который был настроен в предыдущей части.

  • Создаем keystore для хранения пользователя и пароля:

sudo ./bin/kibana-keystore create --allow-root

Команда выполняются из директории /usr/share/kibana

Так как keystore будет создан в каталоге /etc/kibana/ , и keystone требуется файл конфигурации /etc/kibana/kibana.yml, то пользователю, запускающему команду, необходим доступ к этому каталогу и файлу. Я использую sudo и ключ --allow-root. Ключ необходим, так как запускать из под пользователя root нельзя.

Kibana keystore не имеет пароля. Для ограничения доступа используем стандартные средства Linux.

  • Добавляем пользователя kibana_system(встроенный пользователь Elasticsearch) и пароль учетной записи в Kibana keystore:

sudo ./bin/kibana-keystore add elasticsearch.username --allow-rootsudo ./bin/kibana-keystore add elasticsearch.password --allow-root 

Можно использовать так же пользователя kibana, однако, он в системе считается устаревшим (deprecated).

  • перезапускаем Kibana и проверяем открыв нужный адрес в браузере:

Kibana Kibana

Для входа используем учетную запись elastic.

Как можно заменить, трафик между браузером и Kibana не шифруется.

Настраиваем шифрование трафика между Kibana и клиентами

Данная процедура максимально похожа на ту, которую выполняли для получения сертификатов для узлов Elasticsearch.

  • Получаем сертификат при помощи elsticsearch-certutil :

./bin/elasticsearch-certutil cert  -ca /etc/elasticsearch/elastic-stack-ca.p12 -name kibana-certificate -dns kibana01,10.0.3.1,127.0.0.1,localhost -ip 10.0.3.1

При необходимости можем использовать CA (Certificate Authority). В процессе генерации сертификата указываем пароль от CA, если используется, имя будущего сертификата и пароль к нему.

Через -dns и -ip указываем DNS имена и адрес Kibana.

  • Указываем путь к сертификату в файле kibana.yml:

Так как я использовал ранее полученный CA, то указываю путь и к нему (server.ssl.truststore.path).

server.ssl.keystore.path: "/etc/kibana/kibana-certificate.p12"server.ssl.truststore.path: "/etc/elasticsearch/elastic-stack-ca.p12"

Не забывайте о правах доступа, пользователь kibana должен иметь права на чтения.

  • Включаем использование TLS:

server.ssl.enabled: true
  • Добавляем пароли от сертификатов в keystore:

sudo ./bin/kibana-keystore add server.ssl.keystore.password --allow-rootsudo ./bin/kibana-keystore add server.ssl.truststore.password --allow-root
  • Перезагружаем Kibana и проверяем:

Доступ к Kibana по httpsДоступ к Kibana по https

Теперь для подключения к Kibana используем https.

Создаем пользователей и роли

Ранее мы активировали встроенные учетные записи и сгенерировали для них пароли, но использовать пользователя elastic (superuser) не лучшая практика, поэтому рассмотрим, как создавать пользователей и роли к ним.

Для примера создадим администратора Kibana. Открываем Menu > Management > Stack Management, выбираем Users и нажимаем Create user. Заполняем все поля и жмем Create User.

Создание пользователя в KibanaСоздание пользователя в Kibana

Или же можно воспользоваться API. Делать запросы к кластеру можно через консоль Dev Tools инструмента Kibana. Для этого перейдите Menu > Management > Dev Tools. В открывшейся консоли можно писать запросы к Elasticsearch.

POST /_security/user/kibana_admin{  "password" : "password",  "roles" : [ "kibana_admin" ],  "full_name" : "Kibana Administrator",  "email" : "kibana.administrator@example.local"}
Создание пользователя kibana_admin через APIСоздание пользователя kibana_admin через API

После создания пользователя, можно его использовать.

Роль kibana_admin не может создавать пользователей и роли. Для создания пользователей и роли необходима привилегия кластера manage_security. С перечнем всех встроенных ролей можно ознакомится тут.

Далее создадим роль для работы с данными в ранее созданном индексом logstash-logs*. Открываем Menu > Management > Stack Management. Слева выбираем Roles и нажимаем Create role. Настраиваем привилегии, указав в качестве индекса logstash-logs*:

Index privileges

read

Read only права на индекс

Предоставляем пользователю доступ к Kibana, для этого ниже наживаем Add Kibana privilege и выбираем требуемые привилегии:

В поле Spaces указываю All spaces. Что такое Space (пространства) можно почитать на официальном сайте. В рамках данной серии статей Space будет описан в статье о Kibana dashboard.

Чтобы создать роль с привилегиями в Elasticsearch и Kibana через API, делаем запрос к Kibana:

curl -k -i -u 'elastic' -X PUT 'https://10.0.3.1:5601/api/security/role/logstash_reader' \--header 'kbn-xsrf: true' \--header 'Content-Type: application/json' \--data-raw '{  "elasticsearch": {    "cluster" : [ ],    "indices" : [      {        "names": [ "logstash-logs*" ],        "privileges": ["read"]      }      ]  },  "kibana": [    {      "base": [],      "feature": {       "discover": [          "all"        ],        "visualize": [          "all"        ],        "dashboard": [          "all"        ],        "dev_tools": [          "read"        ],        "indexPatterns": [          "read"        ]      },      "spaces": [        "*"      ]    }  ]}'

Создаем пользователя logstash_reader и связываем его с созданной ролью (это мы уже научились делать) и заходим данным пользователем в Kibana.

Главная страница Kibana для пользователя logstash_readerГлавная страница Kibana для пользователя logstash_reader

Как видно, у данного пользователя не так много прав. Он может просматривать индексы logstash-logs*, строить графики, создавать панели и делать GET запросы к этому индексам через Dev Tools.

Настраиваем пользовательские сессии Kibana

  • Закрываем неактивные сессии:

xpack.security.session.idleTimeout: "30m"
  • Устанавливаем максимальную продолжительность одной сессии:

xpack.security.session.lifespan: "1d"
  • Настраиваем интервал принудительной очистки данных о неактивных или просроченных сессиях из сессионного индекса:

xpack.security.session.cleanupInterval: "8h"

Для всех параметров формат времени может быть следующим: ms | s | m | h | d | w | M | Y

Данные о сессии удаляются после того, как пользователь осуществляет закрытие сессии. Если не настроить закрытие неактивных сессий или не ограничить максимальную длительность сессии, то информация об этих сессиях будет накапливаться в сессионном индексе, и Kibana не сможет автоматически удалить данные.

Настраиваем Logstash

На данный момент Logstash не отправляет данные в кластер Elasticsearch, и чтобы это исправить, сделаем несколько настроек.

  • Создаем роль для подключения к кластеру:

В Kibana открываем Menu > Management > Stack Management. Слева выбираем Roles и нажимаем Create role. Указываем имя роли и настраиваем привелегии:

Cluster privileges

manage_index_templates

Все операции над шаблонами индексов

monitor

Read-only права на получение информации о кластере

Index privileges

create_index

Создание индексов

write

Индексирование, обновление и удаление индексов

manage

Мониторинг и управление индексом

manage_ilm

Управление жизненным циклом индексов (IML)

  • Создаем пользователя для подключения к кластер:

Открываем Menu > Management > Stack Management, выбираем Users и нажимаем Create user. Заполняем требуемые данные, указав в качестве роли созданную выше роль.

Создание пользователя logstash_userСоздание пользователя logstash_user
  • Создаем Logstash keystore, и добавляем туда пользователя и пароль от него:

# Создаем keystore с паролемset +o historyexport LOGSTASH_KEYSTORE_PASS=mypasswordset -o historysudo /usr/share/logstash/bin/logstash-keystore create --path.settings /etc/logstash/# Добавляем данныеsudo /usr/share/logstash/bin/logstash-keystore add ES_USER --path.settings /etc/logstash/sudo /usr/share/logstash/bin/logstash-keystore add ES_PWD --path.settings /etc/logstash/
  • Настраиваем аутентификацию в output плагине:

output {  elasticsearch {    ...    user => "${ES_USER}"    password => "${ES_PWD}"  }}
  • Настраиваем TLS в Logstash:

Для подключения по https к Elasticsearch необходимо настроить использование ssl и установить .pem сертификат, который был получен для Kibana.

output {  elasticsearch {    ...    ssl => true    cacert => '/etc/logstash/elasticsearch-ca.pem'  }}
  • Перезагружаем Logstash и проверяем новые записи в индексе

Проверку можно сделать в Kibana через Discovery, как делали в прошлой статье, или через API:

Dev Tools - Console в KibanaDev Tools - Console в Kibana

Создание API ключей

Для работы с Elasticsearch можно не только использовать учетные записи пользователей, но и генерировать API ключ. Для этого необходимо сделать POST запрос:

POST /_security/api_key

В качестве параметров указывают:

name - имя ключа

role_descriptors - описание роли. Структура совпадает с запросом на создание роли.

expiration - Срок действия ключа. По умолчанию без срока действия.

Для примера заменим базовую аутентификацию в Logstash на API ключ.

  • Создаем API ключ в Kibana Dev Tool:

POST /_security/api_key{  "name": "host_logstash01",   "role_descriptors": {    "logstash_api_writer": {       "cluster": ["manage_index_templates", "monitor"],      "index": [        {          "names": ["logstash-logs*"],          "privileges": ["create_index", "write", "manage", "manage_ilm"]        }      ]    }  },  "expiration": "365d"}

Получаем следующий результат:

{  "id" : "979DkXcBv3stdorzoqsf",  "name" : "host_logstash01",  "expiration" : 1644585864715,  "api_key" : "EmmnKb6NTES3nlRJenFKrQ"}
  • Помещаем ключ в формате id:api_key в Keystore:

sudo /usr/share/logstash/bin/logstash-keystore add API_KEY --path.settings /etc/logstash/
  • Указываем API ключ в конфигурационном файле конвейера:

output {  elasticsearch {    hosts => ["https://10.0.3.11:9200","https://10.0.3.12:9200","https://10.0.3.13:9200"]    index => "logstash-logs-%{+YYYY.MM}"    ssl => true    api_key => "${API_KEY}"    cacert => '/etc/logstash/elasticsearch-ca.pem'  }}

Информацию по ключам можно получить в Kibana Menu > Management > API Keys или через API запрос:

GET /_security/api_key?name=host_logstash01{  "api_keys" : [    {      "id" : "9r8zkXcBv3stdorzZquD",      "name" : "host_logstash01",      "creation" : 1613048800876,      "expiration" : 1613049520876,      "invalidated" : false,      "username" : "elastic",      "realm" : "reserved"    }  ]}

Заключение

В рамках данной статьи были рассмотрены основные функции безопасности стека Elastic, позволяющие обезопасить работу нашего кластера, научились создавать пользователей и пользовательские роли, производить настройку пользовательских сессий, настройку шифрования трафика между узлами кластера и между кластером и клиентами, работать с API ключами и keystore.

В следующей статье будет рассмотрена процедура создание кластера ELK с помощью Docker.

Полезные ссылки

Подробнее..

Feature Flags и фабрика ПО

20.02.2021 14:06:35 | Автор: admin

Наши команды практикуют подход Trunk Based Development новый код сразу добавляется в мастер-ветку, сторонние ветки живут максимум несколько дней. А чтобы коммиты не мешали друг другу, разработчики используют фича-флаги (Feature Flags) переключатели в коде, которые запускают и останавливают работу его компонентов.

Рассмотрим обычную итерацию разработки: планирование, уточнение требований, создание задач в трекере, разработка. По мере готовности задачи разворачиваются на тестовом окружении для проверки, релизная ветка стабилизируется. Потом наконец наступает выпуск, и команда может наконец получить реальную обратную связь от пользователей.

Если вы стремитесь сокращать Time-to-Market, это недопустимо долго. Чем раньше вы получите обратную связь от пользователей, тем скорее вы исправите ошибки, тем меньше времени вы тратите на неудачные идеи, тем больше ресурсов можете уделить идеям удачным.

Чтобы обновления быстрее доезжали до прода, одна итерация должна включать одну фичу. Именно поэтому нужно сокращать срок жизни веток.

Проблемы долгоживущих веток

  • Конфликты между коммитами (Merge hell). Откладывание релиза, интеграция с внешней системой, прочие внешние факторы могут привести кол в нерабочее состояние.

  • Трудности с шарингом кода. Другим членам команды может потребоваться код из новой ветки, если фичи зависят друг от друга. Приходится стартовать ещё одну ветку только ради доступа к этому коду.

  • Проблемы тестового окружения. Если тестовый сервер один, а фиче-веток много, параллельно тестировать задачи не получится.

  • Тяжело откатить изменения. Проблемы после релиза обычное дело, и если из-за новой фиче-ветки начинаются сбои, разработчикам приходится выбирать между хотфиксом и ревертом, лезть в исходный код, заново выкладывать решение.

Как Trunk Based Development решает эти проблемы

Trunk Based Development (от англ. trunk ствол дерева) метод разработки кода на основе одной главной ветки. В отличие от подхода Gitflow, TBD позволяет разработчикам добавлять новые модули сразу в master. Второстепенные feature-ветки также могут создаваться, но они имеют короткий срок жизни.

Trunk Based Development предполагает только одну ветку для разработки, которая называется trunk. В любой момент эту ветку можно развернуть её на проде, а разработка, как и прежде, идёт в отдельных фича-ветках. Только теперь эти ветки живут не более двух дней.

Все изменения в trunk вливаются через пул-реквесты. Изменения небольшие, поэтому процесс ревью не затягивается. Попадание нового кода в trunk запускает процессы автоматического билда, тестов и развёртывания на необходимые окружения.

Но как вести разработку в одной ветке, если какие-то фичи ещё не готовы, а релиз завтра? Тут нам на помощь приходят Feature Flags.

Как работают Feature Flags

По сути своей, это IF-блок, который запускает кусок кода при выполнении некого условия. Самое простое разработчик сам прописывает, включать или выключать код. Могут быть параметры посложнее: например, по расписанию или только для пользователей с такими-то уровнем доступа. Или наоборот фича отключается, если нагрузка на систему превышает заданный порог.

В точке переключения мы обращаемся к переключателю (toggle router), который определяет состояние фичи. Чтобы понять, какой нужен флаг, роутер обращается к его конфигурации и контексту. Первая определяет общую стратегию включения флага (основные условия для его работы), второй включает любую дополнительную информацию (например, имя пользователя, который отправил запрос, текущее время и т.д.).

Как использовать Feature Flags

Технически фиче-флаги работают одинаково, а по способу применения их можно разделить на следующие категории:

  • Релизные (release toggles): скрывают неготовые фичи, уменьшают количество веток, открепляют запуск фичи от даты деплоя. Основной тип флагов.

  • Экспериментальные (experiment toggles): используются для A/B тестирования, позволяют таргетировать функции на разные группы пользователей. Таким образом вы можете развернуть новый сервис на Х% аудитории, чтобы оценить нагрузку или собрать первые отзывы.

  • Разрешающие (permission toggles): открывают доступ к платным фичам или закрытым функциям администратора. Такие флаги могут жить очень долго, быть очень динамичными и менять своё состояние при каждом запросе.

  • Операционные (ops toggles): отключают ресурсоёмкие функции. Например, так можно регулировать работу приложения на слабых смартфонах или застраховаться от падения производительности при запуске новой функциональности флаг отключит модуль до того, как тот вызовет критический сбой.

### Что дают Feature Flags

  • Непрерывная доставка фич со стабильным качеством возможность отключить нерабочий код снижает риски в релизной версии.

  • Тестирование новых фич в боевых условиях фиче-флаги позволяют постепенно внедрять сервисы, контролируя риски при релизе на реальную аудиторию.

  • Возможность развивать несколько версий ПО параллельно TBD и фичефлаги позволяют предлагать разные функции разным группам пользователей, при этом поддерживать все эти версии ПО может всё та же одна команда.

Как управлять флагами

  • Проприетарные решения: LaunchDarkly, Bullet-Train, Unleash. Каждый продукт предлагает какие-то свои преимущества, каждый по-своему удобный. Но за лицензию придётся платить, а гибкость настройки зависит от разработчика системы.

  • Open source решения: Moggles, Esquilo. Это бесплатные решения, но чтобы они заработали у вас, потребуется над ними поколдовать. Кроме того, придётся подбирать продукт с таким набором функций, который вас устроит.

  • Собственная система управления: вариант, которым пользуемся мы. Это единственное в своём роде решение, которое целиком нас устраивает. В будущих постах расскажем подробнее.

Как флаги работают у нас

  • Feature FlagsPortal(FF-Portal): Web + REST API приложение для манипулирования состоянием флагов. Напрямую работает с хранилищем флагов.

  • Feature FlagsStorage(FF-Storage): персистентное хранилище с настройками флагов и их статусами.

  • KubernetesConfigMap(FF-configmap): k8s ConfigMap ресурс, который собирается на основе данных, которые хранятся в FF-Storage в удобном формате для конечного приложения. Изменение данных флагов через FF-Portal также влечёт к изменению FF-configmap.

  • Microservice(MS): Микросервис, который использует FF-configmap как источник конфигурации при старте приложения. При изменений FF-configmap, микросервис делает перезагрузку своей конфигурации.

Приложение считывает конфигурацию флагов с FF-ConfigMap, который монтируется к Pod-у как файл. При изменении ConfigMap, k8s обновит и файл, далее приложение среагирует на изменение файла и перегрузит конфигурацию флагов.

Изменение флагов происходит через портал, который отправляет интеграционное сообщение в шину при обновлении статуса. Компонент Config Updater обновляет значения флагов в FF-ConfigMap через K8S API.

Напоследок о тестировании

Возникает вопрос, как тестировать продукт с фиче-флагами? На первый взгляд, флаги усложняют в этот процесс если переключателей становится много, то и количество всевозможных состояний резко растёт.

Но не всегда флаги зависят друг от друга. Поэтому мы для релиза тестируем два предельных случая: 1) все новые флаги выключены и 2) все флаги включены.

Практика показывает, что обычно этого достаточно.

Подробнее..

Нужно ли разработчику знать Kubernetes и в какой мере? Круглый стол Слёрма и MCS

27.02.2021 16:15:57 | Автор: admin

Когда компании пора внедрять микросервисы? Как быть разработчику, который хочет или которого заставляют использовать Kubernetes? Где ответственность разработчика, а где админа? Кто виноват, если после внедрения прилёг продакшен? Об этом говорили на круглом столе учебного центра Слёрм и облачной платформы Mail.ru Cloud Solutions.
Под катом текстовая запись разговора.



Участники круглого стола:


  • Марсель Ибраев, CTO Слёрма, сертифицированный администратор Kubernetes.
  • Сергей Бондарев, администратор с более чем 20 годами опыта, Southbridge.
  • Павел Селиванов, senior DevOps engineer в MCS.
  • Дмитрий Лазаренко, директор по продукту в MCS, разработчик на Java.
  • Виктор Гамов, Developer Advocate в Confluent (ведущий митапа).

Встреча приурочена к старту онлайн-интенсива Kubernetes для разработчиков. В числе спикеров: Сергей Бондарев, Марсель Ибраев и Павел Селиванов. Интенсив начнётся 3 марта, успевайте!


Когда компании пора внедрять Kubernetes?


ВИКТОР ГАМОВ: В своих подкастах и шоу я всегда говорю, что мы как разработчики должны помогать бизнесу существовать. Все наши свистелки, моторчики и прочие клёвые штуки, которые мы сегодня нашли на GitHub, а завтра хотим отправить в прод, тоже должны работать на бизнес. Поэтому давайте подумаем, зачем компании Kubernetes и когда его пора внедрять?


ПАВЕЛ СЕЛИВАНОВ: У меня есть хороший ответ: когда CTO начитался Хабра и таки заметил слово Kubernetes. Срочно нужно тащить к себе!


ВИКТОР ГАМОВ: Отлично. Еще какие версии? На самом деле, ребят, не делайте так. Технические решения внедряют, чтобы решить какую-то конкретную проблему. Какую проблему решает Kubernetes?


ДМИТРИЙ ЛАЗАРЕНКО: В Mail.ru Cloud Solutions есть не только Kubernetes-как-сервис, но и Kubernetes внутри, для собственной разработки. Несколько лет мы жили просто деплоем на bare metal с помощью Ansible. У нас классическая эксплуатация: SRE-инженеры (как сейчас любят себя называть админы) и много команд разработки. Админы всё катили, всё верифицировали и стали узким горлышком. Разработчики перформили гораздо больше, чем могли выкатить админы.


Переход на Kubernetes решил проблему. Сейчас разработчики могут сами выкатывать и эксплуатировать свой сервис, разбираться, что происходит внутри. Фактически они выступают в роли DevOps/SRE, то есть отвечают в том числе и за успешность работы этого сервиса.


Когда мы работали в Ansible и делали подборки на Docker, такого не получалось. Перемены заняли примерно год. Паша [Павел Селиванов] как раз очень активно помогал с переходом на Kubernetes и внедрением идеологии в мозги как админов, так и разработчиков.


ВИКТОР ГАМОВ: Ты сейчас подставился, когда сказал, что разработчики могут доставлять кода больше, чем админы способны поддержать. Нужны ли нам админы, если они не могут поддержать и доставить годноту, которую выкатывают разработчики?


ДМИТРИЙ ЛАЗАРЕНКО: Это хороший вопрос для обсуждения, у меня есть мнение, но я не буду отвечать первым.


ПАВЕЛ СЕЛИВАНОВ: Всё зависит от специфики конкретной компании, инфраструктуры и области бизнеса. Понятно, что когда мы строим облако, мы категорически не можем обходиться без админов, причем админов в классическом смысле слова. Мы эксплуатируем железки в дата-центрах, и их нужно обслуживать: подключать, настраивать, задумываться о рейдах, дисках, процессорах, памяти и т. д.


При этом, учитывая развитие облаков, подходов DevOps и Infrastructure as a Code, многие компании могут обходиться без классических админов. Но скорее всего, без людей, которые отвечают за эксплуатацию и инфраструктуру, не могут. Всё же нужен тот человек, который это на себя возьмет. Но не факт, что он обязательно должен быть админом от сахи, человеком, который пришёл из железок.


ВИКТОР ГАМОВ: То есть если вы деплоите Kubernetes у себя, всё равно должны быть люди, которые немножечко в этом разбираются. Другой вопрос: должны ли разработчики иметь доступ к продакшену?


ПАВЕЛ СЕЛИВАНОВ: Отвечу по своему опыту. Я наблюдал не в одной компании, как это работает. Принцип разделения, когда к продакшену имеют доступ только отдельные люди, конечно, прекрасный. Но как происходит в реальности: есть разработчик, который знает, что ему надо сделать, как это работает, как это осуществить; есть админ с доступом; они объединяются. Разработчик ставит стульчик рядом с рабочим местом админа и на ухо рассказывает тому, что нужно делать. Админ нажимает кнопочки, при этом периодически нажимает что-то не то.


То есть на практике разделение ответственности приводит к лишним затратам человеческих ресурсов, потому что то, что может делать один человек, делают два. Плюс необходимость взаимодействия между специалистами увеличивает количество ошибок.


Отвечая на твой вопрос: мне кажется, что в очень небольшом количестве компаний безопасность выстроена так, что разработчик действительно не может получить доступ к продакшену. Здесь скорее Security through obscurity (безопасность через неясность) получается.


ВИКТОР ГАМОВ: Но если разделение обязанностей мешает, как найти виновного тогда? Вот деплоили, что-то не заработало, у нас убытки, кто виноват?


ПАВЕЛ СЕЛИВАНОВ: Расскажу, как мы в MCS решаем эту проблему. За сервис в любом случае отвечает разработчик, который его разрабатывал. Мы идём в таком направлении: команда разработки сервис пишет, она же за него и отвечает, и она же его эксплуатирует. Когда сервис сломался, задача разработки понять, что там сломалось и найти ответственных за этот компонент. Понятно, что если сломалась база данных, которую предоставляет команда сопровождения, то разработка вряд ли пойдёт поднимать эту базу данных, но задача разработки разобраться и поднять нужных людей.


ВИКТОР ГАМОВ: У нас как раз следующий вопрос связан с этим рассуждениями.


За что отвечают разработчики, а за что DevOps при работе с Kubernetes? Кто более компетентен?


ВИКТОР ГАМОВ: Вот Паша говорит, что разработчики должны поддерживать то, что они написали. Как по мне, это история не про поиск виноватых, а про делегирование и доверие команде. Когда людям предоставляют возможность доказать, что они могут, они начинают немного по-другому мыслить. Начинают работать не с девяти и до обеда, а ради цели.


ДМИТРИЙ ЛАЗАРЕНКО: Это про вовлечение разработчиков, когда они перестают быть кодерами и становятся архитекторами сервисов. Они становятся причастными к созданию чего-то великого, ну и к провалам в том числе, если что-то идет не так.


ВИКТОР ГАМОВ: Поэтому мне всегда больно видеть термин DevOps в значении человек, а не в значении культура. Необходимо изменять сознание и подходы к тому, как работают люди, иначе никакие технологии нам не помогут. Нам необходимо менять культуру и восприятие людей. Кто со мной поспорит?


СЕРГЕЙ БОНДАРЕВ: Культура, конечно, вещь хорошая, но не главная. Ты можешь быть сколь угодно культурным, но если у тебя нет компетенций, тебя ждут только великие провалы.


ВИКТОР ГАМОВ: То есть тот, кто более компетентен, тот и берёт на себя ответственность? Есть админы, есть опсы, кто из них важнее на проекте?


СЕРГЕЙ БОНДАРЕВ: Наверное, никто из них. Продукт оунер, скорее.


ПАВЕЛ СЕЛИВАНОВ: Архитектурный комитет.


ВИКТОР ГАМОВ: Ага, то есть никто. Если есть архитектурный комитет, то дело может сильно затянуться. Марсель, у тебя какие соображения?


МАРСЕЛЬ ИБРАЕВ: Соглашусь, что никто не главный, но зоны ответственности разные. Есть инфраструктурная команда, и все-таки ключевые решения по инфраструктуре, я думаю, за ними. А разработчики уже решают, что и как кодить под эту инфраструктуру, какие инструменты использовать. При этом в идеальном мире должна происходить синергия, и решаться всё это должно не лоб в лоб, а сообща.


ВИКТОР ГАМОВ: Я ждал, кто первым скажет слово синергия. Ты выбиваешь булшит-бинго!


ДМИТРИЙ ЛАЗАРЕНКО: Я добавлю. Паша говорил про архитектурный комитет. В чём сложность ситуации? Вот откройте карту CNCF: там сотни проектов, сотни сервисов, и все это новое. В реальности мало кто годами использовал, например, Istio. И на вопрос, кто главный при выборе Istio, ответ: да хрен его знает. Потому что кто глубже копнет, разберётся и аргументированнее даст ответ, тот и главный. Часто эти люди первопроходцы. И это одна из проблем.


ВИКТОР ГАМОВ: Я сейчас вброшу, а вы поспорьте со мной. В чём DevOps меняет восприятие разработки, так это в том, что можно проводить эксперименты и изучать технологии прямо в процессе. Благодаря Kubernetes мы можем делать AB-тестинг: например, на одной части контура использовать Istio, на другой части ещё какого-нибудь вендора. Таким образом обучение идёт сильно быстрее. Поэтому Kubernetes это не платформа, это базис для построения ваших платформ. В этом смысле он совершенно потрясающий.


ПАВЕЛ СЕЛИВАНОВ: Вот именно, что Kubernetes это не законченная вещь, это конструктор, который нужно собрать под себя. Я видел в нескольких проектах такое разделение: некие мифические DevOpsы строят платформу для разработки, чтобы разработчик мог как можно меньше заморачиваться на этапе разработки по поводу инфраструктурных моментов, меньше ломать, если что-то пойдет не так, и как можно более гибко её использовать. Вот DevOpsы строят платформу на основе Kubernetes, разработчики её эксплуатируют, то есть запускают там свои сервисы, деплоят то, что им нужно, настраивают между ними связи и так далее.


СЕРГЕЙ БОНДАРЕВ: Можно мне поныть на тему изучения новых технологий. Неумеренность в этом вопросе приводит к тому, что приходишь на проект, видишь кучу новых слов, начинаешь в них разбираться, и оказывается, что часть технологий уже прекратила своё развитие, часть из них ещё в глубокой альфе. Но разработчики категорически настаивают, что они хотят это использовать, им это необходимо, и вообще по-другому они никак не могут жить. И тут задача опсов убедить разработчиков, что какие-то вещи ещё рано использовать, а какие-то поздно.


ВИКТОР ГАМОВ: Тут речь как раз про культуру. Когда в команде есть доверие, сложные вопросы решаются легче.


Что для вас знать Kubernetes?


ВИКТОР ГАМОВ: Что для вас знание Kubernetes? Знание ключей и опций kubectl? Архитектуры? Компонентов? Отличий от Docker и Docker Compose? Сертификаты CKA/CKAD? Расшифруйте, чтобы, выровнять понятийный уровень. Что важнее: сертификаты или опыт?


МАРСЕЛЬ ИБРАЕВ: Знания, конечно. Но сертификат штука приятная. Вы можете указать длинный списочек: ваши регалии, грамоты школьные приложить.


ВИКТОР ГАМОВ: Какие сертификаты получат слушатели курса по Kubernetes для разработчиков? Или курс больше нацелен на получение практических знаний?


МАРСЕЛЬ ИБРАЕВ: Мы всегда делали акцент на практику. Наша цель не подготовить к сертификации, а подготовить к применению знаний на практике. В первую очередь знание, а нужен сертификат или нет, каждый решает сам.


СЕРГЕЙ БОНДАРЕВ: Система сертификации пришла к нам, наверное, с Запада. Она рассчитана на то, что незнакомый человек посмотрит на твою доску почета и проникнется, поймёт, что какой-то дядя проверил твои знания и выдал бумажку, что ты вот эту штуку знаешь хорошо. Если он этому дяде доверяет, значит, сертификат хороший. Если это выдано какой-нибудь Районной Академией Наук, то, наверное, сертификат не очень. Сертификация тоже бывает очень разная.


С тех пор как за сертификацию начали брать деньги, это стало отдельным бизнесом. Ситуация такая: если я сделаю нормальную сертификацию, на которой задаются действительно сложные вопросы, никто не придет ее сдавать, я не получу своих денег, поэтому сертификацию мы делаем по низу средних способностей, чтобы хотя бы 70-80% людей, которые к нам приходят, ее сдавали. Другая крайность брать за сертификацию большие деньги, делать ее сложной и ожидать, что придет мало людей, но за этих людей будет платить работодатель. А компаниям, в которых работают крутые специалисты, сертификация особо и не нужна: они уже знают, что у них есть крутые специалисты, зачем их сертифицировать.


ВИКТОР ГАМОВ: Дима или Паша, когда к вам приходят соискатели на вакансию SRE или разработчика, вы смотрите на сертификаты? Или делаете прожарку тестовым заданием?


ДМИТРИЙ ЛАЗАРЕНКО: В MCS мы не смотрим на сертификаты. А смотрим на то, как человек подходит к решению проблемы, насколько попытается разобраться в причине, как коммуницирует с другими людьми (это уже история про софт-скилы), и в целом, насколько разбирается в архитектуре, понимает репликацию в базах данных или как работает Kubernetes. Это лучше, чем просто формальная сдача экзамена на сертификат. Мы смотрим на problem-solving и на то, как ты коммуницируешь с другими людьми во время решения проблемы. Потому что герои-одиночки, которые могут быть токсичными, никому не интересны. Мы отказывали людям, которые не могут хорошо общаться с командой, но при этом очень крутые технические специалисты.


ПАВЕЛ СЕЛИВАНОВ: Когда проходишь собеседование и говоришь, что есть сертификат, обычно на это отвечают: Ага, давайте к следующему вопросу. Мне кажется, сертификаты, особенно кубернетесовские, в основном нужны компаниям. Я работал в двух компаниях, у которых есть сертификация Linux Foundation от CNCF. Соответственно, чтобы компании пройти такую сертификацию, в штате должно быть определённое количество специалистов, которые сертифицированы как администраторы или девелоперы Kubernetes. Это тот случай, когда реально стоит пройти CK или CKD. Если вы думаете, что CK или CKD поднимет зарплату или увеличит шансы устроиться на работу, то вы, вероятно, ошибаетесь. По крайней мере, в России на эту бумажку вообще никто не смотрит.


В какой момент среднестатистическому разработчику стоит задуматься об умении использовать Kubernetes?


ВИКТОР ГАМОВ: Стоит ли полагаться на разработчиков при внедрении или лучше найти DevOps-инженера?


ПАВЕЛ СЕЛИВАНОВ: Что касается внедрения Kubernetes и вообще любых инфраструктурных вещей Если вы стартап, вам надо просто запуститься и показать, какая ваша разработка крутая, то можно обойтись без выделенного человека. Дальше, я боюсь, если вы не наймёте такого человека, то у вас в команде быстренько найдется разработчик, на которого все это свалится. И тут всё зависит от того, хотел разработчик, чтобы на него это свалилось, или не хотел. Он может проклясть вас, а может, и наоборот, обрадоваться, что больше не надо писать эти дурацкие бизнес-приложения.


Отвечая на вопрос, насколько разработчику вообще необходимо уметь использовать Kubernetes, я бы не стал этим заморачиваться до тех пор, пока в компании нет Kubernetes или нет возможности его использовать. Но как только админы или DevOps припрут Kubernetes, вам так или иначе придётся с ним разобраться. Потому что вряд ли вам сразу же напишут красивые дашборд-кнопки, которые нажимаешь и всё разворачивается. Придётся узнать, что такое поды, реплика-сеты, деплойменты, зачем нужны стейтфул-сеты и почему не надо писать в Kubernetes базу данных.


ВИКТОР ГАМОВ: Ты ведь из облачного провайдера, почему ты не говоришь, что cloud-провайдер даёт тебе не просто голый Kubernetes, a managed-Kubernetes, снимает головняк?


ДМИТРИЙ ЛАЗАРЕНКО: Дьявол в деталях. Наверное, самое интересное начинается, когда вы внедрили Kubernetes и первый раз прилёг продакшен. Что происходит потом, можно долго описывать. Разработчик должен понимать все эти примитивы внутри Kubernetes, он должен понимать интеграцию с разными инструментами: зачем ему Prometheus, какие метрики нужно мониторить, как настроить алёрты, как использовать все фишки Prometheus и как правильно работать с логами.


Без понимания эксплуатации всё становится грустно, и приложение чинится сутками. DevOpsы не понимают бизнес-логику работы приложения, а разработчики не понимают, как работает Kubernetes и что там сломалось. Одна из ключевых проблем, которая была в начале с OpenShift, в том, что никто не понимал, как вся эта машина работает. С Kubernetes всё становится попроще, потому что там прям такие кубики. Но в кубиках нужно разбираться. Часть, которая связана с эксплуатацией и реальной жизнью, не менее важна, чем просто научиться ямлики писать.


ВИКТОР ГАМОВ: То есть ты хочешь сказать, что мало знать Java, например, или Golang, и разбираться, как алгоритмы на них написать, ещё нужно понимать, где и как это будет выполняться? Мало того что это будет выполняться в какой-то среде, так эта среда ещё не настоящая. Потому что вокруг этой среды ещё много всего.


ДМИТРИЙ ЛАЗАРЕНКО: Не совсем так. Kubernetes в этом отношении даёт унификацию. В целом понятно, какая среда повторяемая. Пускай даже используются разные облачные провайдеры, но в целом все работает более-менее одинаково. Но среда всё равно непривычная, другая. Там ещё много всего вокруг, и оно может стрельнуть.


ВИКТОР ГАМОВ: Может быть, стоит провайдеру снимать эти головняки? У нас есть админы, которые умеют готовить Kubernetes, есть разработчики, которые в принципе знают, как писать приложение, но ещё им нужно понимать, как варить Kubernetes. Может быть, их кто-то встретит как раз хорошим сервисом, чтобы уменьшить головняк?


ДМИТРИЙ ЛАЗАРЕНКО: Идея хорошая, но это как с безопасностью. Если всё будет безопасно, работать будет невозможно. За всё приходится платить. За автоматизацию, о которой ты говоришь, приходится платить очень жёсткими правилами. К сожалению или к счастью, у нас мультикультурное общество, каждый думает по-своему, и невозможно придумать унифицированные правила для работы приложения. Все пытаются это делать, изобретают фреймворки, но идея утопична. Всякие спинакеры и подобные продукты позволяют унифицировать и упростить процесс CI/CD. Но это не единственный процесс. Обилие open source инструментов делает задачу нерешаемой. Да, облачный провайдер упрощает жизнь и позволяет системным администраторам и DevOps экономить время на выполнении рутинных операций, но это не серебряная пуля. Невозможно всё автоматизировать, иначе люди не нужны будут. И плюс у облачных провайдеров не столько разработчиков, чтобы сделать эту магическую оптимизацию.


СЕРГЕЙ БОНДАРЕВ: Cloud-провайдеры предоставляют набор готовых решений, в которые ты волей-неволей должен упихиваться. Если тебя этот набор удовлетворяет, то в принципе жить в облаке не проблема. Но иногда есть потребности или идеи, которые в облаке реализованы не так, как ты хотел. И ты отказываешься от каких-то частей cloud-решений, потому что они тебя не удовлетворяет по своим возможностям и своим ограничениям. Кроме того, облачные решения консервативны. Если что-то сломалось, чинить это будут долго. А сам ты себе это можешь поставить и нормально работать.


ВИКТОР ГАМОВ: Да, такое будет в любой managed-системе.


Зачем перегружать разработчика информацией, когда можно просто дать ему кнопку?


ПАВЕЛ СЕЛИВАНОВ: Это такой комплексный вопрос, столько сразу слоев. Давайте представим ситуацию: у нас есть бизнес, техническая команда решила, что им нужен Kubernetes, и вся бизнес-разработка останавливается, пока DevOpsы не напилят кнопку, которая удовлетворит все потребности разработчиков. Я думаю, что это нереальная ситуация. В любом случае разработчики будут жить с Kubernetes, сами будут с ним разбираться. Со временем, наверное, это взаимодействие будет уменьшаться, но я не верю, что это произойдёт быстро и разработчик избавится от необходимости знакомиться с Kubernetes.


Опять же, Kubernetes, да и микросервисы вообще, позволяют выкатывать фичи быстро. Так быстро, как это нужно бизнесу, при этом не сильно заморачиваться, как что-то работает под капотом. Гораздо проще написать простой микросервис, какую-нибудь фиговину, которая будет базу данных перекладывать в информацию в формат Json, чем действительно разбираться с новыми или старыми технологиями и писать что-то низкоуровневое. Мне кажется, Kubernetes как раз-таки позволяет удовлетворять современные требования бизнеса.


МАРСЕЛЬ ИБРАЕВ: Тут, конечно, вопрос, как Паша сказал, многослойный. И без привязки к кому-то примеру сложно сказать. Но если мы хостим всё у себя, без облаков, и при этом мы говорим, что у нас DevOps, то, мне кажется, DevOps у нас не получится, если не будет тесной взаимосвязи и понимания, что делает разработка, а что админы.


Что будет на курсе?


ВИКТОР ГАМОВ: Давайте конкретики добавим: что будет на курсе, что поможет, например, Java-разработчику разбираться глубже в вопросе деплоя?


МАРСЕЛЬ ИБРАЕВ: Кстати, вопрос, который был на слайде: что есть Kubernetes? Мы как-то без конкретики его пробежали. Можем вернуться и поконкретнее рассказать.


Что нужно знать разработчику: это, разумеется, основные абстракции куба в чем ваше приложение запускается и какие инструменты поддерживаются. Далее, вы хотите, чтобы ваше приложение работало только со stateful-данными, или вы хотите, чтобы ваше приложение запускалась на каждой ноде кластера, все это разные абстракции. Их определенно нужно знать и админам, и разработчику. Банальный пример: что-то не заработало, надо срочно фиксить. Инфраструктура, конечно, полезет и на крайний случай откатит. Но факт, что проблема возникла после деплоя, намекает: проблема может быть в коде, надо садиться и разбираться. Разбираться лучше уже на стейдже, поэтому какая-то база в голове должна быть.


ПАВЕЛ СЕЛИВАНОВ: Про курсы любят спрашивать: а что мне на курсе расскажут такого, чего нет в документации? зачем мне эти курсы нужны?. Я могу ответить, что в этом курсе гарантированно есть вещи, которых нет в документации.


Среди присланных вопросов был вопрос, как дебажить Java или что-то такое. Это вообще распространенная в Kubernetes штука: у вас есть продакшен, и естественно разработчики хотят прийти на продакшен, залезть в контейнеры и начать там на живых пользователях что-то дебажить. Вот что нужно знать разработчику про Kubernetes.


Про абстракции, джобы, стейтфул-сеты можно почитать документацию недельки чтения будет достаточно. А вот реальная эксплуатация кластера Kubernetes и задачи разработки С этими задачами вам админы не пойдут помогать. Как ваше приложение дебажить, какие инструменты для этого есть, как вам построить локальную разработку так, чтобы код, который вы пишете, одинаково хорошо работал в Docker, Docker-compose, Kubernetres и так далее. Как это все собирать между собой. Вот это те вещи, которые мы хотим разобрать в курсе.

Что использовать для локальной разработки под Kubernetes?


ВИКТОР ГАМОВ: Давайте по тулам поговорим. Здесь был вопрос, мне очень он нравится самому: Что думаете по поводу k3s как способе развернуть кластер и разобраться в его устройстве?.


СЕРГЕЙ БОНДАРЕВ: Это детище компании Rancher. k3s заявлялся как Kubernetes, который будет запускаться на холодильнике.


ВИКТОР ГАМОВ: Это такая штука, которая полностью обрезана.


СЕРГЕЙ БОНДАРЕВ: У него отрезано не так уж и много. Вырезаны облачные контроллеры и прочее, но самое главное, у него вырезан etcd, вместо него используется SK Light, и всё это работало на одной-единственной машинке, грубо говоря. Использовать эту штуку для изучения Kubernetes не самый лучший вариант. Проще и быстрее поставить себе Minikube, или почитать документацию, взять kubeadm в зубы и поставить его на машину с Docker из одного узла и на нём изучать.


ВИКТОР ГАМОВ: То есть ты поклонник подхода Kubernetes the Hard Way? Когда нужно пойти и разобраться.


СЕРГЕЙ БОНДАРЕВ: Я поклонник установки с помощью kubespray.


ВИКТОР ГАМОВ: А ведь мы не сказали, что Сергей Бондарев один из тех, кто коммитит в kubespray.


СЕРГЕЙ БОНДАРЕВ: Я в нём разбираюсь, время от времени чиню баги и дополняю функционал.


ВИКТОР ГАМОВ: Раз уж мы заговорили про тулы внедрения. Какая там сейчас обстановка? Раньше был капс, теперь есть kubeadm, k3s, kubespray что их отличает и что взять? Ты упомянул Minikube, но по моему опыту он достаточно капризный. Под MacOS, например, он очень странно жил.


СЕРГЕЙ БОНДАРЕВ: Это не ко мне вопрос. У меня всегда есть несколько виртуалок с Docker, которые объединены в локальную сеть. Я на них могу поставить что угодно. Необходимости поставить что-то на локальном компьютере у меня не возникает.


ВИКТОР ГАМОВ: k3s был популярен, потому что в нём обрезаны многие лишние вещи. Например, обратная совместимость


СЕРГЕЙ БОНДАРЕВ: Ну как же! Обратная совместимость это самое важное, что есть в Kubernetes.


ВИКТОР ГАМОВ: Мы ведь не говорим про использование k3s в продакшене. Речь про локальную разработку. Паша, как вы в Mail.ru разрабатываете вещи, которые пишете под Kubernetes?


ПАВЕЛ СЕЛИВАНОВ: Очень просто. Если мне нужно сделать что-то локально с самим Kubernetes, то есть разработать то, что я буду запускать в Kubernetes, это Minikube. С MacOS недавно только одну проблемы заметил: они по умолчанию перешли на использование драйвера Docker, там теперь запускается контейнер в контейнере. И в таком случае у него не работают ingress-контроллеры. Они просто изнутри Docker недоступны становятся. Пришлось откатиться локально, использовать Virtualbox или X-hive (встроенную маковскую виртуализацию).


Если нужно решать какие-то админские задачи: нужно что-то в самом кластере проверить, протестировать, как конфигурации какие-то будут работать, взаимодействие между нодами, я использую какое-то облако. В Google, AWS или даже у нас за бонусные баллы его легко получить. Поднимаю на виртуалке, настраиваю там Kubernetes и так далее.


Что касается самих установщиков: Kops это утилита номер один для развёртывания Kubernetes в облаке, для остальных случаев Kubespray.


ВИКТОР ГАМОВ: Марсель, Дима, есть что добавить по поводу тулов, что мы посоветуем разработчикам использовать локально?


МАРСЕЛЬ ИБРАЕВ: Для разработки действительно удобнее Minikube чтобы что-то локально потестить, посмотреть, потыкать. А если есть задача поизучать его, поковырять, разобраться в логике, в компонентах, то поддержу Сергея: лучше взять какой-нибудь kubeadm и развернуть хотя бы однонодный кластер, там уже будет что-то близкое к продакшену.


А что с безопасностью?


ВИКТОР ГАМОВ: Самый важный вопрос обсудить забыли: что у нас с безопасностью? Что есть в Kubernetes, что позволяет обеспечить безопасность.


ПАВЕЛ СЕЛИВАНОВ: В чатике как раз был вопрос, как в синергию админов и разработчиков вписать безопасников, то есть как сделать DevSecOps как создавать тулы безопасников, как их встраивать в общий пайплайн.


Что вижу я: в крупных компаниях безопасник это какой-нибудь отставной подполковник ФСБ, и последнее, что он делал, это Эльбрусы кольцом собирал. Задача безопасника подписывать бумажки и брать на себя ответственность. Поэтому тут вообще вопрос: когда бизнес перестанет воспринимать безопасников как людей, которые подписывают бумажки, и начнет их как людей, которые должны интегрироваться с остальным техническим отделом и идти в ту же сторону, использовать какие-то инструменты.


Инструментов на сегодняшний день огромное количество. Мне как DevOps инженеру, человеку, который пишет пайплайны, было бы интересно всё это дело в свои пайплайны встраивать, просто времени не хватает. Я бы хотел, чтобы кто-то этим занимался. Но у самого Kubernetes есть airbag, это встроенная фишка. Можно подключить какой-нибудь hashicorp vault, чтобы хранить секреты, это, наверное, самое распространенное. Есть еще штуки типа Open Policy Agent, который позволяет просматривать и писать конкретные правила под всё, что запускается в Kubernetes, делать свои собственные политики безопасности, настраивается все это очень гибко, проверяется и так далее. Есть инструменты, которые добавляют просто авторизацию в кластер и делают это нормально, типа Keycloack, Dex. Есть штуки, которые позволяют анализировать содержимое контейнеров, то, что вы собираетесь деплоить на свои продакшен-серверы. Например, Harbor, JFrog и т д. Инструментов огромное количество. Вопрос: кто бы ими занимался, потому что отставные подполковники явно не станут это делать.


ВИКТОР ГАМОВ: Поддержу Пашу. Сегодня безопасность перестаёт быть чем-то загадочным из серии мы сгенерировали ключи, запечатали в конверты и разослали. Есть набор совершенно понятных решений, которые надо внедрять. А вот всеми любимый Kerberos. Как делать Kerberos на Kubernetes?


МАРСЕЛЬ ИБРАЕВ: В Kubernetes точно есть инструментарий, который может с LDAP-ами всякими дружить, и делает это достаточно хорошо. Kerberos я не пробовал.


СЕРГЕЙ БОНДАРЕВ: Для Kerberos мы слишком молоды.


ДМИТРИЙ ЛАЗАРЕНКО: В Keycloak есть штука, которая позволяет обменивать токены одного типа, например, самловские токены в open d connect токены. И за счёт такого пайплайна обмена токенов Kerberosа в open d connect, которые понимает Kubernetes, наверное, можно сделать подобный костыль.


ВИКТОР ГАМОВ. В завершение давайте ещё раз поговорим про тулы. Манифесты пишутся с использованием Helm, как разработчику упростить себе жизнь при работе с ним?


ПАВЕЛ СЕЛИВАНОВ: Могу поделиться, как мы сейчас делаем это в MCS. В третьем Helm есть библиотечные чарты, на базе которых мы собрали единый Helm-чарт. И фактически всё, что нужно знать разработчику, это посмотреть документацию к единому Helm-чарту, посмотреть, какие там есть вэльюсы, и в своем проекте заполнить просто один файлик с вэльюсами (на самом деле, не один, а по одному файлику на каждое окружение). Они еще между собой мёрджатся.


Благодаря этому разработчики не касаются Kubernetes, при этом мы применяем все best practices, которые хочется применять к манифестам, используемым разработчиками. Фактически мы из этих вэльюсов разработки генерим готовые чарты. Точнее, подставляем их в наш общий чарт и деплоим это в кластер. Вот как упрощается жизнь разработчика: они не касаются Helma и Kubernetesa вообще никаким образом.


ВИКТОР ГАМОВ: И хорошо! В конце разговора ещё раз напомню, что 3-5 марта будет проходить интенсив по Kubernetes для разработчиков на платформе Слёрм. Kubernetes можно будет не только изучить, но потрогать и пощупать, потому что ребята из Mail.ru дадут всем участникам бонусные баллы.

Подробнее..

Cortex и не только распределённый Prometheus

04.03.2021 10:11:49 | Автор: admin

В последнее время Prometheus стал де-факто стандартом для сбора и хранения метрик. Он удобен для разработчиков ПО - экспорт метрик можно реализовать в несколько строк кода. Для DevOps/SRE, в свою очередь, есть простой язык PromQL для получения метрик из хранилища и их визуализации в той же Grafana.

Но Prometheus имеет ряд недостатков, способы устранения которых я хочу рассмотреть в этой статье. Также разберём деплой Cortex - распределённого хранилища метрик.

Недостатки

  • Отсутствие отказоустойчивости

    Prometheus работает только в единственном экземпляре, никакого HA.

  • Отсутствие распределения нагрузки

    В принципе, он хорошо скейлится вверх с ростом количества ядер. Так что это проблема только для тех у кого действительно много метрик.

  • Нет поддержки multi-tenancy

    Все метрики летят в один большой котёл и разгребать их потом используя PromQL и метки не всегда удобно. Часто хочется разделить различные приложения и\или команды по своим песочницам чтобы они друг другу не мешали.

    Плюс, многие готовые дашборды для Grafana не готовы к тому что много инстансов одного приложения хранят метрики в одном и том же месте - придётся переделывать все запросы, добавлять фильтры по меткам и так далее.

В принципе, все эти проблемы можно решить настроив несколько HA-пар Prometheus и распределив по ним свои приложения. Если перед каждой парой повесить прокси, то можно получить что-то вроде отказоустойчивости.

Но есть и минусы:

  • После того как один хост из пары упадёт/перезагрузится/whatever - у них случится рассинхронизация. В метриках будут пропуски.

  • Все метрики приложения должны умещаться на один хост

  • Управлять таким зоопарком будет сложнее - какие-то из Prometheus могут быть недогружены, какие-то перегружены. В случае запуска в каком-нибудь Kubernetes это не так важно.

Давайте рассмотрим какими ещё способами можно решить это.

PromQL прокси

Например promxy, который размещается перед 2 или более инстансами Prometheus и делает fan-out входящих запросов на все из них. Затем дедуплицирует полученные метрики и, таким образом, закрывает пропуски в метриках (если, конечно, они не попали на один и тот же временной интервал).

Минусы подобного решения на поверхности:

  • Один запрос нагружает сразу все инстансы за прокси

  • Прокси решает только проблему с пропусками в метриках.

Но для тех, у кого нагрузка укладывается в возможности одного Prometheus (либо ее можно грамотно раскидать по нескольким HA-парам) и кому не нужен multi-tenancy - это очень хороший вариант.

Thanos

Thanos - это уже более продвинутое решение.

Он устанавливает рядом с каждым инстансом Prometheus так называемый Sidecar - отдельный демон, который подглядывает за блоками данных, которые генерирует Prometheus. Как только блок закрывается - Sidecar загружает его в объектное хранилище (S3/GCS/Azure). Длина блоков в Prometheus прибита гвоздями и равна 2 часам.

Также он является прокси между GRPC Thanos StoreAPI и Prometheus для получения метрик, которые еще не были загружены в объектное хранилище.

Отдельный компонент Querier реализует PromQL: в зависимости от временного интервала запроса и настроек глубины хранения данных в Prometheus он может направить его в объектное хранилище, в Sidecar или в разбить на два подзапроса - для свежих данных запрос пойдёт через Sidecar в Prometheus, а для более старых - в объектное хранилище.

Отказоустойчивость свежих данных в Thanos реализуется примерно так же как и в promxy - делается fan-out запросов на все причастные сервера, результаты накладываются друг на друга и дедуплицируются. Задача по защите исторических данных лежит на объектном хранилище.

Multi-tenancy есть в некотором зачаточном состоянии, но в эту сторону проект, судя по всему, не развивается особо.

Cortex

Это наиболее сложный и функциональный проект. Его начали разрабатывать в Grafana Labs для своего SaaS решения по хранению метрик и несколько лет назад выложили в open source, с тех пор разработка идёт на гитхабе.

Как можно видеть на диаграмме выше - в нём очень много компонентов. Но бояться не стоит - большую часть из них можно не использовать, либо запускать в рамках одного процесса - single binary mode.

Так как Cortex изначально разрабатывался как SaaS решение - в нём поддерживается end-to-end multi-tenancy.

Хранение метрик

На данный момент в Cortex есть два движка. Оба они хранят данные в объектном хранилище, среди которых поддерживаются:

  • S3

  • GCS

  • Azure

  • OpenStack Swift (экспериментально)

  • Любая примонтированная ФС (например - NFS или GlusterFS). Хранить блоки на локальной ФС смысла нет т.к. они должны быть доступны всему кластеру.

Далее я буду для краткости называть объектное хранилище просто S3.

Chunks Storage

Изначальный движок в Cortex - он хранит каждую timeseries в отдельном чанке в S3 или в NoSQL (Cassandra/Amazon DynamoDB/Google BigTable), а метаданные (индексы) хранятся в NoSQL.

Chunks Storage, думается, со временем совсем выпилят - насколько я слышал, Grafana Labs свои метрики уже мигрировали в Blocks Storage.

Blocks Storage

Новый, более простой и быстрый движок, основанный на Thanos. Который, в свою очередь, использует формат блоков самого Prometheus. С ним нет нужды в NoSQL и модуле Table Manager (но нужен другой - Store Gateway).

Thanos, в данном, случае является внешней vendored зависимостью в коде Cortex. Есть разговоры о том, чтобы объединить два проекта в один, но когда это будет неизвестно (и будет ли вообще).

Архитектура

Далее я буду рассматривать работу с Blocks Storage.

Упрощённо принцип работы следующий:

  • Prometheus собирает метрики с endpoint-ов и периодически отправляет их в Cortex используя Remote Write протокол. По сути это HTTP POST с телом в виде сериализованных в Protocol Buffers метрик сжатый потом Snappy. В самом Prometheus, при этом, можно поставить минимальный retention period - например 1 день или меньше- читаться из него ничего не будет.

  • Модуль Distributor внутри Cortex принимает, валидирует, проверяет per-tenant и глобальные лимиты и опционально шардит пришедшие метрики. Далее он передает их одному или нескольким Ingester (в зависимости от того применяется ли шардинг).

    Также в рамках этого модуля работает HA Tracker (о нём ниже).

  • Ingester ответственен за запись метрик в долговременное хранилище и выдачу их для выполнения запросов. Изначально метрики записываются в локальную ФС в виде блоков длиной 2 часа. Затем, по истечении некоторого времени, они загружаются в S3 и удаляются с локальной ФС.

    Также поддерживается репликация и zone awareness для дублирования блоков по различным availability domain (стойки, ДЦ, AWS AZ и так далее)

  • Store-Gateway служит для отдачи блоков из S3.

    Он периодически сканирует бакет, находит там новые блоки, синхронизирует их заголовки в локальную ФС (чтобы после перезапуска не скачивать опять) и индексирует.

  • Querier реализует PromQL.

    При получении запроса анализирует его и, если необходимо, разбивает на два - одна часть пойдёт в Store Gateway (для более старых данных), а другая - в Ingester для свежих.

    По факту параллельных запросов может быть больше если запрашиваемый период большой и настроено разбиение по интервалам (об этом дальше в конфиге)

  • Compactor периодически просыпается и сканирует объектное хранилище на предмет блоков, которые можно склеить в более крупные. Это приводит к более эффективному хранению и быстрым запросам.

    Старые блоки не удаляются сразу, а маркируются и удаляются на следующих итерациях чтобы дать время Store-Gateway обнаружить новые, которые уже сжаты.

Отказоустойчивость

Помимо репликации данных между Ingester-ами нам необходимо обеспечить отказоустойчивость самих Prometheus. В Cortex это реализовано просто и элегантно:

  • Два (или более) Prometheus настраиваются на сбор метрик с одних и тех же endpoint-ов

  • В каждом из них настраиваются специальные внешние метки, которые показывают к какой HA-группе принадлежит данный Prometheus и какой у него идентификатор внутри группы.

    Например так:

  external_labels:    __ha_group__: group_1    __ha_replica__: replica_2
  • При приёме метрик Cortex из каждой группы выбирает один Prometheus и сохраняет метрики только от него

  • Остальным отвечает HTTP 202 Accepted и отправляет в /dev/null всё что они прислали

  • Если же активный инстанс перестал присылать метрики (сработал таймаут) - Cortex переключается на приём от кого-то из оставшихся в живых.

Таким образом дедупликация на этом уровне становится не нужна. Правда остаётся вопрос момента переключения - не теряется ли там что-либо (когда старый не прислал, а от нового ещё не приняли), я этот вопрос не изучал глубоко - нужно тестировать.

Авторизация

Каждый запрос на запись метрик из Prometheus должен содержать HTTP-заголовок X-Scope-OrgId равный идентификатору клиента (далее я буду называть их просто tenant, хорошего перевода не придумал). Метрики каждого tenant-а полностью изолированны друг от друга - они хранятся в разных директориях в S3 бакете и на локальной ФС

Таким же образом происходит и чтение метрик - в PromQL запросах тоже нужно тоже указывать этот заголовок.

При этом никакой реальной авторизации Cortex не проводит - он слепо доверяет этому заголовку. Auth Gateway есть в роадмапе, но когда он будет готов неизвестно. Даже просто добавить этот заголовок напрямую в Prometheus нельзя, только используя промежуточный HTTP прокси.

Для более гибкой интеграции Prometheus & Cortex я набросал простенький Remote Write прокси - cortex-tenant, который может вытаскивать ID клиента из меток Prometheus. Это позволяет использовать один инстанс (или HA-группу) Prometheus для отправки метрик нескольким разным клиентам. Мы используем этот функционал для разграничения данных разных команд, приложений и сред.

Авторизацию можно отключить, тогда Cortex не будет проверять наличие заголовка в запросах и будет подразумевать что он всегда равен fake - то есть multi-tenancy будет отключен, все метрики будут падать в один котёл.

При необходимости данные одного клиента можно полностью удалить из кластера - пока это API экспериментально, но работает.

Настройка Cortex

В первую очередь хотелось бы сказать, что Cortex имеет смысл для тех, у кого действительно много метрик, либо хочется хранить централизовано.

Для всех остальных гораздо проще установить несколько HA-пар Prometheus (например на каждую команду или каждый проект) и поверх них натянуть promxy

Так как документация имеет некоторое количество белых пятен - я хочу рассмотреть настройку простого кластера Cortex в режиме single binary - все модули у нас будут работать в рамках одного и того же процесса.

Danger Zone! Дальше много конфигов!

Зависимости

Нам понадобится ряд внешних сервисов для работы.

  • etcd для согласования кластера и хранения Hash Ring

    Cortex также поддерживает Consul и Gossip-протокол, которому не нужно внешнее KV-хранилище. Но для HA-трекера Gossip не поддерживается из-за больших задержек при сходимости. Так что будем юзать etcd

  • memcached для кеширования всего и вся.

    Cortex поддерживает его в нескольких своих модулях. Можно поднять несколько инстансов и указать их все в Cortex - он будет шардить по всем равномерно. В принципе, он не обязателен, но крайне рекомендован с точки зрения производительности.

    Также есть DNS-based discovery через SRV-записи, если не хочется указывать вручную.

  • minio для реализации распределённого S3 хранилища.

    Несколько странный проект, который часто в процессе разработки ломает обратную совместимость и требует полного перезапуска кластера для апгрейда. Также SemVer это для слабаков, поэтому у них версионирование по датам. Его разрабатывают, в основном, индусы - возможно в этом причина...

    Но других вариантов особо нет, можно поднять Ceph с S3 шлюзом, но это еще более громоздко.

    minio поддерживает Erasure Coding для отказоустойчивости, что есть хорошо.

  • HAProxy для связывания компонентов воедино

  • cortex-tenant для распределения метрик по tenant-ам

  • Prometheus собственно для сбора метрик

Общие вводные

  • Кластер мы будем строить плоский из 4 хостов - все они будут идентичны, с одинаковым набором сервисов. Это хорошо для небольших инсталляций, упрощает структуру.

    3 страйпа не поддерживает minio c Erasure Coding - он нарезает от 4 до 16 дисков в один EC-набор. В реальном проекте лучше использовать 5 или какое-либо большее нечетное число чтобы не было Split Brain.

    Также, если у вас много хостов, то некоторые компоненты, такие как etcd, лучше вынести отдельно. etcd основан на Raft и реплицирует данные на все ноды кластера, смысла в их большом количестве нет - это только увеличит среднюю нагрузку лишними репликами.

  • Все данные будем хранить в /data

  • Конфиги я буду приводить для одного хоста, для остальных обычно достаточно поменять адреса и\или хостнеймы

  • В качестве ОС используем RHEL7, но различия с другими дистрибутивами минимальны

  • У нас всё это дело, конечно, раскатывается через Ansible, но плейбук довольно сильно завязан на нашу инфраструктуру. Я постараюсь потом его подчистить и выложить

  • Некоторые RPM пакеты я собираю вручную (etcd, HAProxy и т.п.) с помощью FPM т.к. в репозиториях древние версии.

/etc/hosts
10.0.0.1 ctx110.0.0.2 ctx210.0.0.3 ctx310.0.0.4 ctx4

etcd

Как и Zookeeper, с настройками по умолчанию etcd - бомба замедленного действия. Он не удаляет ненужные снапшоты и разрастается до бесконечности. Зачем так сделано - мне не понятно.

Поэтому настроим его соответственно:

/etc/etcd/etcd.conf
ETCD_NAME="ctx1"ETCD_LOGGER="zap"ETCD_LOG_LEVEL="warn"ETCD_DATA_DIR="/data/etcd/ctx1.etcd"ETCD_LISTEN_CLIENT_URLS="http://personeltest.ru/away/10.0.0.1:2379,http://127.0.0.1:2379"ETCD_LISTEN_PEER_URLS="http://personeltest.ru/away/10.0.0.1:2380"ETCD_ADVERTISE_CLIENT_URLS="http://personeltest.ru/away/10.0.0.1:2379"ETCD_INITIAL_CLUSTER_TOKEN="cortex"ETCD_INITIAL_ADVERTISE_PEER_URLS="http://personeltest.ru/away/10.0.0.1:2380"ETCD_AUTO_COMPACTION_RETENTION="30m"ETCD_AUTO_COMPACTION_MODE="periodic"ETCD_SNAPSHOT_COUNT="10000"ETCD_MAX_SNAPSHOTS="5"ETCD_INITIAL_CLUSTER="ctx1=http://ctx1:2380,ctx2=http://ctx2:2380,ctx3=http://ctx3:2380,ctx4=http://ctx4:2380"

memcached

Тут всё просто, главное выделить нужное количество памяти. Она зависит от количества метрик, которые мы будем хранить. Чем больше уникальных комбинаций меток - тем больше нужно кеша.

/etc/sysconfig/memcached
PORT="11211"USER="memcached"MAXCONN="512"CACHESIZE="2048"OPTIONS="--lock-memory --threads=8 --max-item-size=64m"

Minio

Тут минимум настроек.

По сути мы просто перечисляем хосты, которые будут использоваться для хранения данных (+ путь до директории где данные хранить - /data/minio) и указываем ключи S3. В моем случае это были ВМ с одним диском, если у вас их несколько - то формат URL несколько меняется.

По умолчанию используется странное распределение дисков под данные и под коды Рида-Соломона: половина сырого объема уходит под redundancy. Так как у нас всего 4 хоста - это не особо важно. Но на большем по размеру кластере лучше использовать Storage Classes для снижения доли Parity-дисков.

/etc/minio/minio.env
MINIO_ACCESS_KEY="foo"MINIO_SECRET_KEY="bar"MINIO_PROMETHEUS_AUTH_TYPE="public"LISTEN="0.0.0.0:9000"ARGS="http://personeltest.ru/away/ctx{1...4}/data/minio"

Также нужно будет создать бакет с помощью minio-client - в нашем случае пусть называется cortex

HAProxy

Он у нас будет служить для равномерного распределения нагрузки по кластеру и отказоустойчивости. Все сервисы обращаются к локальному HAProxy, который в свою очередь проксирует запросы куда нужно.

Таким образом мы имеем что-то вроде Full Mesh топологии и отказ или перезапуск любого из сервисов или хостов целиком не влияет на функциональность кластера.

На больших кластерах (сотни-тысячи хостов) такая схема может быть узким местом, но если вы работаете с такими, то и сами это знаете :)

/etc/haproxy/haproxy.cfg
global    daemon    maxconn 10000    log 127.0.0.1 local2    chroot /var/emptydefaults    mode http    http-reuse safe    hash-type map-based sdbm avalanche    balance roundrobin    retries 3    retry-on all-retryable-errors    timeout connect 2s    timeout client 300s    timeout server 300s    timeout http-request 300s    option splice-auto    option dontlog-normal    option dontlognull    option forwardfor    option http-ignore-probes    option http-keep-alive    option redispatch 1    option srvtcpka    option tcp-smart-accept    option tcp-smart-connect    option allbackupslisten stats    bind 0.0.0.0:6666    http-request use-service prometheus-exporter if { path /metrics }    stats enable    stats refresh 30s    stats show-node    stats uri /frontend fe_cortex    bind 0.0.0.0:8090 tfo    default_backend be_cortexfrontend fe_cortex_tenant    bind 0.0.0.0:8009 tfo    default_backend be_cortex_tenantfrontend fe_minio    bind 0.0.0.0:9001 tfo    default_backend be_miniobackend be_cortex    option httpchk GET /ready    http-check expect rstring ^ready    server ctx1 10.0.0.1:9009 check observe layer7 inter 5s    server ctx2 10.0.0.2:9009 check observe layer7 inter 5s    server ctx3 10.0.0.3:9009 check observe layer7 inter 5s    server ctx4 10.0.0.4:9009 check observe layer7 inter 5sbackend be_cortex_tenant    option httpchk GET /alive    http-check expect status 200    server ctx1 10.0.0.1:8008 check observe layer7 inter 5s    server ctx2 10.0.0.2:8008 check observe layer7 inter 5s backup    server ctx3 10.0.0.3:8008 check observe layer7 inter 5s backup    server ctx4 10.0.0.4:8008 check observe layer7 inter 5s backupbackend be_minio    balance leastconn    option httpchk GET /minio/health/live    http-check expect status 200    server ctx1 10.0.0.1:9000 check observe layer7 inter 5s    server ctx2 10.0.0.2:9000 check observe layer7 inter 5s backup    server ctx3 10.0.0.3:9000 check observe layer7 inter 5s backup    server ctx4 10.0.0.4:9000 check observe layer7 inter 5s backup

cortex-tenant

Это просто прокси между Prometheus и Cortex. Главное - выбрать уникальное имя метки для хранения там tenant ID. В нашем случае это ctx_tenant

/etc/cortex-tenant.yml
listen: 0.0.0.0:8008target: http://127.0.0.1:8090/api/v1/pushlog_level: warntimeout: 10stimeout_shutdown: 10stenant:  label: ctx_tenant  label_remove: true  header: X-Scope-OrgID

Prometheus

В случае 4 хостов Prometheus-ы можно разбить их на две HA-пары, каждую со своим ID группы и раскидать job-ы по ним.

host1 /etc/prometheus/prometheus.yml
global:  scrape_interval: 60s  scrape_timeout: 5s  external_labels:    __ha_group__: group_1    __ha_replica__: replica_1remote_write:  - name: cortex_tenant    url: http://127.0.0.1:8080/pushscrape_configs:  - job_name: job1    scrape_interval: 60s    static_configs:      - targets:          - ctx1:9090        labels:          ctx_tenant: foobar  - job_name: job2    scrape_interval: 60s    static_configs:      - targets:          - ctx2:9090        labels:          ctx_tenant: deadbeef
host2 /etc/prometheus/prometheus.yml
global:  scrape_interval: 60s  scrape_timeout: 5s  external_labels:    __ha_group__: group_1    __ha_replica__: replica_2remote_write:  - name: cortex_tenant    url: http://127.0.0.1:8080/pushscrape_configs:  - job_name: job1    scrape_interval: 60s    static_configs:      - targets:          - ctx1:9090        labels:          ctx_tenant: foobar  - job_name: job2    scrape_interval: 60s    static_configs:      - targets:          - ctx2:9090        labels:          ctx_tenant: deadbeef

По сути конфигурации в пределах одной HA-группы должны отличаться только лейблом реплики.

Cortex

Ну и последнее. Так как мы будем запускать все модули вместе - конфиг получится довольно объемный. Поэтому разделим его на части, чтобы читабельнее было.

Многие модули, такие как Distributor, Ingester, Compactor, Ruler кластеризуются с помощью Hash-Ring в etcd. На весь кластер выделяется некоторое количество токенов, которые распределяются между всеми участниками кольца равномерно.

Упрощенно - при приходе, допустим, новой метрики её метки хешируются, результат делится по модулю на количество токенов и в итоге направляется на хост, который владеет данным диапазоном токенов. Если он не отвечает - то отправляют следующему по кольцу хосту.

Если хост выходит из кластера (помер, перезагружается и т.п.), то его диапазон перераспределяется по остальным.

Все настройки у нас будут лежать в /etc/cortex/cortex.yml

Также т.к. Cortex сделан для работы в контейнерах - всё можно настроить через командную строку чтобы не пропихивать конфиг в контейнер.

Глобальные настройки

# Список модулей для загрузкиtarget: all,compactor,ruler,alertmanager# Требовать ли заголовок X-Scope-OrgIdauth_enabled: true# Портыserver:  http_listen_port: 9009  grpc_listen_port: 9095limits:  # Разрешаем HA-трекинг  accept_ha_samples: true  # Названия меток, которые мы используем в Prometheus для  # маркировки групп и реплик  ha_cluster_label: __ha_group__  ha_replica_label: __ha_replica__  # Максимальный период в прошлое на который мы можем делать  # PromQL запросы (1 год).  # Всё что больше будет обрезано до этого периода.  # Это нужно для реализации retention period.  # Для фактического удаления старых блоков нужно еще настроить lifecycle  # правило в бакете S3 на пару дней глубже  max_query_lookback: 8760h

Так как Cortex создавался для работы в распределённом режиме в облаке, то работа всех модулей в одном бинарнике считается нетипичной, но я никаких проблем не наблюдал.

Другой трудностью изначально было то, что Cortex не поддерживал гибкий список модулей, которые нужно активировать. Была возможность либо указать all, который на самом деле ни разу не all:

# cortex -modulesalertmanagerallcompactorconfigsdistributor *flusheringester *purger *querier *query-frontend *query-schedulerruler *store-gateway *table-manager *Modules marked with * are included in target All.

Либо указать строго один модуль.

Поэтому пришлось сделать пулл-реквест чтобы добавить возможность загружать список любых модулей. В данном случае мы используем all + compactor, ruler и alertmanager

Хранилище

storage:  # Выбираем хранилище Blocks Storage  engine: blocks# Конфигурируем егоblocks_storage:  # Тип бэкенда  backend: s3    # Параметры доступа к S3  s3:    endpoint: 127.0.0.1:9001    bucket_name: cortex    access_key_id: foo    secret_access_key: bar    # TLS у нас нет    insecure: true    tsdb:    # Где хранить локальные блоки до загрузки в S3    dir: /data/cortex/tsdb    # Через какое время их удалять    retention_period: 12h    # Сжимать Write-Ahead Log    wal_compression_enabled: true  bucket_store:    # Где хранить индексы блоков, найденных в S3    # По сути это должно быть в модуле Store-Gateway,    # но по какой-то причине тут    sync_dir: /data/cortex/tsdb-sync    # Как часто сканировать S3 в поиске новых блоков    sync_interval: 1m    # Настраиваем различные кеши на наши memcached    # Каждый кеш имеет свой префикс ключей, так что пересекаться они не будут    index_cache:      backend: memcached      memcached:        addresses: ctx1:11211,ctx2:11211,ctx3:11211,ctx4:11211    chunks_cache:      backend: memcached      memcached:        addresses: ctx1:11211,ctx2:11211,ctx3:11211,ctx4:11211    metadata_cache:      backend: memcached      memcached:        addresses: ctx1:11211,ctx2:11211,ctx3:11211,ctx4:11211

Distributor

distributor:  ha_tracker:    # Включить HA-трекер для Prometheus    enable_ha_tracker: true    # Таймаут после которого срабатывает failover на другую реплику Prometheus.    # Нужно настроить так чтобы метрики приходили не реже этого интервала,    # иначе будут ложные срабатывания.    ha_tracker_failover_timeout: 30s    # Настраиваем etcd для HA-трекера    kvstore:      store: etcd      etcd:        endpoints:         - http://ctx1:2379         - http://ctx2:2379         - http://ctx3:2379         - http://ctx4:2379  # Настраиваем etcd для Hash-Ring дистрибьютеров  ring:    kvstore:      store: etcd      etcd:        endpoints:         - http://ctx1:2379         - http://ctx2:2379         - http://ctx3:2379         - http://ctx4:2379

Ingester

ingester:  lifecycler:    address: 10.0.0.1    # Название зоны доступности    availability_zone: dc1    # Немного ждём чтобы всё устаканилось перед перераспределением    # токенов на себя    join_after: 10s    # Храним токены чтобы не генерировать их каждый раз при запуске    tokens_file_path: /data/cortex/ingester_tokens    ring:      # На сколько Ingester-ов реплицировать метрики.      # Если указана зона доступности, то реплики будут выбираться из разных зон      replication_factor: 2      # etcd для Hash-Ring Ingester-ов      kvstore:        store: etcd        etcd:          endpoints:           - http://ctx1:2379           - http://ctx2:2379           - http://ctx3:2379           - http://ctx4:2379

Querier

По поводу подбора правильных величин лучше почитать документацию.

Основная идея в том, чтобы никогда не запрашивать те блоки, которые еще не обработал Compactor:

querier:  # Временные файлы  active_query_tracker_dir: /data/cortex/query-tracker  # Запросы с глубиной больше этой будут направляться в S3  query_store_after: 6h  # Запросы с глубиной меньше этой отправляются в Ingester-ы  query_ingesters_within: 6h5mfrontend_worker:  frontend_address: 127.0.0.1:9095query_range:  # Запросы будут разбиваться на куски такой длины и выполняться параллельно  split_queries_by_interval: 24h  # Выравнивать интервал запроса по его шагу  align_queries_with_step: true  # Включить кеширование результатов  cache_results: true    # Кешируем в memcached  results_cache:    # Сжимаем    compression: snappy    cache:      # TTL кеша      default_validity: 60s      memcached:        expiration: 60s      memcached_client:        addresses: ctx1:11211,ctx2:11211,ctx3:11211,ctx4:11211

Store-Gateway

Этот модуль подгружает из S3 бакета заголовки блоков (комбинации меток, временные интервалы и т.п.).

Если включить шардинг и репликацию, то участники кластера распределят все блоки между собой равномерно и каждый блок будет на 2 или более хостах.

store_gateway:  # Включаем шардинг  sharding_enabled: true  sharding_ring:    # Включаем zone awareness    zone_awareness_enabled: true    # Идентификатор зоны    instance_availability_zone: dc1    # Сколько реплик держать    replication_factor: 2    # Hash-ring для Store-Gateway    kvstore:      store: etcd      etcd:        endpoints:         - http://ctx1:2379         - http://ctx2:2379         - http://ctx3:2379         - http://ctx4:2379

Compactor

Этот модуль работает сам по себе и с остальными никак не взаимодействует. Можно активировать шардинг, тогда все компакторы в кластере распределят между собой tenant-ов и будут обрабатывать их параллельно.

compactor:  # Временная директория для блоков.  # Должно быть достаточно много места чтобы можно было загрузить блоки,  # скомпактить их и сохранить результат.  data_dir: /data/cortex/compactor  # Как часто запускать компакцию  compaction_interval: 30m  # Hash-Ring для компакторов  sharding_enabled: true  sharding_ring:    kvstore:      store: etcd      etcd:        endpoints:         - http://ctx1:2379         - http://ctx2:2379         - http://ctx3:2379         - http://ctx4:2379

Ruler + AlertManager

Эти модули опциональны и нужны только если хочется генерировать алерты на основе правил.

  • Правила в стандартном Prometheus формате мы будем складывать в /data/cortex/rules/<tenant>/rulesN.yml на каждом хосте. Можно использовать для этого S3 или другие хранилища - см. документацию

  • Cortex периодически сканирует хранилище и перезагружает правила

  • Конфиги AlertManager в стандартном формате складываем в /data/cortex/alert-rules/<tenant>.yml

    Аналогично можно складывать в S3 и т.п.

  • Cortex запускает инстанс AlertManager (внутри своего процесса) отдельно для каждого tenant, если находит конфигурацию в хранилище

ruler:  # Временные файлы  rule_path: /data/cortex/rules-tmp  # Включаем шардинг  enable_sharding: true  # Какому AlertManager-у сообщать об алертах  alertmanager_url: http://ctx1:9009/alertmanager  # Откуда загружать правила  storage:    type: local    local:      directory: /data/cortex/rules    # Hash-ring для Ruler-ов  ring:    kvstore:      store: etcd      etcd:        endpoints:         - http://ctx1:2379         - http://ctx2:2379         - http://ctx3:2379         - http://ctx4:2379alertmanager:  # Где хранить состояние алертов  data_dir: /data/cortex/alert-data  # Внешний URL нашего инстанса (нужен для генерации ссылок и т.п.)  external_url: http://ctx1:9009/alertmanager  # Кластеринг - какой адрес слушать и какой анонсировать пирам  cluster_bind_address: 0.0.0.0:9094  cluster_advertise_address: 10.0.0.1:9094  # Список пиров  peers:    - ctx2:9094    - ctx3:9094    - ctx4:9094  # Откуда загружать настройки  storage:    type: local    local:      path: /data/cortex/alert-rules

Заключение

Вот и всё, можно запускать все сервисы - сначала зависимости, потом Cortex, затем - Prometheus.

Я не претендую на полноту, но этого должно быть достаточно чтобы начать работать.

Нужно учитывать, что Cortex активно развивается и на момент написания статьи часть параметров в master-ветке и документации (которая генерируется из неё) уже объявлено deprecated. Так что, вполне возможно, в новых версиях нужно будет конфиги немного исправлять.

Если есть вопросы и\или замечания - пишите, постараюсь добавить в статью.

Подробнее..

Как жили до Kubernetes сравниваем самый популярный оркестратор с другими решениями

24.02.2021 12:05:30 | Автор: admin


Kubernetes сейчас называют стандартом для оркестрации контейнеров. Он лежит в основе многих облачных платформ контейнеризации: например, мы давно развиваем наш Kubernetes aaS на платформе Mail.ru Cloud Solutions.


Однако Kubernetes далеко не первый подобный инструмент на рынке: некоторые из систем-предшественников продолжают активно использовать и вроде бы даже успешно.


Почему так происходит, несмотря на то, что Kubernetes, можно сказать, одержал победу в своем классе и мы видим много примеров, когда он приходит на смену другим решениям? Например, не так давно разработчики Mesosphere DC/OS, в основе которой лежал Apache Mesos, прекратили ее развитие и сфокусировались на другой своей платформе D2iQ Kubernetes (DKP). Думаю, что стоит разобраться, всегда ли хорош Kubernetes, когда оправдано использовать другие оркестраторы и о каких подводных камнях стоит знать.


Я Дмитрий Лазаренко, директор по продуктам облачной платформы Mail.ru Cloud Solutions (MCS). В этой статье расскажу об устройстве ряда оркестраторов-предшественников, сравню их с Kubernetes, посмотрю на его преимущества и недостатки по сравнению с ними.



Критерии для сравнения


В статье я сравню Kubernetes с наиболее известными и часто используемыми системами оркестрации: Docker Swarm, Nomad, Apache Mesos и Fleet.


Для сравнения использую следующие критерии:


  1. Типы рабочих нагрузок: предназначен ли оркестратор для управления Docker-контейнерами, иными контейнерами и неконтейнерными приложениями.
  2. Легкость управления: насколько оркестратор прост в установке и настройке.
  3. Требования к платформе для развертывания: является ли решение платформонезависимым или есть определенные требования к ОС и иные ограничения.
  4. Производительность: среднее время обработки API-вызовов, запуска контейнеров и других важных операций.
  5. Ограничения на количество узлов и контейнеров в кластере: какие существуют ограничения на число управляемых компонентов.
  6. Конфигурация как код: есть ли возможность загрузки схем приложений из YAML- или JSON-файлов.
  7. Шаблоны: доступна ли настройка пользовательских шаблонов.
  8. Сети: как строится сеть, есть ли собственное сетевое решение или необходимо использовать сторонние сетевые плагины.
  9. Возможность обнаружения сервисов: поддерживается ли динамическое обнаружение сервисов путем использования DNS, Proxy и так далее.
  10. Автомасштабирование: есть ли возможность автомасштабирования в зависимости от изменений нагрузки.
  11. Выполнение обновлений и отката: какие стратегии обновлений поддерживаются. Существует ли возможность последовательных обновлений (Rolling Update), когда старые инстансы приложения постепенно заменяются на новые. Насколько просто проводится откат.
  12. Отказоустойчивость: как выполняется обработка сбоев, что происходит при выходе из строя одного из узлов.
  13. Мониторинг: есть ли встроенные механизмы или необходимо использовать внешние инструменты и какие.
  14. Безопасность: есть ли встроенное решение для управления конфиденциальной информацией (логины и пароли).

Выполнив сравнение по этим критериям, разберемся, для решения каких задач могут подойти другие оркестраторы, в чем они уступают Kubernetes и как при желании построить переход от них к Kubernetes с наименьшими усилиями.


I. Docker Swarm vs Kubernetes


Docker Swarm встроенное в сам Docker решение для управления контейнерами на физических или виртуальных машинах. Когда несколько хостов Docker используют режим Swarm, некоторые из них могут быть настроены как управляющие ноды, или менеджеры (Manager), а остальные как рабочие ноды (Worker). Задача менеджеров управлять кластером и делегировать задачи рабочим узлам.


1. Типы рабочих нагрузок


Если Docker Swarm предназначен для работы исключительно с Docker-контейнерами, то Kubernetes поддерживает несколько типов контейнеров: Docker, containerd, CRI-O и любое решение, придерживающееся стандарта CRI (Container Runtime Interface).


2. Легкость управления


По сравнению с Kubernetes Docker Swarm намного проще в установке вручную. Swarm работает поверх Docker, использует интерфейс его командной строки и легко интегрируется с Docker Compose. Kubernetes также может работать поверх Docker, но взаимодействовать с инфраструктурой в этом случае нужно будет при помощи двух разных утилит: Docker CLI и kubectl CLI.


Устройство Kubernetes на порядок сложнее. Он включает в себя множество компонентов: kube-api-server, kube-scheduler, kube-controller-manager, kube-proxy, kubelet и поддерживает несколько типов установщиков для разных типов инфраструктур и задач: Kubeadm, Kops, Kubespray и так далее. Все это требует дополнительного обучения.


То есть порог вхождения в Kubernetes выше по сравнению с Docker Swarm. Но все, что связано непосредственно с администрированием контейнеров: deployments, доведение кластера до нужного состояния, добавление новых нод, в K8s можно выполнить проще и быстрее. Также многие, поработав с обоими оркестраторами, отмечают, что Kubernetes более стабилен.


3. Требования к платформе для развертывания


Docker Swarm, как и Kubernetes, может использоваться в различных ОС: Windows, macOS, Linux. Однако Kubernetes использует различные настройки для каждой ОС. Если требуемые вам конфигурации выходят за рамки стандартной реализации, самостоятельная настройка Kubernetes может превратиться в гигантскую задачу. В этом плане Docker Swarm выигрывает.


4. Производительность


По сравнению с Kubernetes Docker Swarm быстрее. Kubernetes сложнее из-за большего числа дополнительных уровней в архитектуре (планировщик и так далее), что замедляет выполнение операций, но обеспечивает стабильность кластера в целом.


5. Ограничения на количество узлов и контейнеров в кластере


Kubernetes v1.20 поддерживает конфигурации, отвечающие следующим критериям:


  • не более 110 подов на узел, при этом параметр можно настраивать,
  • не более 5 000 узлов,
  • всего не более 150 000 подов,
  • всего не более 300 000 контейнеров.

В документации Docker Swarm даны рекомендации только по числу узлов-менеджеров 7 штук. Максимальное число контейнеров будет определяться, скорее, ограничениями ОС, но пользователи Swarm советуют придерживаться похожих рекомендаций: 100 контейнеров на ноду.


6. Конфигурация как код


В обоих оркестраторах можно использовать YAML-файлы для определения конфигураций. В Kubernetes также доступен JSON-формат, но YAML предпочтителен.


7. Шаблоны


В Docker Swarm нет шаблонизатора, аналогичного Helm в Kubernetes. Некий шаблонизатор приложений анонсировался в Docker Desktop Enterprise 3.0, но в настоящее время это решение не поддерживается.


8. Сети


С точки зрения сетевой модели Kubernetes смотрится предпочтительнее. Он работает с виртуальными сетями и поддерживает намного большее количество разных сетевых решений по сравнению со Swarm. Каждый под получает свой IP-адрес, что означает отсутствие необходимости сопоставления портов контейнера портам хоста. Kubernetes может работать с любым CNI-совместимым сетевым решением.


В Docker Swarm вы можете указать оверлейную сеть для своих служб. Менеджер будет автоматически назначать адреса контейнерам в оверлейной сети при инициализации или обновлении приложения. Однако некоторые пользователи жаловались на производительность нативной сети, советуя применять сетевые плагины вроде Calico.


9. Возможность обнаружения сервисов


Реализована в обоих оркестраторах с использованием встроенного DNS-сервера.


10. Автомасштабирование


В Docker Swarm автомасштабирование недоступно. Для каждой службы вы можете вручную указать количество задач, которые хотите запустить. Когда это число увеличивается или уменьшается, управляющий узел (Manager) автоматически адаптируется, добавляя или удаляя задачи для поддержания желаемого состояния.


В Kubernetes поддерживается автомасштабирование на основе наблюдаемого использования ЦП, памяти и ряда других пользовательских метрик. При этом масштабирование доступно на нескольких уровнях:


  1. Автомасштабирование кластера с использованием Cluster Autoscaler, отвечающее за изменение числа узлов в кластере.
  2. Горизонтальное автомасштабирование подов (Horizontal Pod Autoscaler, HPA), которое автоматически изменяет количество подов в зависимости от значений выбранных показателей.
  3. Вертикальное автомасштабирование подов (Vertical Pod Autoscaler, VPA), которое автоматически изменяет объем ресурсов, выделяемых существующим подам.

11. Выполнение обновлений и отката


И Kubernetes, и Docker Swarm поддерживают последовательные обновления (Rolling Update): во время развертывания вы можете постепенно применять обновления служб к узлам. В случае сбоя можно вернуться к предыдущей версии сервиса. Однако Kubernetes предоставляет возможность более гибкой настройки.


Swarm Manager позволяет контролировать время задержки между развертыванием сервиса на разных наборах узлов, возможность одновременного обновления нескольких задач и действия в случае сбоя обновления.


В Kubernetes гораздо больше настраиваемых опций: максимальное количество недоступных подов, допустимое увеличение числа подов, минимальное время, в течение которого под должен стать доступным, максимальный срок выполнения задач.


12. Отказоустойчивость


В обоих оркестраторах поддерживается высокая доступность приложений.


В Docker Swarm управляющий узел (Manager) постоянно отслеживает состояние кластера и согласовывает любые различия между фактическим состоянием и настроенным вами желаемым состоянием.


В Kubernetes службы балансировки нагрузки обнаруживают поды со сбоями и удаляют их. Используются проверки работоспособности (Health Check).


13. Мониторинг


Использование в Docker Swarm решений для логирования и мониторинга (ELK, Prometheus) возможно, как и в Kubernetes, но требует больше кастомных настроек или использования дополнительных наборов инструментов, таких как Swarmprom.


14. Безопасность


С точки зрения безопасности в Swarm еще недавно не было практически ничего. Для хранения секретов приходилось использовать Vault. Сейчас каждый узел в Swarm применяет взаимную аутентификацию и шифрование TLS для защиты коммуникаций внутри себя и с другими узлами. Также есть возможность использовать самоподписанные корневые сертификаты или сертификаты от настраиваемого корневого Центра сертификации. Есть и встроенное решение для управления секретами.


Однако Kubernetes все равно находится на шаг впереди, предлагая гибкую настройку сетевых политик (Network Policies), использование пространств имен (Namespaces) и прочие преимущества.


II. Nomad vs Kubernetes


Nomad это оркестратор от компании HashiCorp для управления контейнерами и неконтейнерными приложениями. Основу его архитектуры составляют клиенты (Client), на которых можно запускать задачи, и серверы (Server), управляющие клиентами и задачами. Серверы выбирают лидера для обеспечения высокой доступности.


Рабочую нагрузку в Nomad определяет работа (Job), описывающая желаемое состояние кластера и состоящая из одной или нескольких групп задач. Задача (Task) самая маленькая единица работы, которая выполняется драйверами (Docker, QEMU, Java и так далее). Обязанность Nomad поддерживать соответствие между желаемым состоянием, описанным в Job, и фактическим состоянием кластера.


За консультацию по работе Nomad отдельное спасибо manefesto.

1. Типы рабочих нагрузок


В то время как Kubernetes ориентирован на использование контейнеров, Nomad работает с различными видами рабочих нагрузок. Он поддерживает виртуализированные, контейнерные и автономные, микросервисные и пакетные приложения, включая Docker, Java, Qemu и другие, полный список можно посмотреть здесь. Это позволяет оркестрировать не только контейнерами / виртуальными машинами, но и запускать приложения на нодах. Например, можно запустить на нодах тяжелые Java-приложения.


2. Легкость управления


Установка Nomad значительно проще, чем Kubernetes. Nomad доступен в виде предварительно скомпилированного двоичного файла (единого как для клиентов, так и для серверов) и в виде пакетов для различных операционных систем. Вы также можете собрать Nomad из исходников.


Минимальный тестовый стенд можно поднять на хосте без использования сторонних утилит типа Minikube. Достаточно запустить Nomad в dev-режим, и он будет выполнять роль сервера/агента, чего вполне достаточно для локального тестирования.


Однако если Kubernetes стремится предоставить все функции, необходимые для запуска контейнерных приложений (включая управление кластером, автообнаружение служб, обеспечение безопасности и многое другое), то Nomad сосредоточен только на управлении кластером и планировании.


K8s считается фреймворком для построения кластера, в то время как подход HashiCorp больше близок к UNIX-way. Настроить кластер Nomad под нужные требования можно с помощью внешних инструментов: Consul для обнаружения сервисов, Vault для управления конфиденциальной информацией и других. До определенного момента в Nomad не было возможности использовать внешние хранилища, сети, отличные от хостовых и Bridge, но сейчас есть поддержка плагинов CSI, CNI, появилась возможность использовать сети, хранилища так же, как это делает K8s.


В любом случае использовать Nomad несложно: по факту достаточно скопировать бинарный файл и создать Systemd-сервис, который работает в связке с Consul как Service Discovery.


3. Требования к платформе для развертывания


И Kubernetes, и Nomad могут быть развернуты в различных ОС: Linux, macOS, Windows. Однако Kubernetes требует различных настроек в зависимости от ОС поэтому его установка, проводимая вручную, сложнее.


4. Производительность


По производительности оба решения примерно на одинаковом уровне, но Nomad все же впереди за счет архитектурной простоты.


5. Ограничения на количество узлов и контейнеров в кластере


Kubernetes поддерживает кластеры до 5 000 узлов и 300 000 контейнеров. В документации Nomad указано, что он масштабируется до размеров кластера, превышающих 10 000 узлов в реальных производственных средах. Также Nomad успешно участвовал в ряде напряженных тестов на масштабируемость: 1 миллион контейнеров в 2016 году и 2 миллиона контейнеров в 2020 году. Однако на практике вероятность применения настолько масштабных кластеров невелика.


6. Конфигурация как код


Kubernetes поддерживает декларативные развертывания на основе YAML-файлов. Nomad использует собственный язык описания конфигураций HashiCorp HCL. То есть при использовании Nomad вам потребуется дополнительное обучение HCL. Но стоит отметить, что в Nomad присутствуют стандартные средства и команды для преобразования описаний из YAML и JSON в HCL (и обратно): yamlencode/yamldecode, jsonencode/jsondecode. Правда, работают они с определенными ограничениями, а некоторые в тестовом режиме.


7. Шаблоны


В Nomad нет инструмента для шаблонизации, аналогичного Helm для Kubernetes.


8. Сети


В плане организации сетей Kubernetes выглядит лаконичнее и стабильнее. В нем изначально была введена абстракция Pod, позволяющая запускать несколько контейнеров в одном сетевом пространстве, и использовался CNI (Container Networking Interface). Nomad же развивался от меньшего к большему и долгое время использовал исключительно хостовые сети без дополнительных слоев абстракции. Вместо Pod в нем использовались Job без возможности объединения контейнеров внутри них в единое сетевое пространство. Мультиинтерфейсные сети и возможность подключения CNI стали развиваться в Nomad относительно недавно. Можно подключить CNI-плагин для использования Calico, Cilium, Weave.


9. Возможность обнаружения сервисов


В отличие от Kubernetes, в Nomad нет Autodiscovery на основе DNS. Для обнаружения сервисов необходимо использовать дополнительный инструмент Consul. В этом Nomad сильно уступает Kubernetes. И многие считают это одной из основных причин, почему Nomad оказался менее востребован в свое время.


10. Автомасштабирование


Общая черта двух оркестраторов поддержка следующих типов автомасштабирования:


  • горизонтальное автомасштабирование приложений в Nomad и подов в Kubernetes,
  • автомасштабирование кластера.

Дополнительно в Kubernetes реализовано вертикальное автомасштабирование подов, которое автоматически изменяет объем ресурсов, выделяемых существующим подам. Похожее решение в Nomad, состоящее в построении рекомендаций по ЦП и памяти на основе анализа исторических данных, доступно исключительно в Enterprise-версии.


11. Выполнение обновлений и отката


Оба оркестратора предоставляют возможность гибкого управления обновлениями, включая стратегии последовательного (Rolling update), сине-зеленого (Blue and Green) и канареечного (Canary) обновлений. Для настройки доступен целый ряд показателей, влияющих на ход обновлений, включая временные интервалы для проверки работоспособности и прочее.


И K8s, и Nomad поддерживают автоматический возврат к последней стабильной версии в случае сбоя развертывания. История развертывания ведется в обоих случаях.


12. Отказоустойчивость


По умолчанию поведение у обеих систем схожее. В Kubernetes дается минута на определение узла со сбоем и до пяти минут на вытеснение подов на другую ноду. В Nomad примерно такие же дефолтные показатели. Но в Kubernetes с использованием опций kubelet и Control Manager реально добиться того, чтобы уже в течение 10 секунд поды были вытеснены на другую работоспособную ноду.


13. Мониторинг


Оба оркестратора совместимы с популярными инструментами логирования и мониторинга: ELK, Prometheus/Grafana и прочими. Ведется сбор метрик, которые можно получить впоследствии через API либо настроив автоматическую пересылку стороннему провайдеру.


14. Безопасность


Основное, в чем проигрывает Nomad в плане безопасности, это необходимость использования сторонней системы Vault для управления конфиденциальной информацией (логинами и паролями). Хотя безопаснее Vault на современном рынке Open Source-решений, пожалуй, нет его настройка и использование совместно с Nomad является довольно сложной задачей. Коробочный Kubernetes в этом отношении проще, так как может предложить встроенное решение.


Кроме этого, если в Kubernetes по умолчанию поддерживаются пространства имен (Namespaces), которые можно эффективно использовать для разделения сред разработки, то в Nomad данная функциональность доступна только в Enterprise-версии.


III. Apache Mesos (+ Maraphon, Aurora) vs Kubernetes


Apache Mesos это менеджер кластера, поддерживающий различные рабочие нагрузки. Основу архитектуры Mesos составляют мастер (Mesos Master), агенты (Mesos Agent), работающие на каждом узле кластера и управляемые мастером, и фреймворки (Mesos Frameworks), которые запускают задачи на агентах. Обычно разворачивается несколько резервных мастеров, готовых взять на себя управление в случае сбоя, а за выбор лидера среди них отвечает ZooKeeper.


Фреймворк состоит из двух компонентов: планировщика (Scheduler), он регистрируется на главном сервере, которому будут предлагаться ресурсы, и исполнителя (Executor), который запускается на узлах агентов для выполнения задач фреймворка. Мастер предлагает ресурсы агентов фреймворкам, а планировщики выбирают, какие из предложенных ресурсов использовать для запуска своих задач на агентах. В кластере Mesos может работать несколько фреймворков для разных типов задач.


То есть сам по себе Apache Mesos является лишь неким диспетчером, а конечная функциональность будет определяться используемым фреймворком. Поэтому при описании показателей будем иногда ссылаться на два конкретных фреймворка: Maraphon для управления контейнерными приложениями и Apache Aurora для планирования Cron-заданий и долго работающих служб. Aurora больше не поддерживается, но в свое время была довольно распространена и в том числе могла использоваться для контейнерных приложений. Также иногда будем упоминать Mesosphere DC/OS операционную систему, основанную на Apache Mesos, Maraphon и предлагающую ряд дополнительных возможностей (правда, часть из них доступна в платной версии).


1. Типы рабочих нагрузок


Apache Mesos предназначен для обработки различных типов рабочих нагрузок, которые могут быть как контейнерными, так и неконтейнерными. В качестве планировщика заданий (Scheduler) могут быть использованы, например, Hadoop (Big Data), MPI (обмен сообщениями), Jenkins (система непрерывной интеграции). Используя Apache Mesos, можно разработать даже собственный планировщик.


Kubernetes ориентирован исключительно на контейнерные приложения.


2. Легкость управления


Apache Mesos проще развернуть, чем Kubernetes, если мы говорим о ручной установке. Однако дальнейшее администрирование Apache Mesos сложнее по сравнению с K8s, так как необходимо работать с ZooKeeper, уметь администрировать Java и быть готовым к связанным с этим трудностям: утечкам памяти, Xmx, лимитам и так далее. Kubernetes с Golang в этом плане проще.


3. Требования к платформе для развертывания


Mesos работает на Linux и macOS. Агенты могут быть установлены и на Windows.
Kubernetes также поддерживает все ОС.


4. Производительность


Mesos изначально был ориентирован на работу с Big Data поэтому по производительности он опережает Kubernetes.


5. Ограничения на количество узлов и контейнеров в кластере


По масштабируемости Apache Mesos выигрывает у Kubernetes, так как способен поддерживать десятки тысяч узлов (K8s рассчитан на 5 000 максимум). Когда Mesos сочетается с Mesosphere DC/OS, получается платформа, предлагающая практически неограниченную масштабируемость, которая идеально подходит для больших систем. Разработчики заявили, что прекратили ее развитие, но существующих клиентов продолжают поддерживать. Еще в 2015 году Mesos с успехом выдержал тест на масштабирование до 50 000 узлов.


6. Конфигурация как код


В Apache Mesos в сочетании с Maraphon можно использовать определения JSON (для указания репозиториев, ресурсов, числа экземпляров и команд для выполнения). В Kubernetes для этой цели поддерживаются декларативные развертывания и в YAML, и в JSON (первый предпочтительнее).


7. Шаблоны


Если вы работаете в Mesosphere DC/OS, то можете использовать шаблоны конфигураций (с использованием Maraphon-LB). В Apache Aurora при настройке услуг в DSL также были доступны шаблоны во избежание дублирования конфигураций. Но Helm, используемый в K8s, будет более мощным и удобным инструментом.


8. Сети


Долгое время Apache Mesos отставал от Kubernetes в плане сетевой реализации, так как по умолчанию в нем не назначались IP-адреса контейнерам, требовалось проведение сопоставления портов контейнера с портами хоста, которые являются ограниченным ресурсом. Впоследствии была добавлена поддержка CNI (Container Networking Interface) и появилась возможность использования виртуальных сетей вида Calico, Cilium, Weave. Но в Kubernetes сейчас поддерживается большее число сетевых решений.


9. Возможность обнаружения сервисов


Присутствует в обеих системах.


Mesos-DNS обеспечивает обнаружение служб и базовую балансировку нагрузки для приложений. При использовании совместно с Marathon дополнительно доступен Marathon-LB для обнаружения на основе портов с помощью HAProxy. В Aurora была также представлена экспериментальная поддержка Mesos DiscoveryInfo для создания настраиваемой системы обнаружения без использования ZooKeeper.


В Kubernetes доступен встроенный DNS-сервер.


10. Автомасштабирование


Реализация автомасштабирования лучше в Kubernetes. Как уже отмечалось выше, доступны три стратегии: масштабирование кластера, горизонтальное масштабирование подов и вертикальное масштабирование подов. В качестве триггеров можно настраивать показатели ЦП, памяти и пользовательские показатели.


В Apache Mesos автомасштабирование доступно в комбинации с Maraphon (в Mesosphere DC/OS) на основе значений ЦП, памяти и числа запросов в секунду.


11. Выполнение обновлений и отката


Поддерживается в обеих системах. Сине-зеленое (Blue and Green) развертывание доступно в Apache Mesos, также его можно реализовать в Kubernetes, используя встроенные механизмы.


12. Отказоустойчивость


Обе системы отказоустойчивы.


В Apache Mesos экземпляры приложений распределяются по агентам, обеспечивая высокую доступность. Кроме того, ZooKeeper поддерживает доступность кластера через кворум и выборы лидера.


Аналогично поды в Kubernetes реплицируются на несколько узлов. Обычно кластер Kubernetes состоит из нескольких рабочих узлов. В нем также может быть несколько мастеров.


Кроме этого, оба оркестратора предоставляют проверки работоспособности (Health Check). Для Mesos они доступны в случае использования Mesosphere DC/OS.


13. Мониторинг


И в Mesos, и в Kubernetes доступно получение метрик, относящихся к работоспособности и другим показателям. Данные можно запрашивать и агрегировать с помощью внешних инструментов. Типичной практикой является развертывание ELK и Prometheus + Grafana.
Но подключение мониторинга в Kubernetes происходит проще, так как многое строится на готовых решениях благодаря поддержке многочисленного сообщества и богатому инструментарию. В Mesos многое приходится делать самостоятельно, вследствие чего неизбежно увеличивается Time to Market.


14. Безопасность


Сложно отдать кому-то предпочтение. Если говорить об Apache Mesos в связке с Maraphon или Aurora вне Mesosphere DC/OS, то Kubernetes выглядит лучше. Долгое время Mesos не мог предложить в плане безопасности практически ничего. Так, встроенное решение по работе с секретами не имело в нем надлежащей реализации, и пользователи предпочитали использовать сторонние инструменты, например Vault.


Но если обратиться к ОС DC/OS Enterprise сегодня она предлагает богатый функционал в плане корпоративной безопасности, возможно, даже лучший, чем в Kubernetes. Однако эта версия системы является платной, кроме того, ее развитие свернуто разработчиками в пользу новой платформы на основе как раз Kubernetes.


IV. Fleet vs Kubernetes


Fleet это низкоуровневый кластерный движок от CoreOS, похожий на распределенную систему инициализации. В настоящее время он не поддерживается, так как компания стала активно продвигать Kubernetes.


Fleet был основан на systemd. В то время как systemd обеспечивал инициализацию системы и служб на уровне одной машины, Fleet расширил этот процесс до кластера. В архитектуре Fleet на каждой машине запускался fleetd-демон, обеспечивающий две роли: движок (Engine) и агент (Agent). Движок принимал решения по планированию, а агент обрабатывал Systemd Unit-файлы (Unit). Эта обработка чаще всего сводилась к запуску контейнера.


В любой момент времени в кластере был активен только один движок, но все агенты работали. Новые файлы назначались агентам с наименьшей нагрузкой. В качестве хранилища данных в кластере и средства связи между движком и агентами выступал etcd. В нем хранились Unit-файлы, данные об их состоянии, состоянии кластера и так далее.


1. Типы рабочих нагрузок


Если Kubernetes поддерживает работу с контейнерными приложениями, то Fleet использовал модули systemd для запуска контейнеров или любых других процессов на узлах кластера.


2. Легкость управления


Установка Fleet проводилась значительно проще и быстрее по сравнению с Kubernetes. Чтобы запустить свои службы в кластере, необходимо было отправить обычные модули systemd в сочетании с несколькими свойствами, специфичными для Fleet. То есть для управления кластером было достаточно знаний по работе с systemd.


3. Требования к платформе для развертывания


Fleet изначально разрабатывался на базе CoreOS. Kubernetes в настоящее время поддерживает практически все виды ОС.


4. Производительность


Сложно оценить, так как продукт более не поддерживается. Вероятно, Fleet был быстрее, учитывая его архитектурную простоту и ограниченную функциональность.


5. Ограничения на количество узлов и контейнеров в кластере


Fleet уступал по масштабируемости. В последней версии продукта не рекомендовалось запускать кластеры более 100 узлов или с более чем 1000 служб. Kubernetes сейчас поддерживает до 5 000 узлов и 300 000 контейнеров в кластере.


6. Конфигурация как код


В документации Fleet отсутствуют данные о возможности загрузки определений приложений из YAML или JSON, доступной в Kubernetes. Но формировавшиеся представления сохранялись в etcd в формате JSON. Также Fleet предоставлял API для управления состоянием кластера с использованием JSON: создание и удаление модулей, изменение желаемого состояния, вывод списка модулей.


7. Шаблоны


Fleet поддерживал несколько простых шаблонов развертывания на основе настраиваемых параметров модуля systemd. В них, например, можно было использовать определения места запуска контейнеров (Affinity и Anti-Affinity), похожие на селекторы Kubernetes. Однако используемый в Kubernetes шаблонизатор Helm более мощный инструмент.


8. Сети


Fleet это низкоуровневое решение, и его нельзя сравнивать с K8s в плане организации сетей.


9. Возможность обнаружения сервисов


Присутствует в обоих. Но, в отличие от Kubernetes, Fleet не поддерживал интеграцию с DNS. Взамен этого он предлагал модель Sidekick, в которой отдельный агент обнаружения запускался рядом с основным контейнером.


10. Автомасштабирование


В документации Fleet не описана возможность автомасштабирования.


11. Выполнение обновлений и отката


Fleet не поддерживал последовательные обновления, в отличие от K8s: новые модули (Units) планировались, а старые уничтожались вручную.


12. Отказоустойчивость


Обеспечивается в обоих оркестраторах. Архитектура Fleet разработана так, чтобы быть отказоустойчивой: если машина выходила из строя, любые запланированные на ней задания (Unit) перезапускались на новых хостах.


13. Мониторинг


Fleet уступал Kubernetes по возможностям мониторинга. Он поддерживал в экспериментальном режиме получение незначительного количества метрик в формате Prometheus. О возможности использования других инструментов логирования и мониторинга (ELK и прочее) в документации не сказано.


14. Безопасность


Fleet как низкоуровневое решение предлагал меньше возможностей в плане безопасности по сравнению с K8s. Например, он не поддерживал контроль доступа (Access Control List, ACL): все, кто имели доступ к etcd, могли управлять Fleet. Также в нем не было инструментов для управления конфиденциальной информацией (логины и пароли).


V. Преимущества и недостатки систем оркестрации


1. Docker Swarm


Преимущества:


  1. Ниже порог входа: быстро устанавливается, легок в изучении, интегрирован с Docker Compose и Docker CLI.
  2. Позволяет быстрее разворачивать контейнеры.

Недостатки:


  1. Уступает Kubernetes в плане администрирования, особенно в Production-среде.
  2. Отсутствует автомасштабирование.
  3. Проигрывает в плане поддержки сообществом: инструментарий намного меньше, чем у Kubernetes, что приводит к отсутствию готовых решений и необходимости многое настраивать самостоятельно.

Для каких задач подходит: в небольших проектах, где предпочтение отдается простоте и быстрой разработке.


2. Nomad


Преимущества:


  1. Прост в установке и эксплуатации, так как сосредоточен только на управлении кластером.
  2. Поддерживает различные виды рабочих нагрузок.

Недостатки:


  1. Ограниченная функциональность. Требуется установка сторонних инструментов для решения задач, которые K8s реализует по умолчанию: Autodiscovery, управление секретами.
  2. Проигрывает Kubernetes в плане поддержки сообществом.

Для каких задач подходит:


  1. Для небольших/средних команд с ограниченными возможностями поддержки оркестратора.
  2. При сочетании контейнерных и неконтейнерных нагрузок.
  3. При построении сетей L2 с малым количеством контейнеров.

3. Apache Mesos (+ Maraphon, Aurora)


Преимущества:


  1. Высокая масштабируемость.
  2. Поддержка контейнерных и неконтейнерных приложений, возможность совмещения нескольких фреймворков (включая Kubernetes).

Недостатки:


  1. Сложность администрирования.
  2. Проигрывает в плане поддержки сообществом.

Для каких задач подходит:


  1. Масштабные проекты с участием нескольких центров обработки данных и/или десятков тысяч узлов.
  2. При сочетании контейнерных и неконтейнерных нагрузок. В частности, при работе с приложениями по обработке данных: Hadoop, Kafka, Spark.
  3. Комбинация Apache Mesos и Aurora отлично подходила для оркестрации задач, не связанных с контейнерами, но требующих аналогичной обработки, например перезапуска в случае сбоя.

4. Fleet


Преимущества:


  1. Простота

Недостатки:


  1. Ограниченная функциональность
  2. Продукт более не поддерживается

Для каких задач подходил: можно было использовать в качестве основы для запуска инструментов оркестровки более высокого уровня например, для распространения агентов Kubernetes и двоичных файлов на машины в кластере.


5. Kubernetes


Преимущества:


  1. Самодостаточный инструмент оркестровки, в который встроено множество сервисов. Kubernetes предоставляет все функции, необходимые для запуска приложений на основе контейнеров, включая: управление кластером, планирование, обнаружение служб, мониторинг, управление безопасностью и многое другое.
  2. Поддерживается фондом CNCF (Cloud Native Computing Foundation). У Kubernetes самое впечатляющее по числу участников сообщество среди всех оркестраторов, что обеспечивает богатый инструментарий и большое число готовых решений.
  3. Это бесплатный инструмент с открытым исходным кодом, который работает в любой ОС.

Недостатки:


  1. Сложнее настроить вручную, хотя это можно решить с помощью использования Kubernetes aaS.
  2. Предназначен только для контейнерных приложений.
  3. Меньшее количество поддерживаемых узлов по сравнению с Nomad и Mesos.

Для каких задач подходит: идеален в качестве платформы корпоративного уровня, способной запускать тысячи контейнеров в облаке и управлять ими.


Как перейти на Kubernetes с других оркестраторов


Предположим, вы использовали одно из рассмотренных решений и задумались о переходе на Kubernetes.


Что теперь предпринять?


Продумайте окружение. Kubernetes интегрирован со множеством инструментов мониторинга, логирования, построения CI/CD и так далее. Возможно, вы не захотите ограничиться лишь сменой оркестратора и построите более обширную инфраструктуру по сравнению с текущей, максимально задействовав возможности экосистемы K8s.


Перепишите манифесты на YAML Kubernetes. Сложность операции будет определяться их количеством и особенностями прежнего оркестратора:


  1. Переход с Docker Swarm наиболее прост. Можно либо самостоятельно переписать все манифесты, либо использовать доступные инструменты преобразования из файлов Docker Compose в YAML Kubernetes, например Kompose. Первый способ представляется более правильным, так как позволит учесть все преимущества Kubernetes, связанные с deployments, labels, tolerations и так далее. Второй способ позволит избежать переписывания, но менее нативен.
  2. Переход с Nomad и Apache Mesos наиболее сложен, так как их манифесты не совместимы с Kubernetes. Скорее всего, переход с Apache Mesos/Maraphon будет проще, так как в нем использовались JSON-определения в отличие от Apache Mesos/Aurora с собственным синтаксисом (похожим на Python) и Nomad с его HCL.
  3. Если вы использовали Fleet, то, вероятно, как основу для более высокоуровневого оркестратора. То есть для перехода на Kubernetes необходимо переписать манифесты, созданные для того оркестратора, что вы применяли. Либо ничего не переписывать, если у вас уже был Kubernetes поверх Fleet.

Разверните Kubernetes, вспомогательную инфраструктуру и настройте свой кластер. Если у вас нет команды, способной справиться с непростой задачей ручной установки, то можно использовать одно из готовых (Managed) решений. Их провайдеры не только предлагают услуги по развертыванию кластеров Kubernetes, но и оказывают дальнейшую техническую поддержку, а также могут помочь с миграцией (например, с Docker Swarm). В результате вы получите готовый кластер за считаные минуты и все преимущества Cloud Native-приложений.


При этом, если вы хотите по максимуму отказаться от администрирования кластера, с выбором провайдера тоже нужно не ошибиться: не все Managed-решения находятся в зрелом состоянии и позволяют снять с IT-отдела компании многие сложности работы с Kubernetes. Кроме того, не стоит забывать, что Managed-решения не серебряная пуля и кое-какой поддержкой кластера заниматься все равно придется.


Чек-лист: на что обратить внимание при выборе провайдера Kubernetes


Функциональность сервиса. Советуем выяснить, какие возможности провайдер предлагает из коробки. В первую очередь это способ хранения данных, масштабирование, балансировка нагрузки, безопасность, организация сетей. Все, что отсутствует в коробочном решении, вам, вероятно, придется настраивать самостоятельно.


Так, KaaS от Mail.ru Cloud Solutions из коробки включает:


  • автоматическое масштабирование кластера до сотен узлов с использованием Kubernetes Cluster Autoscaler;
  • наличие выделенных балансировщиков нагрузки для распределения трафика;
  • интегрированные Persistent Volumes на базе надежного блочного хранилища CEPH, виртуального файлового хранилища или SSD/NVME-дисков, подключенных по iSCSI к каждому вычислительному серверу;
  • собственный Terraform-провайдер для работы с инфраструктурой как кодом.

Совместимость со стандартными инструментами Kubernetes. Нужно проверить, поддерживает ли провайдер интеграцию с другими приложениями экосистемы K8s, например:


  • Serverless: OpenFaaS, Kubeless;
  • Service Mesh: Istio, Consul, Linkerd;
  • мониторинг: Prometheus, Fluentd, Jaeger, OpenTracing;
  • CI/CD: Gitlab, CircleCI, Travis CI;
  • IaC (описание приложений): Terraform, Helm.

Возможность подключения других сервисов провайдера. Обратите внимание на дополнительные решения провайдера и возможность их использования в своих кластерах. KaaS от MCS позволяет подключить объектное хранилище (Cloud Storage) и DBaaS для хранения данных Stateful-приложений, а также его легко совместно использовать с другими PaaS, например Cloud Big Data. Например, централизованно разворачивать нужные сервисы и управлять ими на одной платформе.


Сертификация CNCF. Подтверждает то, что сервис отвечает всем функциональным требованиям сообщества Cloud Native Computing Foundation (CNCF) и совместим со стандартным Kubernetes API. MCS пока единственный в России облачный провайдер, получивший такую сертификацию.


Техническая поддержка. Как организована поддержка, бесплатная ли она, оказывает ли провайдер помощь в миграции данных и так далее.


Выводы: сравнительный анализ систем оркестрации


Результаты сравнения Kubernetes и других известных оркестраторов наглядно демонстрирует таблица ниже:


  • самая удачная и удобная в использовании реализация;
  • удовлетворительная реализация, уступающая другим по ряду параметров;
  • реализация, уступающая другим по большинству параметров и/или требующая значительно больше времени и ресурсов для ее использования.

Критерий/Оркестратор Docker Swarm Nomad Apache Mesos Fleet K8s
Типы рабочих нагрузок
Легкость установки и исходной настройки (вручную)
Легкость администрирования кластеров
Требования к платформе для развертывания
Производительность
Ограничения на количество узлов и контейнеров в кластере
Конфигурация как код
Шаблоны
Сети
Возможность обнаружения сервисов
Автомасштабирование
Выполнение обновлений и отката
Отказоустойчивость
Мониторинг
Безопасность

Как мы увидели, Kubernetes лидирует по многим показателям. Но есть и недостатки, и самый весомый из них высокий порог входа для новых пользователей при выборе ручной установки. Однако современный рынок предлагает множество Managed-решений, способных преодолеть эту сложность. Главное грамотно подойти к выбору между ними, взвесив все за и против.


Что еще почитать по теме:


  1. Зачем крупным компаниям микросервисы, контейнеры и Kubernetes: как эти три технологии выводят IT на новый уровень.
  2. 10 антипаттернов деплоя в Kubernetes: распространенные практики, для которых есть другие решения.
  3. Наш Телеграм-канал Вокруг Kubernetes в Mail.ru Group.
Подробнее..

Перевод Google признала сложность Kubernetes, поэтому разработала режим Автопилот

26.02.2021 18:20:16 | Автор: admin

Новый режим GKE более дорогой и менее гибкий, но зато проще и безопаснее



Автопилот в GKE управляет подами за вас

О кластерах Kubernetes хорошо известны две вещи. Первое, что это абсолютно лучший инструмент для критически важной задачи оркестровки контейнеров. И второе: его сложность является барьером для внедрения и общей причиной ошибок. Это признаёт даже Google, изобретатель и главный промоутер Kubernetes.

Чтобы упростить развёртывание и управление кластерами, компания представила всем клиентам GKE доступ к сервису Автопилот, который Google уже давно использует в собственных кластерах Borg. Это автоматическая конфигурация ресурсов на основе машинного обучения.

Несмотря на 6 лет прогресса, Kubernetes по-прежнему невероятно сложен, сказал Дрю Брэдсток (Drew Bradstock), руководитель продукта Google Kubernetes Engine (GKE), в интервью The Register. В последние годы мы видели, что многие компании принимают Kubernetes, но затем сталкиваются с трудностями.

GKE это платформа Kubernetes, которая работает в основном на Google Cloud Platform (GCP). Она также доступна и на других облаках или локально как часть Anthos.

Автопилот новый режим работы GKE, он более автоматизирован и предварительно настроен для сокращения операционных затрат на управление кластерами, оптимизации кластеров для продакшна и высокой доступности.


Использование Автопилота в собственной инфраструктуре Google, источник

В Kubernetes есть понятия кластеров (набор физических или виртуальных серверов), узлов (отдельные серверы), подов (блок управления, представляющий один или несколько контейнеров на узле) и самих контейнеров. GKE полностью управляется на уровне кластера. Автопилот распространяет это на узлы и поды.

Проще всего понять особенности и ограничения Автопилота из описания системы. Обратите внимание на предварительно настроенные параметры (pre-configured), которые нельзя изменить.

Сравнение режимов Autopilot и Standard

По сути, это ещё один способ резервирования и управления ресурсами GKE, который жертвует гибкостью ради удобства. Поскольку Google управляет большей частью конфигурации, то для подов Автопилота с распределением по многим зонам она гарантирует более высокий аптайм 99,9% (см. SLA).

В облаке Google регионы состоят из трёх или более зон. Размещение всех ресурсов в одной зоне менее надёжно, чем по нескольким зонам, а максимальную отказоустойчивость даёт расширение на несколько регионов. Кластеры на Автопилоте всегда распределены по регионам, а не зонам: это надёжнее, но дороже.

Другое ограничение Автопилота предустановленная операционная система Linux с Containerd, оптимизированная для контейнеров. Нет возможности использовать Linux с Docker или Windows Server. Максимальное количество подов на узел 32, а не 110, как на стандартном GKE.

SSH-доступ к узлам отсутствует, узлы Автопилота заблокированы. Поддержка GPU и TPU (Tensor Processing Unit) недоступна, хотя и запланирована на будущее. Отказ от SSH был сложным решением, говорит Брэдсток. Конечно, это ограничивает возможности управления. Но Брэдсток сказал, что такое решение было принято по результатам исследований, показавших большой уровень критических ошибок в конфигурировании кластеров.

Деньги


Модель ценообразования здесь тоже отличается. Плату берут не за вычислительные инстансы (виртуальные машины), а за реальное использование CPU, памяти и хранилища всеми подами. Плюс $0,10 в час за каждый кластер на Автопилоте, как в стандартном GKE.

Очевидный вопрос: что будет дороже, стандартный кластер или Автопилот. Ответить непросто. Поскольку это в каком-то смысле премиальный сервис, Автопилот обойдётся дороже, чем тщательно оптимизированное стандартное развертывание GKE. Существует премия по сравнению с обычным GKE, сказал Брэдсток, потому что мы обеспечиваем не только функциональность, но полную поддержку SRE (Site Reliability Engineering) и гарантии SLA.

Тем не менее, Автопилот может обойтись дешевле, чем некорректно сконфигурированный деплой GKE, который не полностью загружен, потому что трудно оценить правильную спецификацию для вычислительных инстансов.


Интегральная функция распределения (CDF) неиспользуемой памяти и занятых машин для 5000 задач после включения Автопилота в собственной инфраструктуре Google, источник


Снижение ошибок памяти (OOM) и доли неиспользуемой памяти для 500 задач после включения Автопилота в инфраструктуре Google, источник

Почему просто не использовать Cloud Run, который запускает рабочие нагрузки контейнеров без какой-либо конфигурации кластеров, узлов и подов, даже на GKE? Cloud Run отличная среда для разработчиков, одно приложение может раскрутиться с нуля до 1000 инстансов и обратно опуститься до нуля, для того и созданы облака, объясняет Брэдсток. Автопилот облегчает жизнь людям, которые хотят использовать именно Kubernetes, хотят всё видеть и держать под контролем, хотят использовать сторонние скрипты, хотят построить свою собственную платформу.

Определённой проблемой является совместимость с существующими надстройками сторонними инструментами для Kubernetes. Некоторые из них пока не совместимы с Автопилотом, но другие уже работают, такие как мониторинг Datadog. Также поддерживается DaemonSets эту функцию для запуска демонов на всех узлах используют многие инструменты.

Конфигурация хранилища, вычислений и сети вынудила отказаться от некоторого уровня гибкости и некоторых интеграций: Но мы определённо хотим, чтобы на нём [Автопилоте] работала сторонняя экосистема, говорит Брэдсток.

С запуском Автопилота расширяется диапазон вариантов, как запускать Kubernetes в облаке Google. Компромисс не только в более высокой стоимости и меньшей гибкости, но и в потенциальной дезориентации девопсов на предприятиях. Однако главная логика в том, что предприятиям лучше сосредоточиться на своём основном бизнесе, а не на услугах, которые выполняются подрядчиком.

У инженерной службы Google репутация гораздо лучше, чем службы поддержки клиентов. Разработчик Кевин Лин (Kevin Lin) недавно описал, как выглядит схема зачисления бонусов для стартапов в AWS и Google.

Google проявила себя как медленная и неэффективная организация, которая в итоге отправила клиента к стороннему партнёру. Первый разговор был целиком посвящён тому, сколько денег я планирую потратить в Google (в отличие от звонка Amazon, где сотрудники хотели помочь мне запустить сервис). У Google Cloud действительно хорошая эргономика и инженеры мирового класса, но ужасная репутация службы поддержки клиентов, сказал он.

Это ещё одно доказательство, что хорошие инженеры не единственный важный фактор при выборе облака.
Подробнее..

Перевод Argo CD готов к труду и обороне в Kubernetes

26.02.2021 20:18:58 | Автор: admin

Привет, Хабр. В рамках курса Инфраструктурная платформа на основе Kubernetes подготовили для вас перевод полезного материала.

Также приглашаем на открытый вебинар Работа с NoSQL базами в k8s (на примере Apache Cassandra). На вебинаре участники вместе с экспертом рассмотрят плюсы и минусы запуска Apache Cassandra в k8s: насколько такой вариант установки готов к продакшену, и какие подводные камни имеются.


В этой статье мы рассмотрим несколько вопросов касательно Argo CD: что это такое, зачем его используют, как его развернуть (в Kubernetes), как его использовать для реализации непрерывного развертывания (continuous deployment), как настроить SSO с помощью GitHub и разрешений и т. д.

Что такое Argo CD и GitOps

Argo CD это декларативный GitOps-инструмент непрерывной доставки (continuous delivery) для Kubernetes.

Но что же такое GitOps?

Официальное определение гласит, что GitOps это способ реализации непрерывного развертывания (continuous deployment) облачных приложений. Он фокусируется на создании ориентированного на разработчиков опыта эксплуатации инфраструктуры с использованием инструментов, с которыми разработчики уже знакомы, включая Git и Continuous Deployment.

Официальное определение не вдается в подробности, не так ли? Возможно, вы не так часто слышали об этой концепции, но, скорее всего, вы уже использовали ее: вы определяете свои K8s ресурсы в YAML или с помощью Helm-диаграммы, вы используете Git в качестве единого источника истины (single source of truth), вы запускаете одни автоматизированные CI задачи для деплоя в продакшн, когда ваша ветвь master изменена, и вы запускаете другие задачи по пул реквесту для деплоя на стейджи.

Почему GitOps

Определения, конфигурации и среды приложений должны быть декларативными и подлежать контролю версий.

Развертывание (деплой) приложений и управление жизненным циклом должны быть:

  • автоматизированными

  • проверяемыми

  • простыми для понимания

Эти правила не требуют пояснений, поскольку они приносят очевидную пользу. Вам не хотелось бы тратить много времени на выяснение, какая версия развернута в какой среде и какой тег git ей соответствует; вам нужна возможность отката до определенной версии; вы хотели бы, чтобы определение приложений и деплоев было легко читаемым для людей; вы хотите, чтобы все было автоматизировано и не исключало возможность проверки.

В этом и заключается концепция GitOps и то, почему он хорош.

Почему Argo CD

Можно ли достичь вышеупомянутых преимуществ GitOps, используя любые другие инструменты CI/CD? Скорее всего, да. Например, вы можете использовать старый добрый Jenkins, определить разные задачи для разных ветвей, после чего задачи будут следить за Git-репозиториями или использовать хуки для реакции на события, а в конвейере вы можете выполнить несколько git clone и helm install. Нет ничего плохого в Jenkins, на что я указывал в моей предыдущей статье о CI: Введение в CI: сравнение 17 основных инструментов CI или Как выбрать лучшее CI в 2020 году.

Если вы не читали ее, я рекомендую вам сделать это, чтобы лучше понять, что мы ищем при выборе инструмента.

По сути, Argo CD упрощает все, о чем я упоминал выше: легко настраивать, легко развертывать, почти без особых напрягов, так что вы можете сосредоточиться на более важных вещах, а не возиться с инструментом, просто чтобы понять, как его использовать и настраивать.

Все еще неубедительно

Хорошо, я понимаю, что у вас есть опасения по поводу внедрения новых инструментов, поэтому вот несколько фактов, которые могут вас убедить:

Это часть фонда Cloud Native Computing Foundation (CNCF).

Он активно поддерживается и постоянно улучшается. Посмотрите количество на коммитов:

Мне порой доставляет удовольствие покопаться в git-репозиториях в поисках разнообразной информации, и вот что я нашел здесь:

  • первый релиз v0.1.0 состоялся в марте 2018 года (относительно новый проект)

  • v1.0.0 зарелижен в мае 2019 (быстро развивается)

  • на момент написания статьи имеет версию v1.7.8 (ноябрь 2020, развивается очень быстро)

  • 4,3 тыс. звезд в репозитории Argo CD (еще больше на других репозиториях того же проекта)

  • 60 открытых PR и 500 открытых задач на сегодняшний день (очень даже неплохо, это означает, что сообщество активно занимается им и постоянно исправляет и придумывает запросы на новый функционал)

Он также упоминается в техническом радаре CNCF:

Он все еще находится на стадии ОЦЕНКА (ASSESS), что означает, что члены CNCF протестировали его, и он показался многообещающим. Он рекомендован к рассмотрению, когда вы сталкиваетесь с конкретной потребностью в подобной технологии в вашем проекте.

Радар является инициативой CNCF End User Community. Это группа из более чем 140 ведущих компаний и стартапов, которые регулярно встречаются для обсуждения проблем и передовых методов внедрения облачных технологий. Если вам лень разбираться, какой инструмент использовать, или если вы чувствуете себя неуверенно в отношении новых вещей, которые вы еще не пробовали, довольно безопасно выбрать один из вариантов, которые предлагает радар, потому что многие крупные компании уже протестировали его за вас, множество из имен которых вы уже слышали. Если это подходит им, есть большая вероятность, что и вам это понравится.

Развертывание

Окей, приступим к практике. У вас должен быть запущен кластер K8s, потому что мы собираемся делать это внутри k8s.

kubectl create namespace argocdkubectl apply -n argocd -f \https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml 

Один YAML, чтоб править всеми.

После развертывания у вас будет несколько запущенных подов и сервисов. Примеры:

Pods:argocd-application-controller-6b47c9bd78-kp6djargocd-dex-server-7b6d8776d8-knsxxargocd-redis-99fb49846-l466kargocd-repo-server-b664bd94b-bmtwrargocd-server-768879948c-sx875Services:argocd-dex-serverargocd-metricsargocd-redisargocd-repo-serverargocd-serverargocd-server-metrics

Комментарии по доступу к сервису и ingress:

Обратите внимание, что в развертывании по умолчанию сервис работает как тип Cluster IP, и ingress по умолчанию нет. Поэтому, если вы хотите получить доступ к сервису, вам нужно будет либо выполнить переадресацию портов, либо изменить тип сервиса на балансировщик нагрузки, либо создать ingress.

Если вы делаете это в производственном кластере, например в EKS в AWS, скорее всего, вы хотите использовать ingress и, вероятно, у вас уже есть ingress-контроллер. Вход для Argo CD здесь немного сложен, потому что на порту 443 он имеет как HTTPS (для веб-интерфейса консоли), так и GRPC для вызовов API командной строки. Если вы используете EKS, например, с ingress-контроллером Nginx, скорее всего, вы уже выполнили завершение TLS там, поэтому вам может потребоваться несколько ingress-объектов и хостов, один для протокола HTTP, другой для GRPC. Подробнее смотрите здесь.

Установка CLI

Для Mac это всего лишь одна команда:

brew install argocd

Инициализация

После установки изначальный пароль совпадает с именем пода сервера. Мы можем войти в систему:

argocd login  (переадресация портов, служба балансировки нагрузки, ingress - на ваш выбор)

и изменить пароль:

argocd account update-password

Вы также можете войти в консоль пользовательского интерфейса со своим юзернеймом и паролем, чтобы прочувствовать:

Страница входа в пользовательский интерфейс Argo CD

Добавление кластеров

Вы можете управлять сразу несколькими кластерами внутри Argo CD, например, у вас могут быть разные кластеры для разных сред, таких как dev, test, staging, production или что-то еще.

По умолчанию кластер, в котором развернут Argo CD, уже настроен с помощью Argo CD:

Вы также можете увидеть список кластеров с помощью интерфейса командной строки:

argocd cluster list

Если вы хотите управлять другими кластерами, вы можете запустить:

argocd cluster add CONTEXTNAMECONTEXTNAME- имя kube контекста в вашей локальной конфигурации.

Helloworld-пример развертывания

Теперь мы можем попробовать создать приложение на Argo CD.

Версия TL;DR или версия Мне не нравится UI в этом разделе это одна команда:

argocd app create helloworld --repo https://github.com/ironcore864/go-hello-http.git --path helm --sync-policy automatic --dest-server https://kubernetes.default.svc --dest-namespace default --values values.yaml --values values.dev.yaml

Эта CLI-команда создаст приложение, развернет его и синхронизирует. Чтобы продемонстрировать простоту Argo CD, я буду делать то же самое в пользовательском интерфейсе, а именно:

Нажмите кнопку NEW APP в консоли пользовательского интерфейса:

Затем вам нужно ввести несколько параметров для задачи, например:

  • Application Name: имя этого приложения. Здесь я назову его просто helloworld

  • Project: вы можете выбрать default. Project (проект) это концепция внутри Argo CD, в рамках которой вы можете создать несколько приложений и связать каждое приложение с проектом

  • Sync policy: вы можете выбрать между Manual и Automatic (что даст вам настоящий GitOps). Здесь я выберу Automatic (обратите внимание, что здесь в пользовательском интерфейсе значение по умолчанию Manual).

Нажмите SYNC POLICY и выберите Automatic

Затем мы перейдем к SOURCE части. Нам нужно указать URL-адрес git. Я собираюсь использовать пример, расположенный по адресу. Если вы перейдете в этот репозиторий, вы обнаружите, что там нет ничего, кроме простого Golang приложения с папкой с именем helm, которая представляет собой диаграмму для развертывания с несколькими файлами значений.

После того, как вы ввели URL-адрес git-репозитория, кликните часть PATH, и вы обнаружите, что Argo CD уже автоматически обнаружил, что у нас есть папка helm в этом репозитории, которая содержит вещи, которые могут нас заинтересовать:

Кликните Path и выберите имя папки helm в раскрывающемся меню.

Итак, здесь мы просто кликаем раздел Path и выбираем папку helm.

Стоит отметить, что Argo CD поддерживает несколько инструментов для развертывания. Сам Argo CD не предвзят; он позволяет использовать собственный YAML k8s, или kustomize, или helm. Например, если файлы в Path представляют собой схему управления, Argo CD знает, что нужно запустить установку Helm; но если это просто файлы YAML k8s, Argo CD знает, что вместо этого нужно запустить kubectl apply. Умно, не правда ли?

В разделе Destination нам нужно выбрать, в каком кластере Kubernetes развернуть это приложение (выбор из раскрывающегося списка) и в каком пространстве имен (введите текст).

Щелкните URL-адрес кластера, выберите кластер для развертывания и введите пространство имен.

Поскольку в этом примере в нашей папке helm есть диаграмма, Argo CD автоматически загружает новый раздел с именем Helm, чтобы попросить вас выбрать, какой файл значений, который нужно применить:

Кликните раздел VALUES FILES, и вы можете выбрать один или несколько файлов из списка, который выбирается из Path, настроенного ранее.

Это раскрывающееся меню, вам даже не нужно вводить имена файлов. Эта часть хорошо интегрирована с helm причина, по которой я предпочитаю создавать приложение в пользовательском интерфейсе, хотя то же самое можно сделать с помощью одной единственной CLI-команды.

Здесь мы указали два файл со значениями, один по умолчанию, другой для dev стейджа, и в нем есть значения, которые переопределяют значения, определенные по умолчанию.

После нажатия кнопки Create Argo CD синхронизирует (sync) статус, определенный в git-репозитории, и если текущее состояние не совпадает с тем, что определено в git, Argo CD синхронизирует его и переведет состояние в то же, что определено в git. Через некоторое время вы увидите, что приложение синхронизировано, и какие компоненты развернуты:

Приложение синхронизированоПриложение синхронизированоПодробное представление приложенияПодробное представление приложения

В этом примере у нас есть развертывание, в котором развернут только 1 под (значения из values.dev.yaml переопределяет 3 пода по умолчанию, определенные в файле values.yaml), и сервис, раскрывающий развертывание. Теперь, если мы перейдем к целевому кластеру и проверим, он действительно уже развернут:

Приложение действительно развернуто, без шутокПриложение действительно развернуто, без шуток

Это демонстрирует весь процесс, в котором вы создаете приложение и развертываете его. Весь процесс занимает около 1 минуты, без написания bash-скриптов для cd в какую-либо папку, а затем для установки helm, или, что еще хуже, если у вас нет подходящего образа с helm, необходимости его собрать или найти.

Там также есть много CLI-команд, которые можно использовать, если вы предпочитаете их пользовательскому интерфейсу, чтобы у вас был контроль над всем, не выходя из зоны комфорта.

GitHub SSO

Последняя, но не по важности, тема это пользователи и разрешения, как и в каждом новом инструменте, который мы хотим внедрить в нашу команду.

После установки Argo CD имеет одного встроенного администратора, который имеет полный доступ к системе. Рекомендуется использовать пользователя с правами администратора только для изначальной настройки, а затем переключиться на локальных пользователей или настроить SSO-интеграцию.

Вы можете создать локального пользователя в Argo CD, но вы, вероятно, захотите настроить SSO.

Argo CD включает и поставляет Dex как часть установочного комплекта с целью делегирования аутентификации внешнему поставщику идентификации. Поддерживаются несколько типов поставщиков идентификации (OIDC, SAML, LDAP, GitHub и т. Д.). Для настройки единого входа (SSO) на Argo CD необходимо отредактировать файл конфигурации argocd-cm с настройками Dex-коннектора. После регистрации нового OAuth приложения в git вы можете отредактировать configmap argocd-cm, чтобы добавить следующие значения:

data:  url: https://argocd.example.com  dex.config: |    connectors:      # GitHub example      - type: github        id: github        name: GitHub        config:          clientID: aabbccddeeff00112233          clientSecret: $dex.github.clientSecret          orgs:          - name: your-github-org      # GitHub enterprise example      - type: github        id: acme-github        name: Acme GitHub        config:          hostName: github.acme.com          clientID: abcdefghijklmnopqrst          clientSecret: $dex.acme.clientSecret          orgs:          - name: your-github-org

После сохранения изменения должны вступить в силу автоматически, и у вас будет GitHub SSO уже для всей вашей команды.

GitHub SSO (здесь в примере корпоративный git)GitHub SSO (здесь в примере корпоративный git)

Если вы запустите GitHub SSO с новым пользователем, входящим в систему, он не увидит список кластеров или только что созданное приложение это из-за функций RBAC, позволяющих ограничивать доступ к ресурсам Argo CD. После того, как мы уже включили SSO, мы можем настроить RBAC, создав следующую configmap argocd-rbac-cm:

apiVersion: v1kind: ConfigMapmetadata:  name: argocd-rbac-cm  namespace: argocddata:  policy.default: role:readonly  policy.csv: |    p, role:org-admin, applications, *, */*, allow    p, role:org-admin, clusters, get, *, allow    p, role:org-admin, repositories, get, *, allow    p, role:org-admin, repositories, create, *, allow    p, role:org-admin, repositories, update, *, allow    p, role:org-admin, repositories, delete, *, allow    g, your-github-org:your-team, role:org-admin

Таким образом, пользователи, вошедшие в систему с помощью нашей системы единого входа GitHub, могут управлять приложениями и видеть кластеры.

Заключение

Установка, инициализация, управление (кластер, SSO, пользователь, RBAC), использование (создание приложения, развертывание) довольно просты. Я настоятельно рекомендую вам попробовать, в любом случае это займет у вас не больше часа. И я гарантирую, что вам понравится его простота и то, что он может вам принести.


Узнать подробнее о курсе Инфраструктурная платформа на основе Kubernetes.

Смотреть открытый вебинар Работа с NoSQL базами в k8s (на примере Apache Cassandra).

Подробнее..

Ломаем и чиним etcd-кластер

01.03.2021 20:22:05 | Автор: admin

etcd это быстрая, надёжная и устойчивая к сбоям key-value база данных. Она лежит в основе Kubernetes и является неотъемлемой частью его control-plane. Именно поэтому критически важно уметь бэкапить и восстанавливать работоспособность как отдельных нод, так и всего etcd-кластера.

В предыдущей статье мы подробно рассмотрели перегенерацию SSL-сертификатов и static-манифестов для Kubernetes, а также вопросы связанные восстановлением работоспособности Kubernetes. Эта статья будет посвящена целиком и полностью восстановлению etcd-кластера.


Для начала я сразу должен сделать оговорку, что рассматривать мы будем лишь определённый кейс, когда etcd задеплоен и используется непосредственно в составе Kubernetes. Приведённые в статье примеры подразумевают что ваш etcd-кластер развёрнут с помощью static-манифестов и запускается внутри контейнеров.

Для наглядности возьмём схему stacked control plane nodes из предыдущей статьи:

(стрелочки указывают на связи клиент --> сервер)(стрелочки указывают на связи клиент --> сервер)

Предложенные ниже команды можно выполнить и с помощью kubectl, но в данном случае мы постараемся абстрагироваться от плоскости управления Kubernetes и рассмотрим локальный вариант управления контейнеризированным etcd-кластером с помощью crictl.

Данное умение также поможет вам починить etcd даже в случае неработающего Kubernetes API.

Подготовка

По этому, первое что мы сделаем, это зайдём по ssh на одну из master-нод и найдём наш etcd-контейнер:

CONTAINER_ID=$(crictl ps -a --label io.kubernetes.container.name=etcd --label io.kubernetes.pod.namespace=kube-system | awk 'NR>1{a=$1} END{print a}')

Так же установим алиас, чтобы каждый раз не перечислять пути к сертификатам в командах:

alias etcdctl='crictl exec "$CONTAINER_ID" etcdctl --cert /etc/kubernetes/pki/etcd/peer.crt --key /etc/kubernetes/pki/etcd/peer.key --cacert /etc/kubernetes/pki/etcd/ca.crt'

Приведённые выше команды являются временными, вам потребуется выполнять их каждый раз перед тем как начать работать с etcd. Конечно, для своего удобства вы можете добавить их в .bashrc. Как это сделать выходит за рамки этой статьи.

Если что-то пошло не так и вы не можете сделать exec в запущенный контейнер, посмотрите логи etcd:

crictl logs "$CONTAINER_ID"

А также убедитесь в наличии static-манифеста и всех сертифиткатов в случае если контейнер даже не создался. Логи kubelet так же бывают весьма полезными.

Проверка состояния кластера

Здесь всё просто:

# etcdctl member list -w table+------------------+---------+-------+---------------------------+---------------------------+------------+|        ID        | STATUS  | NAME  |        PEER ADDRS         |       CLIENT ADDRS        | IS LEARNER |+------------------+---------+-------+---------------------------+---------------------------+------------+| 409dce3eb8a3c713 | started | node1 | https://10.20.30.101:2380 | https://10.20.30.101:2379 |      false || 74a6552ccfc541e5 | started | node2 | https://10.20.30.102:2380 | https://10.20.30.102:2379 |      false || d70c1c10cb4db26c | started | node3 | https://10.20.30.103:2380 | https://10.20.30.103:2379 |      false |+------------------+---------+-------+---------------------------+---------------------------+------------+

Каждый инстанс etcd знает всё о каждом. Информация о members хранится внутри самого etcd и по этому любое изменение в ней будет также обновленно и на остальных инстансах кластера.

Важное замечание, команда member list отображает только статус конфигурации, но не статус конкретного инстанса. Чтобы проверить статусы инстансов есть команда endpoint status, но она требует явного указания всех эндпоинтов кластера для проверки.

ENDPOINTS=$(etcdctl member list | grep -o '[^ ]\+:2379' | paste -s -d,)etcdctl endpoint status --endpoints=$ENDPOINTS -w table

в случае если какой-то из эндпоинтов окажется недоступным вы увидите такую ошибку:

Failed to get the status of endpoint https://10.20.30.103:2379 (context deadline exceeded)

Удаление неисправной ноды

Иногда случается так что какая-то из нод вышла из строя. И вам нужно восстановить работоспособность etcd-кластера, как быть?

Первым делом нам нужно удалить failed member:

etcdctl member remove d70c1c10cb4db26c

Прежде чем продолжить, давайте убедимся, что на упавшей ноде под с etcd больше не запущен, а нода больше не содержит никаких данных:

rm -rf /etc/kubernetes/manifests/etcd.yaml /var/lib/etcd/crictl rm "$CONTAINER_ID"

Команды выше удалят static-pod для etcd и дирректорию с данными /var/lib/etcd на ноде.

Разумеется в качестве альтернативы вы также можете воспользоваться командой kubeadm reset, которая удалит все Kubernetes-related ресурсы и сертифиткаты с вашей ноды.

Добавление новой ноды

Теперь у нас есть два пути:

В первом случае мы можем просто добавить новую control-plane ноду используя стандартный kubeadm join механизм:

kubeadm init phase upload-certs --upload-certskubeadm token create --print-join-command --certificate-key <certificate_key>

Вышеприведённые команды сгенерируют команду для джойна новой control-plane ноды в Kubernetes. Этот кейс довольно подробно описан в официальной документации Kubernetes и не нуждается в разъяснении.

Этот вариант наиболее удобен тогда, когда вы деплоите новую ноду с нуля или после выполнения kubeadm reset

Второй вариант более аккуратный, так как позволяет рассмотреть и выполнить изменения необходимые только для etcd не затрагивая при этом другие контейнеры на ноде.

Для начала убедимся что наша нода имеет валидный CA-сертификат для etcd:

/etc/kubernetes/pki/etcd/ca.{key,crt}

В случае его отсутсвия скопируейте его с других нод вашего кластера. Теперь сгенерируем остальные сертификаты для нашей ноды:

kubeadm init phase certs etcd-healthcheck-clientkubeadm init phase certs etcd-peerkubeadm init phase certs etcd-server

и выполним присоединение к кластеру:

kubeadm join phase control-plane-join etcd --control-plane

Для понимания, вышеописанная команда сделает следующее:

  1. Добавит новый member в существующий etcd-кластер:

    etcdctl member add node3 --endpoints=https://10.20.30.101:2380,https://10.20.30.102:2379 --peer-urls=https://10.20.30.103:2380
    
  2. Сгенерирует новый static-manifest для etcd /etc/kubernetes/manifests/etcd.yaml с опциями:

    --initial-cluster-state=existing--initial-cluster=node1=https://10.20.30.101:2380,node2=https://10.20.30.102:2380,node3=https://10.20.30.103:2380
    

    эти опции позволят нашей ноде автоматически добавиться в существующий etcd-кластер.

Создание снапшота etcd

Теперь рассмотрим вариант создания и восстановления etcd из резервной копии.

Создать бэкап можно довольно просто, выполнив на любой из нод:

etcdctl snapshot save /var/lib/etcd/snap1.db

Обратите внимание я намерянно использую /var/lib/etcd так как эта директория уже прокинута в etcd контейнер (смотрим в static-манифест /etc/kubernetes/manifests/etcd.yaml)

После выполнения этой команды по указанному пути вы найдёте снапшот с вашими данными, давайте сохраним его в надёжном месте и рассмотрим процедуру восстановления из бэкапа

Восстановление etcd из снапшота

Здесь мы рассмотрим кейс когда всё пошло не так и нам потребовалось восстановить кластер из резервной копии.

У нас есть снапшот snap1.db сделанный на предыдущем этапе. Теперь давайте полностью удалим static-pod для etcd и данные со всех наших нод:

rm -rf /etc/kubernetes/manifests/etcd.yaml /var/lib/etcd/member/crictl rm "$CONTAINER_ID"

Теперь у нас снова есть два пути:

Вариант первый создать etcd-кластер из одной ноды и присоединить к нему остальные ноды, по описанной выше процедуре.

kubeadm init phase etcd local

эта команда сгенерирует статик-манифест для etcd c опциями:

--initial-cluster-state=new--initial-cluster=node1=https://10.20.30.101:2380

таким образом мы получим девственно чистый etcd на одной ноде.

# etcdctl member list -w table+------------------+---------+-------+---------------------------+---------------------------+------------+|        ID        | STATUS  | NAME  |        PEER ADDRS         |       CLIENT ADDRS        | IS LEARNER |+------------------+---------+-------+---------------------------+---------------------------+------------+| 1afbe05ae8b5fbbe | started | node1 | https://10.20.30.101:2380 | https://10.20.30.101:2379 |      false |+------------------+---------+-------+---------------------------+---------------------------+------------+

Восстановим бэкап на первой ноде:

etcdctl snapshot restore /var/lib/etcd/snap1.db \  --data-dir=/var/lib/etcd/new  --name=node1 \  --initial-advertise-peer-urls=https://10.20.30.101:2380 \  --initial-cluster=node1=https://10.20.30.101:2380mv /var/lib/etcd/member /var/lib/etcd/member.oldmv /var/lib/etcd/new/member /var/lib/etcd/membercrictl rm "$CONTAINER_ID"rm -rf /var/lib/etcd/member.old/ /var/lib/etcd/new/

На остальных нодах выполним присоединение к кластеру:

kubeadm join phase control-plane-join etcd --control-plane

Вариант второй: восстановить бэкап сразу на всех нодах кластера. Для этого копируем файл снапшота на остальные ноды, и выполняем восстановление вышеописанным образом. В данном случае в опциях к etcdctl нам потребуется указать сразу все ноды нашего кластера, к примеру

для node1:

etcdctl snapshot restore /var/lib/etcd/snap1.db \  --data-dir=/var/lib/etcd/new \  --name=node1 \  --initial-advertise-peer-urls=https://10.20.30.101:2380 \  --initial-cluster=node1=https://10.20.30.101:2380,node2=https://10.20.30.102:2380,node3=https://10.20.30.103:2380

для node2:

etcdctl snapshot restore /var/lib/etcd/snap1.db \  --data-dir=/var/lib/etcd/new \  --name=node2 \  --initial-advertise-peer-urls=https://10.20.30.102:2380 \  --initial-cluster=node1=https://10.20.30.101:2380,node2=https://10.20.30.102:2380,node3=https://10.20.30.103:2380

для node3:

etcdctl snapshot restore /var/lib/etcd/snap1.db \  --data-dir=/var/lib/etcd/new \  --name=node3 \  --initial-advertise-peer-urls=https://10.20.30.103:2380 \  --initial-cluster=node1=https://10.20.30.101:2380,node2=https://10.20.30.102:2380,node3=https://10.20.30.103:2380
Подробнее..

Лучшие практики для деплоя высокодоступных приложений в Kubernetes. Часть 1

03.03.2021 16:23:30 | Автор: admin

Развернуть в Kubernetes приложение в минимально рабочей конфигурации нетрудно. Но когда вы захотите обеспечить своему приложению максимальную доступность и надежность в работе, вы неизбежно столкнётесь с немалым количеством подводных камней. В этот статье мы попытались систематизировать и ёмко описать самые важные правила для развертывания высокодоступных приложений в Kubernetes.

Функциональность, которая не доступна в Kubernetes из коробки, здесь почти не будет затрагиваться. Также мы не будем привязываться к конкретным CD-решениям и опустим вопросы шаблонизации/генерации Kubernetes-манифестов. Рассмотрены только общие правила, касающиеся того, как Kubernetes-манифесты могут выглядеть в конечном итоге при деплое в кластер.

1. Количество реплик

Вряд ли получится говорить о какой-либо доступности, если приложение не работает по меньшей мере в двух репликах. Почему при запуске приложения в одной реплике возникают проблемы? Многие сущности в Kubernetes (Node, Pod, ReplicaSet и др.) эфемерны, т. е. при определенных условиях они могут быть автоматически удалены/пересозданы. Соответственно, кластер Kubernetes и запущенные в нём приложения должны быть к этому готовы.

К примеру, при автомасштабировании узлов вниз, какие-то узлы вместе с запущенными на них Pod'ами будут удалены. Если в это время на удаляемом узле работает ваше приложение в одном экземпляре, то неизбежна полная хотя обычно и непродолжительная недоступность приложения. В целом, при работе в одной реплике любое нештатное завершение работы приложения будет означать простой. Таким образом, приложение должно быть запущено по меньшей мере в двух репликах.

При этом, если реплика экстренно завершает работу, то чем больше рабочих реплик было изначально, тем меньше просядет вычислительная способность всего приложения. К примеру, если у приложения всего две реплики и одна из них перестала работать из-за сетевых проблем на узле, то приложение теперь сможет выдержать только половину первоначальной нагрузки (одна реплика доступна, одна недоступна). Конечно, через некоторое время новая реплика приложения будет поднята на новом узле, и работоспособность полностью восстановится. Но до тех пор увеличение нагрузки на единственную рабочую реплику может приводить к перебоям в работе приложения, поэтому количество реплик должно быть с запасом.

Рекомендации актуальны, если не используется HorizontalPodAutoscaler. Лучший вариант для приложений, у которых будет больше нескольких реплик, настроить HorizontalPodAutoscaler и забыть про указание количества реплик вручную. О HorizontalPodAutoscaler мы поговорим в следующей статье.

2. Стратегия обновления

Стратегия обновления у Deployment'а по умолчанию такая, что почти до конца обновления только 75% Pod'ов старого+нового ReplicaSet'а будут в состоянии Ready. Таким образом, при обновлении приложения его вычислительная способность может падать до 75%, что может приводить к частичному отказу. Отвечает за это поведение параметр strategy.rollingUpdate.maxUnavailable. Поэтому убедитесь, что приложение не теряет в работоспособности при отказе 25% Pod'ов, либо увеличьте maxUnavailable. Округление maxUnavailable происходит вверх.

Также у стратегии обновления по умолчанию (RollingUpdate) есть нюанс: приложение некоторое время будет работать не только в несколько реплик, но и в двух разных версиях разворачивающейся сейчас и развернутой до этого. Поэтому, если приложение не может даже непродолжительное время работать в нескольких репликах и нескольких разных версиях, то используйте strategy.type: Recreate. При Recreate новые реплики будут подниматься только после того, как удалятся старые. Очевидно, здесь у приложения будет небольшой простой.

Альтернативные стратегии деплоя (blue-green, canary и др.) часто могут быть гораздо лучшей альтернативой RollingUpdate, но здесь мы не будем их рассматривать, так как их реализация зависит от того, какое ПО вы используете для деплоя. Это выходит за рамки текущей статьи. (См. также статью Стратегии деплоя в Kubernetes: rolling, recreate, blue/green, canary, dark (A/B-тестирование) в нашем блоге.)

3. Равномерное распределение реплик по узлам

Очень важно разносить Pod'ы приложения по разным узлам, если приложение работает в нескольких репликах. Для этого рекомендуйте планировщику не запускать несколько Pod'ов одного Deployment'а на одном и том же узле:

      affinity:        podAntiAffinity:          preferredDuringSchedulingIgnoredDuringExecution:          - podAffinityTerm:              labelSelector:                matchLabels:                  app: testapp              topologyKey: kubernetes.io/hostname

Предпочитайте preferredDuringScheduling вместо requiredDuringScheduling, который может привести к невозможности запустить новые Pod'ы, если доступных узлов окажется меньше, чем новым Pod'ам требуется. Тем не менее, requiredDuringScheduling может быть полезен, когда количество узлов и реплик приложения точно известно и необходимо быть уверенным, что два Pod'а не смогут оказаться на одном и том же узле.

4. Приоритет

priorityClassName влияет на то, какие Pod'ы будут schedule'иться в первую очередь, а также на то, какие Pod'ы могут быть вытеснены (evicted) планировщиком, если места для новых Pod'ов на узлах не осталось.

Потребуется создать несколько ресурсов типа PriorityClass и ассоциировать их с Pod'ами через priorityClassName. Набор PriorityClass'ов может выглядеть примерно так:

  • Cluster. Priority > 10000. Критичные для функционирования кластера компоненты, такие как kube-apiserver.

  • Daemonsets. Priority: 10000. Обычно мы хотим, чтобы Pod'ы DaemonSet'ов не вытеснялись с узлов обычными приложениями.

  • Production-high. Priority: 9000. Stateful-приложения.

  • Production-medium. Priority: 8000. Stateless-приложения.

  • Production-low. Priority: 7000. Менее критичные приложения.

  • Default. Priority: 0. Приложения для окружений не категории production.

Это предохранит нас от внезапных evict'ов важных компонентов и позволит более важным приложениям вытеснять менее важные при недостатке узлов.

5. Остановка процессов в контейнерах

При остановке контейнера всем процессам в нём отправляется сигнал, указанный в STOPSIGNAL (обычно это TERM). Но не все приложения умеют правильно реагировать на него и делать graceful shutdown, который бы корректно отработал и для приложения, запущенного в Kubernetes.

Например, чтобы сделать корректную остановку nginx, нам понадобится preStop-хук вроде этого:

lifecycle:  preStop:    exec:      command:      - /bin/sh      - -ec      - |        sleep 3        nginx -s quit
  1. sleep 3 здесь для страховки от race conditions, связанных с удалением endpoint.

  2. nginx -s quit инициирует корректное завершение работы для nginx. Хотя в свежих образах nginx эта строка больше не понадобится, т. к. там STOPSIGNAL: SIGQUIT установлен по умолчанию.

(Более подробно про graceful shutdown для nginx в связке с PHP-FPM вы можете узнать из другой нашей статьи.)

Корректно ли ваше приложение обработает STOPSIGNAL, зависит только от него. На практике для большинства приложений приходится гуглить, как оно обрабатывает указанный для него STOPSIGNAL. И если оказывается, что не так, как надо, то делается preStop-хук, который эту проблему решает, либо же STOPSIGNAL меняется на тот, который приложение сможет обработать корректно и штатно завершиться.

Ещё один важный параметр, связанный с остановкой приложения, terminationGracePeriodSeconds. Он отвечает за то, сколько времени будет у приложения на корректное завершение. Если приложение не успеет завершиться в течение этого времени (30 секунд по умолчанию), то приложению будет послан сигнал KILL. Таким образом, если вы ожидаете, что выполнение preStop-хука и/или завершение работы приложения при получении STOPSIGNAL могут занять более 30 секунд, то terminationGracePeriodSeconds нужно будет увеличить. Например, такое может потребоваться, если некоторые запросы у клиентов веб-сервиса долго выполняются (вроде запросов на скачивание больших файлов).

Стоит заметить, что preStop-хук выполняется блокирующе, т. е. STOPSIGNAL будет послан только после того, как preStop-хук отработает. Тем не менее, отсчет terminationGracePeriodSeconds идёт и в течение работы preStop-хука. А процессы, запущенные в хуке, равно как и все процессы в контейнере, получат сигнал KILL после того, как terminationGracePeriodSeconds закончится.

Также у некоторых приложений встречаются специальные настройки, регулирующие время, в течение которого приложение должно завершить свою работу (к примеру, опция --timeout у Sidekiq). Оттого для каждого приложения надо убеждаться, что если у него есть подобная настройка, то она выставлена в значение немного меньшее, чем terminationGracePeriodSeconds.

6. Резервирование ресурсов

Планировщик на основании resources.requests Pod'а принимает решение о том, на каком узле этот Pod запустить. К примеру, Pod не будет schedule'иться на узел, на котором свободных (т. е. non-requested) ресурсов недостаточно, чтобы удовлетворить запросам (requests) нового Pod'а. А resources.limits позволяют ограничить потребление ресурсов Pod'ами, которые начинают расходовать ощутимо больше, чем ими было запрошено через requests. Лучше устанавливать лимиты равные запросам, так как если указать лимиты сильно выше, чем запросы, то это может лишить другие Pod'ы узла выделенных для них ресурсов. Это может приводить к выводу из строя других приложений на узле или даже самого узла. Также схема ресурсов Pod'а присваивает ему определенный QoS class: например, он влияет на порядок, в котором Pod'ы будут вытесняться (evicted) с узлов.

Поэтому необходимо выставлять и запросы, и лимиты и для CPU, и для памяти. Единственное, что можно/нужно опустить, так это CPU-лимит, если версия ядра Linux ниже 5.4 (для EL7/CentOS7 версия ядра должна быть ниже 3.10.0-1062.8.1.el7).

(Подробнее о том, что такое requests и limits, какие бывают QoS-классы в Kubernetes, мы рассказывали в этой статье.)

Также некоторые приложения имеют свойство бесконтрольно расти в потреблении оперативной памяти: к примеру, Redis, использующийся для кэширования, или же приложение, которое течёт просто само по себе. Чтобы ограничить их влияние на остальные приложения на том же узле, им можно и нужно устанавливать лимит на количество потребляемой памяти. Проблема только в том, что, при достижении этого лимита приложение будет получать сигнал KILL. Приложения не могут ловить/обрабатывать этот сигнал и, вероятно, не смогут корректно завершаться. Поэтому очень желательно использовать специфичные для приложения механизмы контроля за потреблением памяти в дополнение к лимитам Kubernetes, и не доводить эффективное потребление памяти приложением до limits.memory Pod'а.

Конфигурация для Redis, которая поможет с этим:

maxmemory 500mb   # если данные начнут занимать 500 Мб...maxmemory-policy allkeys-lru   # ...Redis удалит редко используемые ключи

А для Sidekiq это может быть Sidekiq worker killer:

require 'sidekiq/worker_killer'Sidekiq.configure_server do |config|  config.server_middleware do |chain|    # Корректно завершить Sidekiq при достижении им потребления в 500 Мб    chain.add Sidekiq::WorkerKiller, max_rss: 500  endend

Понятное дело, что во всех этих случаях limits.memory должен быть выше, чем пороги срабатывания вышеуказанных механизмов.

В следующей статье мы также рассмотрим использование VerticalPodAutoscaler для автоматического выставления ресурсов.

7. Пробы

В Kubernetes пробы (healthcheck'и) используются для того, чтобы определить, можно ли переключить на приложение трафик (readiness) и не нужно ли приложение перезапустить (liveness). Они играют большую роль при обновлении Deployment'ов и при запуске новых Pod'ов в целом.

Сразу общая рекомендация для всех проб: выставляйте высокий timeoutSeconds. Значение по умолчанию в одну секунду слишком низкое. Особенно критично для readinessProbe и livenessProbe. Слишком низкий timeoutSeconds будет приводить к тому, что при увеличении времени ответов у приложений в Pod'ах (что обычно происходит для всех Pod'ов сразу благодаря балансированию нагрузки с помощью Service) либо перестанет приходить трафик почти во все Pod'ы (readiness), либо, что ещё хуже, начнутся каскадные перезапуски контейнеров (liveness).

7.1 Liveness probe

На практике вам не так часто нужна liveness probe (дословно: проверка на жизнеспособность), насколько вы думаете. Её предназначение перезапустить контейнер с приложением, когда livenessProbe перестаёт отрабатывать, например, если приложение намертво зависло. На практике подобные deadlockи скорее исключение, чем правило. Если же приложение работает, но не полностью (например, приложение не может само восстановить соединение с БД, если оно оборвалось), то это нужно исправлять в самом приложении, а не накручивать костыли с livenessProbe.

И хотя как временное решение можно добавить в livenessProbe проверку на подобные состояния, по умолчанию livenessProbe лучше вообще не использовать. Как альтернативу её полному отсутствию можно рассмотреть простейшую livenessProbe вроде проверки на то, открыт ли TCP-порт (обязательно выставьте большой таймаут). В таком случае это поможет приложению перезапуститься при возникновении очевидного deadlock'а, но при этом приложение не подвергнется риску войти в цикл перезапусков, когда перезапуск не может помочь.

И риски, которые плохая livenessProbe несёт, весьма серьезные. Самые частые случаи: когда livenessProbe перестаёт отрабатывать по таймауту из-за повышенной нагрузки на приложение, а также когда livenessProbe перестаёт работать, т. к. проверяет (прямо или косвенно) состояние внешних зависимостей, которые сейчас отказали. В последнем случае последует перезагрузка всех контейнеров, которая при лучшем раскладе ни к чему не приведет, а при худшем приведет к полной (и, возможно, длительной) недоступности приложения. Полная длительная недоступность приложения может происходить, если при большом количестве реплик контейнеры большинства Pod'ов начнут перезагружаться в течение короткого промежутка времени. При этом какие-то контейнеры, скорее всего, поднимутся быстрее других, и на это ограниченное количество контейнеров теперь придется вся нагрузка, которая приведет к таймаутам у livenessProbe и заставит контейнеры снова перезапускаться.

Также, если все-таки используете livenessProbe, убедитесь, что она не перестает отвечать, если у вашего приложения есть лимит на количество установленных соединений и этот лимит достигнут. Чтобы этого избежать, обычно требуется зарезервировать под livenessProbe отдельный тред/процесс самого приложения. Например, запускайте приложение с 11 тредами, каждый из которых может обрабатывать одного клиента, но не пускайте извне в приложение более 10 клиентов, таким образом гарантируя для livenessProbe отдельный незанятый тред.

И, конечно, не стоит добавлять в livenessProbe проверки внешних зависимостей.

(Подробнее о проблемах с liveness probe и рекомендациях по предотвращению таких проблем рассказывалось в этой статье.)

7.2 Readiness probe

Дизайн readinessProbe (дословно: проверка на готовность [к обслуживанию запросов]), пожалуй, оказался не очень удачным. Она сочетает в себе две функции: проверять, что приложение в контейнере стало доступным при запуске контейнера, и проверять, что приложение остаётся доступным уже после его запуска. На практике первое нужно практически всегда, а второе примерно настолько же часто, насколько оказывается нужной livenessProbe. Проблемы с плохими readinessProbe примерно те же самые, что и с плохими livenessProbe, и в худшем случае также могут приводить к длительной недоступности приложения.

Когда readinessProbe перестаёт отрабатывать, то на Pod перестаёт приходить трафик. В большинстве случаев такое поведение мало помогает, т. к. трафик обычно балансируется между Pod'ами более-менее равномерно. Таким образом, чаще всего readinessProbe либо работает везде, либо не работает сразу на большом количестве Pod'ов. Есть ситуации, когда подобное поведение readinessProbe может понадобиться, но в моей практике это скорее исключение.

Тем не менее, у readinessProbe есть другая очень важная функция: определить, когда только что запущенное в контейнере приложение стало способно принимать трафик, чтобы не пускать трафик в ещё не доступное приложение. Эта же функция readinessProbe, напротив, нужна нам почти всегда.

Получается странная ситуация, что одна функция readinessProbe обычно очень нужна, а другая очень не нужна. Эта проблема была решена введением startupProbe, которая появилась в Kubernetes 1.16 и перешла в Beta в 1.18. Таким образом, рекомендую для проверки готовности приложения при его запуске в Kubernetes < 1.18 использовать readinessProbe, а в Kubernetes >= 1.18 использовать startupProbe. readinessProbe всё ещё можно использовать в Kubernetes >= 1.18, если у вас есть необходимость останавливать трафик на отдельные Pod'ы уже после старта приложения.

7.3 Startup probe

startupProbe (дословно: проверка на запуск) реализует первоначальную проверку готовности приложения в контейнере для того, чтобы пометить текущий Pod как готовый к приёму трафика, или же для того, чтобы продолжить обновление/перезапуск Deployment'а. В отличие от readinessProbe, startupProbe прекращает работать после запуска контейнера. Проверять внешние зависимости в startupProbe не лучшая идея, потому что если startupProbe не отработает, то контейнер будет перезапущен, что может приводить к переходу Pod'а в состояние CrashLoopBackOff. При этом состоянии между попытками перезапустить неподнимающийся контейнер будет делаться задержка до пяти минут. Это может означать простой в том случае, когда приложение уже может подняться, но контейнер всё ещё выжидает CrashLoopBackOff перед тем, как снова попробовать запуститься.

Обязательна к использованию, если ваше приложение принимает трафик и у вас Kubernetes >= 1.18.

Также предпочитайте увеличение failureTreshold вместо использования initialDelaySeconds. Это позволит контейнеру становиться доступным настолько быстро, насколько это возможно.

8. Проверка внешних зависимостей

Часто можно встретить совет проверять внешние зависимости вроде баз данных в readinessProbe. И хотя такой подход имеет право на существование, предпочтительно разделять проверку внешних зависимостей и проверку на то, не стоит ли остановить идущий на Pod трафик, когда приложение в нём полностью утилизировано.

С помощью initContainers можно проверять внешние зависимости до того, как начнут запускаться startupProbe/readinessProbe основных контейнеров. В readinessProbe, соответственно, проверки внешних зависимостей уже не понадобится. Подобные initContainers не требуют изменений в коде приложения, не требуют собирать контейнеры приложения с дополнительными утилитами для проверок внешних зависимостей, а также в целом довольно просты в реализации:

      initContainers:      - name: wait-postgres        image: postgres:12.1-alpine        command:        - sh        - -ec        - |          until (pg_isready -h example.org -p 5432 -U postgres); do            sleep 1          done        resources:          requests:            cpu: 50m            memory: 50Mi          limits:            cpu: 50m            memory: 50Mi      - name: wait-redis        image: redis:6.0.10-alpine3.13        command:        - sh        - -ec        - |          until (redis-cli -u redis://redis:6379/0 ping); do            sleep 1          done        resources:          requests:            cpu: 50m            memory: 50Mi          limits:            cpu: 50m            memory: 50Mi

Полный пример

Резюмируя, привёдем полный пример того, как уже с учётом всех вышеописанных рекомендаций может выглядеть Deployment stateless-приложения при его боевом развертывании.

Требования: Kubernetes >= 1.18, на узлах Ubuntu/Debian с версией ядра >= 5.4.

apiVersion: apps/v1kind: Deploymentmetadata:  name: testappspec:  replicas: 10  selector:    matchLabels:      app: testapp  template:    metadata:      labels:        app: testapp    spec:      affinity:        podAntiAffinity:          preferredDuringSchedulingIgnoredDuringExecution:          - podAffinityTerm:              labelSelector:                matchLabels:                  app: testapp              topologyKey: kubernetes.io/hostname      priorityClassName: production-medium      terminationGracePeriodSeconds: 40      initContainers:      - name: wait-postgres        image: postgres:12.1-alpine        command:        - sh        - -ec        - |          until (pg_isready -h example.org -p 5432 -U postgres); do            sleep 1          done        resources:          requests:            cpu: 50m            memory: 50Mi          limits:            cpu: 50m            memory: 50Mi      containers:      - name: backend        image: my-app-image:1.11.1        command:        - run        - app        - --trigger-graceful-shutdown-if-memory-usage-is-higher-than        - 450Mi        - --timeout-seconds-for-graceful-shutdown        - 35s        startupProbe:          httpGet:            path: /simple-startup-check-no-external-dependencies            port: 80          timeoutSeconds: 7          failureThreshold: 12        lifecycle:          preStop:            exec:              ["sh", "-ec", "#command to shutdown gracefully if needed"]        resources:          requests:            cpu: 200m            memory: 500Mi          limits:            cpu: 200m            memory: 500Mi

В следующий раз

Осталось ещё немало важных вещей, о которых обязательно надо рассказать, таких как PodDisruptionBudget, HorizontalPodAutoscaler и VerticalPodAutoscaler, чем мы непременно займемся во второй части этой статьи. А пока предлагаем вам поделиться своими лучшими практиками по деплою, либо исправить/дополнить уже описанные.

P.S.

Читайте также в нашем блоге:

Подробнее..

Продолжаем прокачивать Ansible

22.02.2021 06:06:33 | Автор: admin

Поводом для этой статьи послужил пост в чате @pro_ansible:

Vladislav ? Shishkov, [17.02.21 20:59]Господа, есть два вопроса, касаются кастомной долгой операции, например, бекапа: 1. Можно ли через ансибл прикрутить прогрессбар выполнения кастомного баша? (если через плагин, то пните в какой-нибудь пример или документацию плиз) 2. Вроде хочется для этого баша написать плагин, но встает вопрос, как быть и как решать моменты выполнения, которые идемпотентны?

Беглый поиск по задворкам памяти ничего подходящего не подсказал. Тем не менее, я точно вспомнил, что код Ansible легко читаемый, и искаропки поддерживает расширение как плагинами, так и обычными Python-модулями. А раз так, то ничего не мешает в очередной раз раздвинуть границы возможного. Hold my beer!...

Понятно, что стандартный Ansible уже умеет делать оба шага, только вот полученный выхлоп собирается в единое целое и передаётся на управляющий хост уже по завершению процесса, а мы хотим это сделать в реальном времени. Следовательно, можно как минимум посмотреть на существующую реализацию, а как максимум - каким-то образом переиспользовать существующий код.

Исходный вопрос можно свести к двум простейшим шагам:

  1. Захватить stdout команды на целевом хосте

  2. Передать его на управляющий хост.

Передаём данные на управляющий хост

Предлагаю начать с конца: с организации дополнительного канала передачи на управляющий хост. Решение этого вопроса выглядит достаточно очевидным: вспоминаем, что Ansible работает поверх ssh, и используем функцию обратного проброса порта:

Код на Python
# добавляем куда-нибудь сюда:# https://github.com/ansible/ansible/blob/5078a0baa26e0eb715e86c93ec32af6bc4022e45/lib/ansible/plugins/connection/ssh.py#L662self._add_args(    b_command,    (b"-R", b"127.0.0.1:33333:" + to_bytes(self._play_context.remote_addr, errors='surrogate_or_strict', nonstring='simplerepr') + b":33335"),    u"ANSIBLE_STREAMING/streaming set")

Как это работает? При сборке аргументов командной строки для установления ssh-соединения эта конструкция предоставит нам на целевом хосте порт 33333 по адресу 127.0.0.1, который будет туннелировать входящие соединения на контроллер - прямиком на порт 33335.

Для простоты используем netcat (ну правда, ну что за статья без котиков?): nc -lk 33335.

В этот момент, кстати, уже можно запустить Ansible и проверить, что туннель работает так, как следует: хотя пока по нему ничего и не передаётся, мы уже можем на целевом хосте зайти в консоль и выполнить nc 127.0.0.1 33333, введя какую-нибудь фразу и увидев её как результат работы команды выше.

Перехватываем stdout

Полдела сделано - идём дальше. Мы хотим перехватить stdout какой-то команды - по логике работы Ansible нам подойдёт модуль shell. Забавной, что он оказался пустышкой - в нём ни строчки кода, кроме документации и примеров, зато находим в нём отсылку к модулю command. С ним всё оказалось хорошо, кроме того факта, что нужная функция в нём напрямую не описана, хотя и использована. Но это уже было почти попадание в яблочко, потому что в итоге она нашлась в другом файле.

Под мысленное просто добавь воды просто добавляем щепотку своего кода:

Опять код
# в начале basic.py, рядом с прочими import'ами import socket# в функции run_command - где-нибудь тут:# https://github.com/ansible/ansible/blob/5078a0baa26e0eb715e86c93ec32af6bc4022e45/lib/ansible/module_utils/basic.py#L2447clientSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM);clientSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)clientSocket.connect(("127.0.0.1",33333));# в функции run_command - где-нибудь тут:# https://github.com/ansible/ansible/blob/5078a0baa26e0eb715e86c93ec32af6bc4022e45/lib/ansible/module_utils/basic.py#L2455clientSocket.send(b_chunk);# в функции run_command - где-нибудь тут# https://github.com/ansible/ansible/blob/5078a0baa26e0eb715e86c93ec32af6bc4022e45/lib/ansible/module_utils/basic.py#L2481clientSocket.close()

Собираем воедино и запускаем

Осталось сделать что? Правильно, определиться со способом подключения изменённых модулей в стоковый Ansible. На всякий случай напоминаю: мы поправили один connection plugin, и один модуль из стандартной библиотеки Ansible. Новичкам в этом деле могу рекомендовать статью хабраюзера chemtech с расшифровкой моего доклада на Стачке-2019 (там как раз в том числе объясняется, какие Python-модули куда складывать), ну а опытным бойцам эти пояснения вроде и не нужны :-)

Итак, время Ч. Результат в виде статичной картинки не очень показателен, поэтому я настроил tmux и запустил запись скринкаста.

Для внимательных зрителей скринкаста

В анимации можете увидеть два полезных побочных эффекта:

  • Теперь мы видим stdout всех не-Python процессов, которые запускаются Ansible'ом на целевом хосте - например, тех, что запускаются при сборе фактов;

  • Настройки переиспользования ssh-соединений из другой моей статьи позволяют получать этот самый stdout от удалённой команды уже после отключения Ansible от хоста.

Хотите ко мне на тренинг по Ansible?

Раз уж вы здесь - значит, вам как минимум интересно то, что я пишу об Ansible. Так вот, у меня есть опыт ведения такого тренинга внутри компании для коллег.

В прошедшем году я всерьёз начал задумываться о том, чтобы начать вести свой собственный тренинг по этому инструменту для всех желающих, поэтому предлагаю пройти опрос.

Подробнее..

Установка простого приложения (например Superset) в microk8s используя metallb и helm

03.03.2021 10:13:29 | Автор: admin

Snaps являются кросс-дистрибутивными, независимыми и простыми в установке приложениями, упакованными со всеми их зависимостями для запуска во всех основных дистрибутивах Linux. Snaps безопасны они ограничены и не ставят под угрозу всю систему. Они работают под разными уровнями содержания (то есть степень изоляции от базовой системы и друг от друга).


MicroK8s это CNCF-сертифицированное развертывание локального кластера Kubernetes, он предназначен для быстрой и легкой установки потока Kubernetes, изолированной от вашей локальной среды. В качестве оснастки он запускает все службы Kubernetes (т.е. без виртуальных машин), упаковывая при этом весь необходимый набор библиотек и файлов. Эта изоляция достигается за счет упаковки всех двоичных файлов для Kubernetes, Docker.io, iptables и CNI в единый пакет Snap.


Преимущества microk8s:


  • использует только необходимые ему ресурсы
  • кластеризация нескольких microk8s
  • легкая и простая установка в Ubuntu через snap, хваленая изоляция snap пакетов, возможность легкого отката на предыдущую версию
  • наличие аддонов

Apache Superset это веб-приложение для поиска и визуализации данных.


Helm это диспетчер пакетов для Kubernetes, упрощающий для разработчиков и операторов упаковку, настройку и развертывание приложений и служб в кластерах Kubernetes.


MetalLB это реализация балансировщика нагрузки для кластеров Kubernetes на голом железе со стандартными протоколами маршрутизации. Он выделяет службы с отдельными выделенными адресами IP, выделенными из пула.


Операционная система: Ubuntu 18.04


Устанавливаем Snapd, git


sudo apt-get update && sudo apt-get install -y snapd git

Устанавливаем microk8s версии 1.18


sudo snap install microk8s --classic --channel=1.18/stable && sudo snap install helm --classic

Стартуем microk8s


sudo microk8s.start

Добавляем текущего пользователя в группу microk8s


sudo usermod -a -G microk8s $USER

Меняем права директории .kube в домашней директории текущего пользователя


sudo chown -f -R $USER ~/.kube

Выходим из сессии и заходим снова


exit

Делаем алиал kubectl на microk8s.kubectl


alias kubectl=microk8s.kubectl

Активируем дополнения microk8s. В опциях дополнения metallb указываем список IP с ваших сетевых карточек. Если у вас 1 сервер, то это два одинаковых IP адреса. Кластеризацию microk8s я не проверял, но по идее нужно указывать IP адреса обоих серверов. Для этого обязательна кластеризация microk8s. IP на сетевой карте 192.168.22.7. У вас он будет другой.


microk8s enable dns ingress storage metallb:192.168.22.7-192.168.22.7 

Смотрим что все поды у нас Running


kubectl get all --all-namespaces

Скачиваем репозиторий superset


git clone https://github.com/apache/superset.git

Переходим в директорию где хранится helm для superset


cd superset/helm/superset

Скачиваем зависимиости для текущего helm


helm dependency update

Сохраняем конфиг для подключения к Kubernetes


sudo microk8s.kubectl config view --raw > $HOME/.kube/config

Запускаем установку superset с помощью helm используя конфиги в текущей директории


helm install --set persistence.enabled=true,service.type=LoadBalancer,ingress.enabled=true,ingress.hosts[0]=superset.192.168.22.7.xip.io  superset ./

Если вы перейдет по ссылке superset.192.168.22.7.xip.io то увидите вот такой экран.



Логин и пароль по умолчанию admin/admin. Superset настроен. Можно пользоваться.



Если нужно удалить весь кластер Kubernetes в microk8s, то можно воспользоваться командой reset


microk8s reset --destroy-storage
Подробнее..

Перевод Почему нужно автоматизировать эксплуатацию

04.03.2021 12:16:30 | Автор: admin

Сложность эксплуатации ИТ-систем растёт. Приходится управлять данными в локальных системах и облачных дата-центрах, передавать зависимости между разрозненными платформами, интегрировать и настраивать новые инструменты и технологии. Потребность в быстрых изменениях и получении данных в реальном времени всё меньше позволяет полагаться на прописанные в коде свойства, самописные скрипты и ручные процессы. Ради экономии времени, повышения надёжности и уменьшения сложности ИТ-команды должны расширять автоматизацию процессов.

Лидеры в сфере инфраструктуры и эксплуатации вкладываются в инструменты и технологии автоматизации в ответ на потребность в скорости и эффективности работы. Автоматизацию внедряют в разных сферах, включая сети, управление релизами и эксплуатацию облаков, что свидетельствует о широком стремлении увеличить скорость и эффективность инфраструктуры и эксплуатации с помощью автоматизации.

Gartner, 2019-2021 I&O Automation Benchmark Report

Пять преимуществ автоматизации инфраструктуры и эксплуатации

  1. Эффективность. Вместо того, чтобы ждать, пока админ вручную выделит виртуальные машины, можно с помощью автоматического ПО динамически создавать и удалять виртуальные машины в зависимости от текущей нагрузки.

  2. Надёжность. Автоматизация рутинных задач и повторяющихся операций вроде обновления разрешений или конфигурирования серверов уменьшает риск человеческой ошибки, а также снижает частоту и масштаб отказов.

  3. Гибкость. Решения в сфере автоматизации часто предоставляют прямые интеграции и малокодовый доступ к API, что позволяет командам эксплуатации быстро развёртывать и внедрять новые технологии, либо создавать новые кросс-платформенные процессы без написания скриптов.

  4. Прозрачность. Автоматизируя мониторинг процессов и систем, команды эксплуатации могут собирать данные для оптимизации процессов и ресурсов, отслеживать и улучшать SLA за счёт перенаправления ресурсов при угрозе избыточного роста нагрузки, а также автоматически восстанавливать системы после сбоев.

  5. Продуктивность. Команды эксплуатации могут делать больше с меньшим количеством ресурсов. Нагрузка на сотрудников снижается, у них появляется больше времени для решения долгосрочных стратегических задач, полезных для развития компании.

Создание основы для современной эксплуатации

Динамичность цифровой бизнес-инфраструктуры требует от команд эксплуатации поддерживать быстрые изменения в приложениях, динамически масштабировать инфраструктуру и делать выводы на основе имеющихся данных. Непрерывные циклы изменений и обратной связи, необходимые для цифровизации, изменят подходы к мониторингу, автоматизации, управлению сервисами, а также организационные стратегии.

Gartner, Predicts 2019: IT Operations

Автоматизация задач и процессов экономит время, повышает продуктивность и уменьшает количество сбоев. Но это не всё. Поскольку с помощью автоматизации команды эксплуатации могут меньшими средствами добиваться больше, у них остаются силы на улучшение, то есть на оптимизацию.

Сегодня быстро развиваются технологии искусственного интеллекта, малокодовые REST API-адаптеры, а также платформы разработки без необходимости программирования, что позволяет командам создавать динамические и гибкие системы, которые для своей работы почти не требуют внимания человека. Ожидания заказчиков и требования рынка непрерывно меняются, и командам эксплуатации потребуется управлять новыми возможностями, чтобы оставаться на передовой тенденций цифровизации и не уступать конкурентам.

Оркестрация и инфраструктура-как-код

Универсальные коннекторы, прямые интеграции и возможности бесшовно исполнять API (.NET-сборки, RESTful-сервисы, командные строки, хранимые процедуры и т.д.) всё это лежит в основе оркестрации, то есть способности централизованно интегрировать и управлять практически любым процессом.

Инструменты оркестрации скрывают сложность используемых скриптов и позволяют командам эксплуатации создавать сквозные процессы для управления взаимозависимостями без оглядки на используемые технологии. Это открывает путь к автоматизации и управлению процессами в локальных и облачных системах, а также между различными облачными сервисами, освобождаясь от привязки к конкретному вендору.

Кроме того, централизованно оркестрируя автоматизированные процессы ИТ-специалисты могут с помощью инфраструктуры-как-кода интегрировать в сквозные процессы операции выделения ресурсов, конфигурирование и задачи по предоставлению разрешений. И благодаря централизованному управлению можно развернуть мониторинг в рамках всей компании.

AIOps

Для эффективного управления и оптимизации сложных сред компании с помощью ИИ-технологий определяют узкие места, а также возможность сбоев до их возникновения. Собирая и анализируя большие объёмы данных, ИИ-инструменты могут запускать процедуры автовосстановления и перенаправлять ресурсы, чтобы предотвратить перегрузку вычислительных мощностей и сбои в работе процессов.

Кроме того, AIOs-решения обеспечивают прозрачность всех зависимостей приложений и систем, значительно уменьшая среднюю продолжительность восстановления в случае возникновения инцидентов.

AIOps имеет огромную ценность, когда его преимущества и возможности распространяются на среду автоматизации. Команды разработчиков и эксплуатации нуждаются в гибкой ИТ-инфраструктуре, способной в реальном времени адаптироваться к динамичным требованиям.

Гиперавтоматизация

Этим термином описывается использование ИИ-технологий и машинного обучения для поиска и автоматизации как можно большего количества бизнес- и ИТ-процессов. В большинстве компаний используют специализированный подход к автоматизации, развёртывая многочисленные инструменты и оставляя множество ручных задач, которые нужно автоматизировать. Такие дыры в одеяле автоматизации можно заполнить с помощью унифицированного подхода, используя малокодовую разработку и инструменты интеллектуальной оркестрации.

Позднее автоматизированные процессы можно упростить и оптимизировать, выполнять быстрее, с меньшим количеством ошибок и потребляемых ресурсов. Алгоритмы ИИ и машинного обучения могут координировать вычислительные ресурсы, анализировать исторические и текущие данные, а также предотвращать возникновение задержек с помощью автоматизированных операций.

Когда в компании автоматизировано как можно больше задач становится гораздо проще и быстрее создавать надёжные сквозные процессы, которые способствуют достижению новых или меняющихся бизнес-целей. Координируя инструменты с единым унифицированным решением компании могут быстро реагировать на меняющиеся на изменение бизнес-требований и реалий рынка.

NoOps будущее ИТ-эксплуатации?

Такие технологии, как AIOps, облачные вычисления (SaaS/IaaS) и гиперавтоматизация позволяют ИТ-департаментам сильно уменьшать количество ручных процессов и делают возможными полностью автоматизированные автономные среды.

Стратегия NoOps включает в себя интеллектуальные инструменты для полной автоматизации повседневных операций, а также технологии ИИ или машинного обучения для работы с более высокоуровневыми, более трудозатратными задачами. В этом случае представители бизнеса и разработчики смогут через портал самообслуживания самостоятельно исполнять процессы и с помощью инфраструктуры-как-кода выделять нужные ресурсы. Команды эксплуатации фактически не будут вмешиваться.

Облачные провайдеры продолжают развивать стек технологий. Вместо того, чтобы просто предоставлять всё из гипервизора, они сосредоточились на гиперавтоматизации и берут на себя многие задачи по системному администрированию, включая установку патчей, резервное копирование и управление базами данных. Совокупность этих возможностей создаёт NoOps-среду, в которой динамически выделяется ПО и программно-определяемое оборудование.

Deloitte, NoOps In A Serverless World

В своем нынешнем виде NoOps скорее, идеология, согласно которой должно быть автоматизировано всё, что может быть автоматизировано, чтобы значительно ускорить выполнение рутинных задач и сосредоточить больше ресурсов в жизненном цикле разработки ПО ради быстрого удовлетворения потребностей бизнеса. Однако NoOps предполагает использование облачных ИТ-сред и не учитывает меняющиеся требования к данным, новые технологические потребности и управление ИТ-сервисами. Таким образом, несмотря на техническую возможность создания NoOps-среды в облаке, она, скорее всего, недолго пробудет NoOps.

Как сказал один из авторов статьи в Deloitte: NoOps на самом деле недостижима, но это эффективный лозунг.

Подробнее..

Подключение БД с SSH-туннелем к PowerBI

28.02.2021 16:06:27 | Автор: admin

Всем привет!

Оказалось, что PowerBI не имеет встроенной возможности настроить доступ к БД, защищённой SSH-туннелем. Приходится выкручиваться. Мне очень помогла эта статья - спасибо тебе добрый и компетентный в написании инструкций человек, без тебя я бы впала в отчаяние.

И тем не менее, в ней раскрыты не все нюансы. В своём материале я добавлю следующее:

  • Два уникальных совета, как сделать так, чтобы установленный туннель не падал после авторизации

  • Дополнительная инструкция для подключения к SSH при помощи приватного ключа, а не логина и пароля

  • Скрины из самого PowerBI с настройкой БД и советы о том, как работает выборка из подключенной БД и как обновлять данные, полученные по SQL-запросам.

  • Плюс я ориентирую свой материал на продуктовых аналитиков и аналитиков данных, то есть на тех, у кого нет доступа на редактирование БД и кто может не знать, что такое проброс портов и SSH-tunnel в принципе.

Итак, поехали.

Вам понадобится(этап подготовки):

  1. Установленный Putty. Можно взять здесь - https://www.putty.org/

  2. Данные от вашего бекенда или девопса по списку:

    1. IP-адрес SSH-сервера;

    2. порт SSH-сервера;

    3. username для доступа на SSH-сервер;

    4. пароль для доступа или связка приватного и публичного ключа*

    5. IP-адрес самой БД (обычно 127.0.0.1);

    6. порт самой БД;

    7. название БД;

    8. логин доступа к БД (не то же самое, что username для доступа на SSH-сервер);

    9. пароль для доступа к БД.

*Выбирать пароль или ключ не вам, а Хранителю сервера, пароль проще, ключ - безопаснее. В статье будут инструкции на оба случая. Если у вас кейс с ключами, то на этапе подготовки вам надо сгенерить оба ключа, разместить их в нужную папку на вашем компьютере и отдать внешний ключ Хранителю сервера, чтобы он его туда добавил. На эту тему есть много инструкций в интернете, я не буду повторяться.

Поднимаем SSH-туннель

  1. Открываем Putty

  2. В Category/Session вводим IP-адрес SSH-сервера, порт SSH-сервера и выставляем радио-баттон Close window on exit на позицию Never

  3. Переходим в Category/Connection/SSH и ставим галочку на Dont start a shell or command at all

  4. Переходим в Category/Connection/SSH/Tunnels, в поле Source port вбиваем порт самой БД, в поле Destination IP-адрес самой БД:порт самой БД. Жмём Add.

  5. *пункт для тех, кто подключается с приватным ключом, если у вас случай с логином и паролем, то переходите сразу к 6 пункту инструкции

    1. Запустите PuttyGen (установился на ваш компьютер вместе с Putty)

    2. Выберите в верхнем меню Conversions/Import Key

    3. В открывшемся окне Проводника откройте папку, куда вы сохранили файлы приватного и публичного ключа (пункт 2d списка Вам понадобится) и выберите файл приватного ключа. Иногда Windows делает этот файл скрытым. Возможно, вам надо будет включить отображение скрытых файлов в Проводнике, нажав на Вид и поставив галочку напротив Скрытые элементы

    4. Нажимаем Save private key. Даём ключу любое имя на латинице и сохраняем в папку с ключами.

    5. Возвращаемся в Putty. Переходим в Category/Connection/SSH/Auth и нажимаем Browse рядом с Private key file for authentication

    6. В открывшемся окне Проводника выбираем сохранённый в пункте 5d файл приватного ключа.

  6. Переходим в Category/Session, в поле Saved Session вводим имя нашего туннеля (любое), жмём Save. Это позволит нам не вводить все настройки каждый раз заново. После чего жмём Open

  7. В открывшемся окне Терминала рядом с Login as вводим username для доступа на SSH-сервер и жмём Enter

  8. *пункт для тех, у кого авторизация по паролю, если вы авторизовались по связке ключей, то пропускайте этот пункт и переходите сразу к 9.

    1. Вводим пароль для доступа на SSH-сервер и жмём Enter

Настройка PowerBI

SSH-туннель настроен, не закрывайте окно терминала Putty. Теперь переходим в PowerBI. Жмём Получить данные и выбираем База данных MySQL или База данных PostgreSQL в зависимости от того, что у вас. Интерфейс будет одинаковым, а вот вероятность успеха - разной, потому что MySQL И PostgreSQL используют разные драйвера. Убедитесь, что выбрали свою БД правильно.

  1. В поле Сервер вводим IP-адрес самой БД:порт самой БД

  2. В поле База данных вводим название БД

  3. Жмём Расширенные настройки и в поле Инструкция SQL вставляем запрос, по которому нужно импортировать данные. Если вы его не напишете, PowerBI приконнектится ко всей БД, но не позволит вам вытаскивать из неё данные запросами и не позволит построить модели (или я не нашла как, если у вас есть успешный опыт, с удовольствием прочитаю его в комментах)

  4. Жмём ok

  5. Вводим логин доступа к БД и пароль для доступа к БД, жмём Подключение

  6. Возможна вот такая ошибка, это ok

Как обновить данные из БД в PowerBI

  1. Поднимаем SSH-туннель в Putty

  2. Переходим в PowerBI и жмём Обновить. Все созданные запросы ещё раз отправятся на сервер и выгрузят свежую информацию

Подробнее..

Почему язык Go стал стандартом для DevOps-инженеров

25.02.2021 20:10:38 | Автор: admin

Иногда вещи находят себе применение неожиданно и не в том, для чего их задумывали.

В 1960-е годы Кен Томпсон легенда программирования написал компьютерную игру Space Travel для операционной системы Multics. Система была проектом компании Bell Lab, где он работал вместе с Денисом Ритчи. Позже проект закрыли, и чтобы продолжать играть в свою Space Travel, Томпсон решил портировать ее на компьютер PDP-7. Инструменты, которые он создал для порта, затем легли в основу операционной системы Unix.

Томпсон написал в одиночку первые три версии. Для Unix был нужен системный язык так появился B. Позже Денис Ритчи, коллега и друг Томпсона, подхватил разработку и написал язык C. Вот так в основе почти всего, на чем построены современные технологии, лежало желание поиграть в компьютерную игру и пет-проекты для забавы.

Кен Томпсон построил блестящую карьеру исследователя в области computer science. В середине 2000-х он устроился в Google, где вместе с Робом Пайком и Робертом Грейсмером создал Golang один из самых популярных языков последнего времени.


Go придумывали как простой язык для всего

К тому времени Google уже разрастался в гигантскую корпорацию, начинались проблемы со скоростью разработки. Там было очень много кода на C++, поддерживать его становилось все труднее. Задача, которую себе поставила компания, казалась почти наивной изобрести очень простой язык, на котором можно будет делать очень сложные вещи.

Мы все сошлись на том, что ненавидим C++, и решили, что ни одна фича не попадает в язык, пока каждый из нас троих не будет убежден в ее необходимости и тогда язык не обрастет лишним мусором, появившимся непонятно зачем.

Кен Томпсон

Создатели хотели решить проблемы медленной сборки программ, неконтролируемых зависимостей, сложной разработки инструментов и проблем межъязыкового взаимодействия. За основу языка они взяли C, Pascal и Oberton и попытались собрать из них все лучшее. В итоге они стали делать язык с очень простым синтаксисом, строгой статической типизацией, автоматической сборкой мусора и простыми средствами для управления многопоточностью.

Golang анонсировали в 2009 году, в 2012 состоялся релиз. Язык быстро стал набирать популярность, но и сталкивался с критикой. Ключевую фишку языка простоту многие разработчики посчитали и главным минусом.

Из-за стремления к простоте в Go отсутствуют конструкции, которые в остальных языках воспринимаются как что-то естественное. Вначале это может показаться хорошей идеей, но на практике выходит многословный код, писал Гэри Уилоуби. Go был разработан, чтобы быть простым, и он преуспел в этой цели. Он был написан для слабых программистов, используя в качестве заготовки старый язык. Поставляется он в комплекте с простыми инструментами для выполнения простых вещей. Его просто читать и просто использовать. Он крайне многословный, невыразительный и плох для умных программистов.

Но такая критика была и не совсем критикой для создателей языка. Сам Роб Пайк описывал язык почти также, но в отличие от критиков, не говорил о невыразительности как о чем-то плохом:

Ключевой момент здесь, что в гугле работают не исследователи. Они, как правило, молоды, идут работать после учебы, где, возможно, изучали Java, или C/C++, или Python. Они не смогут сразу разобраться в навороченном языке, но в то же время мы хотим, чтобы они создавали хорошее ПО. Именно поэтому язык должен быть прост для понимания и изучения.

Тем не менее, уже в 2012 году многие разработчики увидели перспективы Go в тех областях, для которых его изначально не задумывали. В своем твиттере Дерек Коллисон писал:

* Прогноз: в течение следующих двух лет Go станет доминирующим языком для IaaS, PaaS и оркестрации.

Так и произошло почти в то же время, когда создавали язык, в IT начала стремительно развиваться культура DevOps, в которой Go почти сразу стал стандартом.

19% в DevOps планируют использовать Go в будущем, около 10% уже используют Go19% в DevOps планируют использовать Go в будущем, около 10% уже используют Go

DevOps придумывали как agile для инфраструктурщиков

Долгие годы в цикле разработки ПО царила строгая иерархия программисты писали код, системные администраторы следили, чтобы написанное нормально работало на железе каждый отвечал только за свою область. Когда где-то всплывали баги, начиналась битва профессий. Программисты утверждали, что проблема где-то на серверах и это не их дело; администраторы уверяли, что с серверами все отлично, просто на них положили кривой код.

Рано или поздно ошибку устраняли (или нет), и все начиналось заново.

Но в индустрии все очень быстро менялось, она росла страшными темпами. Сокращалось время доставки фич до пользователей, количество постоянных обновлений увеличивалось, сама неопределенность разработки продуктов становилась более явной некоторые вещи буквально собирали и дорабатывали на ходу регулярными апдейтами.

В таких условиях разобщенность отделов начинала сильно вредить, и даже существующий почти десять лет agile манифест неопределенности и гибкости не особо помогал.

В 2008 году администратор баз данных Патрик Дебуа поехал на конференцию Agile Toronto, где познакомился с другим админом Андрю Клэй Шафером. Оба интересовались аджайлом и тем, как бы получше внедрить его в сисадминское дело. На той же конференции они увидели выступление, где один из спикеров говорил, как в его команде разработчики и админы пытаются работать вместе.

Из всех этих дискуссий Дебуа и Шафер вынесли идею провести отдельную конференцию, посвященную только этим вопросам.

В то время еще не было термина Devops была только идея. Я написал в твиттере, что было бы здорово провести конференцию в Европе и обсудить саму идею. Agile System Administrators так себе название для мероприятия, поэтому мне предложили назвать его DevOpsDays с этого и началось движение Devops.

Через год конференцию провели в Бельгии. Буквально сразу название стало именем нового подхода к работе, который за несколько лет перевернул представление о ролях разработчиков и администраторов в IT.

Суть была такова разработчики участвуют в деплое, администраторы пишут скрипты, все автоматизируется. С этого начался не только сдвиг в философии и отношению к ролям в команде, но и софтверные изменения. Новая практика требовала новых инструментов. Docker, Kubernetes, Terraform и прочие вещи, которые сейчас плотно ассоциируются с работой девопс-инженера появились на этой волне. И почти все они были написаны на Go.


Почему Go и DevOps идеально подошли друг другу

Когда в Google начали разрабатывать Kubernetes у команды уже накопилось огромное наследие инструментов для контейнеризации. Но Кубер начали писать с нуля, поэтому встал вопрос выбора языка. Джо Беда, основной разработчик сервиса, рассказывал, что в Гугле используются многие языки не только свои разработки и они выбирали между С/С++, Java и Python.

Си не взяли, потому что это довольно пугающий язык для многих разработчиков, который оброс колоссально огромной инфраструктурой. Сообществу все труднее и труднее договориться, что, где и как правильно использовать.

Java не подошла, потому что разработчики стремились сделать установку простой на как можно более широком количестве платформ. Python откинули из-за динамической типизации.

А вот Go по словам Беды был и не слишком высокоуровневым, и не слишком низкоуровневым. Список причин, почему команда Kubernetes выбрала его, довольно широк:

  • Все библиотеки есть из коробки почти для всего, что им было нужно.

  • Быстрые инструменты. С ними мы подсели на скорость разработки, пишет Беда.

  • В Go не бывает сложного кода. Никто не пишет на нем фабрики фабрик. Понять любую часть системы, просто пробежавшись по ней взглядом, вполне реально.

  • Анонимные функции.

  • Сборка мусора, о которой не надо задумываться.

  • Строгая типизация.

Но это плюсы для разработки инструмента. Когда обычные девопс-инженеры рассказывают, почему Go стал стандартом в их области, чаще всего называют

Три основные причины

  • Его реально очень просто учить и читать. Многие и разработчики, и девопсы говорят, что достаточно прочитать общую документацию, чтобы идти и использовать код на продакшене без особых проблем.

  • У него самая простая для использования многопоточность. Горутины и Каналы фичи, которые хвалят даже те, кто невзлюбил Go.

  • Он невероятно прост в эксплуатации. И это, пожалуй, главная причина, почему язык так хорош для инфраструктурных инженеров.

По сравнению с Python, Ruby или Node.js, установка единственного исполняемого файла мечта инженеров по эксплуатации. Конечно, это вовсе не такая большая проблема с учетом все более широкого использования Docker, но отдельные исполняемые файлы еще и уменьшают размер контейнеров, пишет Сильвиан Валлез.

Исходный код компилируется в бинарный файл. Из-за этого при деплое приложения не надо заранее устанавливать необходимые зависимости, можно просто переносить и запускать, где угодно.

Что вы сами думаете про Go? Как и почему используете? Заходите к нам в сообщество там мы постоянно разбираем различные проблемы и задачи из сферы Devops, обсуждаем вещи, которые пригодятся и на собеседованиях, и в работе.

Подробнее..

Облачное хранилище компонентов новый этап в развитии Интернет-шлюза ИКС

24.02.2021 16:18:54 | Автор: admin

Начало


Популярность современных UTM-решений, связана в первую очередь с их многофункциональностью. Возможность быстро решить все ИТ-задачи компании, да еще и из одного веб-интерфейса привлекает многих сисадминов.

Наше решение, Интернет Контроль Сервер, также относится к классу UTM-продуктов, объединяя в себе функции защиты сети, управления Интернет-подключениями, контентной фильтрации и многие другие.

Не смотря на очевидные преимущества, у использования подобных решений есть и обратная сторона они зачастую монолитны, что не позволяет реагировать на изменения рынка более гибким образом.

С этой точки зрения более интересным продуктом является шлюз UTM, который может быть построен самим пользователем, исходя из реальных задач компании.

В этом случае, сисадмин собирает свой шлюз из кирпичиков-компонентов, устанавливая только нужные ему модули. Весь инструментарий находится в облаке разработчика, а пользователь скачивает и устанавливает необходимые пакеты. Этот принцип стал основополагающим для наших будущих разработок.

Исторически сложившаяся экосистема FreeBSD нас устраивала и была достаточно хорошо изучена. В качестве наиболее подходящего метода дистрибуции пакетов мы выбрали традиционную утилиту установки пакетов во FreeBSD pkg. В нашем облаке собирается репозиторий, а на клиенте прописывается доступ к нему в традиционном конфиге pkg.

Что мы планировали сделать


Система должна представлять собой конструктор в виде ядра, на которое нанизываются компоненты. Пользователь получает дистрибутив, в который входят только минимально необходимые плагины (router, fierwall и т.д.). Остальное устанавливается по мере необходимости.

Для работы системы нам понадобилось реализовать следующие компоненты:

  • система модифицированное ядро FreeBSD
  • core специальный пакет с настройками продукта, являющийся родительской зависимостью для всех плагинов
  • плагины каждый из них это собранный пакет, который штатным образом устанавливается утилитой pkg

Структура плагинов


Как уже говорилось, плагин это обычный пакет. Он может быть установлен утилитой pkg.
Для того, чтобы поддерживать обратную совместимость, решили, что новая мажорная версия плагина будет отдельным пакетом, не связанным с предыдущей мажорной версией. Например plugin-v1 и plugin-v2. Причина у них могут быть совершенно разные зависимости, возможно даже противоречащие друг другу.

У минорной версии просто меняется номер версии пакета, тут все как обычно.

Работа с плагинами


Для того, чтобы система работала так, как нам нужно, была создана утилита-надстройка над pkg.

Основным инструментом для работы будут команды pkg query и pkg rquery.

Первая собирает информацию по установленным в системе плагинам, вторая обращается к репозиторию.

Для того, чтобы утилита контролировала корректность выполнения команд в системе, выполнение каждой команды проверяется на код возврата. Если получен код возврата 0, значит команда выполнилась, если что-то иное, значит возникла ошибка. Таким образом можно отследить, к примеру, проблемы с сетевым соединением.

Здесь возник интересный нюанс. Если выполнить например поиск всех пакетов по шаблону:



то в случае, если ни один установленный пакет не попадает под условие шаблона, возвращается ошибка 69 без сообщения об ошибке. Разработчики утилиты посчитали, что если поиск ничего не вернул, то это ненормальное поведение. Ну, ОК. Пришлось обрабатывать такой случай специальным образом.

Проблемы обновления


Дальше начинаются проблемы с версионностью при обновлении плагинов.

Во-первых, утилита pkg при выполнении команды pkg upgrade <pkg_name> также обновляет ВСЕ прямые зависимости пакета, такое поведение заложено разработчиками. Но в нашем случае это включает в себя обновление и core, если для него вышла минорная версия, что нежелательно, поскольку core меняет системные параметры, а также требует перезагрузки системы после обновления.

То есть, если у нас в системе установлены 2 пакета pkg-1 и pkg-2, и в зависимостях pkg-1 указан pkg-2, то если мы выполним команду pkg upgrade pkg-1, то обновится также и pkg-2.

Пойдем другим путем.

Построим дерево зависимостей пакета вверх и вниз.
Находим имена всех пакетов, от которых зависит наш пакет:

pkg rquery %rn <pkg_name>

Теперь всех пакетов, которые зависят от нашего пакета:

pkg rquery %dn <pkg_name>

Удалим все зависимые от пакета сущности. Далее начнем удалять сущности, от которых зависит наш пакет вверх по дереву до тех пор, пока не окажемся в core (его удалять не будем конечно). Теперь можно восстановить дерево, установив последние минорные версии всех пакетов в нем.



Например, на рисунке выше мы видим, что пакет ics-plugin-a-v1 зависит от плагина ics-plugin-b-v1. Если нам нужно обновить пакет до версии ics-plugin-v2 то это повлечет и обновление пакета ics-plugin-b-v1, для которого существуют 2 мажорные версии ics-plugin-b-v2 и ics-plugin-b-v3. При этом ни одна из них не поддерживает плагин ics-plugin-c-v1. То есть, при обновлении сначала будет установлен пакет ics-plugin-b-v2 или -v3, затем ics-plugin-a-v1, а ics-plugin-c будет удален и установлен не будет.

Кроме того мажорная версия может быть у core, в этом случае весь состав плагинов должен быть обновлен для соответствия.



Для установки пакета ics-plugin-a, который зависит от ics-core-v2 нужно обновить ics-core, после чего установятся только пакеты мажорных версий, которые зависят от ics-core-v2.

Резервное копирование базы


При работе с репозиторием возможна ситуация, когда во время обновления пропадет связь (возникает системная ошибка код 70 или 3). Кроме того, для того, чтобы корректно удалить плагин, системе необходима действующая база pkg в системе. При выполнении команды pkg update, если нет связи, база сообщает об ошибке и даже локально не выполняет свои функции пока апдейт не выполнится корректно.

Чтобы избежать таких ситуаций, воспользуемся утилитой pkg backup. Перед любой операцией, в процессе которой есть вероятность не получить нужный результат, сохраняем базу:

pkg backup -d <backup_dir>

Если операция завершилась некорректно, возвращаем базу на место:

pkg backup -r <backup_dir>

Ядро


Тут пока все достаточно просто. Если вышло обновление для ядра, то:

  1. скачиваем новый образ ядра в архиве
  2. создаем новый датасет в zfs
  3. монтируем датасет в систему
  4. распаковываем образ
  5. устанавливаем специальный пакет с нужными опциями ядра для нормальной работы
  6. прописываем новый образ как загрузочный
  7. ???

Profit?


Пока еще нет.

Нам нужно восстановить установленные ранее пользователем плагины системы (если они поддерживаются новым ядром конечно). Соответственно, нужно делать отдельный репозиторий плагинов для каждой версии ядра.

Но (как всегда) есть нюанс.
У нас еще не установлено ядро будущей версии, а установить плагин для другой версии мы не можем. Если же мы загрузим систему с нового образа, то не сможем получить доступ к репозиторию (по исторически-техническим причинам маршрутизация это тоже плагин).

Что делать?

Поднимаем сервер с api, который будет отдавать архив с репозиторием плагинов для указанной версии ядра.

Затем наша утилита сгенерирует файл конфига репозитория с указанием пути до папки с распакованным архивом.

Для FreeBSD это будет файл <repo_name>.conf в папке /usr/local/etc/repos или /etc/repos. Здесь стоит обратить внимание, что путь пишется следующим образом: url: file:///path_to_repo (3 слэша!)

Сохраняем данные об установленных плагинах и проверяем их совместимость с будущей версией ядра (если есть несовместимые, сообщим об этом пользователю).

Вот теперь можно перезагружаться.

Последнее


После обновления системы утилите pkg требуется инициализация (bootstrap). Поэтому если выполнить любую команду, возникнет запрос на нее. В нашем случае, утилита-обвязка не поймет, что он нее хотят и посчитает что операция выполнена некорректно.

Для этого мы сделали обработчик ошибки инициализации, к счастью, у нее есть отдельный системный код операции 1. Поэтому если утилита встречает такой код, то просто выполняет

pkg -y

Pkg делает бутстрап, и дальше можно работать в штатном режиме.

Итого


Вот так мы построили наш репозиторий. Пока это прототип, и в будущем он, скорее всего, будет изменяться и усложняться, но проектная база заложена и останется неизменной.

Описанная технология будет применяться в новых разработках Интернет Контроль Сервер, делая его еще более удобным для использования в корпоративных сетях компаний. Скачать и протестировать самую актуальную версию ИКС можно по ссылке.

Триал-период, бесплатная версия на 9 пользователей, демо-онлайн и отзывчивая техподдержка.

Следите за новостями и оставайтесь с нами!
Подробнее..

Категории

Последние комментарии

© 2006-2021, personeltest.ru