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 достаточно сказать:
brew install kubectl
Если вы решили воспользоваться Docker Desktop, включите Kubnernetes в меню Preferences… → Kubernetes. Также рекомендую сразу увеличить количество ресурсов, выделенных под Docker и Kubernetes, так как по умолчанию ресурсов этих немного. Сделать это можно во вкладке Advanced.
Если же вы выбрали вариант с Digital Ocean, или используете любого другого провайдера Kubernetes в виде сервиса, то вам будет предложено скачать файл конфигурации. После этого нужно сказать:
export KUBECONFIG=/путь/до/вашего/kubeconfig.yaml
Независимо от того, какой кубер вы решили использовать, теперь команда:
kubectl get nodes
… должна выводить список доступных физических машин. Например:
NAME STATUS ROLES AGE VERSION quirky-dubinsky-ctnw Ready 8m v1.13.4
Поздравляю, можно переходить к следующим шагам. Для Docker Desktop и Digital Ocean они будут одинаковыми.
Эксперимент
В Kubernetes все описывается при помощи yaml-файлов. Если вы что-то меняете напрямую, а не через yaml, то почти наверняка используете Kubernetes неправильно. Это может обернуться для вас «неубиваемыми» контейнерами и разными другими странными эффектами, поэтому лучше так не делать.
В качестве примера рассмотрим описание простейшего deployment, состоящего из одного контейнера:
apiVersion: apps/v1 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.
Скажем куберу применить новую конфигурацию:
kubectl apply -f nginx.yaml
Вскоре мы увидим соответствующие изменения в списке деплойментов:
kubectl get deployments
Пример вывода:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE nginx-deployment 1 1 1 1 2m
Также в списке подов появится наш первый под:
kubectl get pods
Пример вывода:
NAME READY STATUS RESTARTS AGE 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 deployments kubectl describe pods
При желании можно зайти внутрь контейнера, сказав:
kubectl exec -it nginx-deployment-bff77b7f8-jbl4m -- /bin/sh
С тем же успехом можно выполнять и другие команды в контейнере. Эта возможность бывает полезной, например, если хочется посмотреть переменные окружения внутри контейнера.
Под запущен, но сейчас с ним есть маленькая проблемка. К нему никак нельзя достучаться откуда-то снаружи. Чтобы исправить эту ситуацию, создадим следующий файл:
apiVersion: v1 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 данных подов наружу.
Применим конфигурацию:
kubectl apply -f loadbalancer.yaml
Сервис должен появиться в списке сервисов:
kubectl get svc
Пример вывода:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) kubernetes ClusterIP 10.245.0.1 443/TCP nginx-load-balancer LoadBalancer 10.245.200.93 80:30953/TCP
Спустя какое-то время сменится на реальный внешний IP-адрес. Открыв этот адрес в браузере, мы увидим «Welcome to nginx!». Если вы решили использовать Docker Desktop, то вместо внешнего адреса будет использован localhost.
Теперь допустим, что нагрузка на нашу систему подросла, и один под больше не справляется. Откроем nginx.yaml и увеличим число реплик:
... spec: selector: matchLabels: app: nginx replicas: 3 # <-- изменено ...
Говорим:
kubectl apply -f nginx.yaml
Если все было сделано правильно, то в get pods
теперь будет три пода. При этом LoadBalancer продолжит работать, как ни в чем ни бывало, равномерно размазывая нагрузку по трем подам. Любые другие изменения с подами, такие, как обновление версии образа, происходят аналогично.
Информация о сервисах доступна изнутри контейнеров через переменные окружения. Единственный нюанс заключается в том, что сервис должен существовать на момент запуска контейнера. Таким образом, Kubernetes из коробки имеет service discovery, ставить Consul не нужно. Сервис можно сделать недоступным снаружи, убрав из описания строчку про LoadBalancer
. Подробности по этой теме можно найти в документации о типах сервисов.
Помимо переменных окружений также можно использовать доменные имена:
/ # apk upgrade / # 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 loadbalancer.yaml kubectl delete -f nginx.yaml
Если вы использовали Digital Ocean, то может иметь смысл удалить созданный кластер Kubernetes. В противном случае за него продолжат списываться деньги, несмотря на отсутствие запущенных подов.
Вот и все. Согласитесь, это было не так уж и сложно.
Заключение
Совершенно невозможно рассказать все о Kubernetes в рамках одной статьи.
За кадром остались такие вопросы, как поднятие своего кластера на голом железе, network policies, работа с volumes, ограничения по ресурсам, liveness probes, config maps, аффинити к нодам, работа с K8s API из разных языков программирования, и многое-многе другое. Заинтересованным читателям рекомендуется обращаться к соответствующим разделам документации, поскольку (1) документация у кубера классная, (2) именно она содержит наиболее актуальные сведения, (3) разделы, представляющие интерес, сильно зависят от решаемой вами задачи.
[customscript]techrocks_custom_after_post_html[/customscript]
[customscript]techrocks_custom_script[/customscript]