Эта статья предназначена для быстрого старта в Kubernetes. Цель статьи – максимально просто рассказать о среде Kubernetes так, чтобы вы сразу могли начать работать с ней. Я специально опущу такие вещи, как: пространство имен, задачи, расписания, версионность, репликация, авто-масштабирование, авто определение сервисов, супервайзинг и прочие страшные слова. Оставим их, как бонус, на потом. Мы так же не будем углубляться в архитектуру k8s, это тема для отдельной статьи.
Что такое Kubernetes?
Для простоты будем представлять его, как менеджер контейнеров.
Контейнер – это изолированная среда для работы какого-то приложения. Чаще всего на данный момент таким контейнером служит Docker. Наверняка вам приходилось запускать приложения в Docker-е. А может и несколько приложений, работающий совместно, используя docker-compose.
Pod
В k8s один экземпляр приложения называется pod (от англ. – стручок). Контейнеры в нем – горошины. Дело в том, что kubernetes позволяет запускать несколько контейнеров в одном pod. Все контейнеры внутри pod, как правило, объединены одной логикой. К примеру pod может называться web, а в нем 2 контейнера: php и db.
Запущенный Docker контейнер – это горошина в стручке
Чаще всего внутри pod вы найдете всего один контейнер – само приложение, и это нормально. Вторыми, третьими контейнерами там как правило бывают служебные (типа сбора метрик, адаптера и пр.).
Внутри pod все контейнеры имеют один TCP/IP адрес и могут обращаться друг с другом через localhost !
Deployment и StatefulSet
У приложения (pod), помимо контейнеров существуют: описание, методанные, имя, метки, количество запущенных копий (replicas). Плюс к pod-у мы можем подключать внешние тома (volumes) для хранения данных, init-контейнеры (которые будут настраивать наше приложение до его запуска), и много чего еще.
Такое описание pod-а, с его дополнительными ресурсами называется Deployment. Описание в k8s происходит на языке разметки yaml
.
Вот пример описания Deployment-а:
---
apiVersion: apps/v1beta2
kind: Deployment
metadata:
name: web-site
spec:
replicas: 1
template:
metadata:
labels:
app: web
spec:
containers:
- name: php
image: php-fpm:latest
ports:
- containerPort: 80
volumeMounts:
- name: data
mountPath: /var/www
subPath: data
- name: db
image: mysql:latest
volumeMounts:
- name: db
mountPath: /var/lib/mysql
subPath: db
В данном примере image
– имя образа Docker, доступного из репозитария (docker hub или личного). Пример: image: osixia/openldap:1.2.5
или image: localhost:5000/openldap:latest
. Еще вы можете увидеть описание экспортируемых TCP портов ports
и внешних томов volumeMounts
.
ЗАМЕТКА: Другой вариант Deployment называется StatefulSet – это тот же Deployment, только со статичными именами хостов и особым способом разделения ресурсов: каждый экземпляр реплики получает доступ только ко своей директории. Тогда как в Deployment все реплики имеют доступ к общим директориям. StatefulSet используется реже, как правило для балансировки нагрузки и репликации внутри приложения. К примеру его можно встретить в СУБД PostgreSQL с master-slave репликацией, где у каждой реплики – свой набор данных.
Service
Итак, у нас уже есть приложение, описанное со всеми ресурсами в Deployment. Нам надо к нему обратиться из-вне, к примеру открыть страницу нашего web. Для этого служит новый тип ресурсов: Service. Он позволяет описать что и на каком порту предоставлять в использование:
apiVersion: v1
kind: Service
metadata:
name: web-page
spec:
selector:
app: web
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
nodePort: 9000
protocol: TCP
В данном примере мы описали новый сервис (Service) с именем web-page
. Работать он будет с помощью селектора (selector
), выбирая все, что попадает под его правила. В данном случаи: app: web
. То есть наш pod, описанный в Deployment как раз имеет такую метку (label) (см. выше).
В k8s выборки делаются через метки (label).
Выше указан тип сервиса: type: NodePort
. Существует несколько способов открыть доступ до приложения:
- NodePort – этот тип вывешивает TCP/IP порт прямо на ноде, на которой запущен kubernetes. То есть вы можете обратиться по внешнему IP адресу сервера k8s и этот порт (у нас
nodePort: 9000
) будет перенаправлен в соответствующий pod. - ClusterIP – вывешивает сервис на выделенный IP адрес внутри кластера. Как правило он серый. Это самый используемый тип сервиса, так как позволяет экспортировать порты внутри кластера для общения приложений между собой.
- LoadBalancerIP – выделенный внешний (белый) IP адрес для сервиса. Располагается на балансировщике нагрузок, расположенным перед нодами k8s кластера.
К примеру реверсивный proxy-сервер в вашем кластере может иметь тип LoadBalancerIP и висеть на выделенном IP адресе, обращаясь к другим сервисам, которые имеют тип ClusterIP. Такой proxy-сервер в k8s называется Ingress, о нем будет ниже.
Все! Deployment + Service – нам этого достаточно, чтобы запустить наше приложение в kubernetes!
Принцип работы
Вот упрощенно как будет выглядеть работа приложения в k8s:
Тут app: web
– наше приложение, запущенное в единственном экземпляре. И какое-то другое (app: other
) – масштабируемое. У них разные сервисы и разные метки. По этому прокси сервер при обращении к определенному порту (или имени, в случаи если мы используем Ingress
) – будет переправлять нас на соответствующее приложение внутри k8s.
Ingress
Ingress – это http прокси сервер k8s, позволяющий обращаться к ресурсам по именам. Вот пример описания ingress-сервиса:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: web-ingress
spec:
rules:
- host: www.burlutsky.su
http:
paths:
- path: /
backend:
serviceName: web-page
servicePort: http
По указанным правилам (имя хоста и путь) – прокси сервер выберет соответствующий сервис: serviceName: web-page
, который был описан нами ранее.
ЗАМЕТКА: Тип нашему сервису (Service) web-page, в данном случаи, лучше поставить ClusterIP, убрав директиву nodePort, чтобы не вывешивать его прямо на ноде.
Helm
Все это конечно хорошо, но когда же мы приступим к практике? С чего начать? Я предлагаю сразу в бой! Но для этого нам понадобится шлем (Helm).
Чтобы не составлять все эти yaml – файлы с описанием вручную, не искать их по интернету – мы будем использовать готовые шаблоны (templates).
Дело в том, что работать напрямую с yaml-файлами kubernetes не очень удобно. Во-первых их надо много (чтобы описать все возможные ресурсы). Во-вторых, чтобы что-то изменить – надо искать и править эти файлы. Такой подход не приемлем для множественных установок одного и того же приложения, но с разными параметрами (именами, настройками, логинами, паролями и пр.).
Одним из самых популярных инструментов шаблонизации yaml-файлов для k8s на сегодня является Helm.
Вышеприведенный yaml-файл на нем выглядел бы как-то так:
{{- $fullName := include "fullname" . -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ $fullName }}-ingress
spec:
rules:
- host: {{ .Values.hostname }}
http:
paths:
- path: /
backend:
serviceName: {{ $fullName }}
servicePort: http
Тут вы видите, что изменяемые данные заменены на переменные:
- .Values.hostname – переменная из специального
values.yaml
– файла. Записывается в файле так:
hostname: www.burlutsky.su
После чего становится доступна, как .Values.hostname
. То есть мы вынесли уже статичные данные из yaml-файла и сделали его шаблоном, пригодным для применения с другими данными. Ничего не надо править – только values.yaml .
- $fullName – какая-то дополнительная переменная. В данном случаи обозначает имя нашего приложения. Для таких вспомогательных переменных служит специальный файл: _helpers.tpl.
Все файлы шаблонов находятся в директории templates. Посмотрите любой удобный для вас пример от сюда: https://github.com/helm/charts/tree/master/stable
Найдите в выбранном вами примере шаблоны описания Deployment (или StatefulSet), Service, Ingress. Как правило они располагаются в соответствующих файлах директории templates: deployment.yaml, services.yaml и т.п.
Установка приложения с Helm сводится к правке values.yaml-файла, или созданию нового my-values.yaml – файла, с нужными вам значениями переменных, а затем использованию клиента helm для установки данного набора шаблонов в k8s:
helm install -f my-values.yaml stable/postgresql
Данная команда возьмет переменные из вашего my-values.yaml – файла, совместит их с другими переменными values.yaml – файла, идущего в поставке. После чего на их основе сгенерирует конечные yaml-файлы и применит их в k8s.
Полезные команды
kubectl get pods
– получить все запущенные podkubectl describe pod <name>
– получить детальные описания podkubectl get services
– получить все сервисыkubectl get deployments
– получить все Deploymenthelm list
– получить все установленные пакеты приложений (релизы)
Minikube
Для старта работы с k8s вы можете использовать minikube, который позволяет получить окружение kubernetes у вас на компьютере или в виртуальной машине: https://github.com/kubernetes/minikube
Удачи в освоении k8s!