Непрерывная интеграция и развертывание на примере GitLab CI + Docker + Swarm

Непрерывная интеграция и развертывание на примере GitLab CI + Docker + Swarm.

Общая информация

ОС – ubuntu server 16.04.4 LTS

git.itc-life.ru – запущен на внешнем сервере

gitlab runner запущен в локальной сети через докер контейнер на хосте 192.168.88.10

docker swarm manager – 192.168.88.250. Доменное имя manager.swarm.itc-life.ru. При пинге manager.swarm.itc-life.ru получаем адресс 192.168.88.250

Шаг 1. Подключаем docker runnet к gitlab

Конфиг запуска докер раннера в докере. Смотрим тут

Шаг 2. Создание ssl сертификата для взаимодействия со swarm и создание возможности деплоя в swarm

Все это делаем на ноде, которая будет у нас manager. Предполагается что вы уже сделали

docker swarm init --advertise-addr 192.168.88.250  --cert-expiry 72160h0m0s --data-path-addr enp7s0 --dispatcher-heartbeat 15s --listen-addr enp7s0:2377

Обратите внимание на –advertise-addr 192.168.88.250 – по нему будет доступен api для деплоя.

В рабочей Swarm-среде необходимо защищенное соединение между GitLab Runner и сервисом Docker, запущенном на сервере Manager.

Для этого необходимо использовать единый сертификационный центр для клиента (GitLab Runner) и сервиса Docker (Manager). После создания сертификата и ключа для клиента, их можно использовать для удаленного подключения к сервису Docker и выполнения различных операций. Следует быть максимально осторожными с хранением клиентских сертификатов и ключей, поскольку они дают полное управление надо сервисом Docker.
Итак приступим к генерации ключей.

Для начала нужно создать приватный и публичный RSA-ключ для CA (потребуется придумать кодовое слово длиной не меньше 4 символов):


sudo su
mkdir -p /docker-compose/SWARM/swarmcerts/
cd /docker-compose/SWARM/swarmcerts/
openssl genrsa -aes256 -out ca-key.pem 4096     

Придумываем пароль – мин символа.
Идем далее.
Приступим к созданию локального сертификационного центра. Будут запрошены данные связанные с идентификацией центра. На этапе ввода полного квалифицированного доменного имени (FQDN) требуется ввести доменное имя хоста, по которому доступен сервер manager.swarm.itc-life.ru. Важно чтобы он был доступен по доменному имени внутри той сети, из которой gitlab runnet будет совершать дествия по разворачиванию приложений. Для этого можете поднять свой локальный dns сервер или прописать глобально

openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem

в поле где запросят FQDN вводим

manager.swarm.itc-life.ru 

Или можем ввести ip адресс

192.168.88.250

Теперь создадим приватный ключ для сервера:

openssl genrsa -out server-key.pem 4096

Теперь, когда у нас есть сертификационный центр мы можем создать запрос на подпись SSL сертификата (CSR). Поле CN (Common Name) должно совпадать с использованным на предыдущем шаге значением FQDN:

openssl req -subj "/CN=manager.swarm.itc-life.ru" -sha256 -new -key server-key.pem -out server.csr

или

openssl req -subj "/CN=192.168.88.250" -sha256 -new -key server-key.pem -out server.csr

Дополнительно требуется указать IP-адрес сервера Manager (машина, в которой мы сейчас работаем):

echo subjectAltName = IP:0.0.0.0,IP:127.0.0.1,IP:192.168.88.250 >> extfile.cnf 

Создадим подписанный ключ для сервера:

openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile extfile.cnf

Теперь создадим клиентский сертификат и ключ.

openssl genrsa -out key.pem 4096
openssl req -subj "/CN=client.swarm.itc-life.ru" -new -key key.pem -out client.csr
echo extendedKeyUsage = serverAuth,clientAuth > extfile.cnf
openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out cert.pem -extfile extfile.cnf

Удалим запросы на создание ключей

rm -v client.csr server.csr

Применим права

chmod -v 0400 ca-key.pem key.pem server-key.pemchmod -v 0444 ca.pem server-cert.pem cert.pem

Настроим докер на manager node на работу с ключами

Теперь создадим новый конфигурационный файл(отредактируем) и запишем следующий текст, определяющим использование протокола TLS для доступа к сервису Docker, а также расположение серверного ключа и сертификата:

