Как задеплоить проект на Kubernetes в VK Cloud (бывш. MCS). Часть 3.
Это продолжение практикума по развертыванию Kubernetes-кластера на базе облака VK Cloud (бывш. MCS) и созданию MVP для реального приложения, выполняющего транскрибацию видеофайлов из YouTube.
Я Василий Озеров, основатель агентства Fevlake и действующий DevOps-инженер (опыт в DevOps — 8 лет), покажу все этапы разработки Cloud-Native приложений на K8s: от запуска кластера до построения CI/CD и разработки собственного Helm-чарта.
Напомню, что в первой части статьи мы выбрали архитектуру приложения, написали API-сервер, запустили Kubernetes c балансировщиком и облачными базами, развернули кластер RabbitMQ через Helm в Kubernetes. Во второй части настроили и запустили приложение для преобразования аудио в текст, сохранили результат и настроили автомасштабирование нод в кластере.
В третьей части осталось добавить небольшие улучшения, в частности настроить мониторинг, а также мы построим CI/CD и разработаем собственный Helm-чарт.
Мониторинг с помощью Prometheus
Первое, что нам нужно сделать для получения кастомных метрик — это установить Prometheus, который будет собирать метрики с наших сервисов. Устанавливать его, как и RabbitMQ, будем через Helm. Но это не Prometheus в чистом виде, по его компонентам пройдемся позднее.
Находим prometheus-stack, используя команду:
helm search repo prometheus-stack
Чтобы поиск выполнился корректно, необходимо предварительно убедиться в наличии репозитория prometheus-community с помощью helm repo list и добавить его при необходимости:
Если репозитория в списке нет, добавьте его командой:
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
В результатах поиска нас интересует kube-prometheus-stack — скачиваем его и распаковываем:
helm pull prometheus-community/kube-prometheus-stack
tar zxvf kube-prometheus-stack-12.5.0.tgz
Копируем values-файл в текущую директорию и называем его values.prometheus.stage.yaml:
cp kube-prometheus-stack/values.yaml values.prometheus.stage.yaml
При загрузке Helm-чартов придерживаемся стандартного правила. Загруженные Values мы не редактируем, чтобы чарт можно было легко обновлять в дальнейшем. Вместо этого переносим их на уровень выше и называем по имени сервиса (prometheus или rabbit) и окружения (stage, dev, prod и так далее). Очевидно, что для разных окружений настройки будут отличаться.
Отредактируем values.prometheus.stage.yaml. Чтобы включить Ingress для Prometheus, находим в файле блок ingress, устанавливаем в поле enabled значение true и прописываем имя хоста prometheus.stage.kis.im:
Далее создаем новый Namespace — monitoring:
kubectl create ns monitoring
И деплоим в него prometheus-stack:
helm -n monitoring upgrade --install prometheus-stack -f values.prometheus.stage.yaml ./kube-prometheus-stack/
Деплой запущен:
Проверим статус деплоя:
helm -n monitoring list
Запись появилась, значит все ок:
Теперь проверим, что запустились поды с помощью:
kubectl -n monitoring get pods
Запустилось сразу несколько сервисов: alertmanager, prometheus, grafana, prometheus-operator, kube-state-metrix, node-exporter. Экспортеры (node-exporter) будут собирать информацию с каждой ноды кластера — поэтому их три штуки. Они управляются DaemonSet. При добавлении новых узлов в кластере для них будут автоматически созданы отдельные экспортеры.
Так как мы на этапе настройки подключали Ingress для Prometheus, мы можем обратиться по адресу prometheus.stage.kis.im (предварительно добавив его в DNS) и посмотреть все таргеты. Видим, что с kube-proxy метрики у нас не собираются, а все остальное успешно работает:
Prometheus Operator создает кастомные ресурсы. Просмотреть их можно, используя команду get crd (Custom Resource Definition):
kubectl get crd
Если необходимо собирать метрики со своих приложений, нужно добавить в этот список новый ресурс: либо serviceMonitor, который находит сервисы и обращается к их Endpoints, либо podMonitor, который находит поды и начинает мониторить их. Как только вы создадите этот ресурс, Prometheus Operator это обнаружит и обновит конфигурацию Prometheus. В результате ресурсы попадут в общий список, и Prometheus начнет их мониторить. Это логика работы любого оператора в Prometheus: операторы создают кастомные ресурсы, управляя которыми, вы можете влиять на работу мониторинга.
Для добавления нашего serviceMonitor открываем файл values.rabbitmq.stage.yaml и находим секцию Prometheus Metrics. Устанавливаем в поле enabled значение true.
Теперь этот Helm Chart подключит к RabbitMQ специальный плагин rabbitmq_prometheus, который сможет отдавать метрики в Prometheus:
В секции serviceMonitor также прописываем enabled: true. Эта настройка отвечает за создание serviceMonitor — ресурса, необходимого Prometheus:
В секции additionalLabels добавляем метку release: prometheus-stack:
Эта метка необходима для того, чтобы установленный нами ранее Prometheus-stack обнаружил новый serviceMonitor. В настройках Prometheus-stack при установке указываются метки, на основании которых он будет определять нужные podMonitor и serviceMonitor. Благодаря этому можно установить несколько Prometheus-stack в одном кластере, и они не будут пересекаться.
Теперь нужно обновить RabbitMQ. Предварительно мы указываем аутентификационные переменные auth.password и auth.erlangCookie, загрузив их из секретов, так как иначе будет предупреждение о том, что переменные уже были созданы:
export RABBITMQ_PASSWORD=$(kubectl get secret --namespace stage rabbitmq -o jsonpath=”{.data.rabbitmq-password}” | base64 --decode)
export RABBITMQ_ERLANG_COOKIE=$(kubectl get secret --namespace stage rabbitmq -o jsonpath=”{.data.rabbitmq-erlang-cookie” | base64 --decode)
Теперь можно обновлять RabbitMQ:
helm -n stage upgrade rabbitmq -f values.rabbitmq.stage.yaml --set auth.password=$RABBITMQ_PASSWORD --set auth.erlangCookie=$RABBITMQ_ERLANG_COOKIE ./rabbitmq
После перезапуска RabbitMQ с помощью kubectl get crd в списке ресурсов появится servicemonitors — наш новый ресурс:
И в нем — rabbitmq, который создал Helm Chart RabbitMQ через:
kubectl -n stage get servicemonitors
Если вывести содержимое сервисного монитора rabbitmq, то увидим правила его работы. В namespaceSelector указан отслеживаемый Namespace — stage. В matchLabels описаны искомые метки подов — instance: rabbitmq, name: rabbitmq. Таким образом, монитор находит Endpoints всех подходящих подов и добавляет их в список мониторинга Prometheus:
Если мы сейчас обновим таргеты в Prometheus, то увидим в списке stage/rabbitmq/0. Helm Chart добавил serviceMonitor для RabbitMQ, и Prometheus увидел наш новый сервис:
Теперь здесь можно посмотреть, например, метрику rabbitmq_queue_messages_ready — количество сообщений в статусе Ready. На текущий момент их 0:
Давайте отправим новое сообщение с использованием нашего API:
curl -X POST -d '{"name": "federer20", "video_url": "https://youtube.com/watch?v=n2wfFRsQ-qk" }' -H 'X-API-KEY: 804b95f13b714ee9912b19861faf3d25' -s http://api.stage.kis.im/requests | jq .
Запрос добавлен:

Значение метрики в Prometheus обновится:
Следует учитывать, что метрика rabbitmq_queue_messages_ready показывает общее число сообщений. Если для вашего приложения требуется получение числа сообщений с разбиением по очередям, можно установить другой RabbitMQ Exporter.
Теперь необходимо научиться передавать метрики из Prometheus в Kubernetes, в кастомную группу custom.metrics.k8s.io, чтобы мы могли использовать их для нашего автоскейлинга. По умолчанию Prometheus этого делать не умеет, поэтому установим через Helm еще один продукт — prometheus-adapter с помощью:
helm search repo prometheus-adapter
Загружаем и распаковываем первый Helm-чарт:
helm pull prometheus-community/prometheus-adapter
tar zxvf prometheus-adapter-2.8.1.tgz
Копируем его values.yaml и открываем полученный файл values.pa.stage.yaml для редактирования:
cp prometheus-adapter/values.yaml values.pa.stage.yaml
vi values.pa.stgage.yaml
В файле нас интересует установка URL Prometheus. Прочие настройки можно оставить по умолчанию:
# Url to access prometheus
prometheus:
# Value is templated
url: http://prometheus-stack-kube-prom-prometheus.monitoring.svs
port: 9090
path: ""
Получить искомый URL поможет команда:
kubectl -n monitoring get svc
URL формируется по маске <NAME из вывода команды>.<Namespace (в нашем случае monitoring)>.svc.
Сохраняем yaml-файл и деплоим prometheus-adapter:
helm -n monitoring upgrade --install prometheus-adapter -f values.pa.stage.yaml ./prometheus-adapter/
Все получилось:
После успешной установки он появляется в списке подов, проверяем:
kubectl -n monitoring get pods
Prometheus-adapter создает новую группу метрик в apis/custom.metrics.k8s.io/v1beta1. Мы можем обратиться к ней напрямую:
kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1 | jq . | less
Мы видим все метрики Prometheus, которые prometheus-adapter перенес в Kubernetes:
Чтобы ограничить число метрик, необходимо в файле values.pa.stage.yaml в блоке с правилами переноса метрик rules отключить признак default и указать свои, кастомные метрики. Это более правильный подход:
rules:
default: true
custom: []
# - seriesQuery: '{__name__=~"^some_metric_count$"}'
# resources:
# template: <<.Resource>>
Мы можем посмотреть интересующую нас метрику rabbitmq_queue_messages_ready для всех подов в Namespace stage:
kubectl get --raw /apis/custom.metrics.k8s.io/v1beta1/namespaces/stage/pods/*/rabbitmq_queue_messages_ready | jq . | less
Значение метрики 5751. Это количество сообщений в очереди на текущий момент:
Теперь мы можем отредактировать ранее созданный файл hpa.yaml для Horizontal Pod Autoscaler. В типе метрики type укажем Pods, в названии метрики metricName — rabbitmq_queue_messages_ready, в целевом значении — 1:
metrics:
- type: Pods
pods:
metricName: rabbitmq_queue_messages_ready
targetAverageValue: 1
Сохраняем файл под именем hpa-custom.yaml, удаляем прежнюю версию converter-hpa и применяем новый файл. Теперь при увеличении числа сообщений в очереди Horizontal Pod Autoscaler будет создавать новые поды:
kubectl -n stage delete hpa converter-hpa
kubectl -n stage apply -f hpa-custom.yaml
Во время вебинара эта кастомная метрика у нас почему-то не собиралась. Но позже все заработало, поэтому если у вас будет такая же проблема — попробуйте повторно применить настройки из файла.
Helm-чарт для приложения и настройка CI/CD в GitLab
Следующая задача — автоматизировать развертывание нашего приложения. До этого мы деплоили его через YAML-файлы. Но очевидно, что при большом числе файлов это становится крайне неудобным. Поэтому и появились чарты, внутри которых можно описывать множество шаблонов. Создадим собственный Helm-чарт для деплоя приложения.
Для начала создадим новый репозиторий в GitLab. Назовем его converter-api, сделаем приватным:
У нашего приложения есть Dockerfile, с помощью которого мы его собираем файлы с описанием зависимостей (go.mod, go.sum), и непосредственно код нашего приложения (main.go, requests.go). Эти файлы мы и поместим в репозиторий:
Инициализируем Git, создаем начальный коммит:
git init
git add -A
git commit -m 'Initial commit'
Добавляем удаленный репозиторий origin и отправляем изменения в GitLab:
git remote add origin git@gitlab.com:vozerov/converter-api.git
git push origin master
Вот ссылка на созданный репозиторий: https://gitlab.com/vozerov/converter-api
Рассмотрим содержимое файла gitlab-ci.yml, который описывает наш пайплайн.
В начале мы экспортируем в variables DOCKER_TLS_CERTDIR — это нужно для работы сервиса Docker-in-Docker. Так как мы будем запускаться внутри Docker, в нем нам еще раз понадобится Docker, чтобы собрать контейнер.
Далее идет описание stages: сначала мы билдим, затем деплоим. На стадии build мы логинимся в Docker Hub (используя переменную DOCKER_HUB_TOKEN), после этого применяем команды docker_build и docker_push. И указываем наш образ (IMAGE_NAME), куда это все запушить, и номер версии. Версия будет указываться с помощью хэша Git-коммита (CI_COMMIT_SHORT_SHA).
Поясню подробнее про назначение CI_COMMIT_SHORT_SHA. На каждый push собирается контейнер с тегом хэша коммита. Но кроме сборки и тестирования в автоматическом режиме больше с контейнером ничего не происходит, задеплоить его никуда нельзя. Деплоить можно только теги. Соответственно, когда GitLab видит тег, привязанный к коммиту, он больше не собирает Docker-контейнер, а скачивает предыдущий, который уже был собран и прошел тестирование с этим хэшом:
variables:
DOCKER_TLS_CERTDIR: "/certs"
stages:
- build
- deploy
build:
stage: build
image: docker:latest
services:
- docker:19.03.12-dind
variables:
IMAGE_NAME: vozerov/converter-api:${CI_COMMIT_SHORT_SHA}
before_script:
- echo "$DOCKER_HUB_TOKEN" | docker login -u vozerov --password-stdin
script:
- docker build -t ${IMAGE_NAME} ./
- docker push ${IMAGE_NAME}
Далее переходим к деплою. Деплой использует отдельный образ helm-deployer. Внутри это Alpine с установленными Helm и kubectl. После этого, используя переменную KUBECONFIG, экспортируем настройки Kubernetes, которые необходимы для подключения к кластеру. Добавляем приватный ключ командой gpg (об этом более подробно пойдет речь ниже). И деплоим, используя Helm: переходим в директорию .infra и выполняем стандартный helm upgrade, как мы делали это ранее с RabbitMQ, prometheus-adapter, prometheus-stack и так далее.
При деплое мы устанавливаем converter-api в заданный Namespace и указываем два values-файла: values и secrets. Secrets необходимы нам для того, чтобы не хранить секретные переменные в environment либо файле, о чем мы ранее говорили. Также добавляем image.tag, который устанавливает версию (тег) нашего Docker-образа, который необходимо задеплоить. И в завершение указываем директорию с чартом (chart/).
Совместно с ключом –wait можно использовать ключ –atomic. В таком случае, если при деплое не обновится какой-то ресурс, произойдет откат релиза. Однако wait не выводит логи. Поэтому вместо него можно использовать дополнительные утилиты для вывода логов при деплое, например, werf/kubedog. Он позволяет в real-time режиме получать сообщения о запуске контейнеров, ошибках и так далее:
.deploy_template:
stage: deploy
image: vozerov/helm-deployer:latest
script:
# Setting up kubeconfig
- export KUBECONFIG=${KUBECONFIG}
# Setup GPG for Helm secrets
- echo "$HELM_GPG_KEY" > .helm_secrets_gpg_key.key
- gpg --allow-secret-key-import --import .helm_secrets_gpg_key.key
# Deploy via Helm
- cd .infra/
- helm secrets upgrade --wait --install converter-api --namespace ${KUBE_NAMESPACE} --values values.${BUILD_VARIANT}.yaml --values secrets.${BUILD_VARIANT}.yaml --set image.tag=${CI_COMMIT_SHORT_SHA} chart/
Далее в gitlab-ci.yml следует описание двух environment: deploy_dev и deploy_prod. Для первой будут браться файлы values.dev.yaml и secrets.dev.yaml, для второй values.stage.yaml и secrets.stage.yaml. Так как мы в своем проекте вместо dev использовали stage, отредактируем файл — пропишем в блоке deploy_dev в переменных KUBE_NAMESPACE и BUILD_VARIANT значение stage вместо dev:
deploy_dev:
extends: .deploy_template
variables:
KUBE_NAMESPACE: "stage"
BUILD_VARIANT: "stage"
environment:
name: dev
when: manual
deploy_prod:
extends: .deploy_template
variables:
KUBE_NAMESPACE: "prod"
BUILD_VARIANT: "prod"
environment:
name: prod
only:
- master
when: manual
Переходим к настройке переменных, на которые ссылается gitlab-ci.yml.
Во-первых, необходимо указать DOCKER_HUB_TOKEN, чтобы мы могли подключиться к DOCKER_HUB. Для этого я перехожу на hub.docker.com и создаю новый публичный репозиторий converter-api:
Далее в Docker Hub выбираем «Account Settings» и в пункте меню «Security» создаем новый токен с именем VK:
После создания открывается окно, откуда можно скопировать сгенерированный токен:
Возвращаемся в GitLab и выбираем раздел «Settings» — «CI/CD» — «Variables». Создаем новую переменную с именем DOCKER_HUB_TOKEN, присваиваем ей значение скопированного токена, убираем флажок Protect variable, чтобы переменная была доступна во всех Branch:
Следующая переменная для настройки — KUBECONFIG. Она необходима, чтобы мы из Docker-образа могли подключиться к нашему кластеру. Самый простой вариант ее заполнения — взять содержимое файла kub-vc-dev_kubeconfig.yaml и полностью перенести его в переменную. Но при этом будут переданы полные права абсолютно на весь кластер. Это не самое правильное решение.
Поэтому стоит обратиться к RBAC (Role Based Access Control), доступному в Kubernetes. Принцип работы RBAC можно объяснить на примере трех простых файлов. У меня они расположены в папке roles: sa.yaml, role.yaml, rb.yaml:
В файле sa.yaml описывается создание нового сервисного аккаунта. В метаданных указывается его имя — deployer:
apiVersion: v1
kind: ServiceAccount
metadata:
name: deployer
Применяем полученный файл kubectl -n stage apply -f sa.yaml и создаем аккаунт. Если вывести список сервисных аккаунтов с помощью kubectl -n stage get sa, в нем отобразится созданный нами deployer:
При создании сервисный аккаунт сразу формирует себе секрет — токен, под которым он может обращаться к Kubernetes API:
kubectl -n stage get sa deployer -o yaml
Видим имя этого секрета:
Мы можем вывести содержимое секрета по его имени с помощью:
kubectl -n stage get secret deployer-token-p4r7q -o yaml
Если мы декодируем его в base64, то получим соответствующий токен. Запишем его в переменную TOKEN с помощью:
TOKEN=$(echo '<...token...>' | base64 -d)
Переходим к файлу role.yaml. В нем создается роль и описываются действия, доступные для пользователей, которым эта роль назначена. Здесь для различных API групп определяются доступные ресурсы (в секции resources) и способ доступа к ним (в секции Verbs). Символ * в Verbs означает, что возможны любые действия с ресурсом: get, list, update, watch, create и так далее:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: deployer
rules:
- apiGroups:
- ""
resources:
- pods
- pods/log
- services
- configmaps
- secrets
verbs:
- '*'
- apiGroups:
- "apps"
resources:
- deployments
- replicasets
verbs:
- '*'
- apiGroups:
- "extensions"
resources:
- ingresses
verbs:
- '*'
Применяем файл role.yaml для создания роли deployer:
kubectl -n stage apply -f role.yaml
Наконец, в файле rb.yaml (Role Binding) сервисный аккаунт и роль связываются друг с другом:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: deployer-rb
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: deployer
subjects:
- kind: ServiceAccount
name: deployer
Применяем файл rb.yaml. После этого аккаунту deployer будет сопоставлена роль deployer:
kubectl -n stage apply -f rb.yaml
Следует учесть, что созданные нами Role и Role Binding не кластерные, они относятся только к одному Namespace. В остальных Namespace аккаунту все будет запрещено. Для добавления доступа к нескольким Namespace нужно использовать Cluster Role и Cluster Role Binding. Логика работы с ними точно такая же.
Теперь применим команду set-credentials для добавления нового пользователя deployer-stage в kubectl config. При добавлении укажем токен, сохраненный ранее в переменную TOKEN:
kubectl config set-credentials deployer-stage --token=$TOKEN
Теперь мы можем работать под данным пользователем. Далее изменяем текущий контекст, выбирая пользователя deployer-stage:
kubectl config set-context --current --user=deployer-stage
И можем проверить созданные ограничения доступа. Попробуем вывести поды в Namespace stage с помощью:
kubectl -n stage get pods
Команда выполнилась успешно, а теперь попробуем вывести поды в Namespace default с помощью:
<strong>kubectl get pods default
Команда завершилась с ошибкой Forbidden и сообщением «User “system:serviceaccount:stage:deployer” cannot list resource “pods” in API group ““ in the namespace “default”».
Также мы не добавляли пользователю права на выполнение pods exec, то есть заходить внутрь пода — поэтому мы, например, не сможем выполнить команду:
kubectl -n stage exec -it ubuntu -- bash
Но созданного пользователя вполне хватит для того, чтобы деплоить наши изменения.
Теперь нам остается лишь добавить переменную в GitLab. Для этого копируем содержимое обновленного файла kub-vc-dev_kubeconfig.yaml в значение новой переменной KUBECONFIG в GitLab:
cat ~/Downloads/kub-vc-dev_kubeconfig.yaml
И видим содержимое файла kub-vc-dev_kubeconfig.yaml:
При копировании важно в секции users оставить только добавленного нами пользователя deployer-stage с его токеном. Остальных пользователей необходимо убрать при добавлении значения переменной.
В качестве типа переменной необходимо выбрать File. Это означает, что в переменной KUBECONFIG будет путь к файлу с введенным содержимым. Это важно, так как kubectl будет смотреть на этот файл:
Последняя переменная, которую нам необходимо заполнить в GitLab — это HELM_GPG_KEY. Она связана с использованием утилиты Sops для шифрования секретов. Давайте перейдем в папку Infra. У нас здесь находятся файлы values и secrets для сред prod и stage:
В файлах values мы храним открытые переменные, например, информацию по Ingress, public_env_variables и так далее. Это все можно отдавать в открытый доступ:
ingress:
annotations: {}
fqdn: api.dev.kis.im
public_env_variables:
LISTEN: ":8080"
А в файлах secrets у нас хранятся зашифрованные переменные: RABBIT_URI, PGSQL_URI и так далее. Посмотрим:
cat secrets.stage.yaml
Для шифрования используется Sops — утилита от создателей Mozilla, которая применяет PGP-ключи для шифрования и дешифрования файлов. Для просмотра ключей можно вызвать команду:
gpg -k
Для демонстрации работы Sops создадим новый текстовый файл test.txt, используя публичную часть PGP-ключа:
sops --pgp F46CF40C2EAC453F7AD8F7B6584B4F8E7AB03AFC text.txt
Внутри файла укажем некоторый текст и сохраним его:
Теперь при открытии файла в поле data можно увидеть зашифрованное значение:
Чтобы дешифровать файл, применим команду:
sops –d test.txt
То есть логика такая: вы создаете у себя локально PGP-ключ, с помощью него и Sops выполняете шифрование секретных переменных и отправляете все в Git-репозиторий. А для того, чтобы это расшифровали члены вашей команды, вы передаете им приватную часть PGP-ключа, например, через One Time Secret или One Password. Они импортируют ключ себе и после этого могут работать с секретными переменными.
Конечно, использовать Sops необязательно, это один из возможных вариантов работы с секретами. Но в нашем проекте мы его используем — поэтому заполним переменную HELM_GPG_KEY значением приватной части PGP-ключа. Для этого возьмем публичную часть ключа и применим к ней команду:
gpg --armor --export-secret-key --ex F46CF40C2EAC453F7AD8F7B6584B4F8E7AB03AFC
Создадим в GitLab переменную HELM_GPG_KEY и скопируем в нее результат вывода предыдущей команды:
Вернемся к файлу gitlab-ci.yml, чтобы пояснить работу с ключами PGP. Здесь сначала происходит импорт приватной части ключа из переменной HELM_GPG_KEY. Затем с использованием плагина secrets секреты расшифровываются и передаются в helm, который выполняет деплой:
# Setup GPG for Helm secrets
- echo "$HELM_GPG_KEY" > .helm_secrets_gpg_key.key
- gpg --allow-secret-key-import --import .helm_secrets_gpg_key.key
# Deploy via Helm
- cd .infra/
- helm secrets upgrade --wait --install converter-api --namespace ${KUBE_NAMESPACE} --values values.${BUILD_VARIANT}.yaml --values secrets.${BUILD_VARIANT}.yaml --set image.tag=${CI_COMMIT_SHORT_SHA} chart/
Теперь кратко пройдемся по описанию нашего Helm-чарт. Переходим в папку /app-git/.infra/chart. Основное, что здесь есть — это папка templates, в которой описаны все ресурсы, которые необходимо создать для приложения:
Открываем deployment.yaml. В нем указываются метаданные, Labels, количество реплик, селекторы и так далее.
Здесь стоит обратить внимание на environment-переменные. Переменные из public_env_variables сразу прописываются в Deployment. Приватные переменные из private_env_variables предварительно создаются в секретах, а здесь для них в секции valueFrom указывается, в каком они находятся секрете и под каким ключом. Сами секреты создаются в secret.yaml:
env:
{{- range $key, $value := .Values.public_env_variables }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
{{- range $key, $value := .Values.private_env_variables }}
- name: {{ $key }}
valueFrom:
secretKeyRef:
name: {{ $root.Chart.Name }}-env
key: {{ $key }}
{{- end }}
Выполняем отправку всех внесенных изменений в GitLab и переходим к запуску наших пайпланов. Сначала выполняем Build:
Затем деплоим на Dev и Prod:
В случае успешной сборки можно применить команду helm -n stage list и увидеть наш релиз converter-api, который автоматически создаст все необходимые ресурсы:
Например, если применить команду kubectl -n stage get ingress, то можно увидеть добавленный converter-api-chart:
Соответственно, с этого момента все изменения можно отправлять в Git: чарты, переменные и так далее. Будет производиться автоматический деплой, а ручные действия больше не понадобятся.
Выводы: чему мы научились
Мы с вами рассмотрели основные этапы построения Cloud-Native приложения на базе Kubernetes-кластера. Подобрали оптимальную архитектуру для нужд нашей системы и последовательно добавили все необходимые компоненты: API-сервер, брокер сообщений RabbitMQ, базу данных PostgreSQL, бакет S3 и обработчики, отвечающие за конвертацию видео в текст. Много работали непосредственно с самим кластером: выполнили его настройку в облаке и познакомились с большим количеством команд его клиента kubectl. Научились деплоить приложения как через YAML-файлы, так и через Helm Charts. Наконец, коснулись таких важных моментов, как автомасштабирование, мониторинг и построение CI/CD-конвейеров.
Разумеется, мы охватили далеко не все возможности K8s. Да и приложение было далеко не самым сложным. Однако перед собой я ставил цель показать вам, что Kubernetes, о котором многие пишут и говорят, но далеко не все решаются использовать, не так сложен на практике. А при использовании Managed-решений от облачных провайдеров работа с Kubernetes-кластером становится по-настоящему удобной и быстрой: как минимум, сокращается время настройки и уменьшаются затраты на оборудование благодаря автомасштабированию.
Надеюсь, представленная в статье информация поможет вам начать работу с Kubernetes либо вывести ее на более качественный уровень.