Задумался как-то раз я об автоматизации развертывания своего проекта. gitlab.com любезно предоставляет для этого все инструменты, и я конечно решил воспользоваться, разобравшись и написав небольшой сценарий деплоя. В статье я делюсь своим опытом с сообществом.
- Настроить VPS: отключить root, вход по паролю, поставить dockerd, настроить ufw
- Сгенерировать сертификаты для сервера и клиента https://docs.docker.com/engine/security/https/#create-a-ca-server-and-client-keys-with-openssl Включить управление dockerd через tcp сокет: убрать опцию -H fd:// из конфига докера.
- Прописать пути до сертификатов в docker.json
- Прописать в переменные gitlab в настройках CI/CD с содержимым сертификатов. Написать скрипт .gitlab-ci.yml для деплоя.
Все примеры я буду показывать на дистрибутиве Debian.
Вот вы купили инстанс например на DO, первое, что необходимо предпринять, это защитить ваш сервер от агрессивного внешнего мира. Я не буду ничего доказывать и утверждать, просто покажу лог /var/log/auth.log
своего виртуального сервера:
Во-первых установим файервол 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
на сервере.
В сценарии запуска демона docker убираем опцию -H df://
, эта опция отвечает, на каком хосте можно управлять демоном докера.
# At /lib/systemd/system/docker.service
[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd
Далее следует создать файл настроек, если его еще нет и прописать опции:
{
"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.
Для того чтобы воркер гиталаба смог выполнять команды на удаленном хосте докера необхоимо определиться, как и где хранить сертификаты и ключ для шифрованного соединения с dockerd. Я решил данную проблему просто прописав в переменные в настройках gitlbab:
Просто выводите содержимое сертификатов и ключа через cat
: cat ca.pem
. Копируете и вставляете в значение переменных.
Пропишем сценарий для деплоя через гитлаб. Использовать будет docker-in-docker (dind) образ.
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 # скрипт деплоя тут
Содержимое скрипта деплоя с комментариями:
#!/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