nano /etc/docker/daemon.json

Вывод

{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "metrics-addr": "0.0.0.0:9323",
  "experimental": true,
  "hosts": ["tcp://0.0.0.0:2376","fd://"],
  "tlsverify": true,
  "tlscacert": "/docker-compose/SWARM/swarmcerts/ca.pem",
  "tlscert": "/docker-compose/SWARM/swarmcerts/server-cert.pem",
  "tlskey": "/docker-compose/SWARM/swarmcerts/server-key.pem"
}

По-умолчанию доступ к сервису Docker имеет только пользователь-владелец процесса. Для выполнения операций по развертыванию приложения с удаленного хоста, нам необходимо разрешить подключение извне, при этом использовать TLS-протокол. Мы уже получили необходимые сертификаты и ключи, теперь осталось настроить Docker для работы с ними.

Мы создадим отдельный конфигурационный файл явно прописывающий хосты, по которым будет доступен Docker, поэтому для начала нам нужно удалить стандартный параметр -H, прописывающий хост. Для этого создадим новую директорию docker.service.d, в которой переопределим параметры запуска сервиса:

mkdir -p /etc/systemd/system/docker.service.d
nano /etc/systemd/system/docker.service.d/exec-start.conf

Вставляем туда следующее содержимое.

[Service]
ExecStart=
ExecStart=/usr/bin/dockerd

Рестартуем докер на manager ноде

systemctl daemon-reload
systemctl restart docker

Сейчас у нас есть всё необходимое для настройки защищенного доступа между GitLab Runner и рабочей Swarm-средой.

Для добавления нод worker в swarm нам необходимо

docker swarm join --token SWMTKN-1-1lhmuomvb060rnom4jqj8gxc565f4wgwadjs9ucvqx6huwvbfc-6vt1ljdhldxtetjv2hnct7sh4 192.168.88.250:2377

Токен берем на ноде manager

docker swarm join-token manager

Настройка секретных переменных в GitLab CI
Мы не будем хранить данные клиентских ключей на машине Runner из соображений безопасности. Для таких задач в GitLab CI реализована функция секретных переменных среды.

Заходим в наш проект

Setting >> CI/CD >> Secret variables

Нам необходимо добавить и сохранить три переменные со следующими названиями и значениями файлов, которые мы создали на предыдущем шаге:

Переменные

переменная TLSCACERT >> cat ca.pem;
переменная TLSCERT >> cat cert.pem;
переменная TLSKEY >> cat key.pem.
переменная CI_REGISTRY_USER >> пользователь gitlab
переменная CI_REGISTRY_PASSWORD >> пароль пользователя gitlab
переменная CI_REGISTRY >> registry-gitlab.itc-life.ru:4567

Шаг 3.Подключение Docker Registry в GitLab

gitlab у меня запущен в докер. Отредактируем файл настроек

nano gitlab.rb

Приведем к виду

registry_external_url 'https://registry-gitlab.itc-life.ru:4567'
registry_nginx['enable'] = true
registry_nginx['listen_port'] = 4567
registry_nginx['ssl_certificate'] = "/etc/letsencrypt/live/itc-life.ru-0002/fullchain.pem"
registry_nginx['ssl_certificate_key'] = "/etc/letsencrypt/live/itc-life.ru-0002/privkey.pem"

И перенастроим. Рестаранем или:

gitlab-ctl reconfigure

так же сделаем жизни время токена авторизации для регистри 60 минут – чтобы пушить большие образы. Заходим в админку в настройки.


или просто рестрартанем докер c gitlab.

Шаг 4.Создание приложения

Создадим тестовый проект

itc-life/itc-deploy

т.е. проект в группе itc-life с именем itc-deploy.
Проект будет представлять собой простой nginx – proxy. Далее склонируем репу.

git clone ssh://git@gitlab.itc-life.ru:2224/itc-life/itc-deploy.git
cd itc-deploy

Создадим файл из которго мы будем делать деплой дальше

