Всем привет.
У нас не так много задач, которым необходим полноценный CI. Некоторое время мы использовали в качестве CI-сервиса Jenkins. Там всё довольно очевидно, он прост и гибок в настройке, имеет кучу плагинов, но пару раз мы столкнулись с OOM-убийцами агентов на слабых машинах и решили рассмотреть в качестве CI-сервиса Gitlab CI, потому что мы любим эксперименты и тем более в комментариях к нашей прошлой статье задавали такой вопрос.
Установка GitLab-CE
Тут всё довольно тривиально, т. к. есть Omnibus package.
Устанавливаем и запускаем необходимые пакеты:
sudo yum install curl openssh-server openssh-clients postfix cronie
sudo service postfix start
sudo chkconfig postfix on
Устанавливаем Gitlab-CE:
curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | sudo bash
sudo yum install gitlab-ce
Настраиваем и запускаем Gitlab-CE:
sudo gitlab-ctl reconfigure
Установка раннера
GitLab Runner — это агент, который собственно и занимается выполнением инструкций из специального файла .gitlab-ci.yml.
В отличие от Jenkins раннеры гитлаба написаны на Go, поэтому они очень маленькие и быстрые. И умеют запускать задачи совершенно различными способами: локально, в докер-контейнерах, в различных облаках или через ssh-коннект к какому либо серверу. Подробности, как всегда, в документации
Кто-то в комментариях к прошлой статье просил рассмотреть Gitlab для тестирования ansible-плейбуков, его и возьмём.
Для обеспечения идентичности среды тестирования и продакшен будем использовать Docker.
Для работы раннера в Docker — сначала необходимо установить docker:
curl -sSL https://get.docker.com/ | sh
Установка раннера
# Для Debian/Ubuntu
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.deb.sh | sudo bash
# для RHEL/CentOS
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-ci-multi-runner/script.rpm.sh | sudo bash
# Для Debian/Ubuntu
sudo apt-get install gitlab-ci-multi-runner
# Для RHEL/CentOS
sudo yum install gitlab-ci-multi-runner
Настройка и подключение раннера к CI-сервису:
sudo gitlab-ci-multi-runner register
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/ci )
http://domain.example.com/ci
Please enter the gitlab-ci token for this runner
bQ0nvkVJACDUrvQ9ttqx
Please enter the gitlab-ci description for this runner
my-runner
INFO[0034] fcf5c619 Registering runner... succeeded
Please enter the executor: shell, docker, docker-ssh, ssh?
docker
Please enter the Docker image (eg. ruby:2.1):
centos:7
INFO[0037] Runner registered successfully. Feel free to start it, but if it's
running already the config should be automatically reloaded!
Указываем URL нашего Gitlab, и прописываем токен для авторизации.
Также необходимо задать название раннера, способ запуска джоба, в случае с docker — указываем образ который будет запускать раннер.
Конфигурация для раннера указана по урлу example.com/groupname/projectname/runners
Здесь можно редактировать название раннера и метки, с которыми будет собираться проект на этом раннере. Например, нам нужно на разных стадиях протестировать проект сначала в shell, затем запаковать его в docker-контейнер и выкатить куда-нибудь по ssh. Об этом немного позже.
Оттуда необходимо взять URL мастера и токен для авторизации раннера на «мастере».
Запуск
sudo gitlab-ci-multi-runner start
После этого он должен появиться в списке раннеров проекта:
Установка Container Registry
Не так давно в Gitlab интегрировали Container Registry.
GitLab Container Registry — это защищённый приватный репозиторий для хранения Docker-образов (Docker images).
Ищем в /etc/gitlab/gitlab.rb секцию Container registry settings
registry_external_url 'https://domain.example.com'
# Settings used by GitLab application
gitlab_rails['registry_enabled'] = true
gitlab_rails['registry_host'] = "domain.example.com"
gitlab_rails['registry_port'] = "5000"
gitlab_rails['registry_api_url'] = "http://localhost:5000"
gitlab_rails['registry_key_path'] = "/var/opt/gitlab/gitlab-rails/certificate.key"
gitlab_rails['registry_path'] = "/var/opt/gitlab/gitlab-rails/shared/registry"
# gitlab_rails['registry_issuer'] = "omnibus-gitlab-issuer"
# Settings used by Registry application
registry['enable'] = true
registry['username'] = "registry"
registry['group'] = "registry"
# registry['uid'] = nil
# registry['gid'] = nil
registry['dir'] = "/var/opt/gitlab/registry"
registry['log_directory'] = "/var/log/gitlab/registry"
registry['log_level'] = "info"
registry['rootcertbundle'] = "/var/opt/gitlab/registry/gitlab-registry.crt"
registry['storage_delete_enabled'] = true
Из необходимого:
нужно выставить gitlab_rails['registry_enabled'] = true и registry['enable'] = true
В registry_external_url указываем доменное имя сервера, на котором будет находится репозиторий.
Также нужно найти следующие настройки:
registry_nginx['ssl_certificate'] = "/path/to/certificate.pem"
registry_nginx['ssl_certificate_key'] = "/path/to/certificate.key"
И указать правильные пути к сертификатам.
Если будут использоваться самоподписные сертификаты, то на стороне docker-daemon, с которого будет проходить вся работа с образами нужно выставить опцию --insecure-registry, в противном случае при попытке залогинится — мы получим ошибку (раннеров тоже касается).
В Debian: /etc/systemd/system/multi-user.target.wants/docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network.target docker.socket
Requires=docker.socket
[Service]
Type=notify
ExecStart=/usr/bin/docker daemon -H fd:// --insecure-registry domain.example.com
MountFlags=slave
LimitNOFILE=1048576
LimitNPROC=1048576
LimitCORE=infinity
TimeoutStartSec=0
[Install]
WantedBy=multi-user.target
(Да, порт указывать не нужно. Существует API для registry — он висит на localhost:5000 и фронт, через который происходит авторизация и дальнейшая работа с образами. Я же долго искал способ перевесить API с локалхоста :) )
применяем изменения
systemctl daemon-reload
systemctl restart docker
И пробуем зайти под нашей учётной записью gitlab
docker login domain.example.com
Username: root
Password:
Email: admin@example.com
WARNING: login credentials saved in /root/.docker/config.json
Login Succeeded
Ну что, теперь самое время что-нибудь с этим сделать, построить первый пайплайн и посмотреть, как проект будет собираться.
Настройка CI
Приступаем к тестированию ansible-плейбуков:
Я не буду вдаваться в глубины и рассказывать о serverspec и test-kitchen, о них уже было написано в моём прошлом посте.
Первым делом — собираем простой образ с окружением для тестов. Обойдёмся Dry run и ansible-lint.
vim Dockerfile
FROM centos:7
RUN yum -y update && yum -y install epel-release && yum -y install ansible python-pip
RUN pip install ansible-lint
# Default command
CMD ["/bin/bash"]
Окей, собраем образ
docker build -t centos:7 .
и пушим в Registry
docker tag centos:7 domain.example.com/<groupname>/<projectname>
docker push domain.example.com/<groupname>/<projectname>
Теперь самое время описать пайплайн
В корне нашего проекта создаём файл .gitlab-ci.yml (опять YAML, ага) и описываем шаги сборки проекта.
image: domain.example.com/root/my-repo
stages:
- test
- deploy
test_job:
stage: test
script:
- ansible-lint playbook.yml
- ansible-playbook --check playbook.yml
tags:
- ansible
deploy_job:
stage: deploy
script:
- ansible-playbook playbook.yml
tags:
- ansible
Здесь мы указываем стадии сборки проекта. На стадии тестирования — мы проходимся lint'ом на предмет синтаксических ошибок и запускаем Ansible в Dry mode, то есть не применяя изменения на хосте, а просто их показывая. Если вдруг что-то ломается во время проигрывания плейбука — мы об этом узнаем до того, как конфигурация на хосте изменится.
Соответсвенно, если мы сейчас попробуем в плейбук добавить где-нибудь пробелов — то конфигурация не применится, lint сообщит об ошибке и упадёт на этапе тестирования, о чём можно узнать после коммита прямо в веб-интерфейсе gitlab.
У .gitlab-ci.yml очень много различных опций на все случаи стадии жизни проекта. К сожалению, за один вечер со всем ознакомиться не удалось.
Как видите, Gitlab ничем не хуже других CI-сервисов, имеет позитивный и удобный интерфейс, но есть особенности в плане написания сценария тестирования и деплоя.
Спасибо за внимание. Удачной автоматизации!
Поделиться с друзьями
QtRoS
Правильно ли я понял, что CI в таком варианте, по сути, настраивается для одного репозитория? Зависимости от нескольких репозиториев можно сделать?
Как дела обстоят с шаблонами? Допустим, у меня несколько контуров тестирования, девеоперский и продакшн, и все нужно собирать похожим образом с похожим наборов параметров. Удастся ли тут легко организовать такую схему?
Возможно, глупый вопрос, но все же — Python скрипты можно пускать в шагах сборки?
nik_OS
А вообще кроме этой статьи еще советую прочитать на ту же тему блог гитлаба https://about.gitlab.com/2016/08/26/ci-deployment-and-environments/
axdr
Так же есть отличная статья по ознакомлению с GitLab CI и понятию CI в целом.
NelSon29
На своей работе используем gitlab, в частности gitlab-CI.
> Допустим, у меня несколько контуров тестирования, девеоперский и продакшн, и все нужно собирать похожим образом с похожим наборов параметров. Удастся ли тут легко организовать такую схему?
Да, это делается достаточно легко. Помимо этого, возможно создать зависимости, например, если промежуточные тесты не проходят, CI-сервер даже не будет приступать к продакшн тестам.
> Python скрипты можно пускать в шагах сборки?
Конечно. На компьютере, который играет роль сервера, можно развернуть runner, который будет выполнять написанные сценарии либо в некой виртуальной машине, контейнере Docker, либо же в обычной командной строке (как cmd, так и bash).
> CI в таком варианте, по сути, настраивается для одного репозитория?
Верно, в каждом репозитории лежит свой файл сценария сборки и тестирования.
> Зависимости от нескольких репозиториев можно сделать?
Смотря что вы имеете в виду под зависимостями. Зависимость от успешной сборки другого, нигде не указанного репозитория? Зависимость от подмодуля?
P.S. Писал в личный блог пост по применению этой системы для сборки C++ проектов для Visual Studio и ARM DS-5. Если сообществу будет интересно, приведу в более приемлемый для хабра вид и опубликую.
Serhii_M
Все build steps указываються в .gitlab-ci.yml, который лежит в корне репозитория и да — для одного репозитория.
В .gitlab-ci.yml можно указывать enviroments, которые можно настроить в настройках проекта ( pipelines ), соответсвенно конфигурация может меняться, в зависимости от того, для какого енва ты билдишь и куда деплоишь.
Можно запускать все что угодно — главное, что бы на машине, на которой раниться gitlab-runner были все необходимые компоненты.
Мы используем собранный под себя имейдж докера с нодой и некоторыми другими инструментами для билда. И все инструкции описанные в .gitlab-ci.yml выполняются в этом контейнере.
Anthrax_Beta
Отличная, на мой взгляд статья. Хорошая альтернатива Jenkins-у.
tuupic
Как-то, на уровне подсознания, инструкции установки вида «curl некий_магический_скрипт | bash» вызывают недоверие.
Anthrax_Beta
Никто не мешает скачать скрипт и посмотреть, что он делает
RaveNoX
Мы у себя рассматривали gitlab-ci как альтернативу jenkins для сборки .net проекта. На текущий момент как ci он нормально работает, но есть пару моментов:
— нельзя задать какое количество сборок, для которых нужно хранить артефакты, только время их хранения.
— сам файл конфигурации хранится в репозитории как результат сложно сделать схему, когда deploy должен быть предварительно одобрен (или в ручную запущен) ограниченным количеством ответственных лиц. Это можно попробовать сделать при помощи protected branch, но никто не мешает разработчику изменить файл в своём бранче и залить что угодно на прод.
В результате как cd его пока использовать сложно.
Если есть у кого-нибудь опыт использования в реалиях, которые я описал, прошу поделиться своим опытом.
Prototik
Как вариант — в одной из последних версий gitlab'a появились блокировки на файл. Какой-нибудь team-lead или deploy-manager лочит на себя этот файл — и все остальные лишаются возможности редактировать этот файл.
vitalybaev
Учитывая, как развивался GitLab в последнее время, легко можно запросить такую фичу.
zartdinov
На счет безопасности, в некоторых CI есть интересная встроенная защита от таких случаев.
Пошло от Travis CI, по-моему, Например, как это реализовано в drone.
Переменные зашифровывают и заливают в корневую папку вместе с сигнатурой на файл конфигурации.
Поэтому если файл изменится CI откажется подставлять зашифрованные переменные в эту сборку.
Возможно и в Gitlab CI есть нечто подобное.
rekby
Посмотрите http://docs.gitlab.com/ce/ci/yaml/README.html#stages
Manual actions
возможно это то, что вам нужно.
Ограничения по изменениям — можно просто административно. Если этого недостаточно — завести отдельный репозиторий из которого будет делаться публикация (и для этого репозитория прописать шаг запуска публикации).
Для этого же спец. репозитория заданы переменные, необходимые для публикации (ключи доступа на сервер например), без которых публикация невозможна.
В этом случае разработчик не сможет путем локальных изменений что-то опубликовать, т.к. доступа к спец. репозиторию не имеет.
farcaller
Как насчет добавить самоподписанный сертификат в список корневых?