Кубернетис что это простыми словами
Зачем нужен Kubernetes и почему он больше, чем PaaS?
В большой production пришёл не только Docker, но и Kubernetes. И если даже с контейнерами далеко не всегда всё достаточно просто, то уж «кормчий» и подавно остаётся за гранью правильного понимания среди многих системных администраторов, DevOps-инженеров, разработчиков. В этой небольшой статье предпринята попытка ответить на один из вечных вопросов (в контексте Kubernetes) с помощью наглядного объяснения идеи и особенностей данного проекта. Возможно, именно этого вам не хватало для того, чтобы начать плотное знакомство с Kubernetes или даже его эксплуатацию?
Соучредитель и архитектор крупного онлайн-сервиса Box (около 1400 сотрудников) Sam Ghods в своём прошлогоднем выступлении на KubeCon указал на типовую ошибку восприятия Kubernetes. Многие рассматривают этот продукт как очередной фреймворк для оркестровки контейнеров. Но если бы всё действительно было так, то зачем его разработчики неустанно напоминают про «корни Kubernetes API, уходящие в архитектуру*, создаваемую более 10 лет в рамках проекта Google Borg».
Google Borg — это менеджер кластеров, предназначенный для параллельного запуска тысяч задач, распределённых по тысячам приложений, запускаемых на многочисленных кластерах. Именно эту архитектуру и унаследовал Kubernetes, перенося кластерные идеи на современную почву контейнеров. Чем же это отличается от многочисленных облачных платформ, существующих сегодня? Начнём с самого понятия платформы.
* Архитектура Kubernetes создана таким образом, что позволяет расширять эту платформу, но разработчиков при этом просят следовать основополагающим принципам.
Kubernetes как платформа
Архитектор Box даёт такой вариант определения: «Платформа предоставляет уровень абстракции, забирающий у вас какую-либо проблему, чтобы вы могли творить поверх неё [не думая о ней]». Примеры: платформа Linux даёт возможность исполнять системные вызовы вне зависимости от аппаратного обеспечения компьютера, а платформа Java — исполнять приложения вне зависимости от операционной системы. Какова же должна быть платформа для запуска приложений, созданных по принципам микросервисной архитектуры?
Ключевые характеристики такой платформы — портируемость и расширяемость. Каждая облачная платформа предлагает свои варианты для достижения этих целей. Например, для автоматического масштабирования у AWS имеются Auto Scaling Groups, у Google Cloud Platform — Autoscaler, у Microsoft Azure — Scale Set, у OpenStack — autoscaling API в Heat. Всё это само по себе неплохо, т.к. потребности выполняются, однако у конечного пользователя начинаются сложности. Чтобы разместить приложение, для каждого сервисного провайдера необходимо поддерживать его механизмы: добавлять поддержку API, учитывать специфику работы используемой реализации и т.п. Вдобавок, всем этим решениям не хватает системы обнаружения сервисов для по-настоящему удобного и автоматизированного развёртывания микросервисов. А если вам нужно быть гибким и иметь возможность размещать приложения в разных окружениях (в публичном облаке, в своём дата-центре, на серверах клиента…)?
В этом заключается первый плюс и суть Kubernetes как платформы, то есть по-настоящему универсальной системы для развёртывания приложений, физическое размещение которых может производиться где и как угодно: на голом железе, в публичных или частных облаках вне зависимости от их разработчиков и специфичных API. Но здорово в Kubernetes не только то, где запускать, но и что: ведь это могут приложения на разных языках и под разные ОС, они могут быть stateless и stateful. Поддерживается принцип «если приложение может запускаться в контейнере, оно должно отлично запускаться в Kubernetes».
Предназначение Kubernetes как платформы — предоставить базовую, абстрактную платформу как услугу (Platform as a Service, PaaS), сохранив гибкость в выборе конкретных компонентов этой PaaS.
Kubernetes и PaaS
О том, что Kubernetes не является традиционной PaaS, рассказывается в документации проекта, где поясняется, что авторы стремятся сохранить возможность пользовательского выбора в местах, где это важно. В частности, поэтому:
Заключение
Что должно быть в стандартной библиотеке C++? Идеалом для программиста является возможность найти каждый интересный, значимый и разумно обобщённый класс, функцию, шаблон и т.п. в библиотеке. Однако вопрос не в том, «что должно быть в какой-то библиотеке», а в том, «что должно быть в стандартной библиотеке». И ответ «Всё!» — первое разумное приближение к ответу на первый вопрос, но не последний. Стандартная библиотека — то, что должен предоставлять каждый автор и делать это так, чтобы каждый программист мог на это положиться [т.е. действительно нуждался в этом — прим. перев.].
Применительно к Kubernetes можно сказать, что эта система — фундамент, та самая «стандартная библиотека» для построения PaaS и других подобных решений.
Что такое Kubernetes?
Kubernetes — это платформа с открытым исходным кодом для управления кластером контейнерных приложений и сервисов, которую часто называют операционной системой для облака. Платформа Kubernetes была разработана инженерами Google Джо Беда (Joe Beda), Бренданом Бернсом (Brendan Burns) и Крейгом Маклакки (Craig McLuckie) в 2014 году, вскоре после этого ее исходный код стал открытым, а сама она превратилась в самостоятельную cloud native экосистему. Сегодня Kubernetes, что на древнегреческом означает «рулевой» или «пилот», управляется фондом Cloud Native Computing Foundation (CNCF), частью проекта Linux Foundation.
Kubernetes стал первым законченным проектом для CNCF и одним из самых быстрорастущих проектов с открытым исходным кодом в истории. К настоящему моменту Kubernetes насчитывает более 2300 участников и широко используется как крупными, так и мелкими компаниями, а также половиной списка Fortune 100.
Основы Kubernetes—Основные термины
Для начала познакомимся с несколькими основными терминами, связанными с Kubernetes. Более подробный список представлен на странице глоссария стандартных терминов по Kubernetes. Можно также воспользоваться Памяткой по Kubernetes, содержащей список популярных флагов и команд kubectl.
Кластер
Набор машин, по отдельности называемых узлами, которые используются для запуска контейнерных приложений, управляемых Kubernetes.
Виртуальная или физическая машина. Кластер состоит из главного узла и нескольких рабочих узлов.
Облачный контейнер
Образ, содержащий программное обеспечение и его зависимости.
Модуль
Один контейнер или набор контейнеров, работающих в кластере Kubernetes.
Развертывание
Объект, управляющий реплицированными приложениями, которые представлены модулями. Модули развертываются на узлах кластера.
Набор реплик
Обеспечивает одновременное выполнение определенного количества реплик модулей.
Сервисы
Описывает процесс получения доступа к приложениям, представленным набором модулей. Сервисы обычно описывают порты и балансировщики нагрузки и могут использоваться для управления внутренним и внешним доступом к кластеру.
Что такое KubeCon?
KubeCon — это ежегодная конференция разработчиков и пользователей Kubernetes. Со времени первой конференции KubeCon, прошедшей в 2015 году и собравшей 500 участников, KubeCon стала важным событием для сообщества разработчиков облачных технологий. В 2019 году команда KubeCon в Сан-Диего, штат Калифорния, собрала 12 000 разработчиков и инженеров по обеспечению надежности сайтов для проведения мероприятия, посвященного созданию экосистемы с открытым исходным кодом на базе платформы облачной оркестрации Kubernetes.
Что такое контейнеры Kubernetes?
Поскольку разработчики все чаще развертывают программное обеспечение самых разных вычислительных сред с разными облаками, тестовыми средами, ноутбуками, устройствами, операционными системами и платформами, проблема обеспечения надежной работы программного обеспечения приобретает первостепенное значение. Им на помощь приходят контейнеры. Они связывают приложение со всей его средой выполнения. В этом смысле контейнеры представляют собой форму виртуализации, поскольку они создают «пузырь», в котором приложение может работать, включая правильные библиотеки, зависимости и операционные системы. Но контейнеры меньше виртуальных машин, потому что они содержат только ресурсы, необходимые приложению, и не более того.
Сравнение Kubernetes и Docker
Из каких компонентов состоит Kubernetes?
Основными компонентами Kubernetes являются кластеры, узлы и плоскость управления. Кластеры содержат узлы. Каждый узел включает в себя как минимум одну рабочую машину. На узлах размещаются модули, содержащие элементы развернутого приложения. Плоскость управления управляет узлами и модулями в кластере, часто на большом количестве компьютеров, для обеспечения высокой доступности.
Плоскость управления включает следующие компоненты.
Компоненты узла включают следующее.
Какие преимущества дает Kubernetes?
С контейнерами Вы можете быть уверены, что Ваши приложения укомплектованы всем, что им нужно для работы. Но по мере добавления контейнеров, которые часто содержат микросервисы, Вы можете автоматически управлять ими и распространять их с помощью Kubernetes.
Возможности, которые Kubernetes дает компаниям:
Автоматическое масштабирование. | Увеличение или уменьшение развертывания в зависимости от потребности. |
Поиск сервисов | Поиск контейнерных сервисов по DNS или IP-адресу. |
Балансировка нагрузки | Стабилизация развертывания за счет распределения сетевого трафика. |
Управление хранилищем | Выбор локального или облачного хранилища. |
Контроль версий | Выберите типы контейнеров, которые Вы хотите запустить, и те, которые нужно заменить, используя новый образ или ресурсы контейнера. |
Обеспечение безопасности | Безопасное обновление паролей, токенов OAuth и ключей SSH, связанных с определенными образами контейнеров. |
Какие проблемы возникают при использовании Kubernetes?
Несмотря на то что платформа Kubernetes легко компонуется и может поддерживать приложения любого типа, в ней сложно разобраться и ее непросто использовать. По словам некоторых членов CNCF, Kubernetes не всегда является правильным решением для конкретной нагрузки. Вот почему экосистема Kubernetes содержит ряд связанных облачных инструментов, которые компании создали для решения конкретных проблем с нагрузками.
Kubernetes развертывает контейнеры, а не исходный код и не создает приложения. Для ведения журналов, промежуточного программного обеспечения, мониторинга, настройки, CI/CD и многих других производственных операций требуются дополнительные инструменты. Тем не менее платформа Kubernetes является расширяемой и доказала свою эффективность в самых разных сценариях использования — от реактивных самолетов до машинного обучения. Фактически поставщики облачных решений, включая Oracle, Google, Amazon Web Services и другие, используют собственную расширяемость Kubernetes для создания управляемых Kubernetes, которые представляют собой сервисы для снижения сложности и повышения продуктивности разработчиков.
Что такое управляемый Kubernetes?
Oracle Cloud Infrastructure Container Engine for Kubernetes — это удобный для разработчиков управляемый сервис, который можно использовать для развертывания контейнерных приложений в облаке. Используйте Container Engine for Kubernetes, если Ваша команда разработчиков хочет надежно создавать, развертывать cloud native приложения и управлять ими. Вы указываете вычислительные ресурсы, которые требуются Вашим приложениям, а Oracle Container Engine for Kubernetes предоставляет их в существующей арендованной облачной инфраструктуре Oracle.
Несмотря на то что Вам необязательно использовать управляемый сервис Kubernetes, решение Oracle Cloud Infrastructure Container Engine for Kubernetes — это простой способ запустить высокодоступные кластеры с контролем, безопасностью и предсказуемой производительностью Oracle Cloud Infrastructure. Container Engine for Kubernetes поддерживает как системы без виртуализации, так и виртуальные машины как узлы, и сертифицирован соответствующим образом организацией CNCF. Вы также получаете все обновления Kubernetes, и совместимость с экосистемой CNCF обеспечивается без каких-либо дополнительных действий с Вашей стороны.
Cloud Native и Kubernetes меняют подход AgroScout к поддержке разработчиков.
Контейнеризация понятным языком: от самых азов до тонкостей работы с Kubernetes
Чем контейнеры отличаются от виртуальных машин, почему Docker настолько популярен, что такое Kubernetes и в чём его преимущества и недостатки. В интервью АйТиБороде СТО «Слёрма» Марсель Ибраев и старший инженер Southbridge Николай Месропян рассказали о контейнеризации понятным языком. Мы перевели интервью в текст для тех, кому лень смотреть.
Мне не лень смотреть, мне лень читать
Разница между контейнеризацией и виртуализацией
Что такое виртуализация?
Виртуализация появилась как средство уплотнения окружений на одном и том же железе. Сначала программный продукт выполнялся на железном сервере. Потом, чтобы иметь возможность поселять в одно и то же железо больше клиентов, чтобы максимально полно утилизировать производительные мощности, придумали виртуализацию. Теперь на одном и том же железе можно держать несколько окружений. В зависимости от среды, опять же. Есть полностью проприетарные решения, такие как vmware vsphere, есть опенсорсные решения, как QEMU KVM, на основе которого Red Hat делает свой коммерческий гипервизор — Red Hat Virtualization. На платформе Windows есть Hyper-V.
Благодаря виртуализации мы получаем возможность более полно утилизировать ресурсы железа. Но при этом речь идёт о полной изоляции: в виртуальной машине полностью изолированное ядро, все библиотеки, строго ограниченные ресурсы по процессору и памяти.
Ядра разделяются физически или можно виртуально разделить там одно физическое ядро на несколько при виртуализации?
Если у вас на хосте один процессор, то в виртуальной машине вы два иметь не можете. Ресурсы хоста можно делить произвольным образом между всеми виртуальными машинами. Либо статично, выделяя под конкретную виртуальную машину один, два, три процессора. Либо динамически, чтобы использовались просто свободные ресурсы в нужное время.
Что такое контейнеры и контейнеризация, и чем отличаются?
Детали зависят от операционной системы, на которой выполняется контейнер, но вообще контейнер делит с хостом ядро, пространство памяти ядра, и своё у контейнера только пользовательское окружение. Первая широко распространенная технология контейнеризации в Linux — это OpenVZ, которая потом превратилась в коммерческий продукт Virtuozzo. Мы много работали и работаем с OpenVZ. У нас клиентские окружения жили в контейнерах OpenVZ, пока мы не перешли на более современные технологии.
То есть контейнер от виртуальной машины отличается только тем, что в контейнере общее адресное пространство?
Нет. Виртуальная машина изолируется полностью средствами процессора (технологии Intel, AMD, VMX).
Контейнер работает на ядре хостовой операционной системы и использует для изоляции возможности не железа, а операционной системы, так называемое пространство имён. Если мы говорим о Docker, как о наиболее распространённой сейчас технологии виртуализации, используются так называемые cgroups в ядре Linux.
Контейнер – это продолжение виртуализации? То есть это технология, которая является преемником виртуализации?
Нет. Они ни в коем случае не конкурируют. Они занимают совершенно разные ниши в использовании.
Тогда почему их постоянно сравнивают? И постоянно есть вопрос, что лучше виртуализация или контейнеризация?
С моей точки зрения сравнить контейнеризацию и виртуализацию нельзя. Это сравнение теплого с мягким.
Где лучше использовать виртуализацию, а где контейнеризацию? Для как разработчика нет разницы: и то, и то используется для развертывания приложений. Два-три приложения ты фигачишь контейнером. Ты можешь виртуальных машин столько создать, и в каждой из них запустить своё приложение. В чем разница для обычных девелоперов?
Для тебя виртуальная машина — это обычная изолированная операционная система, целиком: своё ядро, свой init, systemd и так далее. Чем она отличается от контейнера с точки зрения потребления ресурсов? Тем, что она полностью занимает все ресурсы, под неё выделенные. То есть, есть механизмы, когда можно динамически, то есть в зависимости от потребления процессами внутри виртуальной машины, освобождать память на хосте или занимать её. Но это всё полумеры.
Виртуальная машина — это полностью готовая операционная система. Для человека, который с ней работает изнутри, она вообще ничем не отличается от железного компьютера. С помощью специальных инструментов можно выяснить, мы на железе или на виртуальном окружении, но для любого работающего на ней ПО разницы нет никакой.
Если мы говорим о Docker (а в рамках разговора мы не сможем обсудить все варианты контейнеризации), то он рассчитан на то, что в одном контейнере работает одно приложение.
Возвращаясь к твоему первому вопросу, разница вот в чём. Допустим, если у тебя на хосте Linux или VMware, то виртуальная машина у тебя может быть Windows. Если у тебя в контейнере Linux, то у тебя и снаружи Linux. Потому что мы в первую очередь пользуемся для изоляции не средствами железа, не средствами гипервизора, а средствами операционной системы — cgroups и namespace.
Почему контейнеры разворачиваются быстрее? Потому что они маленькие, содержат в себе там одно приложение? Почему быстрее развернуть контейнер, нежели зафигачить, законфигурировать?
Виртуалка сама по себе большая, так как содержит целую операционную систему. Если нам нужно развернуть виртуальную машину, то нужно нести с собой и ядро, и всё пользовательское окружение, и какой-то запас места (потому что динамически оно с хостом шариться в общем случае не может). Я не видел линуксовую виртуальную машину весом меньше 10 Гб, и это без данных. Потом к ней еще нужно прицепить диски для данных, в зависимости от того, что будет внутри.
Если говорить о контейнерах, есть разные дистрибутивы, в том числе специально созданные для контейнеризации, тот же Alpine Linux, который в голом виде весит 20 или 50 Мб в зависимости от версии. То есть ничего не весит, собственно говоря.
Виртуалка тянет полностью всю операционку, а когда Docker создаешь, ты тянешь только какие-то небольшие пакеты?
Нет. Чтобы создать Docker-контейнер ты должен собрать образ. Ты берёшь какой-то базовый образ, тот же Alpine, CentOS или Ubuntu. В него с помощью специальных команд зашиваешь свое приложение и выгружаешь уже туда, где оно будет работать.
То есть все равно ты в контейнере используешь полноценную операционку? Вот тот же образ Alpine Linux.
Она может быть сильно порезаной по сравнению с операционной системой, которую ты засовываешь в виртуальную машину.
Но потенциально ты можешь и полноценный Linux запустить в контейнере?
Потенциально да, можешь.
Но смысла в этом, наверное, нет.
В этом совершенно нет никакого смысла, потому что хорошей практикой при использовании Docker считается один контейнер — одно приложение.
Один контейнер? А это не слишком жирно использовать для одного приложения, ну пусть и урезанную, но операционную систему?
Когда нужна изоляция — это не слишком жирно.
Понял. Есть ли какие-то еще инструменты, которые позволяют сделать что-то похожее на контейнеризацию, но не контейнеризация?
Контейнеризация сама по себе использует механизмы изоляции, которые предоставляет ядро. Если делать что-то другое, то это тоже получится контейнеризация.
Почему Docker захватил весь рынок? Вот ты говорил, что было решение какое-то изначально в Linux?
Нет. Оно занимало и занимает совершенно другую нишу. Docker захватил весь рынок в первую очередь потому, что он первым начал использовать технологии namespace и cgroups для, так сказать, народа. Понизил порог вхождения в эти технологии до того, чтобы можно было выйти на широкий рынок, на широкого пользователя.
Docker предоставляет общий интерфейс через фактически одну команду к массе возможностей. То есть из единого командного интерфейса мы управляем всеми нюансами создания контейнеров, их запуска, монтирования томов в них, запуска процессов у них — всё что угодно.
А как тут обстоит дело с дебагом твоего кода, логированием и всем остальным? Со стороны кажется, что это сложновато: нужно залезть внутрь какого-то контейнера, который представляет из себя урезанную операционку…
Когда работаешь с контейнерами, в принципе не обязательно думать, что это операционка, не операционка. Там начинается другой мир. Да, к нему надо привыкнуть, но с дебагом, логированием проблем нет никаких, потому что хорошим тоном считается писать все логи в stdout/stderr контейнера, а не в файлики внутри него.
Docker-контейнер знаменит тем, что он одноразовый. Он запустился, а после того, как ты контейнер удаляешь, — если ты специально никаких мер не предпринимал, чтобы сохранить в нём данные, — у тебя всё удаляется. Поэтому все логи обычно пишут в stdout/stderr, средствами Docker или внешних утилит экспортируют их в ElasticSearch, ClickHouse или какие-то другие системы хранения логов и централизованно уже с ними работают. В первую очередь потому, что контейнеров много. Контейнеров в сетапах могут быть десятки, сотни, тысячи и десятки тысяч.
Как правило, они весьма короткоживущие. Если мы сетапим железные сервер или виртуалку, они могут работать годами, то контейнер живёт до обновления образа максимум. Поэтому контейнеров много, они сравнительно короткоживущие, эфемерные, непостоянные. И поэтому всё, что нужно хранить вне них, нужно хранить специальными методами.
Что насчет контейнеризации в Windows? Насколько я помню, там если не всё очень плохо, то не всё так просто, как на Linux.
Там, действительно, очень сложно. Я ни в коем случае не Windows-админ, знаком поверхностно. Но насколько я знаю, нативная контейнеризация в Windows есть. Есть средства изоляции и по ресурсам, и по пространствам имен, сетевые пространства имен, для памяти, под файлы и так далее. То есть можно Windows запустить как контейнер Windows. Это Windows Server Containerization, если я не ошибаюсь (Windows-админы, не обессудьте).
Но если мы говорим о том, чтобы запускать Docker в Windows, то здесь начинаются пляски. Docker — это технология Linux, потому что использует специфические средства для изоляции, для создания контейнеров.
Когда контейнер выполняется, он не представляет собой некий образ. Когда выполняется виртуальная машина — это образ, внутри которого своя файловая система, свои разделы, где всё это нарезано и всё это варится. Когда выполняется контейнер, для операционной системы это просто набор ограничений. Когда мы смотрим на процесс виртуальной машины с хоста, мы видим один процесс. В винде это Microsoft Hyper-V, в Linux это QEMU KVM, в vSphere это тоже один процесс. Когда мы смотрим с хоста на контейнер, то видим дерево процессов.
Но почему мы образы передаем друг другу? Я приложение запаковываю в Docker, и мы девелоперы передаём друг другу образы.
Образ — это то, из чего контейнер запускается. А с точки зрения хоста – это дерево процессов, которые ограничены через встроенные средства ограничения, то есть через namespace и cgroups. Это я к тому, что Docker по своей сути линуксовый.
А почему нельзя было сделать универсальное решение, чтобы оно и для Linux, и для винды работала? Там нет общих API или в Linux есть что-то, чего нет…
Архитектура разная, да?
Да, API Windows и API Linux — это совершенно разные вещи. По той же причине нет нативного Docker для macOS. Потому что используются средства изоляции линуксового ядра.
Я думал, что ядра macOS и Linux очень похожи.
Нет. macOS больше UNIX-like, нежели Linux. Потому что, как известно GNU — is not UNIX (рекурсивный акроним). А macOS внутри более, так сказать, близка к юниксам. И там нет таких механизмов, как в Linux. Они развиваются независимо.
Docker и для Windows, и для macOS — это чужеродное тело, которое запускается в линуксовой виртуалке.
Получается, чтобы запустить контейнер, нужно запустить еще и виртуалку?
Мы запускаем линуксовую виртуалку, а уже в ней мы уже запускаем эти контейнеры. Docker Desktop скрывает от пользователя все сложные процессы, но внутри все равно остаются всякие. Ну не то, чтобы это очень неэффективно. Если вам нужно разрабатывать что-то под Docker, но у вас только Windows или только macOS, то это позволяет работать, да. Но в продакшене с нагрузками так ничего толком не запустишь.
Я понял, что ты в основном с Linux работаешь, но вдруг ты слышал про WSL (Windows Subsystem for Linux)?
Разумеется, я на OpenNET читаю об этом всём и удивляюсь.
А может ли эта штука запустить контейнеры нативно? Я просто не знаю, она тоже под виртуалкой?
Насколько я понимаю, WSL — это Wine наоборот. То есть трансляция вызовов API в нативные для винды. Если у нас Wine — это трансляция вызовов виндового API для ядра Linux, то WSL — это наоборот. И поэтому средств изоляции там ядерных линуксовых нет. Поэтому увы, увы.
Про оркестрацию
Скажем, у нас микросервисная архитектура, и не одно приложение, а много всего: 10, 20, 40, 100 микросервисов. Руками их конфигурировать совсем не прикольно. Как с этим разбираются?
Да, это вполне типовая ситуация. Сейчас особенно, потому что стильно, модно, молодежно. Постепенно приложение обрастает логикой, микросервисов становится больше и больше. И одного Docker, и даже Docker Compose уже становится мало. Ну и плюс ко всему, наверное, еще хочется какую-то отказоустойчивость, чтобы это на нескольких серверах работало. Возможно, какой-то Service Discovery и прочее.
Постепенно компания утыкается в потолок, когда им нужно свежее и очень продуктивное решение. И здесь, конечно, нужен оркестратор контейнеров. То есть такой тип программного обеспечения, который управляет всеми микросервисами, смотрит за ними, чинит, переносит с машины на машину, строит сеть и в целом является такой входной точкой во всю инфраструктуру проекта.
Марсель Ибраев, СТО «Слёрм»
Docker Compose не позволяет нам ничего делать? Ведь это тоже средство управления несколькими контейнерами.
Docker Compose, как минимум, не позволяет запускать проект на нескольких серверах. То есть это все равно все-таки история про одну ноду. Поэтому, да.
ОК. Что придумано? Что есть сейчас, чтобы это все делать?
Сразу нужно сказать, что инфраструктурный стандарт — это всё-таки Kubernetes. Штука, которая в свое время была произведена в Google. И Google по зову сердца, по доброте своей решил поделиться с миром.
Есть ещё ряд решений, например, Docker Swarm, Mesos, OpenShift и другие, но всё-таки наиболее популярен и пользуется спросом Kubernetes. Компании, которые задумываются о том, что им нужен оркестратор, в первую очередь смотрят на Kubernetes.
Где обычно применяются оркестраторы, в частности Kubernetes?
Да, это очень важный вопрос. Дело в том, что Kubernetes все проблемы не решает. Компания работает, работает, у них всё плохо (как правило, плохо с процессами) они такие: «Блин, Kubernetes классная штука. Давайте её себе поставим — у нас всё сразу станет хорошо!» Но становится сильно хуже.
К Kubernetes нужно подходить уже осознанно. Работу с Kubernetes стоит рассматривать, когда у вас действительно большое количество микросервисов, когда есть определённые требования к уровню доступности вашего сервиса, когда над одной частью приложения трудятся несколько команд, когда нужна инфраструктура для автоматизации деплоя и тестов. На этом этапе да, действительно стоит задуматься о Kubernetes.
Если вы небольшая компания или если у вас монолит, и вы такие: «Сейчас мы его в куб засунем и все станет хорошо!» Нет, не станет.
Kubernetes работает только с контейнерами Docker и с их оркестрацией?
Kubernetes работает с контейнерами, но не только с Docker. У Kubernetes есть такая штука, которая называется Container Runtime Interface. В принципе, все системы контейнеризации, которые сейчас есть и которые поддерживают Container Runtime Interface, могут работать с Kubernetes. Например, rkt.
Сейчас возникло движение энтузиастов, которые выкорчевывают Docker из Kubernetes и используют что-то другое. Потому что Docker тоже не без проблем. Главная проблема Docker — это его демон, который имеет свойство зависать, особенно при большой нагрузке. Но зачем демон, если у нас уже есть Kubernetes, есть достаточно зрелая инфраструктура и нам надо просто какое-то место для запуска контейнеров.
Дополнительный демон по сути не нужен. В эту сторону движение сейчас активно идёт, но, я думаю, дойдёт не быстро. Устоявшееся мнение, что контейнеры равно Docker, будет держаться долго.
А что может быть использовано вместо Docker более оптимальным путем?
Оптимально пока сложно сказать, потому что у конкурентов Docker есть свои минусы. К примеру, containerd не имеет нормального средства управления им. К слову, с версии 1.11, кажется, под капотом Docker containerd и работает. По сути, сейчас Docker выполняет роль обёртки над containerd, а там containerd, а внутри ещё runC, если уж совсем углубляться.
Кто-то говорит про Podman: делайте просто алиас Podman — Docker, и можно сразу работать. Но тоже есть свои нюансы, поэтому мы в том числе пока работаем с Docker.
Расскажи подробнее, как вообще Kubernetes работает? Что у него происходит под капотом? Для начала уточним, Kubernetes — это сервис или это какое-то ПО, которое можно ставить на сервера, или это и то и то?
Ну это ПО, да. И при этом ПО, которое сейчас очень активно развивается и предоставляется облачными провайдерами как сервис. При этом ничто не мешает его поставить на железные серверы.
Всегда нужно держать в голове, что Kubernetes — это в первую очередь оркестратор контейнеров. Когда вы это понимаете, то вы понимаете, для чего он нужен.
Kubernetes состоит из нескольких компонентов, которые выполняют каждый свою роль (подробно о них ещё поговорим). Из этого вытекает две особенности:
Теперь по поводу самих компонентов. Основной компонент — это API-сервер. Это просто апишка, REST API (разработчики понимают, о чём речь): управление с помощью http-запросов, версионирование кстати тоже. Очень важно, что там есть версия API, при обновлении мы можем на эти версии API завязываться и за счёт этого обновляться менее болезненно. Есть API, с которым работают все: и клиент (мы, как оператор кластера), и компоненты остальные в том числе.
API-сервер работает с хранилищем, которое представляет из себя просто etcd. Etcd — это key-value хранилище, то есть «ключ-значение». Вот и API-сервер — это единственный компонент, который с этим хранилищем взаимодействует.
Это какая-то разработка команды kubernetes?
Нет, это отдельная штука, очень древняя.
А почему её у Redis нет, например?
У Redis есть проблемы с многопоточностью, есть проблемы с кластеризацией (хотя они ее постепенно решают). А etcd штука древняя, все детские болезни там уже вылечены, и она достаточно такая отказоустойчивая.
Кстати, это хороший показатель, что если разработчики Kubernetes уже начиная с первых версий используют etcd, то, наверное, у себя его тоже можно использовать как key-value в кластер-режиме.
API-сервер единственный, кто с etcd работает, он записывает, считывает информацию. А в etcd у нас хранится всё. Там наши настройки кластера, манифесты — всё, что мы делаем.
Мы как клиент хотим что-то создать, запустить приложение, и мы эту информацию передаем в API-сервер. Мы непосредственно это не делаем, конечно, там есть такая утилита, которая называется kubectl. С её помощью мы управляем всем кластером, делаем все операции, в том числе и запускаем приложения. Передаем yaml-манифест, где у нас в декларативном формате описано, как должно выглядеть приложение в кластере. Вот мы это передаем. Оно сохраняется в etcd и следующие компоненты постоянно смотрят в API-сервер.
Если немного углубиться, там есть подписка на событие и они по сути watch’ат. То есть никакого DDoS’а самого себя там нет. Следующий компонент, который берёт эту историю в работу — это kube-controller-manager. По сути, мозг кластера Kubernetes. В него вшиты множество контроллеров: node-controller, endpoint-controller. Практически у всех абстракций, которые есть в Kubernetes, есть контроллер, и он вшит в этот бинарь. Эти контроллеры занимаются просто контролем вот этой абстракции: смотрят, есть ли новые, нужно ли что-то удалить и так далее.
Давай на примере. Если продолжать говорить о приложении, то контроллер, который отвечает за какое-то конкретное приложение, точнее за его манифест, за его абстракцию — он видит, что мы что-то хотим создать, запустить. И он выполняет соответствующую работу, а именно дописывает манифест в etcd, обновляет информацию. Тут, конечно, без некоторого углубления нормально не объяснишь. Но есть такая абстракция, которая называется ReplicaSet. Она позволяет запускать приложение в нескольких инстансах. Через нее мы можем увеличивать, уменьшать количество реплик. И все здорово.
Это балансировка нагрузки?
Это просто контроль за количеством инстансов одного и того же приложения.
А зачем?
Чтобы иметь возможность в случае чего скейлить свое приложение или скейлить обратно. То есть хотим в три инстанса реплики — просто пишем три — у нас три инстанса.
Ну это очень похоже на балансировку нагрузок.
Балансировкой уже занимается другая абстракция, которая уже трафик распределяет на вот эти три инстанса.
То есть они в принципе могут в паре работать?
Да. Они в паре и работают.
ReplicaSet не только создаёт реплики, она ещё и следит, чтобы их действительно было три. Причем не больше, не меньше.
Инстансы, которые запускает ReplicaSet, называются подами. В подах и работает наше приложение (про поды мы ещё поговорим).
И вот как раз, когда мы создаем, например, ReplicaSet, у нас есть такой ReplicaSet controller в этом контроллер-менеджере, который описание подов для ReplicaSet генерирует, и туда же, грубо говоря, в etcd через API-сервер скидывает.
Потом подключается следующий компонент. После того, как мы поняли, какое приложение нам нужно из скольких инстансов запускать, оно вот в etcd хранится этот манифест. Далее у нас идет такой компонент, который называется scheduler. Его роль достаточно проста. Он решает, на каких серверах это приложение надо запускать. Но делает это не просто так, у него есть свои алгоритмы принятия решения.
Ну в частности, он смотрит на ресурсы, то есть сколько ресурсов на ноде, если мы для этого приложения запрашиваем 1 ГБ ОЗУ, а на ноде только 512 свободны, он туда не отправляет.
Под приложением ты понимаешь Docker-контейнер с приложением?
Контейнер с приложением каким-то.
Технологии scheduler’а несколько сложнее, если будет интересно, то можем туда углубиться. В целом, у него есть некоторый ряд алгоритмов, он выставляет очки каждой ноде и условно та нода, которая больше очков набрала, туда приложение и уходит на запуск.
Это сказывается на стабильности работы системы в целом? Правильно я понимаю, если у нас есть какой-то нестабильный сервак, который может там валиться очень часто, то у него будет меньше очков.
На стабильность он не смотрит. Он смотрит в первую очередь на ресурсы. Какой смысл отправлять приложение на запуск туда, где их недостаточно. Смотрит ещё на priority class — это такая штука, с помощью которой мы можем задать приоритет.
Например, в кластере два окружения: продакшн и стейджинг. Конечно, продакшн более важен. И для них мы priority class выставляем высокий. Для стейджинга мы можем поставить поменьше. Когда происходит авария, Kubernetes понимает, что часть серверов отвалилась (за это будет отвечать Node Controller, который контролирует жизнь нод), он принимает решение, что надо те поды, которые там были, запустить в живых серверах. Scheduler будет запускать в первую очередь поды продакшена.
Интересно, что если поды продакшена не лезут, то поды стейджинга будут убиваться и на место их будут запускаться поды продакшена.
А если не хватит под продакшн места?
Если не хватит, ну сорян. Поды будут висеть в pending, то есть ждать, когда появятся ресурсы. И scheduler назначает… Если на такой низкий уровень опуститься, то в манифесте пода есть специальное поле, которое называется nodeName — имя ноды. И вот пока scheduler не принял решение — оно пустое. Scheduler говорит, что вот этот под, вот это приложение нужно запускать там на Node №2, и он эту информацию передает, API-сервер это записывает в etcd и в это поле вносит это имя. А далее в работу вступает последний компонент всей этой схемы, который называется kubelet.
Kubelet — это компонент своего рода «node agent», то есть агент, который запущен на всех серверах кластера. Он тоже постоянно в API-сервер смотрит. И он видит, что появился под, то есть приложение, у которого в поле «имя сервера» написано его имя, там, где он работает. Он такой: «Ага! Значит его нужно у себя запустить!» Он видит, что у него запущено, и что от него хотят. Он передает Docker API, из манифеста считывает, что там конкретно нужно запустить, и говорит Docker, какой контейнер нужно запустить.
Kubelet, получается, замена Docker демона?
Вот в том то и дело, что не замена, к сожалению. Поэтому вот эти альтернативы и изобретаются, поэтому туда люди идут, потому что Docker демон висит. Но по сути да, он общается с Docker демоном по API, но без него вполне можно было обойтись. Причем он не просто их запускает, он постоянно смотрит за статусом, и статус этот передаёт в API-сервер.
Хелс-чек такой?
В том числе хелс-чек тоже делает Kubelet. И мы постоянно видим, какой статус у наших приложений в реальном времени. Вот то, что там сейчас пулинг образа идёт, что там сейчас она запускается, вот он на раннинг — все хорошо, все запустилось. И вот только на этом этапе у нас физический запуск произошёл. То есть всё вот это — это подготовка.
Ноды — это всегда сервер или это может быть кластер серверов?
Ноды — это место, где запущен Kubelet.
Это может быть виртуалка, как я понимаю?
Да, может быть виртуалка.
Ты сказал, что в результате этих действий мы получаем физически развёрнутое приложение. Kubelet посылает какие-то свои статусы, либо он просто stdout контейнера фигачит? К чему этот вопрос. Потому что, если у тебя приложение в stdout выдает логи, какой-то дебаг kubernetes как-то умеет это в одно место собирать и предоставлять в удобочитаемом виде, или это не его обязанность вообще?
В твоем вопросе, два вопроса скрыты. Статус самого контейнера (жив или не жив) — берёт из Docker. Функционал приложения (работает ли оно) — вот эти дебаг, логи, какие-то хелс-чеки — это все тоже делает Kubelet, но для этого надо несколько строчек в манифест добавить и сказать, как именно проверять.
На данный момент поддерживается три возможности проверять приложение:
Есть три типа проверки контейнеров: это liveness, readiness и startup пробы.
Liveness проба — это контроль за жизнью приложения. Постоянно Kubelet смотрит, ходит и смотрит. Там гибкие настройки, можно написать, как часто ходить, как проверять и так далее.
Readiness проба — проверяет, а готово ли приложение принимать трафик. Потому что разные истории могут быть, это могут быть разные инпоинты у приложения. Мы проверяем, работает ли приложение, готово ли оно принимать трафик.
Startup проба – это больше для легаси таких историй, которые очень долго поднимаются, молотятся в самом начале. То есть очень долго инициализируются. И startup проба проверяет, запустилось ли вообще приложение.
На каком размере архитектуры может работать Kubernetes? Может ли он контролировать сразу миллион инстансов?
Насколько я помню из документации, это 5000+, что ли, нод. На одной ноде по умолчанию можно запустить 110 подов, 110 экземпляров приложения.
Под — это экземпляр одного и того же приложения? Или могут быть два разных контейнера на одном серваке и это будет два разных пода?
Под — это абстракция, в которой запускается приложение. Тут важно понять, что это не какая-то физическая оболочка, не какой-то процесс ещё один, это скорее именно абстракция, с которой работает Kubernetes.
Kubernetes не умеет работать с контейнерами. Мы не можем сказать: «заскейль нам вот это приложение в трёх контейнерах». Мы можем только сказать: «заскейль нам в трех подах». В поде может быть как один контейнер, так и несколько. То есть мы можем туда запихнуть, например, nginx и php-fpm в связке, и они будут скейлится по два контейнера в связке.
Но тут надо понимать, что хорошая практика — засовывать в контейнер неделимые части приложения. Всё-таки, если 2-3 контейнера надо засовывать, то может, стоит ещё поиграться с логикой приложения. Обычно один контейнер засовывают и там есть еще второй, который сам запускается, это pause контейнер, который держит сетевой namespace, чтобы все контейнеры в поде были в одном namespace, и чтобы всё хорошо работало.
Это первая часть беседы. Во второй будет про хранение данных в Kubernetes и про Ansible. Не пропустите!