Kubernetes (он же K8s) — это ещё одна инструментина для управления контейнерами в кластере. Она решает, в какой части кластера контейнер будет запущен, следит, чтобы его запрошенная конфигурация («запущен», «пять реплик») выполнялась, чтобы у контейнера была сеть и айпишка, настроен доступ извне (если нужно), обновления приходили в нужном порядке, и т.п.
Изначально Kubernetes разрабатывался Гуглом, но те передали его в open source, так что теперь K8s свободен, как бесплатное пиво.
Да, K8s — не замена для Docker. Более того, Докер ему понадобится для, собственно, запуска контейнеров (правда, rkt — ещё один контейнерный движок — для этих целей тоже подойдёт). Чему Kubernetes альтернатива, так это Docker Swarm. Хотя они и используют похожие идеи и терминологию, вроде сервисов, реплик, запрошенной конфигурации и её выполнения, Kubernetes более гибкий, что ли. И, зная, что его папа — Гугл, глупо сомневаться, что K8s потянет кластер любого размера. С другой стороны, как и со всеми остальными детьми гугла (в основном, с API), с K8s сложновато иметь дело. Да и понимать его, местами, нелегко.
K8s может работать как на реальных машинах, так и на виртуалках, нативно в Google Compute Engine и с некоторыми оттенками серого в AWS и Azure. Он даже может работать с Windows Server контейнерами, блин!
Итак, какой будет план. Создадим-ка мы какой-нибудь локальный Kubernetes кластер и осмотримся. Установим в него что-нибудь, пооткрываем страниц в браузере. В общем, ничего сложного, просто посмотрим, на что же он похож, этот ваш Kubernetes.
Что очень сильно понадобится
Очень сильно понадобится VT-x или AMD-v виртуализация, включённая в BIOS. но обычно она включена и так. Всё остальное можно скачать.
Установка
Я обитаю на маке, поэтому все инструкции и скачиваемые пакеты будут для него. Но установка на Windows и особенно на Linux не должна фундаментально отличаться.
В общем, вот, что нам понадобится:
kubectl
— для запуска команд в кластере.minikube
— дла создания кластера.VirtualBox
— для жилища кластера.
Установка kubectl и minikube очень простая: скачать, добавить право на запуск, скопировать. Всё выполняется методом копи-пасты команды в терминал.
Kubectl:
1 2 3 |
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl chmod +x ./kubectl sudo mv ./kubectl /usr/local/bin/kubectl |
Minikube:
1 2 3 |
curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.20.0/minikube-darwin-amd64 chmod +x minikube sudo mv minikube /usr/local/bin/ |
Установка VirtualBox тоже удивительно тривиальна.
После того, как всё установилось, можно, наконец, создать кластер при помощи команды minikube start
:
1 2 3 4 5 |
minikube start #Starting local Kubernetes v1.6.4 cluster... #Starting VM... #Downloading Minikube ISO #... |
Вот теперь можно играться.
Ноды и поды (это не считалка)
На самом верху кластерной иерархии Kubernetes живут две вещи: мастер-сервисы (masters) и работяги-ноды (nodes). Пока мастера управляют кластером и распределяют работу («возьми контейнер тут, запусти там»), работяги послушно кивают и делают то, что им сказали. Ноды — это хосты кластера, на которых в конечном итоге и будут запускаться контейнера.
Так как у нас уже есть какой-никакой кластер, можно, например, спросить Kubernetes, сколько у него нодов. Команда для этого гениальна: kubectl get nodes
:
1 2 3 |
$ kubectl get nodes #NAME STATUS AGE VERSION #minikube Ready 3m v1.6.4 |
Всего один, но могло быть и хуже.
Если идти дальше по иерархии, то будет вот какой момент. Хотя я уже несколько раз использовал слово контейнер, минимальный юнит работы в Kubernetes кластере на самом деле называется под (pod). Это всего лишь абстракция над контейнером, у которой будет своё имя, айпишка, и внутри которой-таки будет сидеть контейнер. Или два. Или больше. Все контейнеры внутри пода будут делить общую айпишку и могут общаться друг с другом по, например, localhost.
Можно использовать ту же самую kubectl get
команду, чтобы посмотреть, какие поды сейчас запущены:
1 2 3 4 5 6 7 |
$ kubectl get pod #No resources found. $ kubectl get pod --all-namespaces #NAMESPACE NAME READY STATUS RESTARTS AGE #kube-system kube-addon-manager-minikube 1/1 Running 0 58s #kube-system kube-dns-1301475494-p8gvb 3/3 Running 0 43s #kube-system kubernetes-dashboard-hmh8f 1/1 Running 0 44s |
У нас — никакие. Но если посмотреть по всех пространствах имён (--all-namespaces
), то будут аж три, созданных самим Kubernetes для своих таинственных нужд. Один из них, kubernetes-dashboard
, очень, кстати, интересный.
kubernetes-dashboard
Что здорово, в комплекте с K8s идёт собственный дашборд. Он не только может показать, что сейчас запущено и где, но сможет и поделиться, сколько ресурсов на это уходит, и даже запустить команду-другую. Самый простой способ посмотреть, как он выглядит, это запустить minikube dashboard
:
1 2 |
$ minikube dashboard # Opening kubernetes dashboard in default browser... |
Запускаем первый pod
В каком-то отношении запуск пода очень похож на запуск контейнера в Докер. Та же run
команда, то же имя образа на вход и, опционально, номер порта. Но магия происходит совсем другая. kubectl run
не разрешит вот просто взять и запустить под. Он создаст deployment, который сам разберётся с запуском. Разберётся и будет следить, чтобы потом с подом не произошло чего. Если тот упадёт, то деплоймент тут же создаст новый.
Создадим чего-нибудь и мы. Какой-нибудь контейнеризированный nginx сервер, например:
1 2 3 4 5 6 7 8 9 10 |
$ kubectl run nginx --image=nginx #deployment "nginx" created $ kubectl get deployment #NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE #nginx 1 1 1 1 1m $ kubectl get pod #NAME READY STATUS RESTARTS AGE #nginx-158599303-hq212 1/1 Running 0 1m |
Как и в Докер, у K8s есть команды и для описания объектов (kubectl describe
), и для запроса логов (kubectl logs nginx-158599303-hq212
) и даже для того, чтобы залезть внутрь пода и запустить там что-нибудь (kubectl exec -ti nginx-158599303-hq212 bash
):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ kubectl describe deployment/nginx # Name: nginx # Labels: run=nginx # ... $ kubectl get pod # NAME READY STATUS RESTARTS AGE # nginx-158599303-ffscb 1/1 Running 0 16m $ kubectl describe pod/nginx-158599303-ffscb # Name: nginx-158599303-ffscb # Namespace: default # Labels: pod-template-hash=158599303 # run=nginx # .. |
Если вам показалось, что между предпоследними абзацами айдишка пода изменилась с nginx-158599303-hq212
на nginx-158599303-ffscb
, то это не галлюцинация или не иной признак ментального нездоровья. Айдишка действительно поменялась. Просто, чтобы убедиться, что в случае чего деплоймент действительно воссоздаст pod, я вмешался в ход событий командой kubectl delete
, и деплоймент действительно заметил потерю пода и завёл себе новый.
Открываем pod миру и сети
Тот pod, что мы создали, он ведь может общаться только внутри сети кластера. А кому это нужно? Но с подключением его к большой сети была бы проблема. Ведь даже если мы настроим проброс портов пода наружу, его деплоймент может же пересоздать под на другой машине. Там тоже, что ли, пробрасывать? А откуда я узнаю, где он теперь? А если он вообще клонирован, и их там десяток?
Чтобы связать точку входа с одной стороны, и непонятное количество подов с другой, у Kubernetes есть ещё одна абстракция — сервисы (services). Сервис — это прокся. Что в ней интересно, так это способ, которым она находит целевые поды. Если посмотреть ещё раз на вывод команды kubectl describe pod/nginx-158599303-ffscb
, то у пода, оказывается, в описании было поле labels. Метки. Kubernetes добавил их автоматически, но мы могли бы добавить и своих.
И вот какая чёрная магия бывает: сервисы используют метки как фильтр «своих» подов. Те могут быть даже созданы из разных образов, nginx и httpd, например. Сервису плевать. Если мы создадим сервис через kubectl expose
команду, то K8s скопирует начальный набор меток для фильтра прямо из deployment:
1 2 3 4 5 6 7 |
$ kubectl expose deployment/nginx --type="NodePort" --port 80 #service "nginx" exposed $ kubectl describe service/nginx #Name: nginx #Namespace: default #Labels: run=nginx #NodePort: <unset> 32543/TCP |
Мы использовали «NodePort» тип сервиса, чтобы тот привязывал внутренний порт пода к внешнему порту нода. Но можно было бы использовать «ClusterIP», чтобы сервис не высовывался из внутренней сети кластера, или «LoadBalancer», чтобы использовать балансировщик нагрузки облачного провайдера (если тот поддерживает), или даже «ExternalName», чтобы подключить к сервису магию DNS.
Описание сервиса содержало внешний номер порта (32543), так что заполучив к нему в пару айпишку самого нода, в теории можно, наконец, обратиться к поду с nginx извне:
1 2 |
$ kubectl describe node/minikube | grep InternalIP # InternalIP: 192.168.99.100 |
Теория сработала, и теперь у нас есть под в кластере, к которому можно достучаться снаружи.
Убираем кластер назад
Есть ещё много вещей, с которыми можно поэксперементировать в Kubernetes кластере, но как только это всё надоест, кластер можно прибить одной-единственной командой:
1 2 3 |
$ minikube delete # Deleting local Kubernetes cluster... # Machine deleted. |
Итого
Хочется верить, что эти нехитрые эксперименты хоть немного показали, на что же похож Kubernetes. Конечно, в продакшене мы бы не запускали поды по одному и точно не руками — есть YAML конфигурации для этого. Да и взаимодействие контейнеров и их обновление мы не тронули вообще никак. Но откуда-то же надо начинать, так что почему бы не с кластера из одной машины, и пода с бессмысленным сервером внутри.
А вот ето интересненько 🙂
Спасибо большое за статью!
Для старта, чтобы разобраться, то что нужно!
Пожалуйста
А зачем в этой статье упомянается VirtualBox?
Поставили:
— Kubectl
— Minikube
— VirtualBox
А потом:
«minikube start»
«$ kubectl get nodes»
И т.д.
Похоже, что в статье не используется VirtualBox. Или нет?
А minikube создаёт виртуальную машину для кластера именно в VirtualBox.
Классная статья, всё подробно и понятно описано