Настройка CD через gitlab

Задумался как-то раз я об автоматизации развертывания своего проекта. gitlab.com любезно предоставляет для этого все инструменты, и я конечно решил воспользоваться, разобравшись и написав небольшой сценарий деплоя. В статье я делюсь своим опытом с сообществом.

TL;DR

  1. Настроить VPS: отключить root, вход по паролю, поставить dockerd, настроить ufw
  2. Сгенерировать сертификаты для сервера и клиента docs.docker.com/engine/security/https/#create-a-ca-server-and-client-keys-with-openssl Включить управление dockerd через tcp сокет: убрать опцию -H fd:// из конфига докера.
  3. Прописать пути до сертификатов в docker.json
  4. Прописать в переменные gitlab в настройках CI/CD с содержимым сертификатов. Написать скрипт .gitlab-ci.yml для деплоя.

Все примеры я буду показывать на дистрибутиве Debian.

Первоначальная настройка VPS

Вот вы купили инстанс например на DO, первое, что необходимо предпринять, это защитить ваш сервер от агрессивного внешнего мира. Я не буду ничего доказывать и утверждать, просто покажу лог /var/log/messages своего виртуального сервера:

СкриншотНастройка CD через gitlab

Во-первых установим файервол ufw:

apt-get update && apt-get install ufw

Включим политику по-умолчанию: блокируем все входящие соединения, разрешаем все исходящие соединения:

ufw default deny incoming
ufw default allow outgoing

Важно: не забудем разрешить соединение по ssh:

ufw allow OpenSSH

Общий синтаксис такой: Разрешить соединение по порту: ufw allow 12345, где 12345 — номер порта или же название сервиса. Запретить: ufw deny 12345

Включаем файервол:

ufw enable

Выходим из сессии и снова логинимся по ssh.

Добавьте пользователя, назначьте ему пароль и добавьте его в группу sudo.

apt-get install sudo
adduser scoty
usermod -aG sudo scoty

Далее по плану следует отключить вход по паролю. для этого скопируйте ваш ssh-ключ на сервер:

ssh-copy-id [email protected]

ip сервера должен быть указан ваш. Попробуйте теперь залогиниться под созданным ранее пользователем, пароль вводить больше не надо. Далее в настройках конфигурации меняем следующее:

sudo nano /etc/ssh/sshd_config

отключаем вход по паролю:

PasswordAuthentication no

Перезапускаем демон sshd:

sudo systemctl reload sshd

Теперь если вы или кто-то другой попробует войти через пользователя root, у него ничего не получится.

Далее ставим dockerd, тут процесс уже не буду описывать, так как все может быть уже изменено, сходите по ссылке на официальный сайт и пройдите этапы установки docker на вашу виртуалку: https://docs.docker.com/install/linux/docker-ce/debian/

Генерация сертификатов

Чтобы управлять демоном докера удаленно требуется шифрованное TLS соединение. Для этого необходимо иметь сертификат и ключ, которые надо сгенерировать и перенести на удаленную вашу машину. Следуйте шагам, заданным в инструкции на официальном сайте docker: https://docs.docker.com/engine/security/https/#create-a-ca-server-and-client-keys-with-openssl Все сгенерированные *.pem файлы для сервера, а именно ca.pem, server.pem, key.pem надо поместить в директорию /etc/docker на сервере.

Настройка dockerd

В сценарии запуска демона docker убираем опцию -H df://, эта опция отвечает, на каком хосте можно управлять демоном докера.

# At /lib/systemd/system/docker.service
[Service]
Type=notify
ExecStart=/usr/bin/dockerd

Далее следует создать файл настроек, если его еще нет и прописать опции:

/etc/docker/docker.json

{
  "hosts": [
    "unix:///var/run/docker.sock",
    "tcp://0.0.0.0:2376"
  ],
  "labels": [
    "is-our-remote-engine=true"
  ],
  "tls": true,
  "tlscacert": "/etc/docker/ca.pem",
  "tlscert": "/etc/docker/server.pem",
  "tlskey": "/etc/docker/key.pem",
  "tlsverify": true
}