nano docker-compose.yml
version: "3.4"
services:
  nginx:
    image: registry-gitlab.itc-life.ru:4567/itc-life/itc-deploy/nginx:${CI_COMMIT_SHA}
    ports:
      - "80:80"
    deploy:
      #mode: replicated
      replicas: 1
      # service resource management
      resources:
        # Hard limit - Docker does not allow to allocate more
        limits:
          cpus: '1'
          memory: 256MB
        # Soft limit - Docker makes best effort to return to it
        reservations:
          #cpus: '1'
          memory: 4MB
      # service restart policy
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
        window: 20s
      # service update configuration
      update_config:
        parallelism: 1
        delay: 10s
        failure_action: continue
        monitor: 5s
        max_failure_ratio: 0.3
      # placement constraint - in this case on 'worker' nodes only
      placement:
        constraints: [node.role == manager]

блок services включает в себя описание всех создаваемых сервисов;
в каждом сервисе есть раздел image, который определяет используемый образ для создания контейнеров на его основе. Подобный формат записи позволяет получать образы с хранилища, доступного по адресу registry-gitlab.itc-life.ru:4567. Последний аргумент ${CI_COMMIT_SHA} – переменная окружения, связанная с значением хеша текущего коммита, которую мы используем для различия сборок друг от друга в данном руководстве.
В секции placement мы указали чтобы будем запускать его на manager.

Далее создадим nginx докер из которого будем делать сборку

mkdir nginx
cd nginx
nano Dockerfile
FROM nginx:latest
RUN rm /etc/nginx/conf.d/default.conf
COPY kibana.conf /etc/nginx/conf.d/

Save and exit

Здесь я просто создам файлик c проксирование на kibana – для примера

nano kibana.conf
upstream kibana {
server                   192.168.88.10:5601;
}
server {
  listen                    80;
  server_name               kibana.itc-life.ru;
  location / {
    proxy_pass http://192.168.88.10:5601;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection 'upgrade';
    proxy_set_header Host $host;
    proxy_cache_bypass $http_upgrade;
  }
}

Управление GitLab CI осуществляется через файл конфигурации:

nano .gitlab-ci.yml
image: docker:18.03.1-ce
services:
- docker:18.03.1-ce-dind
stages:
  - build
  - deploy
docker-build:
  stage: build
  script:
  - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  - docker build -t $CI_REGISTRY/itc-life/itc-deploy/nginx:$CI_COMMIT_SHA ./nginx
  - docker push $CI_REGISTRY/itc-life/itc-deploy/nginx:$CI_COMMIT_SHA
  tags:
  - docker
deploy-to-swarm:
  stage: deploy
  variables:
    DOCKER_HOST: tcp://manager.swarm.itc-life.ru:2376
    DOCKER_TLS_VERIFY: 1
    DOCKER_CERT_PATH: "/certs"
  before_script:
    - mkdir $DOCKER_CERT_PATH
    - echo "$TLSCACERT" > $DOCKER_CERT_PATH/ca.pem
    - echo "$TLSCERT" > $DOCKER_CERT_PATH/cert.pem
    - echo "$TLSKEY" > $DOCKER_CERT_PATH/key.pem
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker stack deploy -c docker-compose.yml --with-registry-auth  test
    - rm -rf $DOCKER_CERT_PATH
  environment:
    name: master
    #default url $CI_ENVIRONMENT_URL
    url: http://192.168.88.250
  #when: manual
  #allow_failure: false
  #cache: {}
  #dependencies: []
  only:
    - master
  tags:
    - docker

Пробуем

git add --all
git commit -m "init"
git push origin master

Теперь, если на предыдущих шагах не было совершенно ошибки произойдет “пуш” в наш репозиторий GitLab, пройдут все тесты и сборка образов Docker, а затем развертывание в Docker Swarm.

Для отслеживания процессов перейдем в GitLab в раздел Pipelines и откроем последний:

Если ваш результат отличается от приведенного, перейдите в раздел Jobs и посмотрите логи по неудавшейся операции, часто это бывают опечатки или неверные адреса серверов.

Перейдем в раздел Environments:

Здесь происходит управление развернутыми средами для различных целей. Сейчас мы используем только среду master, но это не мешает вам настроить их под свои процессы.

Если было произведено уже несколько коммитов в одну среду, можно использовать функцию откатывания на предыдущую версию – для этого раскройте среду master, нажатием на название среды:

Для отката на предыдущую версию достаточно нажать кнопку Rollback, которая запустит стадию deploy для выбранного коммита.

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

Готово

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

 

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.