- PVSM.RU - https://www.pvsm.ru -

Мы в Dailymotion начали использовать Kubernetes в продакшене 3 года назад. Но развертывать приложения на нескольких кластерах то еще удовольствие, поэтому в последние несколько лет мы старались улучшить наши инструменты и рабочие процессы.
Здесь мы расскажем, как мы развертываем наши приложения на нескольких кластерах Kubernetes по всему миру.
Чтобы развернуть несколько объектов Kubernetes разом, мы используем Helm [1], и все наши чарты хранятся в одном репозитории git. Чтобы развернуть полный стек приложения из нескольких сервисов, мы используем так называемый обобщающий чарт. По сути, это чарт, который объявляет зависимости и позволяет инициализировать API и его сервисы одной командой.
Еще мы написали небольшой скрипт Python поверх Helm, чтобы делать проверки, создавать чарты, добавлять секреты и развертывать приложения. Все эти задачи выполняются на центральной платформе CI с помощью образа docker.
Перейдем к сути.
Примечание. Когда вы это читаете, первый релиз-кандидат Helm 3 уже был объявлен. Основная версия содержит целый набор улучшений, призванных решить некоторые проблемы, с которыми мы сталкивались в прошлом.
Для приложений мы используем ветвление, и этот же подход решили применить к чартам.
У каждой среды есть свой частный репозиторий, который хранит наши чарты, и мы используем Chartmuseum [2] с очень полезными API. Таким образом мы гарантируем строгую изоляцию между средами и проверку чартов в реальных условиях, прежде чем использовать их в продакшене.
Репозитории чартов в разных средах
Стоит отметить, что когда разработчики отправляют ветвь dev, версия их чарта автоматически отправляется в dev Chartmuseum. Таким образом все разработчики используют один репозиторий dev, и нужно внимательно указывать свою версию чарта, чтобы случайно не использовать чьи-нибудь изменения.
Более того, наш небольшой скрипт Python проверяет объекты Kubernetes по спецификациям Kubernetes OpenAPI с помощью Kubeval [4], прежде чем опубликовать их в Chartmusem.
Было время, когда мы использовали федерацию кластеров Kubernetes [7], где можно было объявлять объекты Kubernetes из одной конечной точки API. Но возникли проблемы. Например, некоторые объекты Kubernetes нельзя было создать в конечной точке федерации, поэтому было сложно обслуживать объединенные объекты и другие объекты для отдельных кластеров.
Чтобы решить проблему, мы стали управлять кластерами независимо, что значительно упростило процесс (использовали первую версию federation; во второй что-то могло поменяться).
Сейчас наша платформа распределена по 6 регионам — 3 локально и 3 в облаке.
[8]
Распределенное развертывание
4 глобальных значения Helm позволяют определять различия между кластерами. Для всех наших чартов есть минимальные значения по умолчанию.
global:
cloud: True
env: staging
region: us-central1
clusterName: staging-us-central1
Глобальные значения
Эти значения помогают определить контекст для наших приложений и используются для разных задач: мониторинг, трассировка, логирование, совершение внешних вызовов, масштабирование и т. д.
Вот конкретный пример:
{{/* Returns Horizontal Pod Autoscaler replicas for GraphQL*/}}
{{- define "graphql.hpaReplicas" -}}
{{- if eq .Values.global.env "prod" }}
{{- if eq .Values.global.region "europe-west1" }}
minReplicas: 40
{{- else }}
minReplicas: 150
{{- end }}
maxReplicas: 1400
{{- else }}
minReplicas: 4
maxReplicas: 20
{{- end }}
{{- end -}}
Пример шаблона Helm
Эта логика определена во вспомогательном шаблоне, чтобы не засорять Kubernetes YAML.
Наши инструменты развертывания основаны на нескольких файлах YAML. Ниже приведен пример того, как мы объявляем сервис и его топологию масштабирования (количество реплик) в кластере.
releases:
- foo.world
foo.world: # Release name
services: # List of dailymotion's apps/projects
foobar:
chart_name: foo-foobar
repo: git@github.com:dailymotion/foobar
contexts:
prod-europe-west1:
deployments:
- name: foo-bar-baz
replicas: 18
- name: another-deployment
replicas: 3
Определение сервиса
Это схема всех шагов, которые определяют наш рабочий процесс развертывания. Последний шаг развертывает приложение одновременно на нескольких рабочих кластерах.
[9]
Шаги развертывания в Jenkins
Что касается безопасности, мы отслеживаем все секреты из разных мест и храним их в уникальном хранилище Vault [10] в Париже.
Наши инструменты развертывания извлекают значения секретов из Vault и, когда приходит время развертывания, вставляют их в Helm.
Для этого мы определили сопоставление между секретами в Vault и секретами, которые нужны нашим приложениям:
secrets:
- secret_id: "stack1-app1-password"
contexts:
- name: "default"
vaultPath: "/kv/dev/stack1/app1/test"
vaultKey: "password"
- name: "cluster1"
vaultPath: "/kv/dev/stack1/app1/test"
vaultKey: "password"
apiVersion: v1
data:
{{- range $key,$value := .Values.secrets }}
{{ $key }}: {{ $value | b64enc | quote }}
{{ end }}
kind: Secret
metadata:
name: "{{ .Chart.Name }}"
labels:
chartVersion: "{{ .Chart.Version }}"
tillerVersion: "{{ .Capabilities.TillerVersion.SemVer }}"
type: Opaque
Сейчас мы разделяем разработку чартов и приложений. Это значит, что разработчикам приходится работать в двух репозиториях git: один для приложения, а второй — для определения его развертывания в Kubernetes. 2 репозитория git — это 2 рабочих процесса, и новичку легко запутаться.
Как мы уже говорили, обобщенные чарты очень удобны для определения зависимостей и быстрого развертывания нескольких приложений. Но мы используем --reuse-values, чтобы избежать передачи всех значений каждый раз, когда мы развертываем приложение, входящее в этот обобщенный чарт.
В рабочем процессе непрерывной поставки у нас всего два значения, которые меняются регулярно: количество реплик и тег образа (версия). Другие, более стабильные значения, изменяются вручную, и это довольно сложно. Более того, одна ошибка в развертывании обобщенного чарта может привести к серьезным сбоям, как мы убедились на собственном опыте.
Когда разработчик добавляет новое приложение, ему приходится изменять несколько файлов: объявление приложения, список секретов, добавление приложения в зависимости, если оно входит в обобщенный чарт.
Сейчас у нас есть один AppRole [11], который читает все секреты из Vault.
Для отката нужно выполнить команду на нескольких кластерах, а это чревато ошибками. Мы выполняем эту операцию вручную, чтобы гарантированно указать правильный идентификатор версии.
Мы хотим вернуть чарт в репозиторий приложения, которое он развертывает.
Рабочий процесс будет таким же, как для разработки. Например, когда ветвь отправляется в мастер, развертывание будет запускаться автоматически. Основная разница между таким подходом и текущим рабочим процессом будет в том, что все будет управляться в git (само приложение и способ его развертывания в Kubernetes).
Преимуществ несколько:
Наши разработчики используют этот рабочий процесс уже 2 года, так что нам нужна максимально безболезненная миграция. Поэтому мы решили добавить промежуточный этап на пути к цели.
Первый этап простой:
apiVersion: "v1"
kind: "DailymotionRelease"
metadata:
name: "app1.ns1"
environment: "dev"
branch: "mybranch"
spec:
slack_channel: "#admin"
chart_name: "app1"
scaling:
- context: "dev-us-central1-0"
replicas:
- name: "hermes"
count: 2
- context: "dev-europe-west1-0"
replicas:
- name: "app1-deploy"
count: 2
secrets:
- secret_id: "app1"
contexts:
- name: "default"
vaultPath: "/kv/dev/ns1/app1/test"
vaultKey: "password"
- name: "dev-europe-west1-0"
vaultPath: "/kv/dev/ns1/app1/test"
vaultKey: "password"
Мы поговорили со всеми разработчиками, так что процесс миграции уже начался. Первый этап по-прежнему контролируется с использованием платформы CI. Скоро я напишу еще один пост о втором этапе: как мы перешли на рабочий процесс GitOps с Flux [12]. Я расскажу, как мы все настроили и с какими трудностями столкнулись (несколько репозиториев, секреты и т. д.). Следите за новостями.
Здесь мы попытались описать наш прогресс в рабочем процессе развертывания приложений за последние годы, который привел к мыслям о подходе GitOps. Мы еще не достигли цели и будем сообщать о результатах, но сейчас убеждены, что правильно сделали, когда решили все упростить и приблизить к привычкам разработчиков.
Автор: nAbdullin
Источник [13]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/sistemnoe-administrirovanie/323002
Ссылки в тексте:
[1] Helm: https://helm.sh/
[2] Chartmuseum: https://chartmuseum.com/
[3] Image: https://habrastorage.org/webt/rz/vt/uk/rzvtuk6q7b_rkeaxnyujzhmfjog.png
[4] Kubeval: https://kubeval.instrumenta.dev/
[5] Image: https://habrastorage.org/webt/yd/cw/qw/ydcwqw-vqfitu5bj8ky4nh7xxea.png
[6] gazr.io: https://gazr.io/
[7] федерацию кластеров Kubernetes: https://kubernetes.io/docs/concepts/cluster-administration/federation/
[8] Image: https://habrastorage.org/webt/jq/c1/mr/jqc1mru36g5byams4wddzducauw.png
[9] Image: https://habrastorage.org/webt/iu/qh/xk/iuqhxki4nfqoi0mus258j0feylu.png
[10] Vault: https://www.vaultproject.io/
[11] AppRole: https://www.vaultproject.io/docs/auth/approle.html
[12] Flux: https://github.com/weaveworks/flux
[13] Источник: https://habr.com/ru/post/458934/?utm_source=habrahabr&utm_medium=rss&utm_campaign=458934
Нажмите здесь для печати.