Kubernetes (часто сокращают до k8s) — открытая система оркестрации контейнеров, представленная компанией Google в 2014 году. Kubernetes реализует идею, ранее использованную во внутренней системе Google под названием Borg [PDF] . Если вкратце, идея состоят в том, что ваш деплоймент строится на базе контейнеров (например, Docker ), а также описании того, сколько этих контейнеров нужно и какие ресурсы они используют. Kubernetes на базе этого описания и доступных физических машин разворачивает контейнеры и делает все возможное для поддержания требуемой конфигурации. В том числе, он перезапускает упавшие контейнеры, перемещает их для выделения ресурсов, необходимых новым контейнерам, и так далее.
Зачем это нужно?
Другими словами, используется декларативный подход — мы описываем, что требуется достичь, а не как . Из преимуществ данного подхода можно отметить следующие. Система сама себя восстанавливает в случае сбоев. У вас не болит голова о том, на какой физической машине запущен тот или иной контейнер, и куда его перенести, чтобы запустить новый тяжелый сервис. Система становится повторяемой. Если у вас все развернулось и работает в тестовом окружении, вы можете с хорошей долей уверенности сказать, что оно развернется в точно такую же систему и на продакшене. Наконец, система становится версионируемой. Если что-то пошло не так, вы можете достать из Git ‘а старую конфигурацию и развернуть все в точности, как было раньше.
Стоит однако понимать, что кубер является просто инструментом, а не серебряной пулей. В частности, такие проблемы, как миграции схем баз данных или обеспечение обратной совместимости API , остаются на вас. Не следует сломя голову внедрять в проекте кубер, просто потому что сейчас так модно. Определитесь, какую конкретную проблему вы хотели бы решить, и является ли она настолько приоритетной, что решать ее нужно именно сейчас. Затем поднимите где-нибудь на стенде кубер, или воспользуйтесь услугами одной из компаний, предоставляющих его в качестве сервиса . Посмотрите, решает ли кубер вашу проблему, и не создает ли при этом парочку новых. В общем, совсем не факт, что в каждой IT-компании обязательно нужно использовать Kubernetes.
Цель этой заметки как раз заключается в том, чтобы помочь вам составить собственное мнение о кубере, и понять, нужен ли он вам.
Подготовка к эксперименту
Самый простой способ познакомиться с Kubernetes — это установить Docker Desktop . На момент написания этих строк Docker Desktop был доступен в виде пакетов только для Windows и MacOS. Как альтернативный вариант, вы можете зарегистрироваться в Digital Ocean по моей реферальной ссылке , чтобы воспользоваться Kubernetes as a Service. Ссылка дает некоторую сумму денег на счету, которой за глаза хватит, чтобы наиграться с кубером.
Также понадобится установить утилиту kubectl. Ее установка в разных системах описана здесь . Например, в MacOS достаточно сказать:
Если вы решили воспользоваться Docker Desktop, включите Kubnernetes в меню Preferences… → Kubernetes. Также рекомендую сразу увеличить количество ресурсов, выделенных под Docker и Kubernetes, так как по умолчанию ресурсов этих немного. Сделать это можно во вкладке Advanced.
Если же вы выбрали вариант с Digital Ocean, или используете любого другого провайдера Kubernetes в виде сервиса, то вам будет предложено скачать файл конфигурации. После этого нужно сказать:
Независимо от того, какой кубер вы решили использовать, теперь команда:
… должна выводить список доступных физических машин. Например:
quirky-dubinsky-ctnw Ready <none> 8m v1.13.4
Поздравляю, можно переходить к следующим шагам. Для Docker Desktop и Digital Ocean они будут одинаковыми.
Эксперимент
В Kubernetes все описывается при помощи yaml-файлов. Если вы что-то меняете напрямую, а не через yaml, то почти наверняка используете Kubernetes неправильно. Это может обернуться для вас «неубиваемыми» контейнерами и разными другими странными эффектами, поэтому лучше так не делать.
В качестве примера рассмотрим описание простейшего deployment, состоящего из одного контейнера:
kind : Deployment
metadata :
name : nginx-deployment
spec :
selector :
matchLabels :
app : nginx
replicas : 1
template :
metadata :
labels :
app : nginx
spec :
containers :
— name : nginx
image : nginx:1.15.9-alpine
ports :
— containerPort : 80
protocol : TCP
Здесь для примера я использовал образ Nginx , но вы с тем же успехом можете запускать любые другие образы. В том числе, собранные самостоятельно из Dockerfile.
Скажем куберу применить новую конфигурацию:
Вскоре мы увидим соответствующие изменения в списке деплойментов:
Пример вывода:
nginx-deployment 1 1 1 1 2m
Также в списке подов появится наш первый под:
Пример вывода:
nginx-deployment-bff77b7f8-jbl4m 1/1 Running 0 2m
Pod в кубере является минимальной единицей развертывания. Часто в одном поде содержится один контейнер, но в общем случае в поде может содержаться и несколько контейнеров. В последнем случае эти контейнеры будут всегда разворачиваться вместе, на одной физической машине. То есть, невозможна ситуация, при которой одна половина пода развернулась на одной физической машине (ноде), а вторая — на второй физической машине.
У get pods
доступны следующие полезные кючи:
kubectl get pods -l app =nginx
# показывает внутренние IP подов
kubectl get pods -o wide
# вывод в JSON — удобно в скриптах
kubectl get pods -o json
# чтобы не зависеть от jq:
kubectl get pods -o jsonpath = ‘{.items[:].metadata.name}’
Бывает так, что в кубере что-то почему-то не стартует. Разобраться в причине обычно помогает describe:
kubectl describe pods
При желании можно зайти внутрь контейнера, сказав:
С тем же успехом можно выполнять и другие команды в контейнере. Эта возможность бывает полезной, например, если хочется посмотреть переменные окружения внутри контейнера.
Под запущен, но сейчас с ним есть маленькая проблемка. К нему никак нельзя достучаться откуда-то снаружи. Чтобы исправить эту ситуацию, создадим следующий файл:
kind : Service
metadata :
name : nginx-load-balancer
spec :
type : LoadBalancer
selector :
app : nginx
ports :
— protocol : TCP
port : 80
targetPort : 80
name : http
Здесь объявлен сервис с типом LoadBalancer, который находит все поды с меткой app=nginx
и прокидывает порт 80 данных подов наружу.
Применим конфигурацию:
Сервис должен появиться в списке сервисов:
Пример вывода:
kubernetes ClusterIP 10.245.0.1 <none> 443/TCP
nginx-load-balancer LoadBalancer 10.245.200.93 <pending> 80:30953/TCP
Спустя какое-то время <pending>
сменится на реальный внешний IP-адрес. Открыв этот адрес в браузере, мы увидим «Welcome to nginx!». Если вы решили использовать Docker Desktop, то вместо внешнего адреса будет использован localhost.
Теперь допустим, что нагрузка на нашу систему подросла, и один под больше не справляется. Откроем nginx.yaml и увеличим число реплик:
spec :
selector :
matchLabels :
app : nginx
replicas : 3 # <— изменено
…
Говорим:
Если все было сделано правильно, то в get pods
теперь будет три пода. При этом LoadBalancer продолжит работать, как ни в чем ни бывало, равномерно размазывая нагрузку по трем подам. Любые другие изменения с подами, такие, как обновление версии образа, происходят аналогично.
Информация о сервисах доступна изнутри контейнеров через переменные окружения . Единственный нюанс заключается в том, что сервис должен существовать на момент запуска контейнера. Таким образом, Kubernetes из коробки имеет service discovery, ставить Consul не нужно. Сервис можно сделать недоступным снаружи, убрав из описания строчку про LoadBalancer
. Подробности по этой теме можно найти в документации о типах сервисов .
Помимо переменных окружений также можно использовать доменные имена:
/ # apk add curl
…
/ # curl nginx-load-balancer 2>/dev/null | grep title
<title>Welcome to nginx!</title>
/ # curl nginx-load-balancer.default.svc.cluster.local 2>/dev/null |
> grep title
<title>Welcome to nginx!</title>
Наконец, удалим load balancer и поды:
kubectl delete -f nginx.yaml
Если вы использовали Digital Ocean, то может иметь смысл удалить созданный кластер Kubernetes. В противном случае за него продолжат списываться деньги, несмотря на отсутствие запущенных подов.
Вот и все. Согласитесь, это было не так уж и сложно.
Заключение
Совершенно невозможно рассказать все о Kubernetes в рамках одной статьи.
За кадром остались такие вопросы, как поднятие своего кластера на голом железе, network policies , работа с volumes , ограничения по ресурсам , liveness probes , config maps , аффинити к нодам , работа с K8s API из разных языков программирования, и многое-многе другое. Заинтересованным читателям рекомендуется обращаться к соответствующим разделам документации, поскольку (1) документация у кубера классная, (2) именно она содержит наиболее актуальные сведения, (3) разделы, представляющие интерес, сильно зависят от решаемой вами задачи.
А используете ли вы Kubernetes, и если да, то каковы ваши впечатления от работы с ним?
Дополнение: Поднимаем кластер Kubernetes из одной ноды под Linux