Сделал свою первую работающую пипелину под GitLab на проекте «hello». Она небольшая, но умеет довольно много:
- собирает docker-образ Nginx, выводя на главной странице SHA коммита
- запускает его на порту, который определен в переменных проекта GitLab
- настраивает необходимым образом реверс-прокси сервер
Выглядит она так:
stages:
- build
- deploy
build docker image:
stage: build
tags:
- docker-image-builder
script:
- echo "Commit SHA ${CI_COMMIT_SHA}" >> public/index.html
- docker build . -f docker/nginx/Dockerfile -t hello_nginx:${CI_COMMIT_SHA}
run docker container:
stage: deploy
tags:
- deploy
script:
- docker stop hello_from_ci || true
- docker run --rm -d -p ${HTTP_PORT}:80 --name hello_from_ci hello_nginx:${CI_COMMIT_SHA}
setup Caddy:
stage: deploy
when: manual
tags:
- deploy
script:
- envsubst < deploy/caddy/hello.deb24.ru | sudo tee /etc/caddy/sites-enabled/hello.deb24.ru
- sudo service caddy reload
Во-первых, я использовал человекочитаемые названия: «setup Caddy», а не «setup_caddy», как принято на работе. Посмотрим, насколько это удобно.
Во-вторых, два шага этапа deploy запускаются параллельно, причем один из шагов — в ручном режиме.
В-третьих, в этой скромной пипелине есть довольно много: от использования переменных до запуска операций с sudo.
build docker image
Вначале я думал использовать docker runner для сборки образа. Но затем не стал заморачиваться и сделал на shell-раннере. На данный момент теги «docker-image-builder» и «deploy» относятся к одному и тому же shell-раннеру. Возможно, что в будущем собирать образы будет отдельный раннер на основе dind. Его можно сделать так (уже не помню, я взял откуда-то или написал сам):
FROM docker:dind
RUN apk add --no-cache bash git dumb-init gitlab-runner && \
mkdir /home/gitlab-runner
ENTRYPOINT ["/usr/bin/dumb-init", "gitlab-runner"]
CMD ["run", "--working-directory=/home/gitlab-runner"]
Но вернемся к пипелине. На этом этапе интересно тегирование образа хешем коммита:
-t hello_nginx:${CI_COMMIT_SHA}
А на этапе запуска контейнера используется тот же самый хеш. Таким образом, можно взять какую-то прошлую пипелину, запустить стадию deploy заново, и главная страница откатится до версии на момент той самой сборки — это проверено. Выглядит так:
# Какая-то старая версия (и тут запустили deploy из истории) - показывается
Hello from CI/CD!!!
New uuid 5be560cd43c14eb6f8fedd1e9f5e05ff8e6eaf04
# Версия из последнего коммита - заменена старой версией, не показывается
Hello from CI/CD!!!
New uuid 1737b23dd8955132d11a0ceaf6b2a48eb78b4bc2
run docker container
На этом шаге происходит остановка прошлого контейнера и запуск нового, на основе собранного образа:
- docker stop hello_from_ci || true
- docker run --rm -d -p ${HTTP_PORT}:80 --name hello_from_ci hello_nginx:${CI_COMMIT_SHA}
Предварительно следует добавить раннеру права на работу с docker:
sudo usermod -aG docker gitlab-runner
setup Caddy
Этот шаг настраивает веб-сервер Caddy, который я использую в режиме реверс-прокси. Настройка одноразовая, поэтому выбран manual запуск. Однако при смене порта нужно запустить этот шаг повторно.
Настроить и перезапустить Caddy можно еще до старта контейнера приложения, поэтому шаг выполняется одновременно с этим самым запуском приложения. Проще говоря, пока приложение все еще стартует, можно запустить конфигурирование реверс-прокси:
- envsubst < deploy/caddy/hello.deb24.ru | sudo tee /etc/caddy/sites-enabled/hello.deb24.ru
- sudo service caddy reload
Конфигурирование заключается в подстановке номера порта через envsubst в очень простой конфиг:
hello.deb24.ru {
reverse_proxy :$HTTP_PORT
}
Этот конфиг записывается в кастомный каталог /etc/caddy/sites-enabled. А чтобы Caddy этот каталог учитывал, в /etc/caddy/Caddyfile необходимо добавить это:
import sites-enabled/*
Для перезапуск сервиса нужны root-привилегии, которыми надо снабдить gitlab-runner:
sudo visudo
# добавить эту строку:
gitlab-runner ALL=(ALL:ALL) NOPASSWD: ALL
Этот опыт ответил на некоторые мои вопросы. Но возникли новые мысли:
- Можно ли сделать крон-задачи на GitLab?
- Сделать сборку в отдельном dind runner, используя buildx / Docuum
- Подключить какое-то хранилище паролей. variables хорошо, но хотелось бы возможность сохранить все пароли себе куда-то в файл на случай тотального падения. Код можно будет достать из bitbucket, а креды — из этого файла.
- Реально запустить какой-то свой проект: tendera online, mailtester или lucky.