В этой статье мы покажем, как правильно использовать и хранить секретную и несекретную конфигурацию приложения.
В предыдущих статьях конфигурация добавлялась прямо в контейнеры при сборке или использовалась как есть в переменных окружения контейнеров при развёртывании.
Теперь для безопасности и гибкости конфигурация будет сохраняться в ConfigMap и Secret. А в дополнение к параметрам Helm-чарта (Values) и секретам werf будут продемонстрированы подходы параметризации и переиспользования конфигурации, а также хранения конфиденциальных данных вместе с кодом в Git-репозитории проекта.
Приложение в этой статье не предназначено для использования в production без доработки. Готовое к работе в production приложение мы получим в конце руководства.
Подготовка окружения
Если вы ещё не подготовили своё рабочее окружение на предыдущих этапах, сделайте это в соответствии с инструкциями статьи «Подготовка окружения».
Если ваше рабочее окружение работало, но перестало, или же последующие инструкции из этой статьи не работают — попробуйте следующее:
Запустим приложение Docker Desktop. Приложению понадобится некоторое время для того, чтобы запустить Docker. Если никаких ошибок в процессе запуска не возникло, то проверим, что Docker запущен и корректно настроен:
docker run hello-world
Результат успешного выполнения команды:
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
b8dfde127a29: Pull complete
Digest: sha256:9f6ad537c5132bcce57f7a0a20e317228d382c3cd61edae14650eec68b2b345c
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
При возникновении проблем обратитесь к документации Docker для их устранения.
Запустим приложение Docker Desktop. Приложению понадобится некоторое время для того, чтобы запустить Docker. Если никаких ошибок в процессе запуска не возникло, то проверим, что Docker запущен и корректно настроен:
docker run hello-world
Результат успешного выполнения команды:
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
b8dfde127a29: Pull complete
Digest: sha256:9f6ad537c5132bcce57f7a0a20e317228d382c3cd61edae14650eec68b2b345c
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
При возникновении проблем обратитесь к документации Docker для их устранения.
Запустим Docker:
sudo systemctl restart docker
Убедимся, что Docker запустился:
sudo systemctl status docker
Результат выполнения команды, если Docker успешно запущен:
● docker.service - Docker Application Container Engine
Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
Active: active (running) since Thu 2021-06-24 13:05:17 MSK; 13s ago
TriggeredBy: ● docker.socket
Docs: https://docs.docker.com
Main PID: 2013888 (dockerd)
Tasks: 36
Memory: 100.3M
CGroup: /system.slice/docker.service
└─2013888 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
dockerd[2013888]: time="2021-06-24T13:05:16.936197880+03:00" level=warning msg="Your kernel does not support CPU realtime scheduler"
dockerd[2013888]: time="2021-06-24T13:05:16.936219851+03:00" level=warning msg="Your kernel does not support cgroup blkio weight"
dockerd[2013888]: time="2021-06-24T13:05:16.936224976+03:00" level=warning msg="Your kernel does not support cgroup blkio weight_device"
dockerd[2013888]: time="2021-06-24T13:05:16.936311001+03:00" level=info msg="Loading containers: start."
dockerd[2013888]: time="2021-06-24T13:05:17.119938367+03:00" level=info msg="Loading containers: done."
dockerd[2013888]: time="2021-06-24T13:05:17.134054120+03:00" level=info msg="Daemon has completed initialization"
systemd[1]: Started Docker Application Container Engine.
dockerd[2013888]: time="2021-06-24T13:05:17.148493957+03:00" level=info msg="API listen on /run/docker.sock"
Теперь проверим, что Docker доступен и корректно настроен:
docker run hello-world
Результат успешного выполнения команды:
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
b8dfde127a29: Pull complete
Digest: sha256:9f6ad537c5132bcce57f7a0a20e317228d382c3cd61edae14650eec68b2b345c
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
This message shows that your installation appears to be working correctly.
При возникновении проблем обратитесь к документации Docker для их устранения.
Запустим кластер minikube, уже настроенный в начале статьи “Подготовка окружения”:
minikube start
Выставим Namespace по умолчанию, чтобы не указывать его при каждом вызове kubectl
:
kubectl config set-context minikube --namespace=werf-guide-app
Результат успешного выполнения команды:
😄 minikube v1.20.0 on Ubuntu 20.04
✨ Using the docker driver based on existing profile
👍 Starting control plane node minikube in cluster minikube
🚜 Pulling base image ...
🎉 minikube 1.21.0 is available! Download it: https://github.com/kubernetes/minikube/releases/tag/v1.21.0
💡 To disable this notice, run: 'minikube config set WantUpdateNotification false'
🔄 Restarting existing docker container for "minikube" ...
🐳 Preparing Kubernetes v1.20.2 on Docker 20.10.6 ...
🔎 Verifying Kubernetes components...
▪ Using image gcr.io/google_containers/kube-registry-proxy:0.4
▪ Using image k8s.gcr.io/ingress-nginx/controller:v0.44.0
▪ Using image registry:2.7.1
▪ Using image docker.io/jettech/kube-webhook-certgen:v1.5.1
▪ Using image docker.io/jettech/kube-webhook-certgen:v1.5.1
▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🔎 Verifying registry addon...
🔎 Verifying ingress addon...
🌟 Enabled addons: storage-provisioner, registry, default-storageclass, ingress
🏄 Done! kubectl is now configured to use "minikube" cluster and "werf-guide-app" namespace by default
Убедитесь, что вывод команды содержит строку:
Restarting existing docker container for "minikube"
Если её нет, значит был создан новый кластер minikube вместо использования старого. В таком случае повторите установку рабочего окружения с minikube с самого начала.
Теперь запустите команду в фоновом PowerShell-терминале и не закрывайте его:
minikube tunnel --cleanup=true
Запустим кластер minikube, уже настроенный в начале статьи “Подготовка окружения”:
minikube start --namespace werf-guide-app
Выставим Namespace по умолчанию, чтобы не указывать его при каждом вызове kubectl
:
kubectl config set-context minikube --namespace=werf-guide-app
Результат успешного выполнения команды:
😄 minikube v1.20.0 on Ubuntu 20.04
✨ Using the docker driver based on existing profile
👍 Starting control plane node minikube in cluster minikube
🚜 Pulling base image ...
🎉 minikube 1.21.0 is available! Download it: https://github.com/kubernetes/minikube/releases/tag/v1.21.0
💡 To disable this notice, run: 'minikube config set WantUpdateNotification false'
🔄 Restarting existing docker container for "minikube" ...
🐳 Preparing Kubernetes v1.20.2 on Docker 20.10.6 ...
🔎 Verifying Kubernetes components...
▪ Using image gcr.io/google_containers/kube-registry-proxy:0.4
▪ Using image k8s.gcr.io/ingress-nginx/controller:v0.44.0
▪ Using image registry:2.7.1
▪ Using image docker.io/jettech/kube-webhook-certgen:v1.5.1
▪ Using image docker.io/jettech/kube-webhook-certgen:v1.5.1
▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🔎 Verifying registry addon...
🔎 Verifying ingress addon...
🌟 Enabled addons: storage-provisioner, registry, default-storageclass, ingress
🏄 Done! kubectl is now configured to use "minikube" cluster and "werf-guide-app" namespace by default
Убедитесь, что вывод команды содержит строку:
Restarting existing docker container for "minikube"
Если её нет, значит был создан новый кластер minikube вместо использования старого. В таком случае повторите установку рабочего окружения с minikube с самого начала.
Если вы непреднамеренно удалили Namespace приложения, то необходимо выполнить следующие команды, чтобы продолжить прохождение руководства:
kubectl create namespace werf-guide-app
kubectl create secret docker-registry registrysecret \
--docker-server='https://index.docker.io/v1/' \
--docker-username='<ИМЯ ПОЛЬЗОВАТЕЛЯ DOCKER HUB>' \
--docker-password='<ПАРОЛЬ ПОЛЬЗОВАТЕЛЯ DOCKER HUB>'
Результат успешного выполнения команды:
namespace/werf-guide-app created
secret/registrysecret created
Если ничего не помогло, то пройдите статью «Подготовка окружения» с начала, подготовив новое окружение с нуля. Если и это не помогло, тогда, пожалуйста, расскажите о своей проблеме в нашем Telegram или оставьте Issue на GitHub, и мы обязательно вам поможем.
Подготовка репозитория
Обновим существующий репозиторий с приложением:
Выполним следующий набор команд в PowerShell:
cd ~/werf-guide/app
# Чтобы увидеть, какие изменения мы собрались вносить далее в этой статье, заменим все файлы приложения
# в репозитории новыми, уже измененными файлами приложения, которые содержат описанные далее изменения.
git rm -r .
cp -Recurse -Force ~/werf-guide/guides/examples/laravel/080_configuration/* .
git add .
git commit -m WIP
# Показать, какие файлы мы собираемся изменить.
git show --stat
# Показать изменения.
git show
Выполним следующий набор команд в Bash:
cd ~/werf-guide/app
# Чтобы увидеть, какие изменения мы собрались вносить далее в этой статье, заменим все файлы приложения
# в репозитории новыми, уже измененными файлами приложения, которые содержат описанные далее изменения.
git rm -r .
cp -rf ~/werf-guide/guides/examples/laravel/080_configuration/. .
git add .
git commit -m WIP
# Показать, какие файлы мы собираемся изменить.
git show --stat
# Показать изменения.
git show
Не работает? Попробуйте инструкции на вкладке «Начинаю проходить руководство с этой статьи» выше.
Подготовим новый репозиторий с приложением:
Выполним следующий набор команд в PowerShell:
# Склонируем репозиторий с примерами в ~/werf-guide/guides, если он ещё не был склонирован.
if (-not (Test-Path ~/werf-guide/guides)) {
git clone https://github.com/werf/website $env:HOMEPATH/werf-guide/guides
}
# Скопируем файлы приложения (пока без изменений) в ~/werf-guide/app.
rm -Recurse -Force ~/werf-guide/app
cp -Recurse -Force ~/werf-guide/guides/examples/laravel/050_s3 ~/werf-guide/app
# Сделаем из директории ~/werf-guide/app git-репозиторий.
cd ~/werf-guide/app
git init
git add .
git commit -m initial
# Чтобы увидеть, какие изменения мы собрались вносить далее в этой статье, заменим все файлы приложения
# в репозитории новыми, уже измененными файлами приложения, которые содержат описанные далее изменения.
git rm -r .
cp -Recurse -Force ~/werf-guide/guides/examples/laravel/080_configuration/* .
git add .
git commit -m WIP
# Показать, какие файлы мы собираемся изменить.
git show --stat
# Показать изменения.
git show
Выполним следующий набор команд в Bash:
# Склонируем репозиторий с примерами в ~/werf-guide/guides, если он ещё не был склонирован.
test -e ~/werf-guide/guides || git clone https://github.com/werf/website ~/werf-guide/guides
# Скопируем файлы приложения (пока без изменений) в ~/werf-guide/app.
rm -rf ~/werf-guide/app
cp -rf ~/werf-guide/guides/examples/laravel/050_s3 ~/werf-guide/app
# Сделаем из директории ~/werf-guide/app git-репозиторий.
cd ~/werf-guide/app
git init
git add .
git commit -m initial
# Чтобы увидеть, какие изменения мы собрались вносить далее в этой статье, заменим все файлы приложения
# в репозитории новыми, уже измененными файлами приложения, которые содержат описанные далее изменения.
git rm -r .
cp -rf ~/werf-guide/guides/examples/laravel/080_configuration/. .
git add .
git commit -m WIP
# Показать, какие файлы мы собираемся изменить.
git show --stat
# Показать изменения.
git show
ConfigMap и Secret
В Kubernetes есть специальные типы ресурсов ConfigMap и Secret, которые предназначены для отделения конфигурации, зависящей от среды и окружения, от образов контейнеров.
Оба ресурса позволяют хранить данные в парах «ключ-значение» и впоследствии использовать их как переменные окружения, аргументы командной строки или как файлы, примонтированные в выбранный контейнер.
ConfigMap предназначен для хранения неконфиденциальных данных, в отличие от Secret, который используется для хранения различных типов секретов.
Подробнее про эти типы ресурсов можно почитать в официальной документации Kubernetes (ConfigMaps, Secrets). Далее мы разберём частые случаи их использования на примере нашего приложения.
Хранение конфигурационных файлов приложения в ConfigMap
Сейчас конфигурационный файл nginx.conf копируется в образ прямо во время сборки. Из-за этого при каждом его изменении будут происходить пересборка образа и перезапуск Pod’ов. Также сейчас нет простой возможности шаблонизировать nginx.conf
.
Эти проблемы решаются, если перенести .werf/nginx.conf
в отдельный ConfigMap — для того, чтобы монтировать nginx.conf
во время развертывания, а не добавлять файл при сборке:
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-conf
data:
nginx.conf: |
user nobody;
worker_processes 1;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format json_combined escape=json
'{'
'"time_local":"$time_iso8601",'
'"client_ip":"$http_x_forwarded_for",'
'"remote_addr":"$remote_addr",'
'"remote_user":"$remote_user",'
'"request":"$request",'
'"status":"$status",'
'"body_bytes_sent":"$body_bytes_sent",'
'"request_time":"$request_time",'
'"http_referrer":"$http_referer",'
'"http_user_agent":"$http_user_agent",'
'"request_id":"$request_id"'
'}';
access_log /dev/stdout json_combined;
server {
listen 8080;
server_name _;
root /www;
index index.php;
error_page 404 /index.php;
charset utf-8;
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
# Отдадим ассеты напрямую из файловой системы NGINX-контейнера.
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location = /favicon.ico { access_log off; log_not_found off; }
location = /robots.txt { access_log off; log_not_found off; }
# Все запросы, кроме запросов на получение ассетов, отправляются на php-fpm-бэкенд.
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php-fpm.sock;
fastcgi_param DOCUMENT_ROOT /app/public;
fastcgi_param SCRIPT_FILENAME /app/public/$fastcgi_script_name;
include fastcgi_params;
}
}
}
Теперь добавим этот ConfigMap в Deployment, примонтировав его как файл внутрь контейнера frontend
:
...
- name: frontend
image: {{ .Values.werf.image.frontend }}
ports:
- containerPort: 8080
name: http
volumeMounts:
- mountPath: /var/run/php
name: run-php
- mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
name: nginx-conf
Не забудем удалить более ненужный файл .werf/nginx.conf
, а также команду копирования этого файла в образ во время сборки, после чего сборка образа frontend
станет выглядеть так:
...
# NGINX-образ с публичными файлами.
FROM nginx:stable-alpine as frontend
WORKDIR /www
# Копируем публичные файлы из assets образа.
COPY --from=assets /app/public /www
EXPOSE 8080
Перезапуск Deployment при изменении ConfigMap и Secret
По умолчанию, изменения в ConfigMap и Secret, примонтированных к Deployment, StatefulSet или DaemonSet, не приведут к перезапуску Pod’ов с новой конфигурацией. Чтобы Pod’ы обновились, их нужно аннотировать хеш-суммами всех используемых Pod’ом ConfigMap и Secret. Тогда при изменении ConfigMap и Secret аннотация изменится и Pod пересоздастся. Так выглядит аннотация с хеш-суммой ConfigMap с nginx.conf
:
...
template:
metadata:
labels:
app: werf-guide-app
annotations:
checksum/configmap-nginx: '{{ include (print $.Template.BasePath "/configmap-nginx.yaml") . | sha256sum }}'
Для каждого подключенного ConfigMap и Secret потребуется отдельная аннотация.
Авторы самоучителя предпочитают вместо аннотаций с хеш-суммами использовать операторы вроде stakater/Reloader, т.к. они проще, гибче и удобнее в работе.
Values
Использование Helm-чарта для развёртывания приложения даёт ряд преимуществ — например, возможность шаблонизировать манифесты. Ключевой встроенный объект шаблонизации — это Values
, который предоставляет доступ к значениям, передаваемым в чарт из различных источников.
При использовании werf все данные, передаваемые в chart, можно условно разделить на несколько категорий:
- обычные пользовательские данные: параметры из файлов
values.yaml
и соответствующих опций; - пользовательские секреты: параметры из файлов
secret-values.yaml
; - сервисные данные: информация о проекте, релизе, собранных образах и т.д.
Переиспользование конфигурации с Values и ConfigMap
Для упрощения конфигурации манифестов часто используемые параметры можно выносить в .helm/values.yaml
:
...
mysql:
storageSize: "100Mi"
… и далее использовать в манифесте следующим образом:
...
volumeClaimTemplates:
- metadata:
name: mysql-data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: "{{ .Values.mysql.storageSize }}"
Это также позволит иметь разные значения для разных окружений, о чем более подробно будет рассказано в следующих разделах самоучителя.
Но особенно полезным будет перенос в .helm/values.yaml
повторяющейся конфигурации, например, переменных окружения для приложения, которые мы используем в нескольких местах сразу:
...
app:
envs:
LOG_CHANNEL: stderr
LOG_STDERR_FORMATTER: Monolog\\Formatter\\JsonFormatter
LOG_LEVEL: info
DB_HOST: mysql
DB_DATABASE: werf-guide-app
AWS_ENDPOINT: "http://minio:9000"
AWS_DEFAULT_REGION: us-east-1
AWS_BUCKET: werf-guide-app
AWS_USE_PATH_STYLE_ENDPOINT: "true"
Теперь переменные окружения из .Values.app.envs
можно либо подставлять в манифест в env
контейнера, как было сделано ранее, либо вынести эти переменные окружения в ConfigMap, который потом подключить в контейнер через envFrom
.
Первый вариант проще, но вариант с ConfigMap удобнее при большом количестве общих переменных окружения, т.к. позволит избежать их дублирования между контроллерами. ConfigMap может выглядеть так:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-envs
data:
{{- range $key, $val := .Values.app.envs }}
"{{ $key }}": "{{ $val }}"
{{- end }}
Подключаем этот ConfigMap через envFrom
в Deployment как набор переменных окружения:
...
containers:
- name: backend
image: {{ .Values.werf.image.backend }}
volumeMounts:
- mountPath: /var/run/php
name: run-php
envFrom:
- configMapRef:
name: app-envs
Не забываем про аннотации с хеш-суммами, которые приведут к пересозданию Pod’ов при изменении ConfigMap:
...
template:
metadata:
labels:
app: werf-guide-app
annotations:
checksum/configmap-nginx: '{{ include (print $.Template.BasePath "/configmap-nginx.yaml") . | sha256sum }}'
checksum/configmap-app-envs: '{{ include (print $.Template.BasePath "/configmap-app-envs.yaml") . | sha256sum }}'
Аналогично этот ConfigMap подключается и в остальные ресурсы, в которых требуются те же переменные окружения.
Использование конфиденциальных данных с Values и Secret
Чтобы начать работу с секретами, сначала требуется сгенерировать симметричный ключ шифрования, что можно сделать командой werf helm secret generate-secret-key
. Однако, поскольку мы уже заранее подготовили и зашифровали секреты, то и ключ шифрования мы сгенерировали за вас. Он находится в репозитории в файле .werf_secret_key
и начнёт использоваться автоматически.
При работе с реальными приложениями ключ НЕЛЬЗЯ хранить в репозитории. Вместо этого рекомендуется передавать его через переменную окружения
WERF_SECRET_KEY
, храня его в безопасном месте. Подробнее про работу с ключами шифрования можно прочитать в документации werf.
Конфигурация приложения содержит данные, которые не должны храниться в незашифрованном виде в репозитории — например, логин и пароль от базы данных. Вместо того, чтобы хранить логин и пароль в открытом виде в манифесте контроллера, мы будем хранить их зашифрованными в .helm/secret-values.yaml
вместе с другими секретными параметрами:
app:
secretEnvs:
APP_KEY: 10000f02004508feddf9746539c6f937238dfa0bb1cdf3e628547721d868ad1ba5b5a9a97535d7a4d218355bd2a0df22972e90b2a2c91a0f1e754c2c0b40aa4145b44d9c202535f945d95e14f3bb20399b65
DB_USERNAME: 1000eb0a862c8a80dec5e7cd5c179177e9fe68ecc55896a01f0f16f5212c4ad9522d
DB_PASSWORD: 10001bd1c973a299589f796896bcdb9afce3840dd3990537a18fd453ed7b2dca6747
AWS_ACCESS_KEY_ID: 10004ce322cc0d7b02845cfa4b2b2a1f8b9a24dbb1849b6229484af470374b97ca7c
AWS_SECRET_ACCESS_KEY: 1000ee9f9f758763cdfef3a8e78565bb05b0364bb6b6b43fca06cd4016f149d965f2
mysql:
secretEnvs:
MYSQL_ROOT_PASSWORD: 10007d80d8b6dff5ef78b73866b2fc7c167615f5974fa9b4f68b44595b8c203be855
minio:
secretEnvs:
MINIO_ROOT_USER: 1000347c3348673966f1f6a0c037ad8bdd3cda7cfedc989b8a0edf7a1b97fad99e8c
MINIO_ROOT_PASSWORD: 1000216183bc27254749b6012ed68bb6af7d298e6b64d63ade285ed5f5d5da202000
Чтобы увидеть расшифрованными секреты, хранящиеся в .helm/secret-values.yaml
, можно выполнить следующую команду:
werf helm secret values decrypt .helm/secret-values.yaml
Ожидаемый результат:
app:
secretEnvs:
APP_KEY: base64:GcPVmSxMZwsOJtNOJ9eVNNeU6B5buHuln93+w0TSvfE=
DB_USERNAME: root
DB_PASSWORD: password
AWS_ACCESS_KEY_ID: minioadmin
AWS_SECRET_ACCESS_KEY: minioadmin
mysql:
secretEnvs:
MYSQL_ROOT_PASSWORD: password
minio:
secretEnvs:
MINIO_ROOT_USER: minioadmin
MINIO_ROOT_PASSWORD: minioadmin
Теперь нужно передать секреты из .helm/secret-values.yaml
обратно в конфигурационный файл приложения. Для этого сначала передадим их в ресурс Secret:
apiVersion: v1
kind: Secret
metadata:
name: app-envs
type: Opaque
data:
{{- range $key, $val := .Values.app.secretEnvs }}
"{{ $key }}": "{{ $val | b64enc }}"
{{- end }}
… а затем примонтируем Secret в контейнеры как набор переменных окружения:
...
containers:
- name: backend
image: {{ .Values.werf.image.backend }}
volumeMounts:
- mountPath: /var/run/php
name: run-php
envFrom:
- configMapRef:
name: app-envs
- secretRef:
name: app-envs
Изменения в остальных файлах .helm/templates
для вынесения секретной конфигурации в Secret аналогичны, поэтому приводить здесь листинги не будем, на их содержимое можно посмотреть в репозитории.
Для хранения и монтирования секретных конфигурационных файлов целиком также можно использовать Secret. Выглядит это аналогично использованию ConfigMap для монтирования несекретных файлов конфигурации, описанному выше, за тем лишь исключением, что само содержание Secret должно храниться зашифрованным в файлах .helm/secret/...
или в .helm/secret-values.yaml
. Подробнее об этом можно прочитать в документации werf.
Больше информации по работе с секретами также доступно в документации werf.
Проверка работоспособности
Убедимся, что изменения в конфигурации не повлияли на работоспособность приложения:
werf converge --repo <ИМЯ ПОЛЬЗОВАТЕЛЯ DOCKER HUB>/werf-guide-app
Ожидаемый результат:
...
┌ ⛵ image backend
│ ┌ Building stage backend/dockerfile
│ │ backend/dockerfile Sending build context to Docker daemon 533kB
│ │ backend/dockerfile Step 1/19 : FROM php:8.0-fpm-alpine as base
│ │ backend/dockerfile ---> 52c511f481c5
...
│ │ backend/dockerfile Successfully built 91ec44f42d84
│ │ backend/dockerfile Successfully tagged d972fcf1-88cc-4a11-a2b8-e76e397914f1:latest
│ ├ Info
│ │ name: <DOCKER HUB USERNAME>/werf-guide-app/werf-guide-app:b12f6a22c119f88d808e9bf5daf5bb0eab8138f0539769e478647e70-1634037356083
│ │ id: 91ec44f42d84
│ │ created: 2022-10-12 14:15:55 +0000 UTC
│ │ size: 58.9 MiB
│ └ Building stage backend/dockerfile (19.73 seconds)
└ ⛵ image backend (24.98 seconds)
┌ ⛵ image frontend
│ ┌ Building stage frontend/dockerfile
│ │ frontend/dockerfile Sending build context to Docker daemon 533kB
│ │ frontend/dockerfile Step 1/29 : FROM php:8.0-fpm-alpine as base
│ │ frontend/dockerfile ---> 52c511f481c5
...
│ │ frontend/dockerfile Successfully built a61e4952387d
│ │ frontend/dockerfile Successfully tagged b6cc14ad-f7d6-47d9-a53d-b53cd80838d3:latest
│ ├ Info
│ │ name: <DOCKER HUB USERNAME>/werf-guide-app/werf-guide-app:55170630d763de2af7ac5f4ca4a3c1bdb4f98c9782e99fdd8b07d2bb-1634037415695
│ │ id: a61e4952387d
│ │ created: 2022-10-12 14:16:55 +0000 UTC
│ │ size: 9.4 MiB
│ └ Building stage frontend/dockerfile (77.28 seconds)
└ ⛵ image frontend (82.49 seconds)
┌ Waiting for release resources to become ready
│ ┌ Status progress
│ │ DEPLOYMENT REPLICAS AVAILABLE UP-TO-DATE
│ │ werf-guide-app 1/1 1 1
│ │ │ POD READY RESTARTS STATUS
│ │ ├── guide-app-54d48f7d4-zvkqd 2/2 0 Running
│ │ └── guide-app-6b8cf46f5b-zj4d9 2/2 0 Terminating
│ │ STATEFULSET REPLICAS READY UP-TO-DATE
│ │ minio 1/1 1 1
│ │ mysql 1/1 0->1 1 ↵
│ │
│ │ │ POD READY RESTARTS STATUS
│ │ └── 0 0/1 0 ContainerCreating
│ └ Status progress
└ Waiting for release resources to become ready (30.34 seconds)
┌ Waiting for helm hook job/migrate-db termination
│ ┌ job/migrate-db po/migrate-db-vvtfd container/migrate-db logs
│ │ mysqld is alive
│ │ Nothing to migrate.
│ └ job/migrate-db po/migrate-db-vvtfd container/migrate-db logs
│
│ ┌ Status progress
│ │ JOB ACTIVE DURATION SUCCEEDED/FAILED
│ │ migrate-db 0 13s 0->1/0
│ │ │ POD READY RESTARTS STATUS
│ │ └── db-vvtfd 0/1 0 Running -> Completed
│ └ Status progress
└ Waiting for helm hook job/migrate-db termination (13.08 seconds)
┌ Waiting for helm hook job/setup-minio termination
│ ┌ Status progress
│ │ JOB ACTIVE DURATION SUCCEEDED/FAILED
│ │ setup-minio 0 13s 0->1/0
│ │ │ POD READY RESTARTS STATUS
│ │ └── minio-d8cmm 0/1 0 Running -> Completed
│ └ Status progress
└ Waiting for helm hook job/setup-minio termination (14.02 seconds)
Release "werf-guide-app" has been upgraded. Happy Helming!
NAME: werf-guide-app
LAST DEPLOYED: Tue Oct 12 14:17:12 2022
NAMESPACE: werf-guide-app
STATUS: deployed
REVISION: 20
TEST SUITE: None
Running time 155.26 seconds
Проверим доступность приложения:
curl http://werf-guide-app.test/ping
Ожидаемый результат:
pong
Теперь секретная конфигурация приложения хранится безопасно, дублирование конфигурации минимизировано, а файлы конфигурации приложений могут шаблонизироваться и больше не требуют пересборок при изменениях.