У нас есть проект, работающий в Kubernetes, которые необходимо запустить миграции SQL во время развертывания.
Чтобы запустить миграцию надо клонировать репозиторий GitHub и запустить на самом деле миграции, хранящиеся в нем.
В настоящее время это делается с Kubernetes initContainers и есть два из них — первый с Гит клонирует репозиторий с файлами миграций в Кубернаны объем , а потом еще один с SQL-мигрировать Запускает эти миграции из этого общего объема.
Тем не менее, есть несколько вопросов с этим подходом:
- Каждый раз, когда мы запускаем новый POD, он управляет своими инициаторами и миграциями
- Если развертывание раскрутит пару стручков — каждый запускает миграции
- Если миграции будут работать на w whume и не будут отвечать на готовность Kubernetes — он может быть убит без отделки миграций
Чтобы избежать все вышеперечисленного, давайте перенастроить процесс, используя Kubernetes Работа Чтобы запустить только один POD и добавив Хелм крючки Чтобы вызвать миграцию во время развертывания.
Примечание: KK вот псевдоним для kubectl.
Подготовка
Docker Image
Сначала давайте создадим наш собственный докерный образ с Blackjack и Git и https://github.com/rubenv/sql-migrate Отказ
Создать DockerFile:
FROM golang:alpine AS builder RUN apk add --no-cache git gcc g++ RUN go get -v github.com/rubenv/sql-migrate/sql-migrate RUN mv /go/bin/sql-migrate /bin/sql-migrate
Построить и толкать его:
$ docker build -t projectname/sql-migrate-git . $ docker push projectname/sql-migrate-git
Аутентификация Git.
Второе вещью — аутентификация GitHub.
На данный момент наш Git-Container аутентифицируется через ключ RSA, который проводится в секретах Kubernetes, то он проходит в POD через переменную среды, откуда она принимается скриптом Bash /opt/git/git.sh который используется для создания ключевого файла /root/.ssh/id_rsa Внутри контейнера, и этот ключ, наконец, используется для аутентификации.
initcontainers В нашем развертывании в настоящее время выглядит следующим:
...
initContainers:
- name: git-clone
image: projectname/git-cloner
env:
- name: SSH_PRIVATE_KEY
valueFrom:
secretKeyRef:
name: git-ssh-key
key: id_rsa
- name: REPOSITORY_URL
value: {{ .Values.git.repo }}
- name: GIT_BRANCH
value: {{ .Values.git.branch }}
command: ['sh', '-c', '/opt/git/git.sh']
volumeMounts:
- name: git-volume
mountPath: "/git"
readOnly: false
- name: init-migration
image: fufuhu/sql-migrate:latest
command: ['sh', '-c', 'while [! -d /git/db/migrations]; do sleep 2; done && sleep 2; /bin/sql-migrate up -config=/config/config.yaml -env=main']
volumeMounts:
- name: migration-config
mountPath: "/config/"
readOnly: true
- name: git-volume
mountPath: "/git"
readOnly: false
...
Много шагов, много объектов, сложный процесс.
Вместо этого будем использовать логин и Github токен который будет передан в наш контейнер из переменных среды, а затем мы можем клонировать репозиторий через HTTPS.
Давайте проверим это:
~ # export GIT_AUTHUSER=backend-user ~ # export GIT_AUTHKEY=cdc***0fe ~ # git clone [https://$GIT_AUTHUSER:$GIT_AUTHKEY@github.com/projectname-dev/backend-services.git](https://%24GIT_AUTHUSER:%24GIT_AUTHKEY@github.com/projectname-dev/backend-services.git) Cloning into 'backend-services'… … Receiving objects: 100% (5115/5115), 846.55 KiB | 1.30 MiB/s, done. Resolving deltas: 100% (2826/2826), done.
Хорошо, «это работает» ©
Миграция SQL в Куберане
Теперь мы можем начать писать файл манифеста Шаблоны/appname-api-mygrations.yaml Для описания нашей работы Kubernetes, которая позже будет вызвать рулем крюка.
Работа Kubernetes
Гит клон
Во-первых, чтобы убедиться, что работа работает — давайте напишем его без переменных и значений HELM, все переменные среды POD будут установлены в виде открытых значений, а действие здесь будет Гит клон теперь:
apiVersion: batch/v1
kind: Job
metadata:
name: "migration-job"
labels:
annotations:
spec:
backoffLimit: 0
template:
metadata:
name: "migration-job-pod"
spec:
restartPolicy: Never
containers:
- name: db-migrations
image: projectname/sql-migrate-git:latest
command: ["/bin/sh", "-c"]
args:
- git clone --single-branch --branch develop [https://backend-user:cdc***0fe@github.com/projectname/backend-services.git](https://backend-user:cdc***0fe@github.com/projectname/backend-services.git) &&
ls -l backend-services/db/migrations
Здесь, в RestArtPolicy Мы установили не перезапустить контейнер, если он не удается, так как мы хотели бы видеть, что миграции были выполнены неудачными, и то же самое в Backofflimit = 0 — Чтобы не повторно создать стручок, если он не удастся и просто оставьте работу с Не удалось статус.
В Гит клон Филиал будет установлен из задания Jenkins, пользователь и URL-адрес будут установлены в Значения.yaml и токен аутентификации будет храниться с Секреты Helm Позже переместит его в переменную среды.
Создайте работу:
$ kk -n eks-dev-1-appname-api-ns apply -f appname-api-jobs.yaml job.batch/migration-job created
Проверьте свои журналы:
$ kk -n eks-dev-1-appname-api-ns logs job/migration-job Cloning into 'backend-services'… total 20 -rw-r — r — 1 root root 538 Oct 24 12:20 BS_1_init_schema.up.sql -rw-r — r — 1 root root 180 Oct 24 12:20 BS_2_add_brand_field.up.sql -rw-r — r — 1 root root 225 Oct 24 12:20 BS_3_alter_table.up.sql -rw-r — r — 1 root root 194 Oct 24 12:20 BS_4_add_created_at_field.sql -rw-r — r — 1 root root 272 Oct 24 12:20 BS_5_alter_table_nourishment_diet.up.sql
Репозиторий был клонирован, теперь доступны миграционные фильмы.
Проверьте статус POD:
$ kk -n eks-dev-1-appname-api-ns get pod NAME READY STATUS RESTARTS AGE migration-job-f72vs 0/1 Completed 0 9s
И статус работы:
$ kk -n eks-dev-1-appname-api-ns get job NAME COMPLETIONS DURATION AGE migration-job 1/1 2s 5s
Теперь может продолжаться с точным процессом миграции.
Секретарь
Чтобы запустить миграции, нам нужно создать файл конфигурации, который будет храниться в Kubernetes Configmap , но в этом файле пароль базы данных должен быть установлен.
Не очень хорошая идея хранить его в открытом тексте в конфигурации и файле, но SQL-мигрировать Позволяет использовать переменную среды в файле, проверять свою документацию — https://github.com/rubenv/sql-migrate#as-a-standalone-tool
Итак, мы создадим переменную для POD под названием $ Db_password , и сохранит фактический пароль в секретах Кубератеса, а затем в Хелме, мы будем использовать Секреты Helm Хранить его зашифровано в значениях графика.
Также в этом секретах мы будем хранить значение для $ Git_token Переменная среды для использования в Гит клон команда.
Еще в Шаблоны/appname-api-mygrations.yaml Добавить секрет:
... --- apiVersion: v1 kind: Secret metadata: name: backend-db-password type: Opaque stringData: db_password: password git_token: cdc***0fe
В spec.containers.env Из вакансии добавляют переменные и обновите Гит клон использовать $ Git_token переменная:
...
containers:
- name: db-migrations
image: projectname/sql-migrate-git:latest
command: ["/bin/sh", "-c"]
args:
- git clone --single-branch --branch develop [https://backend-user:$GIT_TOKEN@github.com/projectnamev/backend-services.git](https://backend-user:%24GIT_TOKEN@github.com/projectnamev/backend-services.git) &&
ls -l backend-services/db/migrations;
cat /config/config.yaml
env:
- name: GIT_TOKEN
valueFrom:
secretKeyRef:
name: backend-db-password
key: git_token
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: backend-db-password
key: db_password
...
Configmap.
Далее создайте конфигурацию, чтобы сохранить /config/config.yaml Содержание для SQL-мигрировать и использовать $ Db_password Переменная в нем:
...
---
apiVersion: v1
kind: ConfigMap
metadata:
name: migration-config
data:
config.yaml: |
main:
dialect: mysql
datasource: backend-user:${DB_PASSWORD}@tcp(stage.backend-db3-master.example.com:3306)/dbname?parseTime=true
dir: backend-services/db/migrations
table: backend_services_migrations
В шаблоне POD работой добавляют объемы, а в SPEC.Containers через Облумерены Установите громкость с помощью конфигурации как /config/config.yaml файл.
Полный манифест работы сейчас следующий:
apiVersion: batch/v1
kind: Job
metadata:
name: "migration-job"
labels:
annotations:
spec:
backoffLimit: 0
template:
metadata:
name: "migration-job-pod"
spec:
restartPolicy: Never
containers:
- name: db-migrations
image: projectname/sql-migrate-git:latest
command: ["/bin/sh", "-c"]
args:
- git clone --single-branch --branch develop [https://backend-user:$GIT_TOKEN@github.com/projectname/backend-services.git](https://backend-user:%24GIT_TOKEN@github.com/projectname/backend-services.git) &&
ls -l backend-services/db/migrations;
cat /config/config.yaml
env:
- name: GIT_TOKEN
valueFrom:
secretKeyRef:
name: backend-db-password
key: git_token
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: backend-db-password
key: db_password
volumeMounts:
- name: migration-config
mountPath: "/config/config.yaml"
subPath: "config.yaml"
readOnly: true
volumes:
- name: migration-config
configMap:
name: migration-config
items:
- key: "config.yaml"
path: "config.yaml"
...
Запустить его:
$ kk -n eks-dev-1-appname-api-ns apply -f appname-api-jobs.yaml job.batch/migration-job created secret/backend-db-password created configmap/migration-config created
Проверять:
$ kk -n eks-dev-1-appname-api-ns logs job/migration-job
Cloning into 'backend-services'…
total 20
-rw-r — r — 1 root root 538 Oct 24 13:41 BS_1_init_schema.up.sql
-rw-r — r — 1 root root 180 Oct 24 13:41 BS_2_add_brand_field.up.sql
-rw-r — r — 1 root root 225 Oct 24 13:41 BS_3_alter_table.up.sql
-rw-r — r — 1 root root 194 Oct 24 13:41 BS_4_add_created_at_field.sql
-rw-r — r — 1 root root 272 Oct 24 13:41 BS_5_alter_table_nourishment_diet.up.sql
main:
dialect: mysql
datasource: backend-user:${DB_PASSWORD}@tcp(stage.backend-db3-master.example.com:3306)/dbname?parseTime=true
dir: backend-services/db/migrations
table: backend_services_migrations
Хорошо — репозиторий был клонирован, создан конфигурационный файл.
Бег миграции
И теперь мы можем описать процесс миграции, пока -Дрирун Опция, а со второй командой — проверьте его статус:
...
args:
- git clone --single-branch --branch develop [https://backend-user:$GIT_TOKEN@github.com/projectname/backend-services.git](https://backend-user:%24GIT_TOKEN@github.com/projectname/backend-services.git) &&
ls -l backend-services/db/migrations &&
cat /config/config.yaml &&
/bin/sql-migrate up -config=/config/config.yaml -env=main -dryrun &&
/bin/sql-migrate status -config=/config/config.yaml -env=main
...
Беги и проверьте свои журналы:
$ kk -n eks-dev-1-appname-test-migrations-ns logs job/migration-job
Cloning into 'backend-services'…
total 20
-rw-r — r — 1 root root 538 Oct 24 14:02 BS_1_init_schema.up.sql
-rw-r — r — 1 root root 180 Oct 24 14:02 BS_2_add_brand_field.up.sql
-rw-r — r — 1 root root 225 Oct 24 14:02 BS_3_alter_table.up.sql
-rw-r — r — 1 root root 194 Oct 24 14:02 BS_4_add_created_at_field.sql
-rw-r — r — 1 root root 272 Oct 24 14:02 BS_5_alter_table_nourishment_diet.up.sql
main:
dialect: mysql
datasource: backnd-user:${DB_PASSWORD}@tcp(stage.backend-db3-master.example.com:3306)/dbname?parseTime=true
dir: backend-services/db/migrations
table: backend_services_migrations
+ — — — — — — — — — — — — — — — — — — — — — + — — — — — — — — — — — — — — — -+
| MIGRATION | APPLIED |
+ — — — — — — — — — — — — — — — — — — — — — + — — — — — — — — — — — — — — — -+
| BS_1_init_schema.up.sql | 2020–05–07 12:21:25 +0000 UTC |
| BS_2_add_brand_field.up.sql | 2020–05–12 14:31:17 +0000 UTC |
| BS_3_alter_table.up.sql | 2020–05–13 06:17:25 +0000 UTC |
| BS_4_add_created_at_field.sql | 2020–07–21 09:55:49 +0000 UTC |
| BS_5_alter_table_nourishment_diet.up.sql | 2020–07–21 09:55:49 +0000 UTC |
+ — — — — — — — — — — — — — — — — — — — — — + — — — — — — — — — — — — — — — -+
Теперь можно перейти к хелме.
Шаблон хелма
Что нам нужно сделать в старом графике?
- Удалить
initcontainers - Удалить старые секреты
- Переместить значения для наших новых переменных в
Values.yaml. - Переместите пароль токена и базы данных в
Secrets.yaml.
И основная часть здесь состоит в том, чтобы добавить аннотации, чтобы вызвать процесс миграции во время Helm развертывать
Добавьте Аннотации на работу:
apiVersion: batch/v1
kind: Job
metadata:
name: {{ .Chart.Name }}-migration-job
labels:
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-weight": "-1"
"helm.sh/hook-delete-policy": before-hook-creation
spec:
backoffLimit: 0
...
Здесь:
"helm.sh/hook": предварительная установка, предварительное обновление: запустить работу доhelm установитьилиОбновление(В нашем трубопроводе Дженкинса он начался сSecrets Helm Uppreade --install)"helm.sh/hook very": "-1": Приоритет создания ресурсов, как сначала нам нужно создать конфигурацию и секрет, который будет использоваться нашей работой, поэтому установить вес меньше, чем для работы"helm.sh/hook-delete-policy": значение по умолчанию — раньше крюк-творчество (Проверьте документацию ), установите, если для тестирования, а затем его можно изменить на Крюк-успех (Но в этом случае вы не сможете проверить журналы, если миграция потерпит неудачу)
Добавьте Аннотации Блок на конфигурацию и секреты с Крюк-вес меньше, чем на работе.
Манифест Configmap теперь полный контент:
---
apiVersion: v1
kind: ConfigMap
metadata:
name: migration-config
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-weight": "-5"
"helm.sh/hook-delete-policy": before-hook-creation
data:
config.yaml: |
main:
dialect: {{ .Values.backendConfig.db.driver }}
datasource: {{ .Values.backendConfig.db.user }}:${DB_PASSWORD}@tcp({{ .Values.backendConfig.db.host }}:{{ .Values.backendConfig.db.port }})/{{ .Values.backendConfig.db.database }}?parseTime=true
dir: backend-services/db/migrations
table: {{ .Values.backendConfig.db.migrationsTable }}
Секретный:
---
apiVersion: v1
kind: Secret
metadata:
name: {{ .Chart.Name }}-migration-secrets
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-weight": "-10"
"helm.sh/hook-delete-policy": before-hook-creation
type: Opaque
stringData:
backend-db-password: {{ .Values.backendConfig.db.password }}
git_token: {{ .Values.git.token }}
И работа:
apiVersion: batch/v1
kind: Job
metadata:
name: {{ .Chart.Name }}-migration-job
labels:
annotations:
"helm.sh/hook": pre-install,pre-upgrade
"helm.sh/hook-weight": "-1"
"helm.sh/hook-delete-policy": before-hook-creation
spec:
backoffLimit: 0
template:
metadata:
name: {{ .Chart.Name }}-migration-job-pod
spec:
restartPolicy: Never
containers:
- name: {{ .Chart.Name }}-db-migrations
image: projectname/sql-migrate-git:latest
command: ["/bin/sh", "-c"]
args:
- git clone --single-branch --branch {{ .Values.git.branch }} [https://{{](https://%7B%7B) .Values.git.user }}:$GIT_TOKEN@{{ .Values.git.repo }} &&
ls -l backend-services/db/migrations &&
cat /config/config.yaml &&
/bin/sql-migrate up -config=/config/config.yaml -env=main || exit 1;
/bin/sql-migrate status -config=/config/config.yaml -env=main
env:
- name: GIT_TOKEN
valueFrom:
secretKeyRef:
name: {{ .Chart.Name }}-migration-secrets
key: git_token
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Chart.Name }}-migration-secrets
key: backend-db-password
volumeMounts:
- name: migration-config
mountPath: "/config/config.yaml"
subPath: "config.yaml"
readOnly: true
volumes:
- name: migration-config
configMap:
name: migration-config
items:
- key: "config.yaml"
path: "config.yaml"
Здесь я добавил Выход 1 к /bin/sql-migrate u Так что работа будет Потерпеть неудачу В случае ошибок во время миграции и, следовательно, не запускают процесс развертывания.
Беги в Дженкинс:
В Крючки Мы видим, что сначала секрет был создан, как у него есть Вес крючка ":" -10 " , затем configmap, и работа наконец.
И процесс развертывания выглядит сейчас, как следующий:
Сначала удаляется секрет, конфигурация и ресурсы рабочих мест (в соответствии с точкой «HELM.SH/Hook-delete-policy»: перед тем, как создано для создания крюка ), а затем созданы.
Проверьте статус работы:
$ kk -n eks-stage-1-appname-api-ns get job NAME COMPLETIONS DURATION AGE appname-api-migration-job 1/1 3s 6m21s
Его журналы:
$ kk -n eks-stage-1-appname-api-ns logs job/appname-api-migration-job
Cloning into 'backend-services'…
total 20
-rw-r — r — 1 root root 538 Oct 26 11:32 BS_1_init_schema.up.sql
-rw-r — r — 1 root root 180 Oct 26 11:32 BS_2_add_brand_field.up.sql
-rw-r — r — 1 root root 225 Oct 26 11:32 BS_3_alter_table.up.sql
-rw-r — r — 1 root root 194 Oct 26 11:32 BS_4_add_created_at_field.sql
-rw-r — r — 1 root root 272 Oct 26 11:32 BS_5_alter_table_nourishment_diet.up.sql
main:
dialect: mysql
datasource: backend-user:${DB_PASSWORD}@tcp(stage.backend-db3-master.example.com:3306)/dbname?parseTime=true
dir: backend-services/db/migrations
table: backend_services_migrations
Applied 0 migrations
+ — — — — — — — — — — — — — — — — — — — — — + — — — — — — — — — — — — — — — -+
| MIGRATION | APPLIED |
+ — — — — — — — — — — — — — — — — — — — — — + — — — — — — — — — — — — — — — -+
| BS_1_init_schema.up.sql | 2020–05–07 12:21:25 +0000 UTC |
| BS_2_add_brand_field.up.sql | 2020–05–12 14:31:17 +0000 UTC |
| BS_3_alter_table.up.sql | 2020–05–13 06:17:25 +0000 UTC |
| BS_4_add_created_at_field.sql | 2020–07–21 09:55:49 +0000 UTC |
| BS_5_alter_table_nourishment_diet.up.sql | 2020–07–21 09:55:49 +0000 UTC |
+ — — — — — — — — — — — — — — — — — — — — — + — — — — — — — — — — — — — — — -+
Наносится 0 миграции , поскольку в файлах миграций нет изменений после последнего Применяется Отказ
Все сделано.
Первоначально опубликовано в RTFM: Linux, DevOps и системное управление Отказ
Оригинал: «https://dev.to/setevoy/kubernetes-running-sql-migrations-with-kubernetes-job-and-helm-hook-503j»