Из 2024 в 2025: вспоминаем лучшие практики CI/CD
Привет всем читающим. Меня зовут Данил, я DevOps-инженер, работаю в Nixys. Добро пожаловать в 2025 год.
В современном мире разработки ПО скорость выхода новых версий и обновлений имеет решающее значение. Чтобы оставаться конкурентоспособными, компании стремятся сократить время на разработку и внедрение новых функций. Этого можно достичь благодаря таким методологиям, как CI (Continuous Integration, непрерывная интеграция) и CD (Continuous Delivery/Deployment, непрерывная доставка/развертывание).
Если вы вдруг забыли или не знаете, что такое CI/CD.
CI/CD — это ключевые процессы, направленные на автоматизацию и ускорение разработки, тестирования и доставки программного обеспечения. Они позволяют разработчикам объединять свои изменения в единую кодовую базу, что снижает вероятность возникновения ошибок на поздних стадиях. Этот подход также улучшает управление версиями и обеспечивает более частые релизы, что, в свою очередь, увеличивает гибкость и скорость реакции на изменения в требованиях. CI/CD не только ускоряет разработку, но и делает ее более предсказуемой и контролируемой.
Когда компания внедряет CI/CD, она:
Сокращает время на тестирование. Автоматизация позволяет быстро и эффективно запускать тесты, избегая ручных проверок, что ускоряет цикл обратной связи.
Минимизирует ошибки на этапе интеграции. Частые небольшие изменения проще тестировать и обнаруживать ошибки, чем большие обновления, которые могут быть более сложными для тестирования.
Ускоряет вывод продукта на рынок. Благодаря автоматизированным процессам внедрения новых функций или исправлений программного обеспечения, разработчики могут выпускать обновления гораздо быстрее, снижая время вывода на рынок.
Упрощает управление версиями ПО. Каждое изменение кода может быть упаковано в отдельный релиз, что упрощает отслеживание и управление версиями программного обеспечения.
В 2024 году эти процессы продолжили свою эволюцию: появились новые инструменты и подходы. В этой статье вспомним лучшие практики CI/CD, с которыми наша команда встретила новый 2025 год.
Best practices CI/CD
1. Multi-stage сборка Docker-образа
Одной из ключевых рекомендаций является использование multi-stage сборки Docker-образа. Этот подход позволяет значительно уменьшить размер итогового образа, так как в конечный образ попадает только необходимый код и библиотеки, а временные и вспомогательные файлы остаются на стадии сборки.
Преимущества multi-stage сборки:
Минимизация размера финального Docker-образа.
Упрощение управления зависимостями.
Снижение рисков уязвимостей благодаря уменьшению ненужных библиотек.
2. Билд через Kaniko
Kaniko — это инструмент для безопасной сборки Docker-образов внутри Kubernetes-кластера без необходимости привилегированного доступа. Это делает его отличным выбором для использования в CI/CD пайплайнах, где безопасность имеет первостепенное значение.
Основные бенефиты Kaniko:
Безопасность. Kaniko не требует выполнения привилегированных операций, в отличие от Docker-in-Docker (DinD), который может представлять угрозу для безопасности кластера.
Легкость интеграции с Kubernetes. Kaniko легко интегрируется с Kubernetes-платформами, что упрощает процесс автоматизации.
Ускорение повторных сборок. Когда части образа остаются неизменными между сборками, Kaniko использует закэшированные слои, что значительно сокращает время сборки. Это особенно важно при частых запусках пайплайнов.
Простота интеграции с Kubernetes. Kaniko был разработан специально для Kubernetes, поэтому он легко интегрируется с различными системами CI/CD, работающими в Kubernetes-кластерах. Он упрощает автоматизацию процессов сборки образов и их деплоя, минимизируя сложность настройки.
Почему не стоит использовать Docker-in-Docker:
DinD требует привилегированных контейнеров, что делает его менее безопасным в сравнении с Kaniko.
При использовании DinD могут возникать проблемы с производительностью из-за сложностей с запуском Docker внутри Docker.
3. Тегирование и использование protected веток в Gitlab
Для улучшения процесса релизов и управления версиями важно использовать стратегии тегирования и работы с защищёнными ветками (protected branches) в Gitlab:
Тегирование. Все релизы должны сопровождаться уникальными тегами, что позволяет легко отслеживать версионность и фиксировать конкретные состояния приложения.
Protected branches. Защищенные ветки позволяют ограничить доступ к изменению важнейших веток, например, master или production. Это помогает избежать случайных изменений и ошибок в ключевых ветках.
4. Создание репозитория с шаблонами CI
В организациях, где множество проектов, рекомендуется создавать репозитории с шаблонами CI/CD пайплайнов для унификации процессов. Это значительно облегчает масштабирование и управление проектами. Шаблоны позволяют:
Быстро разворачивать новые проекты на базе готовых пайплайнов.
Обеспечить консистентность процессов сборки и деплоя во всех проектах.
Уменьшить время на настройку CI/CD для новых команд.
Однако, если у вас только один проект, лучше использовать один пайплайн без child или downstream пайплайнов, так как это упростит поддержку и отладку процессов, а так же позволит более гибко управлять его логикой.
5. Использование гибких правил для триггера пайплайнов
Часто нет необходимости запускать полный пайплайн на каждое изменение в кодовой базе. Поэтому важно использовать гибкие правила для триггеров:
Триггерить пайплайн только при изменениях в определённых директориях или файлах (например, для деплоя на production запускать пайплайн только при изменениях в папке с конфигурациями).
Ограничение запуска пайплайнов по событиям (например, запускать пайплайн только при слиянии в защищённые ветки).
В рамках данной статьи мы будем использовать следующие инструменты:
Gitlab CI для организации процессов сборки, включая сборку Docker-образа;
ArgoCD для деплоя приложений;
Vault для безопасного хранения и использования секретов, интегрированного на уровне Gitlab CI.
А теперь посмотрим все эти практики в действии.
Лучшие практики CI/CD: билд приложение через GitLab CI
1. Пример multi-stage Dockerfile
Для начала создадим multi-stage Dockerfile, который позволяет собрать минимальный и оптимизированный образ для нашего приложения. В качестве примера используем PHP-приложение:
## common_artifact
FROM registry.examle.ru/infra/ubuntu-base:common AS common_artifact
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN su app -c 'wget --quiet https://repo1.maven.org/maven2/com/google/javascript/closure-compiler/v.../closure-compiler-v....jar -O /opt/closure-tools/compiler.jar --no-check-certificate'
COPY --chown=app:app . /app
ARG db_string
ARG db_user_name
ARG db_password
ARG db_host
ARG db_port
ARG db_name
RUN echo "${db_host} pgsql.db" >> /etc/hosts && \
/usr/bin/php some commads
COPY --chown=app:app ./.infra/files/js_min.sh /app/js_min.sh
RUN su app -c '/bin/bash /app/js_min.sh'
WORKDIR /app/somedir/protected
RUN su app -c '/bin/bash gulpc'
### frontend
FROM registry.examle.ru/infra/nginx-upstream-limit:nginx-gc AS frontend
COPY ./.infra/files/frontend/nginx.conf /etc/nginx/nginx.conf
COPY ./.infra/files/frontend/content /app/somedir/content
COPY . /app
RUN rm -rf /app/somedir/protected/modules \
/app/somedir/protected/resource \
/app/somedir/js \
/app/_sql/sqlLocalizationUpdate*
COPY --from=common_artifact /app/somedir/protected/modules /app/somedir/protected/modules
COPY --from=common_artifact /app/somedir/protected/resource /app/somedir/protected/resource
COPY --from=common_artifact /app/somedir/js /app/somedir/js
COPY --from=common_artifact /app/_sql/sqlLocalizationUpdate* /app/_sql/
## backend
FROM registry.examle.ru/infra/ubuntu-base:backend AS backend
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
ENV LC_ALL=ru_RU.UTF-8
ENV LANG=ru_RU.UTF-8
COPY --chown=app:app ./.infra/files/backend/fonts /usr/share/fonts/TTF
RUN chown -R app:app /usr/share/fonts/TTF && chmod -R 0755 /usr/share/fonts/TTF
COPY ./.infra/files/frontend/wp_content /app/somedir/wp-content
COPY --chown=app:app ./.infra/files/somedir/cron.d /etc/cron.d
COPY --chown=app:app ./.infra/files/somedir/somedir /etc/somedir
COPY --chown=app:app ./.infra/files/somedir/d /etc/service/d
COPY --chown=app:app ./.infra/files/somedir/supercronic_run /etc/service/supercronic/run
COPY --chown=app:app ./.infra/files/backend/php-fpm.conf /etc/php/7.4/fpm/php-fpm.conf
COPY --chown=app:app ./.infra/files/backend/php.ini /etc/php/7.4/cli/php.ini
COPY --chown=app:app ./.infra/files/backend/php-fpm.ini /etc/php/7.4/fpm/php.ini
COPY --chown=app:app . /app
WORKDIR /app
RUN rm -rf /app/somedir/protected/modules \
/app/somedir/protected/resource \
/app/somedir/js \
/app/_sql/sqlLocalizationUpdate* && \
mkdir -p /app/somedir/protected/runtime && \
chown -R app:app /app/somedir/protected/runtime
COPY --from=common_artifact --chown=app:app /app/somedir/protected/modules /app/somedir/protected/modules
COPY --from=common_artifact --chown=app:app /app/somedir/protected/resource /app/somedir/protected/resource
COPY --from=common_artifact --chown=app:app /app/somedir/js /app/somedir/js
COPY --from=common_artifact --chown=app:app /app/_sql/sqlLocalizationUpdate* /app/_sql/
Этот Dockerfile разбит на 3 этапа:
common_artifact stage: установка зависимостей, вписывание аргументов для сборки приложения и его подготовка.
frontend stage: копирование финального приложения в образ, замена и оптимизация кода, минимизируя размер Docker-образа.
backend stage: копирование финального приложения в образ, замена и оптимизация кода, минимизируя размер Docker-образа.
2. Пример шаблона для GitLab CI с Kaniko
Для более гибкого и масштабируемого процесса, мы можем создать отдельный репозиторий с шаблонами для CI/CD. Этот подход особенно полезен для организаций с большим количеством проектов, где требуется унифицированный подход к сборке, тестированию и деплою. В данном случае мы создадим репозиторий, который будет содержать директории для различных этапов CI/CD — сборки, тестирования, деплоя и других шагов.
Структура репозитория с шаблонами CI/CD
ci-templates/
├── build/
│ └── kaniko-build-template.yml
├── test/
│ └── test-template.yml
├── deploy/
│ └── argo-deploy-template.yml
└── .gitlab-ci.yml
Описание директорий:
build/ — содержит шаблоны для сборки Docker-образов, в том числе Kaniko для различных окружений.
test/ — включает шаблоны для автоматизированного тестирования приложений (юнит-тесты, интеграционные тесты).
deploy/ — содержит шаблоны для деплоя, например, с использованием ArgoCD для различных сред (production, staging, development).
.gitlab-ci.yml — основной файл, который инклюдит шаблоны из других директорий и определяет общие правила.
Шаблон для Kaniko-сборки
В директории build/ создадим файл kaniko-build-template.yml, который будет отвечать за этапы сборки для разных окружений. В этом файле определим задачи для prod и dev окружений, используя правила и параметры, специфичные для каждого окружения:
stages:
- build
include:
- local: stage-ci.yml
.build:
stage: build
image:
name: registry-url/infra/kaniko-executor:v1.16.0-debug
entrypoint: [""]
script:
- mkdir -p /kaniko/.docker
- cat ${CR_CONFIG} > /kaniko/.docker/config.json
- touch new-test
- echo "test" >> new-test
- >
/kaniko/executor
--context "${CI_PROJECT_DIR}"
--dockerfile "${DOCKERFILE}"
--destination "registry-url/${REGISTRY}/${IMAGE}"
--cache=true
--cache-repo "registry-url/${REGISTRY}/${CI_PROJECT_NAME}-cache"
build_dev:
extends:
- .build
variables:
REGISTRY: $CR_AGENCY_DEV_ID
CR_CONFIG: $CR_AGENCY_DEV_CONFIG
IMAGE: ${CI_PROJECT_NAME}:${CI_COMMIT_SHORT_SHA}
rules:
- if: $CI_COMMIT_BRANCH =~ /^feature\/.*/
- if: $CI_COMMIT_BRANCH == "develop"
cache:
policy: push
build_prod:
extends:
- .build
variables:
REGISTRY: $CR_AGENCY_PROD_ID
CR_CONFIG: $CR_AGENCY_PROD_CONFIG
IMAGE: ${CI_PROJECT_NAME}:${CI_COMMIT_TAG}
rules:
- if: $CI_COMMIT_TAG != null
build_stage:
extends:
- .build
variables:
REGISTRY: $CR_AGENCY_PROD_ID
CR_CONFIG: $CR_AGENCY_PROD_CONFIG
IMAGE: ${CI_PROJECT_NAME}:${CI_COMMIT_TAG}
rules:
- if: '$CI_COMMIT_REF_NAME == "staging"'
Описание задачи для сборки:
build_template — шаблон, который содержит основные настройки для всех задач сборки, таких как образ Kaniko, кэширование, и авторизация в Docker Registry.
Отдельные задачи для окружений (build.prod, build.dev) — каждая задача предназначена для определённого окружения. Например, для продакшена будет собираться образ с тегом prod, для staging — с тегом stage, и так далее.
Каждое окружение имеет свои правила для триггеров пайплайна:
Сборка для продакшена запускается если коммит происходит с тегом.
Сборка для dev окружения — при коммите в ветку содержащую в название feature, при коммите в ветку develop.
Основной .gitlab-ci.yml файл
Основной файл .gitlab-ci.yml в репозитории проекта должен включать шаблон из директории с шаблонами. Это позволяет повторно использовать шаблоны для разных проектов, что значительно упрощает управление пайплайнами.
include:
- project: 'ci-templates'
file: 'build/kaniko-build-template.yml'
# Определение триггеров для сборки
workflow:
rules:
- if: '$CI_COMMIT_REF_NAME == "main"'
- if: '$CI_COMMIT_REF_NAME == "staging"'
- if: '$CI_COMMIT_REF_NAME == "develop"'
Здесь:
include — подключает шаблон kaniko-build-template.yml из репозитория ci-templates, который содержит всю логику для сборки Docker-образов.
workflow — задает условия для запуска пайплайнов: сборка запускается только при работе с ветками main, staging или develop.
Преимущества данного подхода:
Унификация процессов. Использование шаблонов позволяет обеспечить единообразие процессов CI/CD для всех проектов. Это особенно важно для крупных организаций с большим количеством проектов.
Повторное использование. Шаблоны могут быть использованы в разных проектах, что сокращает время на настройку CI/CD и минимизирует вероятность ошибок.
Гибкость. При необходимости шаблоны можно модифицировать для определённых проектов, сохраняя при этом общую структуру.
Облегчение управления изменениями. Все изменения в пайплайнах можно вносить централизованно, в репозитории с шаблонами. Это упрощает поддержку и обновление CI/CD процессов для всех проектов одновременно.
ArgoCD: перейдём к деплою
Преимущества ArgoCD и почему его стоит использовать
ArgoCD — это мощный инструмент для автоматизации процессов деплоя в Kubernetes с использованием методологии GitOps, что делает его важным элементом CI/CD пайплайнов.
Преимущества ArgoCD:
GitOps-ориентированный деплой. ArgoCD автоматически синхронизирует состояние приложения в кластере с его состоянием в репозитории Git. Это делает деплой полностью управляемым через Git, улучшая контроль версий и прозрачность процессов.
Автоматическая синхронизация. ArgoCD непрерывно следит за изменениями в репозитории и автоматически обновляет Kubernetes-кластер, когда изменения происходят.
Гибкость и поддержка различных инструментов. ArgoCD поддерживает деплой из Helm-чартов, Kustomize, Jsonnet и других методов описания инфраструктуры.
Простота визуализации и управления. Встроенная панель управления (Web UI) позволяет легко следить за состоянием всех приложений, их версиями и статусами синхронизации.
Сравнение ArgoCD с FluxCD
FluxCD и ArgoCD оба являются GitOps-решениями для автоматизации деплоя в Kubernetes, но между ними есть ключевые различия:
Параметр | ArgoCD | FluxCD |
UI | Имеет удобный веб-интерфейс для управления приложениями и отслеживания состояния синхронизации. | Веб-интерфейс отсутствует, управление осуществляется через CLI. |
Поддержка Helm | Полноценная поддержка Helm-чартов и управление релизами через UI. | Поддержка Helm через дополнительный компонент helm-controller. |
Установка и настройка | Более сложная установка и настройка, но более удобное управление после внедрения. | Простая установка, но управление требует использования сторонних инструментов. |
Синхронизация | Поддерживает как ручную, так и автоматическую синхронизацию с возможностью отката изменений. | Основной упор на автоматическую синхронизацию без встроенной поддержки ручных операций. |
В целом, ArgoCD более удобен для команд, которые хотят гибкости в управлении деплоем и удобный интерфейс, в то время как FluxCD больше подходит для сценариев, требующих минимальной инфраструктуры и полной автоматизации.
Установка ArgoCD через Helm
Для того чтобы установить ArgoCD через Helm и настроить его под свои нужды, включая настройку Ingress с хостом argo.example.com, необходимо отредактировать файл values.yaml. Этот файл позволяет кастомизировать установку ArgoCD, включая конфигурацию Ingress, ресурсы, безопасность и другие параметры.
Пример файла values.yaml для ArgoCD с включением Ingress:
# Общие настройки для ArgoCD
global:
image:
repository: argoproj/argocd
tag: v2.9.0 # Укажите актуальную версию ArgoCD
installCRDs: true
# Настройки для сервера ArgoCD
server:
service:
type: ClusterIP
port: 80
# Настройка Ingress для доступа к UI ArgoCD
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: "letsencrypt-prod" # Опционально, если вы используете cert-manager для TLS
hosts:
- host: argo.example.com
paths:
- /
tls:
- secretName: argocd-tls
hosts:
- argo.example.com
# Настройки безопасности
# Определение ресурсов для ArgoCD серверов
controller:
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
repoServer:
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
# Настройка синхронизации проектов
applicationSet:
enabled: true
# Опции RBAC для пользователей
rbacConfig:
policy.default: role:readonly
scopes: "[groups]"
# Автоматическое создание пользователя admin с паролем
initialAdminPassword: "supersecretpassword"
Описание ключевых параметров:
global.image — определяет репозиторий и тег (версию) для образа ArgoCD. Важно указывать актуальную версию.
server.service — указывает тип сервиса для ArgoCD. Мы используем тип ClusterIP, чтобы сервис был доступен только внутри кластера. Если требуется внешний доступ, можно заменить на LoadBalancer.
server.ingress — настройка Ingress контроллера для доступа к веб-интерфейсу ArgoCD:
enabled — включает Ingress.
annotations — опционально добавляем аннотации для интеграции с cert-manager, если требуется автоматическая настройка TLS сертификатов.
hosts — задаёт доменное имя (в данном случае argo.example.com), по которому будет доступен ArgoCD.
tls — настройка для автоматического получения TLS-сертификатов, указав secretName для хранения сертификатов.
controller.resources и repoServer.resources — задают ресурсы для компонентов ArgoCD (ограничения по CPU и памяти).
rbacConfig — позволяет настроить права доступа по умолчанию для пользователей, задавая роль readonly для базовых пользователей.
initialAdminPassword — задаёт начальный пароль для пользователя admin, который будет создан при установке ArgoCD.
Установка ArgoCD с использованием редактированного values.yaml
После редактирования файла values.yaml можно установить ArgoCD с помощью Helm:
Сначала добавим репозиторий Helm для ArgoCD:
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update
Выполним установку ArgoCD с использованием нашего файла values.yaml:
helm install argo-cd argo/argo-cd --namespace argocd --create-namespace -f values.yaml
После завершения установки ArgoCD будет доступен по адресу https://argo.example.com, если настроен правильный DNS и сертификаты для Ingress.
Написание Helm-чарта с использованием nxs-universal-chart
Helm-чарт для приложения будет основан на nxs-universal-chart, который предоставляет универсальные шаблоны для управления различными типами приложений. Пример значений для web-приложения можно взять из образца.
Пример файла values.yml для вашего приложения:
app:
name: "my-app"
version: "1.0.0"
image:
repository: "my-registry/my-app"
tag: "latest"
pullPolicy: "IfNotPresent"
replicaCount: 2
service:
type: "ClusterIP"
port: 80
ingress:
enabled: true
annotations: {}
hosts:
- host: "my-app.example.com"
paths:
- "/"
tls: []
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 50m
memory: 64Mi
Интеграция ArgoCD с GitLab CI
Теперь мы создадим GitLab CI файл для деплоя через ArgoCD в три разных окружения: prod, stage и dev.
Шаблон деплоя с ArgoCD — создадим файл argo-deploy-template.yml:
stages:
- deploy
.deploy_template: &deploy_template
image: bitnami/kubectl:latest
script:
- kubectl config set-cluster $K8S_CLUSTER --server=$K8S_SERVER --insecure-skip-tls-verify=true
- kubectl config set-credentials $K8S_USER --token=$K8S_TOKEN
- kubectl config set-context $K8S_CONTEXT --cluster=$K8S_CLUSTER --user=$K8S_USER
- kubectl config use-context $K8S_CONTEXT
- argocd app sync my-app --prune --timeout 300
# Деплой на production
deploy_prod:
<<: *deploy_template
stage: deploy
environment:
name: production
script:
- argocd app sync my-app-prod --prune --timeout 300
rules:
- if: '$CI_COMMIT_REF_NAME == "main"'
# Деплой на staging
deploy_stage:
<<: *deploy_template
stage: deploy
environment:
name: staging
script:
- argocd app sync my-app-stage --prune --timeout 300
rules:
- if: '$CI_COMMIT_REF_NAME == "staging"'
# Деплой на development
deploy_dev:
<<: *deploy_template
stage: deploy
environment:
name: development
script:
- argocd app sync my-app-dev --prune --timeout 300
rules:
- if: '$CI_COMMIT_REF_NAME == "develop"'
Этот шаблон:
Настраивает kubectl для работы с Kubernetes-кластером через предоставленные переменные (сервер, токен, контекст).
Использует команду argocd app sync для синхронизации приложений в разных окружениях (prod, stage, dev).
Основной .gitlab-ci.yml — инклюдит шаблон:
include:
- local: 'argo-deploy-template.yml'
workflow:
rules:
- if: '$CI_COMMIT_REF_NAME == "main"'
- if: '$CI_COMMIT_REF_NAME == "staging"'
- if: '$CI_COMMIT_REF_NAME == "develop"'
ArgoCD предлагает мощные инструменты для GitOps-ориентированного деплоя приложений, с поддержкой автоматической синхронизации и удобного управления через UI. Мы рассмотрели его установку через Helm, создание Helm-чарта на базе nxs-universal-chart, а также интеграцию с GitLab CI для деплоя в разные окружения.
HashiCorp Vault: Преимущества, Установка и Интеграция с GitLab CI
Преимущества использования Vault
HashiCorp Vault — это инструмент для безопасного управления секретами и доступом к ним в приложениях и инфраструктуре. Он поддерживает шифрование данных, динамическое управление доступом и аудит использования секретов, что делает его важным элементом в CI/CD пайплайнах.
Преимущества Vault:
Централизованное управление секретами. Vault предоставляет единое место для безопасного хранения секретов (пароли, токены, API-ключи и другие конфиденциальные данные), что упрощает управление ими.
Динамическая генерация секретов. Vault может динамически генерировать временные доступы, такие как креды для баз данных или облачных сервисов, которые автоматически истекают через определенное время.
Гибкие политики доступа. Политики позволяют настроить гибкий контроль над доступом к секретам на основе ролей и сервисов.
Аудит и безопасность. Vault ведёт полный аудит использования секретов, что помогает отслеживать и контролировать доступ к конфиденциальным данным.
Шифрование данных в движении и покое. Все секреты в Vault хранятся в зашифрованном виде, что обеспечивает высокий уровень безопасности.
Сравнение Vault с FluxCD Secret Management
Параметр | HashiCorp Vault | FluxCD Secret Management |
Управление секретами | Централизованное, с поддержкой динамических секретов. | Ограничено Kubernetes Secret и интеграцией с SOPS. |
Шифрование | Полноценное шифрование секретов в хранилище и при передаче. | Шифрование секретов через внешние инструменты. |
Политики и доступ | Гибкое управление доступом через политики и роли. | Доступ на основе ролей Kubernetes и RBAC. |
Поддержка облаков и баз данных | Поддерживает динамическое создание временных учетных данных для облаков и баз данных. | Отсутствует поддержка динамических секретов. |
Vault обеспечивает более мощное и гибкое управление секретами, в то время как FluxCD ограничен базовой работой с Kubernetes Secret и интеграцией с инструментами шифрования, такими как SOPS.
Установка Vault через Helm
Чтобы развернуть HashiCorp Vault в Kubernetes-кластере, можно использовать Helm для установки. Установка включает редактирование файла values.yaml для кастомизации конфигурации под ваши нужды.
Добавим репозиторий Helm для Vault:
helm repo add hashicorp https://helm.releases.hashicorp.com
helm repo update
Создадим файл values.yaml, чтобы кастомизировать установку Vault, включая настройку Ingress.
Пример файла values.yaml для Vault с поддержкой Ingress:
server:
# Включение режима HA (High Availability) для Vault
ha:
enabled: true
replicas: 3
# Настройка сервиса для Vault
service:
type: ClusterIP
# Включение и настройка Ingress для доступа к Vault UI
ingress:
enabled: true
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: "letsencrypt-prod" # Опционально, если вы используете cert-manager
hosts:
- host: vault.example.com
paths:
- /
tls:
- hosts:
- vault.example.com
secretName: vault-tls
# Политики и начальные настройки
extraConfig: |
listener "tcp" {
address = "0.0.0.0:8200"
tls_disable = 1
}
storage "file" {
path = "/vault/data"
}
ui = true
# Задание ресурсов для Vault
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 250m
memory: 256Mi
Описание параметров:
ha.enabled — включает режим High Availability (HA) для повышения отказоустойчивости, с тремя репликами Vault.
ingress — настраивает Ingress для доступа к Vault через домен vault.example.com. TLS поддерживается через cert-manager.
extraConfig — конфигурация для работы Vault. Включаем интерфейс UI и определяем хранилище данных.
resources — определение лимитов и запросов по ресурсам для оптимального использования кластера.
Установка Vault с нашим values.yaml:
helm install vault hashicorp/vault --namespace vault --create-namespace -f values.yaml
После установки Vault будет доступен через Ingress по адресу https://vault.example.com.
Интеграция Vault с GitLab CI
Теперь рассмотрим, как интегрировать Vault с GitLab CI для безопасного доступа к секретам во время сборки и деплоя приложения.
1. Шаблон для использования Vault в GitLab CI
Создадим файл vault-secrets-template.yml, который будет использоваться для извлечения секретов из Vault в процессе сборки.
stages:
- build
# Шаблон для использования Vault
.vault_template: &vault_template
image: hashicorp/vault:latest
script:
- vault login $VAULT_TOKEN
- export DB_PASSWORD=$(vault kv get -field=password secret/db-creds)
- echo "Database password retrieved from Vault: $DB_PASSWORD"
# Билд для production
build_prod:
<<: *vault_template
stage: build
environment:
name: production
script:
- vault login $VAULT_TOKEN
- export DB_PASSWORD=$(vault kv get -field=password secret/prod/db-creds)
- ./build.sh
rules:
- if: '$CI_COMMIT_REF_NAME == "main"'
# Билд для staging
build_stage:
<<: *vault_template
stage: build
environment:
name: staging
script:
- vault login $VAULT_TOKEN
- export DB_PASSWORD=$(vault kv get -field=password secret/staging/db-creds)
- ./build.sh
rules:
- if: '$CI_COMMIT_REF_NAME == "staging"'
# Билд для development
build_dev:
<<: *vault_template
stage: build
environment:
name: development
script:
- vault login $VAULT_TOKEN
- export DB_PASSWORD=$(vault kv get -field=password secret/dev/db-creds)
- ./build.sh
rules:
- if: '$CI_COMMIT_REF_NAME == "develop"'
Описание пайплайна:
vault login — логин в Vault с использованием токена, который передаётся в переменной окружения $VAULT_TOKEN.
vault kv get — команда для извлечения секретов из Vault. В этом примере мы извлекаем пароль базы данных.
build_prod, build_stage, build_dev — задачи для каждого окружения (production, staging, development), где мы получаем секреты, специфичные для окружения, и запускаем процесс сборки.
2. Основной .gitlab-ci.yml файл
Основной .gitlab-ci.yml файл должен инклюдить шаблон для использования Vault и настроить пайплайн для трёх окружений:
include:
- local: 'vault-secrets-template.yml'
workflow:
rules:
- if: '$CI_COMMIT_REF_NAME == "main"'
- if: '$CI_COMMIT_REF_NAME == "staging"'
- if: '$CI_COMMIT_REF_NAME == "develop"'
Интеграция HashiCorp Vault с GitLab CI позволяет безопасно управлять секретами в процессе сборки и деплоя приложений. Мы рассмотрели процесс установки Vault через Helm, настройку Ingress, использование Vault для управления секретами через GitLab CI и создание пайплайнов для разных окружений. Этот подход улучшает безопасность и удобство работы с секретами в CI/CD процессах.
После рассмотрения всех шагов, включая интеграцию HashiCorp Vault и использование ArgoCD, мы можем объединить все настройки в один итоговый .gitlab-ci.yml файл. Этот файл будет включать три основных этапа: сборку образов с использованием Kaniko, деплой с помощью ArgoCD и использование Vault для управления секретами. Пайплайн будет разделён на три окружения: production, staging, и development.
Итоговый .gitlab-ci.yml файл
# Включение шаблонов для сборки, деплоя и работы с секретами Vault
include:
- local: 'kaniko-build-template.yml'
- local: 'argo-deploy-template.yml'
- local: 'vault-secrets-template.yml'
# Определение этапов пайплайна
stages:
- build
- deploy
# Определение триггеров для пайплайнов на основе веток
workflow:
rules:
- if: '$CI_COMMIT_REF_NAME == "main"'
- if: '$CI_COMMIT_REF_NAME == "staging"'
- if: '$CI_COMMIT_REF_NAME == "develop"'
# Билд для production с Kaniko и Vault
build_prod:
stage: build
image: gcr.io/kaniko-project/executor:latest
environment:
name: production
script:
# Вход в Vault и получение секретов для продакшена
- vault login $VAULT_TOKEN
- export DB_PASSWORD=$(vault kv get -field=password secret/prod/db-creds)
# Билд Docker-образа через Kaniko
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:prod --cache=true
rules:
- if: '$CI_COMMIT_REF_NAME == "main"'
# Билд для staging с Kaniko и Vault
build_stage:
stage: build
image: gcr.io/kaniko-project/executor:latest
environment:
name: staging
script:
- vault login $VAULT_TOKEN
- export DB_PASSWORD=$(vault kv get -field=password secret/staging/db-creds)
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:stage --cache=true
rules:
- if: '$CI_COMMIT_REF_NAME == "staging"'
# Билд для development с Kaniko и Vault
build_dev:
stage: build
image: gcr.io/kaniko-project/executor:latest
environment:
name: development
script:
- vault login $VAULT_TOKEN
- export DB_PASSWORD=$(vault kv get -field=password secret/dev/db-creds)
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:dev --cache=true
rules:
- if: '$CI_COMMIT_REF_NAME == "develop"'
# Деплой на production через ArgoCD
deploy_prod:
stage: deploy
image: bitnami/kubectl:latest
environment:
name: production
script:
- kubectl config set-cluster $K8S_CLUSTER --server=$K8S_SERVER --insecure-skip-tls-verify=true
- kubectl config set-credentials $K8S_USER --token=$K8S_TOKEN
- kubectl config set-context $K8S_CONTEXT --cluster=$K8S_CLUSTER --user=$K8S_USER
- kubectl config use-context $K8S_CONTEXT
- argocd app sync my-app-prod --prune --timeout 300
rules:
- if: '$CI_COMMIT_REF_NAME == "main"'
# Деплой на staging через ArgoCD
deploy_stage:
stage: deploy
image: bitnami/kubectl:latest
environment:
name: staging
script:
- kubectl config set-cluster $K8S_CLUSTER --server=$K8S_SERVER --insecure-skip-tls-verify=true
- kubectl config set-credentials $K8S_USER --token=$K8S_TOKEN
- kubectl config set-context $K8S_CONTEXT --cluster=$K8S_CLUSTER --user=$K8S_USER
- kubectl config use-context $K8S_CONTEXT
# Синхронизация приложения через ArgoCD
- argocd app sync my-app-stage --prune --timeout 300
rules:
- if: '$CI_COMMIT_REF_NAME == "staging"'
# Деплой на development через ArgoCD
deploy_dev:
stage: deploy
image: bitnami/kubectl:latest
environment:
name: development
script:
- kubectl config set-cluster $K8S_CLUSTER --server=$K8S_SERVER --insecure-skip-tls-verify=true
- kubectl config set-credentials $K8S_USER --token=$K8S_TOKEN
- kubectl config set-context $K8S_CONTEXT --cluster=$K8S_CLUSTER --user=$K8S_USER
- kubectl config use-context $K8S_CONTEXT
- argocd app sync my-app-dev --prune --timeout 300
rules:
- if: '$CI_COMMIT_REF_NAME == "develop"'
Обзор итогового пайплайна:
Сборка (build):
Используется Kaniko для сборки Docker-образов для каждого окружения (prod, staging, dev).
В процессе сборки, перед запуском Kaniko, из Vault извлекаются секреты для каждого окружения (например, пароли для баз данных).
Деплой (deploy):
После успешной сборки происходит деплой через ArgoCD.
Для каждого окружения используется отдельное приложение в ArgoCD (my-app-prod, my-app-stage, my-app-dev).
Workflow:
Пайплайн запускается только при работе с ветками main (production), staging, и develop.
Заключение
Эффективный CI/CD-процесс сегодня — это не просто автоматизация сборки и деплоя, а комплексная система, которая включает управление секретами, безопасное окружение для сборки, гибкость конфигураций и контроль на каждом этапе. Интеграция инструментов, таких как GitLab CI, Kaniko, ArgoCD и HashiCorp Vault, позволяет создавать мощные и безопасные пайплайны, которые обеспечивают стабильность и предсказуемость процесса разработки.
А какие практики CI/CD будут актуальными ещё долгое время? Делитесь своим мнением в комментах.
Кстати, наша команда ещё публикует полезный контент и на других платформах: в телеграм-канале DevOps FM, на vc.ru и YouTube. Будем ждать вас и там :)