Разворачиваем кластер Kubernetes на платформе VK Cloud (бывш. MCS)
Для полноценной работы с кластером Kubernetes, помимо стандартных сервисов, которые входят в дистрибутив, необходимо установить некоторые дополнительные сервисы:
- Сеть — настройка диапазонов IP, инкапсуляции, маршрутизации.
- Мониторинг.
- Ingress Controller — балансировщик нагрузки http/https, который позволяет маршрутизировать http-запросы на основе доменного имени и пути. С помощью него можно хостить на одном IP-адресе много сайтов и приложений и экономить IP-адреса.
- Persistent Storage — для постоянного хранения данных в условиях динамично меняющейся инфраструктуры: добавление/удаление нод, перезапуск подов на различных машинах и так далее.
- Helm — пакетный менеджер для автоматизации развёртывания приложений.
На облачной платформе VK Cloud (бывш. MCS) можно развернуть кластер Kubernetes с нуля. В кластере «из коробки» запущены 4 из этих 5 дополнительных сервисов. Рассмотрим каждый из них и проверим их работоспособность. В конце покажем, как просто добавить в кластер Helm.
Итак, что у нас есть после запуска кластера Kubernetes на VK:
Запущенная сеть Calico
Каждой ноде назначается своя подсеть для подов. Обычно у сетей в Kubernetes есть два режима работы: оверлейный и неоверлейный (host gateway).
- В оверлейном режиме вся сеть между подами инкапсулируется. Протокол инкапсуляции зависит от конкретной реализации сети (например: calico — IPinIP, flannel — vxlan).
- В неоверлейном режиме трафик между подами не инкапсулируется, а ходит по хостовой сети с внутренними IP-адресами подов. Маршрутизация в этом режиме организована по принципу “NodeSubnet via NodeIP”. Например, в Calico — при помощи BGP.
На VK по умолчанию действует неоверлейный режим работы.
Посмотрим запущенные поды в системном неймспейсе Kubernetes kube-system:
kubectl get po -n kube-system
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-79c97cf859-4zdgt 1/1 Running 0 3h
calico-node-55p66 2/2 Running 0 3h
calico-node-b7lsd 2/2 Running 0 3h
calico-node-l5m88 2/2 Running 0 3h
calico-node-rrdd8 2/2 Running 0 3h
Доказательством того, что сеть настроена и работает корректно, может служить тот факт, что в запущенном кластере можно стартовать работающие приложения. Ниже мы запустим несколько приложений.
2. Система сбора метрик Prometheus и Grafana
Для сбора метрик в Kubernetes используется система Prometheus. Она устанавливается в кластере на VK по умолчанию.
В Prometheus есть встроенная база данных временных рядов. Prometheus собирает метрики с различных экспортеров на нодах кластера. Например, node-exporter собирает метрики хостов: загрузка процессора, оперативной памяти, диска, показатели работы сетевого стека и так далее. Метрики также собираются со многих компонентов Kubernetes и его дополнений: kube-apiserver,kube-controller-manager, kube-scheduler, kubelet, etcd и других.
Метрики можно просматривать через встроенный веб-интерфейс, но он не очень удобен для постоянного отображения метрик. С этой задачей куда лучше справляется Grafana, который позволяет создавать информативные дашборды.
По умолчанию поды мониторинга запускаются в неймспейсе prometheus-monitoring. Посмотрим поды, запущенные в этом неймспейсе:
kubectl get po -n prometheus-monitoring
NAME READY STATUS RESTARTS AGE
prometheus-monitoring grafana-dd64f69cc-2mmpf 1/1 Running 0 3h
prometheus-monitoring prometheus-7cdfbd7d5f-sv6j5 1/1 Running 0 3h
Чтобы получить доступ к дашборду, выполним команду kubectl proxy и зайдём на адрес http://127.0.0.1:8001/api/v1/namespaces/kube-system/services/monitoring-grafana/proxy
При создании кластера по умолчанию ставится минималистичный Kubernetes dashboard, который позволяет управлять всеми базовыми ресурсами Kubernetes. Дополнительно можно установить систему сбора метрик Heapster, она позволит отображать базовые метрики Kubernetes прямо в Kubernetes dashboard. Она не так функциональна, как Prometheus, но её достаточно для сбора метрик о потреблении ресурсов подами и нодами. Вместе с Heapster устанавливается база данных InfluxDB, в которую пишутся все собранные метрики, и дашборд Grafana для отображения метрик в удобном виде.
kubectl get po --all-namespaces
NAME READY STATUS RESTARTS AGE
heapster-5c6d75b6c7-72hsj 1/1 Running 0 3h
Для подключения к дашборду можно использовать тот же kubectl proxy. Дашборд будет открываться по адресу http://127.0.0.1:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/
3. Load balancer Nginx-Ingress
kubectl get po -n ingress-nginx
NAME READY STATUS RESTARTS AGE
default-http-backend-85c9b5f6f8-8m8c4 1/1 Running 0 21h
default-http-backend-85c9b5f6f8-rsggf 1/1 Running 0 21h
nginx-ingress-controller-7c95b49bb6-d44ck 1/1 Running 0 21h
nginx-ingress-controller-7c95b49bb6-pb8kv 1/1 Running 0 21h
kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default-http-backend ClusterIP 10.254.171.158 80/TCP 21h
ingress-nginx LoadBalancer 10.254.45.49 192.0.2.124 80:32604/TCP,443:32312/TCP 21h
Чтобы проверить работу ingress-controller, создадим сначала pod с веб сервером:
kubectl run nginx --image=nginx -l app=hello-world
И сервис для него:
kubectl expose deployment/nginx --port=80 --target-port=80
Ingress-controller в Kubernetes выполняет задачи по балансировке трафика, маршрутизации по доменным именам и подпутям в HTTP, поддерживает терминацию TLS. Создавая ресурс Ingress, мы создаём новые правила для балансировщика нагрузки. В данном случае все запросы на домен example.com будут отправлены на сервис nginx, порт 80:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
rules:
- host: example.com
http:
paths:
- path: /
backend:
serviceName: nginx
servicePort: 80
Запускаем ingress-ресурс:
kubectl create -f ingress.yaml
Смотрим, что запустилось:
kubectl get ing
NAME HOSTS ADDRESS PORTS AGE
test-ingress example.com 192.0.2.124 80 3m
Ingress-controller маршрутизирует трафик по доменам на основании заголовка «Host:» в запросе. Чтобы можно было зайти по URL через браузер, добавляем адрес сервиса ingress-nginx в файл hosts на своём компьютере:
192.0.2.124 example.com
Результат можно увидеть в браузере по адресу example.com:
4. Persistent Storage
В VK для организации хранилища используется интеграция с OpenStack Cinder.
В Kubernetes в имплементации VK уже заданы четыре Storage Class (SC). Два HDD и два SSD. Отличаются они Reclaim policy. Если Reclaim policy = retain, то при удалении PVC не будет удалён сам PV, к которому был привязан данный PVC.
kubectl get storageclasses
NAME PROVISIONER AGE
hdd (default) kubernetes.io/cinder 21h
hdd-retain kubernetes.io/cinder 21h
ssd kubernetes.io/cinder 21h
ssd-retain kubernetes.io/cinder 21h
Некоторые сервисы уже используют хранилище:
kubectl get pvc --all-namespaces
NAMESPACE NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
kube-system grafana-pvc Bound pvc-a0b500f9-e286-11e8-9dcd-fa163efef724 10Gi RWO hdd 7d
kube-system influxdb-pvc Bound pvc-9e3b9fd9-e286-11e8-9dcd-fa163efef724 10Gi RWO hdd 7d
prometheus-monitoring grafana-pvc Bound pvc-bdd5aba5-e286-11e8-9dcd-fa163efef724 10Gi RWO hdd 7d
prometheus-monitoring prometheus-pvc Bound pvc-b53a0789-e286-11e8-9dcd-fa163efef724 10Gi RWO hdd 7d
Для проверки persistent storage создадим PVC и Pod:
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: myclaim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 8Gi
storageClassName: ssd
---
kind: Pod
apiVersion: v1
metadata:
name: mypod
spec:
containers:
- name: myfrontend
image: nginx
volumeMounts:
- mountPath: "/var/www/html"
name: mypd
volumes:
- name: mypd
persistentVolumeClaim:
claimName: myclaim
Зайдём в под и запишем что-нибудь на persistent volume:
kubectl exec -it mypod /bin/bash
root@mypod:/# cd /var/www/html
root@mypod:/var/www/html# echo 'Hello World!' > index.html
Удалим под:
kubectl delete po mypod
И создадим заново:
kind: Pod
apiVersion: v1
metadata:
name: mypod
spec:
containers:
- name: myfrontend
image: nginx
volumeMounts:
- mountPath: "/var/www/html"
name: mypd
volumes:
- name: mypd
persistentVolumeClaim:
claimName: myclaim
Проверим, что данные были сохранены:
kubectl exec -it mypod cat /var/www/html/index.html
Hello World!
Как показано выше, данные сохранились, несмотря на то, что под с приложением nginx был удалён.
Остается добавить крайний дополнительный компонент — пакетный менеджер Helm
Helm в комплекте не идёт, но его очень легко поставить.
Для начала скачайте Helm на свой локальный компьютер:
curl -LO https://storage.googleapis.com/kubernetes-helm/helm-v2.11.0-linux-amd64.tar.gz
tar -xvf helm-v2.11.0-linux-amd64.tar.gz
cd linux-amd64/
Создайте CA для шифрования соединений с Helm:
mkdir HELM-CA
cd HELM-CA
openssl genrsa -out ca.key.pem 4096
openssl req -key ca.key.pem -new -x509 -days 7300 -subj '/ON=tiller/CN=tiller' -sha256 -out ca.cert.pem -extensions v3_ca
openssl genrsa -out tiller.key.pem 4096
openssl genrsa -out helm.key.pem 4096
openssl req -key tiller.key.pem -new -sha256 -out tiller.csr.pem -subj '/ON=Tiller Server/CN=tiller-server'
openssl req -key helm.key.pem -new -sha256 -out helm.csr.pem -subj '/CN=helm'
openssl x509 -req -CA ca.cert.pem -CAkey ca.key.pem -CAcreateserial -in tiller.csr.pem -out tiller.cert.pem -days 365
openssl x509 -req -CA ca.cert.pem -CAkey ca.key.pem -CAcreateserial -in helm.csr.pem -out helm.cert.pem -days 365
mkdir $(../helm home)
cp ca.cert.pem $(../helm home)/ca.pem
cp helm.cert.pem $(../helm home)/cert.pem
cp helm.key.pem $(../helm home)/key.pem
cd ..
Helm использует серверный компонент tiller для взаимодействия с Kubernetes API. Для его нормальной работы необходимо создать RBAC для аутентификации в Kubernetes.
yaml-файл:
apiVersion: v1
kind: ServiceAccount
metadata:
name: tiller
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: tiller
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: tiller
namespace: kube-system
Создаем RBAC:
kubectl apply -f tiller-rbac.yaml
Инициализируем Helm:
./helm init --tiller-tls
--tiller-tls-cert HELM-CA/tiller.cert.pem
--tiller-tls-key HELM-CA/tiller.key.pem
--tls-ca-cert HELM-CA/ca.cert.pem
--tiller-tls-verify
--service-account=tiller
Теперь можно работать с Helm!
Пример использования Helm
Для примера запустим WordPress через Helm:
./helm install --name my-wordpress --set ingress.hosts[0].name=wordpress.local
--set ingress.enabled=true --set persistence.storageClass=ssd stable/wordpress --tls
При запуске Helm мы передаем аргументы для кастомизации установки: включаем создание ingress, задаем ему доменное имя, подключаем персистентное хранилище для базы данных.
Через некоторое время wordpress запустится:
kubectl get po
NAME READY STATUS RESTARTS AGE
my-wordpress-mariadb-0 1/1 Running 0 4m
my-wordpress-wordpress-69dfc4d786-988h7 1/1 Running 0 4m
Чтобы увидеть результат, пропишем адрес wordpress.local в /etc/hosts. После этого результат можно увидеть в своём браузере: