В предыдущих статьях о dapp было рассказано про сборку приложений и про запуск в Minikube. При этом dapp запускался локально на машине разработчика. Однако инструмент задумывался для поддержки процессов непрерывной интеграции (CI) и сами мы используем его в основном в связке с GitLab. Чем dapp помогает в процессах CI/CD?
Во-первых, конечно же, это сборка. Dapp позволяет ускорить инкрементальную сборку приложений, привязывая команды сборки к изменениям между коммитами в Git-репозитории (подробнее об этом и других оптимизациях на этапе сборки см. в докладе «Собираем Docker-образы для CI/CD быстро и удобно вместе с dapp»: статья, видео).
Во-вторых, dapp помогает выкатывать приложение в кластер Kubernetes с помощью Helm. Помимо некоторого упрощения работы с секретами и проверки Helm-шаблонов, dapp помогает ожиданию выката
Deployments
, указанных в шаблонах.В-третьих, в dapp реализована логика очистки кэша как в локальном, так и в удалённом Registry с Docker-образами. Очистка была улучшена в последних версиях: теперь dapp удаляет образы, созданные по веткам Git, если эти ветки удалены из Git-репозитория. С образами по тегам немного сложнее: остаётся не более 10 образов не старше 30 дней. В следующих версиях планируется сделать настраиваемые политики очистки.
Всё перечисленное критично в большей степени для сервера сборки, поэтому далее с помощью несложного стенда GitLab + Minikube покажу пример внедрения dapp в процессы непрерывной интеграции и доставки (CI/CD).
Стенд GitLab + Minikube + dapp
Стенд состоит из установленного GitLab, GitLab Runner, Registry и кластера Kubernetes:
Схема приближена к варианту, который используется нами в реальных проектах. Вкратце всё работает так:
- Разработчик push'ит свои изменения в Git-репозиторий.
- GitLab запускает задачу сборки, GitLab Runner запускает dapp, который собирает образ и push'ит образ в Registry.
- Чтобы выкатить приложение в кластер, запускается задача деплоя: GitLab Runner (с доступом к kubectl и Helm) выполняет
dapp kube deploy
. - Кластер Kubernetes при получении обновлённых ресурсов проверяет, есть ли новый образ в Registry, скачивает его и запускает поды с новым образом.
Стенд — демонстрационный, поэтому, чтобы не плодить виртуальные машины, вместе с GitLab нужно установить Registry, GitLab Runner, dapp, Docker, kubectl и Helm. В качестве Kubernetes-кластера используется Minikube как самый простой способ запустить K8s на локальной машине.
В качестве приложения опять используется symfony-demo. Сборка этого проекта в локальном варианте была описана в статье «Практика с dapp. Часть 1: Сборка простых приложений», а пример выката приложения в Minikube был описан в статье «Практика с dapp. Часть 2. Деплой Docker-образов в Kubernetes с помощью Helm». Отличие от второй статьи будет в том, что Registry для Minikube становится внешним (расположен в виртуальной машине с GitLab) и команда
dapp kube minikube setup
не требуется.Подготовка хост-системы
Перед созданием виртуальных машин лучше заранее добавить имена хостов, например, в
/etc/hosts
:192.168.33.20 gitlab.example.com # доступ к интерфейсу gitlab
192.168.33.20 registry.gitlab.example.com # доступ к registry
192.168.33.100 cluster.example.com # доступ к приложению и к api k8s
GitLab в виртуальной машине
Установка GitLab с помощью готового
Vagrantfile
(https://github.com/rgl/gitlab-vagrant) была упомянута во второй части «Практики с dapp», но теперь опишу подробнее. Чтобы запустить виртуальную машину, понадобится отредактировать Vagrantfile
, сменить базовый образ на xenial64
и увеличить память с 2048 до 4096.После
vagrant up
нужно установить GitLab Runner по инструкции проекта. Также потребуется инсталляция Docker и dapp. И для деплоя — скачать бинарники kubectl и Helm.Чтобы запустить Registry, нужно отредактировать
/etc/gitlab/gitlab.rb
, раскомментировав там строчки:gitlab_rails['registry_enabled'] = true
gitlab_rails['registry_host'] = "registry.gitlab.example.com"
gitlab_rails['registry_port'] = "5000"
gitlab_rails['registry_path'] = "/var/opt/gitlab/gitlab-rails/shared/registry"
gitlab_rails['registry_api_url'] = "http://localhost:5000"
gitlab_rails['registry_key_path'] = "/var/opt/gitlab/gitlab-rails/certificate.key"
gitlab_rails['registry_issuer'] = "omnibus-gitlab-issuer"
registry['registry_http_addr'] = "0.0.0.0:5000"
После сохранения — запустить
gitlab-ctl reconfigure
. Omnibus изменит конфигурацию и перезапустит GitLab.Всё вышеперечисленное уже есть в форке gitlab-vagrant — достаточно его склонировать и выполнить
vagrant up
.Minikube
Время запустить и настроить Minikube. Инструкция довольно проста: скачать бинарник проекта и вызвать команду:
minikube start --insecure-registry registry.gitlab.example.com:5000 --host-only-cidr 192.168.33.1/24
К сожалению, для работы в составе стенда придётся остановить кластер (
minikube stop
) и вручную отредактировать ~/.minikube/machines/minikube/config.json
, включив HostDNSResolver
, чтобы виртуальная машина воспринимала /etc/hosts
хоста. Также, если Minikube был установлен после прочтения второй части, проверьте ключ InsecureRegistry
.{
"Driver": {
…
"HostDNSResolver": true,
…
“HostOptions”: {
"EngineOptions": {
"InsecureRegistry": [
"registry.gitlab.example.com:5000"
],
…
Чтобы проверить доступность кластера после запуска
minikube start
, можно выполнить команду kubectl get all
.Настройка GitLab Runner
Кластер запущен — нужно настроить связь с кластером для gitlab-runner. Для этого в виртуальную машину копируется локальный конфиг из
.kube
и сертификаты для доступа к Kubernetes API:$ cd ~
$ tar zcf kube-config.tar.gz .kube/config .minikube/ca.crt .minikube/apiserver.*
$ cp kube-config.tar.gz $GITLAB_VM_DIR
$ cd $GITLAB_VM_DIR
$ vagrant ssh
ubuntu@gitlab:~$ sudo su - gitlab-runner
gitlab-runner@gitlab:~$ tar zxf /vagrant/kube-config.tar.gz
Следующий шаг — отредактировать
.kube/config
, чтобы был правильный путь к файлам:- certificate-authority:
/home/
gitlab-runner/.minikube/ca.crt
- client-certificate:
/home/
gitlab-runner/.minikube/apiserver.crt
- client-key:
/home/
gitlab-runner/.minikube/apiserver.key
Далее можно проверить связь и настроить Helm:
gitlab-runner@gitlab:~$ kubectl get all
Если Minikube уже был установлен ранее по второй части, то tiller уже есть и достаточно команды:
gitlab-runner@gitlab:~$ helm init --client-only
Если minikube не был ранее установлен, то нужно, чтобы установился tiller:
gitlab-runner@gitlab:~$ helm init
Для dapp необходимо добавить plugin
template
:gitlab-runner@gitlab:~$ helm plugin install https://github.com/technosophos/helm-template
Импорт проекта и pipeline
Теперь можно импортировать репозиторий symfony-demo в GitLab. В списке проектов нажать New Project, выбрать Import, затем Repo by URL, ввести URL, группу и имя нового проекта.
В проекте уже есть ветка с
Dappfile
и шаблонами в .helm
, созданными при работе над предыдущими статьями, — dapp_deploy_minikube
.Для демонстрации работы CI/CD нужно добавить конфигурацию CI —
.gitlab-ci.yml
. Это будет простой pipeline из двух заданий:Задание Build
Build:
stage: build
script:
- dapp --version
- dapp dimg build --build-dir ~/dapp_build/${CI_PROJECT_NAME}
- dapp dimg push --build-dir ~/dapp_build/${CI_PROJECT_NAME} ${CI_REGISTRY_IMAGE} --tag-ci
tags:
- build
Задание 3 раза запускает dapp. Первый раз — информативный, чтобы видеть версию dapp. Второй запуск — сборка образов, описанных в
Dappfile
. Третий — push собранных образов в Registry, при этом теги образам будут проставлены на основании переменных CI_*
(документация по опциям тегирования).Задание Deploy
Deploy:
stage: deploy
script:
- dapp --version
- dapp kube deploy
--tag-ci
--namespace ${CI_PROJECT_NAME}-stage
--set "global.env=stage"
--set "global.git_rev=${CI_COMMIT_SHA}"
$CI_REGISTRY_IMAGE
tags:
- build
Здесь тоже первым запуском выводится версия dapp. Второй запуск — выкат приложения в кластер.
Можно заметить, что в пространстве имён используется суффикс
stage
— это сделано, чтобы показать, что имя namespace можно задать любое. В полноценном варианте pipeline потребуется создать несколько заданий для нужных окружений.Helm-шаблоны
Registry, установленный в GitLab, в отличие от Registry, устанавливаемого командой
dapp kube minukube setup
, имеет разграничение прав и поэтому в Helm-шаблоны нужно добавить registrysecret
с логином и паролем для Registry. Можно сформировать секрет вручную с помощью команды base64
, а можно воспользоваться подсказкой.В итоге, в
.helm/values.yaml
добавятся такие значения:imageCredentials:
registry: registry.gitlab.example.com:5000
username: root
password: password
А в
backend.yaml
— такой ресурс:apiVersion: v1
kind: Secret
type: kubernetes.io/dockercfg
metadata:
name: registrysecret
data:
.dockercfg: {{ printf "{\"%s\": {\"auth\": \"%s\"}}" .Values.imageCredentials.registry (printf "%s:%s" .Values.imageCredentials.username .Values.imageCredentials.password | b64enc) | b64enc }}
… и
imagePullSecrets
в spec шаблонов контейнеров:spec:
template:
...
spec:
imagePullSecrets:
- name: registrysecret
containers:
- command: [ '/demo/start.sh' ]
image: {{ tuple "symfony-demo-app" . | include "dimg" }}
Выкат по таким Helm-шаблонам уже должен быть успешен — результат можно наблюдать в браузере по адресу
http://cluster.example.com/symfony-demo
:Резюмируя
В целом можно считать, что развёрнут стенд с процессом CI/CD, очень приближенным к тому, что работает у наших клиентов. Следующими шагами будет усложнение pipeline (см. «GitLab CI для непрерывной интеграции и доставки в production. Часть 1: наш пайплайн» и «Часть 2: преодолевая трудности»), введение динамических окружений (обзорная статья коллеги), добавление очистки Registry по расписанию, добавление запуска интеграционных тестов. Вопросы про описанный стенд и про dapp можно задать в комментариях и в нашем Telegram-чате.
P.S.
Читайте также в нашем блоге:
bondsman
Ваша утилита (dapp) пытается перекрыть штатный функционал GitLab, в котором есть и кэширование, и интеграция с Kubernetes (консоль + rollback).
Так же кажется странной установка компонентов GitLab НЕ в Kubernetes а на отдельные ВМ.