Разрешим подключения по порту 2376:

sudo ufw allow 2376

Перезапустим dockerd с новыми настройками:

sudo systemctl daemon-reload && sudo systemctl restart docker

Проверим:

sudo systemctl status docker

Если все «зеленое», то считаем, что на сервере мы успешно настроили docker.

Настройка continuous deleivery на gitlab

Для того чтобы воркер гиталаба смог выполнять команды на удаленном хосте докера необхоимо определиться, как и где хранить сертификаты и ключ для шифрованного соединения с dockerd. Я решил данную проблему просто прописав в переменные в настройках gitlbab:

Заголовок спойлераНастройка CD через gitlab

Просто выводите содержимое сертификатов и ключа через cat: cat ca.pem. Копируете и вставляете в значение переменных.

Пропишем сценарий для деплоя через гитлаб. Использовать будет docker-in-docker (dind) образ.

.gitlab-ci.yml

image:
  name: docker/compose:1.23.2
  # перепишем entrypoint , чтобы работало в dind
  entrypoint: ["/bin/sh", "-c"]

variables:
  DOCKER_HOST: tcp://docker:2375/
  DOCKER_DRIVER: overlay2

services:
  - docker:dind

stages:
  - deploy

deploy:
  stage: deploy
  script:
    - bin/deploy.sh # скрипт деплоя тут

Содержимое скрипта деплоя с комментариями:

bin/deploy.sh

#!/usr/bin/env sh
# Падаем сразу, если возникли какие-то ошибки
set -e
# Выводим, то , что делаем
set -v

# 
DOCKER_COMPOSE_FILE=docker-compose.yml
# Куда деплоим
DEPLOY_HOST=185.241.52.28
# Путь для сертификатов клиента, то есть в нашем случае - gitlab-воркера
DOCKER_CERT_PATH=/root/.docker

# проверим, что в контейнере все имеется
docker info
docker-compose version

# создаем путь (сейчас работаем в клиенте - воркере gitlab'а)
mkdir $DOCKER_CERT_PATH
# изымаем содержимое переменных, при этом удаляем лишние символы добавленные при сохранении переменных.
echo "$CA_PEM" | tr -d 'r' > $DOCKER_CERT_PATH/ca.pem
echo "$CERT_PEM" | tr -d 'r' > $DOCKER_CERT_PATH/cert.pem
echo "$KEY_PEM" | tr -d 'r' > $DOCKER_CERT_PATH/key.pem
# на всякий случай даем только читать
chmod 400 $DOCKER_CERT_PATH/ca.pem
chmod 400 $DOCKER_CERT_PATH/cert.pem
chmod 400 $DOCKER_CERT_PATH/key.pem

# далее начинаем уже работать с удаленным docker-демоном. Собственно, сам деплой
export DOCKER_TLS_VERIFY=1
export DOCKER_HOST=tcp://$DEPLOY_HOST:2376

# проверим, что коннектится все успешно
docker-compose 
  -f $DOCKER_COMPOSE_FILE 
  ps

# логинимся в docker-регистри, тут можете указать свой "местный" регистри
docker login -u $DOCKER_USER -p $DOCKER_PASSWORD

docker-compose 
  -f $DOCKER_COMPOSE_FILE 
  pull app
# поднимаем приложение
docker-compose 
  -f $DOCKER_COMPOSE_FILE 
  up -d app

Основная проблема была в том, чтобы «вытащить» из переменных gitlab CI/CD содержимое сертификатов в нормальном виде. Я не мог понять, почему не работало соединение с удаленным хостом. На хосте посмотрел журнал sudo journalctl -u docker, там ошибка при рукопожатии. Решил глянуть, что вообще хранится в переменных, для этого можно посмотреть так cat -A $DOCKER_CERT_PATH/key.pem. Ошибку поборол, добавив удаление символа каретки tr -d ‘r’.

Далее в сценарий можно добавить пост-релизные таски на свое усмотрение. Ознакомиться с рабочей версией можете в моем репозитории https://gitlab.com/isqad/gitlab-ci-cd

Источник: habr.com