Данная статья будет интересна как тестировщикам, так и разработчикам, но рассчитана в большей степени на автоматизаторов, которые столкнулись с проблемой настройки GitLab CI/CD для проведения интеграционного тестирования в условиях недостаточности инфраструктурных ресурсов и/или отсутствия платформы оркестрации контейнеров. Я расскажу, как настроить развертывание тестируемых окружений при помощи docker compose на одном единственном GitLab shell раннере и так, чтобы при развертывании нескольких окружений запускаемые сервисы друг другу не мешали.



Содержание




Предпосылки


  1. В моей практике частенько случалось "лечить" интеграционное тестирование на проектах. И зачастую первой и самой значительной проблемой является CI pipeline, в котором интеграционное тестирование разрабатываемого сервиса(ов) проводится в dev/stage окружении. Это вызывало не мало проблем:


    • Из-за дефектов в том или ином сервисе в процессе интеграционного тестирования тестовый контур может быть испорчен битыми данными. Бывали случаи, когда отправка запроса с битым JSON-форматом вешал сервис, что приводило стенд полностью в нерабочее состояние.
    • Замедлением работы тестового контура с ростом тестовых данных. Думаю, описывать пример с очисткой/откатом БД не имеет смысла. В своей практике я не встречал проекта, где эта процедура проходила бы гладко.
    • Риск нарушить работоспособность тестового контура при тестировании общих настроек системы. Например, user/group/password/application policy.
    • Тестовые данные от автотестов мешают жить ручным тестировщикам.

    Кто-то скажет, что хорошие автотесты должны чистить данные после себя. У меня есть аргументы против:


    • Динамические стенды весьма удобны в использовании.
    • Не каждый объект можно удалить из системы через API. Например вызов на удаление объекта не реализован, так как противоречит бизнес логике.
    • При создании объекта через API может создаваться огромное количество метаданных, которые удалить проблематично.
    • Если тесты имеют зависимость между собой, то процесс очистки данных после выполнения тестов превращается в головную боль.
    • Дополнительные (и, на мой взгляд, не оправданные) вызовы к API.
    • И главный аргумент: когда тестовые данные начинают чистить прямо из БД. Это превращается в настоящий PK/FK цирк! От разработчиков слышно: «Я только табличку добавил/удалил/переименовал, почему 100500 интеграционных тестов попадало?»

    По моему мнению, самое оптимальное решение — это динамическое окружение.


  2. Много кто использует docker-compose для запуска тестового окружения, но мало кто использует docker-compose при проведении интеграционного тестирования в CI/CD. И тут я не беру в расчет kubernetes, swarm и другие платформы оркестрации контейнеров. Не в каждой компании они есть. Хорошо бы было, если бы docker-compose.yml был универсальный.
  3. Если даже у нас есть свой QA раннер, как нам сделать так, чтобы сервисы запускаемые через docker-compose не мешали друг-другу?
  4. Как собирать логи тестируемых сервисов?
  5. Как чистить раннер?

У меня есть собственный GitLab раннер для своих проектов и с этими вопросами я столкнулся при разработке Java клиента для TestRail. А точнее при запуске интеграционных тестов. Вот далее и будем решать эти вопросы с примерами из данного проекта.


К содержанию



GitLab Shell Runner


Для раннера рекомендую линуксовую виртуалку с 4 vCPU, 4 GB RAM, 50 GB HDD.
На просторах интернета очень много информации по настройке gitlab-runner, поэтому коротко:


  • Заходим на машинку по SSH
  • Если у вас менее 8 GB RAM, то рекомендую сделать swap 10 GB, чтобы не приходил OOM killer и не убивал нам задачи из-за нехватки RAM. Такое может случится, когда запускается одновременно более 5 задач. Задачи будут проходить помедленнее, зато стабильно.


    Пример с OOM killer

    Если в логах задачи вы увидите bash: line 82: 26474 Killed, то просто выполните на раннере sudo dmesg | grep 26474


    [26474]  1002 26474  1061935   123806     339        0             0 java
    Out of memory: Kill process 26474 (java) score 127 or sacrifice child
    Killed process 26474 (java) total-vm:4247740kB, anon-rss:495224kB, file-rss:0kB, shmem-rss:0kB

    И если картина выглядит примерно так, то или добавляйте swap, или докидывайте RAM.




  • Устанавливаем gitlab-runner, docker, docker-compose, make.
  • Добавляем пользователя gitlab-runner в группу docker
    sudo groupadd docker
    sudo usermod -aG docker gitlab-runner
  • Регистрируем gitlab-runner.
  • Открываем на редактирование /etc/gitlab-runner/config.toml и добавляем


    concurrent=20
    [[runners]]
      request_concurrency = 10

    Это позволит запускать параллельные задачи на одном раннере. Более подробно читать тут.
    Если у вас машинка помощнее, например 8 vCPU, 16 GB RAM, то эти цифры можно сделать как минимум в 2 раза больше. Но все зависит от того, что конкретно будет запускаться на данном раннере и в каком количестве.



Этого достаточно.


К содержанию



Подготовка docker-compose.yml


Основная задача — это docker-compose.yml, который будет использован как локально, так и в CI pipeline.


Для запуска нескольких экземпляров окружения будет использоваться переменная COMPOSE_PROJECT_NAME (см. makefile).


Пример моего docker-compose.yml


version: "3"

# Для корректной работы web (php) и fmt нужно, 
# чтобы контейнеры имели общий исполняемый контент.
# В нашем случае, это директория /var/www/testrail
volumes:
  static-content:

services:
  db:
    image: mysql:5.7.22
    environment:
      MYSQL_HOST: db
      MYSQL_DATABASE: mydb
      MYSQL_ROOT_PASSWORD: 1234
      SKIP_GRANT_TABLES: 1
      SKIP_NETWORKING: 1
      SERVICE_TAGS: dev
      SERVICE_NAME: mysql

  migration:
    image: registry.gitlab.com/touchbit/image/testrail/migration:latest
    links:
    - db
    depends_on:
    - db

  fpm:
    image: registry.gitlab.com/touchbit/image/testrail/fpm:latest
    container_name: "testrail-fpm-${CI_JOB_ID:-local}"
    volumes:
    - static-content:/var/www/testrail
    links:
    - db

  web:
    image: registry.gitlab.com/touchbit/image/testrail/web:latest
    # Если переменные TR_HTTP_PORT или TR_HTTPS_PORTS не определены,
    # то сервис поднимается на 80 и 443 порту соответственно.
    ports:
      - ${TR_HTTP_PORT:-80}:80
      - ${TR_HTTPS_PORT:-443}:443
    volumes:
      - static-content:/var/www/testrail
    links:
      - db
      - fpm

К содержанию



Подготовка Makefile


Я использую Makefile, так как это весьма удобно как для локального управления окружением, так и в CI.


Далее комментарии инлайн


# У меня в проектах все вспомогательные вещи лежат в директории `.indirect`,
# в том числе и `docker-compose.yml`

# Использовать bash с опцией pipefail 
# pipefail - фейлит выполнение пайпа, если команда выполнилась с ошибкой
SHELL=/bin/bash -o pipefail

# Если переменная CI_JOB_ID не определена 
ifeq ($(CI_JOB_ID),)
    # присваиваем значение local
    CI_JOB_ID := local
endif

# Экспортируем переменную окружения
export COMPOSE_PROJECT_NAME = $(CI_JOB_ID)-testrail

# Останавливаем и удаляем контейнеры, сеть, volumes
docker-down:
    docker-compose -f .indirect/docker-compose.yml down

# Предварительно выполняем docker-down (опционально)
docker-up: docker-down
    # Забираем последние образы из docker-registry
    docker-compose -f .indirect/docker-compose.yml pull
    # Запускаем окружение
    # force-recreate - принудительное пересоздание контейнеров
    # renew-anon-volumes - не использовать volumes предыдущих контейнеров
    docker-compose -f .indirect/docker-compose.yml up --force-recreate --renew-anon-volumes -d
    # Ну и, на всякий случай, вывести что там у нас в принципе запущено на машинке
    docker ps

# Коллектим логи сервисов
docker-logs:
    mkdir -p ./logs
    docker logs $${COMPOSE_PROJECT_NAME}_web_1       >& logs/testrail-web.log       || true
    docker logs $${COMPOSE_PROJECT_NAME}_fpm_1       >& logs/testrail-fpm.log       || true
    docker logs $${COMPOSE_PROJECT_NAME}_migration_1 >& logs/testrail-migration.log || true
    docker logs $${COMPOSE_PROJECT_NAME}_db_1        >& logs/testrail-mysql.log     || true

# Очистка раннера
docker-clean:
    @echo Останавливаем все testrail-контейнеры
    docker kill $$(docker ps --filter=name=testrail -q) || true
    @echo Очистка докер контейнеров
    docker rm -f $$(docker ps -a -f --filter=name=testrail status=exited -q) || true
    @echo Очистка dangling образов
    docker rmi -f $$(docker images -f "dangling=true" -q) || true
    @echo Очистка testrail образов
    docker rmi -f $$(docker images --filter=reference='registry.gitlab.com/touchbit/image/testrail/*' -q) || true
    @echo Очистка всех неиспользуемых volume
    docker volume rm -f $$(docker volume ls -q) || true
    @echo Очистка всех testrail сетей
    docker network rm $(docker network ls --filter=name=testrail -q) || true
    docker ps

Проверяем локальный запуск
$ make docker-up 
docker-compose -f .indirect/docker-compose.yml pull
Pulling db        ... done
Pulling migration ... done
Pulling fpm       ... done
Pulling web       ... done
docker-compose -f .indirect/docker-compose.yml up --force-recreate --renew-anon-volumes -d
Creating network "local-testrail_default" with the default driver
Recreating local-testrail_db_1 ... done
Recreating local-testrail_migration_1 ... done
Recreating local-testrail_fpm_1       ... done
Recreating local-testrail_web_1       ... done
docker ps
CONTAINER ID        NAMES
3b8f9d4af29c        local-testrail_web_1
5622c7d742d5        local-testrail_fpm_1
b580e3392038        local-testrail_migration_1
e467630bd3a5        local-testrail_db_1

Проверяем CI запуск
$ export CI_JOB_ID=123456789
$ make docker-up 
docker-compose -f .indirect/docker-compose.yml pull
Pulling db        ... done
Pulling migration ... done
Pulling fpm       ... done
Pulling web       ... done
docker-compose -f .indirect/docker-compose.yml up --force-recreate --renew-anon-volumes -d
Creating network "123456789-testrail_default" with the default driver
Creating volume "123456789-testrail_static-content" with default driver
Creating 123456789-testrail_db_1 ... done
Creating 123456789-testrail_fpm_1       ... done
Creating 123456789-testrail_migration_1 ... done
Creating 123456789-testrail_web_1       ... done
docker ps
CONTAINER ID        NAMES
ccf1ad33d0e8        123456789-testrail_web_1
bc079964f681        123456789-testrail_fpm_1
10dc9d4d8f2a        123456789-testrail_migration_1
fe98d43c380e        123456789-testrail_db_1

Проверяем сбор логов
$ make docker-logs
mkdir -p ./logs
docker logs ${COMPOSE_PROJECT_NAME}_web_1       >& logs/testrail-web.log       || true
docker logs ${COMPOSE_PROJECT_NAME}_fpm_1       >& logs/testrail-fpm.log       || true
docker logs ${COMPOSE_PROJECT_NAME}_migration_1 >& logs/testrail-migration.log || true
docker logs ${COMPOSE_PROJECT_NAME}_db_1        >& logs/testrail-mysql.log     || true


К содержанию



Подготовка .gitlab-ci.yml



Запуск интеграционных тестов


Integration:
  stage: test
  tags:
    - my-shell-runner
  before_script:
    # Аутентифицируемся в registry
    - docker login -u gitlab-ci-token -p ${CI_JOB_TOKEN} ${CI_REGISTRY}
    # Генерируем псевдоуникальные TR_HTTP_PORT и TR_HTTPS_PORT
    - export TR_HTTP_PORT=$(shuf -i10000-60000 -n1)
    - export TR_HTTPS_PORT=$(shuf -i10000-60000 -n1)
  script:
    # поднимаем наше окружение
    - make docker-up
    # запускаем тесты исполняемым jar (у меня так)
    - java -jar itest.jar --http-port ${TR_HTTP_PORT} --https-port ${TR_HTTPS_PORT}
    # или в контейнере
    - docker run --network=testrail-network-${CI_JOB_ID:-local} --rm itest
  after_script:
    # собираем логи
    - make docker-logs
    # останавливаем окружение
    - make docker-down
  artifacts:
    # сохраняем логи
    when: always
    paths:
      - logs
    expire_in: 30 days

В результате запуска такой задачи в артефактах директория logs будет содержать логи сервисов и тестов. Что очень удобно в случае возникновения ошибок. У меня каждый тест в параллели пишет свой лог, но об этом я расскажу отдельно.



К содержанию



Очистка раннера


Задача будет запускаться только по расписанию.


stages:
- clean
- build
- test

Clean runner:
  stage: clean
  only:
    - schedules
  tags:
    - my-shell-runner
  script:
    - make docker-clean

Далее идем в наш GitLab проект -> CI/CD -> Schedules -> New Schedule и добавляем новое расписание



К содержанию



Результат


Запускаем 4 задачи в GitLab CI


В логах последней задачи с интеграционными тестами видим контейнеры от разных задач


CONTAINER ID  NAMES
c6b76f9135ed  204645172-testrail-web_1
01d303262d8e  204645172-testrail-fpm_1
2cdab1edbf6a  204645172-testrail-migration_1
826aaf7c0a29  204645172-testrail-mysql_1
6dbb3fae0322  204645084-testrail-web_1
3540f8d448ce  204645084-testrail-fpm_1
70fea72aa10d  204645084-testrail-mysql_1
d8aa24b2892d  204644881-testrail-web_1
6d4ccd910fad  204644881-testrail-fpm_1
685d8023a3ec  204644881-testrail-mysql_1
1cdfc692003a  204644793-testrail-web_1
6f26dfb2683e  204644793-testrail-fpm_1
029e16b26201  204644793-testrail-mysql_1
c10443222ac6  204567103-testrail-web_1
04339229397e  204567103-testrail-fpm_1
6ae0accab28d  204567103-testrail-mysql_1
b66b60d79e43  204553690-testrail-web_1
033b1f46afa9  204553690-testrail-fpm_1
a8879c5ef941  204553690-testrail-mysql_1
069954ba6010  204553539-testrail-web_1
ed6b17d911a5  204553539-testrail-fpm_1
1a1eed057ea0  204553539-testrail-mysql_1

Более детальный лог
$ docker login -u gitlab-ci-token -p ${CI_JOB_TOKEN} ${CI_REGISTRY}
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /home/gitlab-runner/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
Login Succeeded
$ export TR_HTTP_PORT=$(shuf -i10000-60000 -n1)
$ export TR_HTTPS_PORT=$(shuf -i10000-60000 -n1)
$ mkdir ${CI_JOB_ID}
$ cp .indirect/docker-compose.yml ${CI_JOB_ID}/docker-compose.yml
$ make docker-up
docker-compose -f ${CI_JOB_ID:-.indirect}/docker-compose.yml kill
docker network rm testrail-network-${CI_JOB_ID:-local} || true
Error: No such network: testrail-network-204645172
docker network create testrail-network-${CI_JOB_ID:-local}
0a59552b4464b8ab484de6ae5054f3d5752902910bacb0a7b5eca698766d0331
docker-compose -f ${CI_JOB_ID:-.indirect}/docker-compose.yml pull
Pulling web       ... done
Pulling fpm       ... done
Pulling migration ... done
Pulling db        ... done
docker-compose -f ${CI_JOB_ID:-.indirect}/docker-compose.yml up --force-recreate --renew-anon-volumes -d
Creating volume "204645172-testrail_static-content" with default driver
Creating 204645172-testrail-mysql_1 ... 
Creating 204645172-testrail-mysql_1 ... done
Creating 204645172-testrail-migration_1 ... done
Creating 204645172-testrail-fpm_1       ... done
Creating 204645172-testrail-web_1       ... done
docker ps
CONTAINER ID        IMAGE                                                          COMMAND                  CREATED              STATUS              PORTS                                           NAMES
c6b76f9135ed        registry.gitlab.com/touchbit/image/testrail/web:latest         "nginx -g 'daemon of…"   13 seconds ago       Up 1 second         0.0.0.0:51148->80/tcp, 0.0.0.0:25426->443/tcp   204645172-testrail-web_1
01d303262d8e        registry.gitlab.com/touchbit/image/testrail/fpm:latest         "docker-php-entrypoi…"   16 seconds ago       Up 13 seconds       9000/tcp                                        204645172-testrail-fpm_1
2cdab1edbf6a        registry.gitlab.com/touchbit/image/testrail/migration:latest   "docker-entrypoint.s…"   16 seconds ago       Up 13 seconds       3306/tcp, 33060/tcp                             204645172-testrail-migration_1
826aaf7c0a29        mysql:5.7.22                                                   "docker-entrypoint.s…"   18 seconds ago       Up 16 seconds       3306/tcp                                        204645172-testrail-mysql_1
6dbb3fae0322        registry.gitlab.com/touchbit/image/testrail/web:latest         "nginx -g 'daemon of…"   36 seconds ago       Up 22 seconds       0.0.0.0:44202->80/tcp, 0.0.0.0:20151->443/tcp   204645084-testrail-web_1
3540f8d448ce        registry.gitlab.com/touchbit/image/testrail/fpm:latest         "docker-php-entrypoi…"   38 seconds ago       Up 35 seconds       9000/tcp                                        204645084-testrail-fpm_1
70fea72aa10d        mysql:5.7.22                                                   "docker-entrypoint.s…"   40 seconds ago       Up 37 seconds       3306/tcp                                        204645084-testrail-mysql_1
d8aa24b2892d        registry.gitlab.com/touchbit/image/testrail/web:latest         "nginx -g 'daemon of…"   About a minute ago   Up 53 seconds       0.0.0.0:31103->80/tcp, 0.0.0.0:43872->443/tcp   204644881-testrail-web_1
6d4ccd910fad        registry.gitlab.com/touchbit/image/testrail/fpm:latest         "docker-php-entrypoi…"   About a minute ago   Up About a minute   9000/tcp                                        204644881-testrail-fpm_1
685d8023a3ec        mysql:5.7.22                                                   "docker-entrypoint.s…"   About a minute ago   Up About a minute   3306/tcp                                        204644881-testrail-mysql_1
1cdfc692003a        registry.gitlab.com/touchbit/image/testrail/web:latest         "nginx -g 'daemon of…"   About a minute ago   Up About a minute   0.0.0.0:44752->80/tcp, 0.0.0.0:23540->443/tcp   204644793-testrail-web_1
6f26dfb2683e        registry.gitlab.com/touchbit/image/testrail/fpm:latest         "docker-php-entrypoi…"   About a minute ago   Up About a minute   9000/tcp                                        204644793-testrail-fpm_1
029e16b26201        mysql:5.7.22                                                   "docker-entrypoint.s…"   About a minute ago   Up About a minute   3306/tcp                                        204644793-testrail-mysql_1
c10443222ac6        registry.gitlab.com/touchbit/image/testrail/web:latest         "nginx -g 'daemon of…"   5 hours ago          Up 5 hours          0.0.0.0:57123->80/tcp, 0.0.0.0:31657->443/tcp   204567103-testrail-web_1
04339229397e        registry.gitlab.com/touchbit/image/testrail/fpm:latest         "docker-php-entrypoi…"   5 hours ago          Up 5 hours          9000/tcp                                        204567103-testrail-fpm_1
6ae0accab28d        mysql:5.7.22                                                   "docker-entrypoint.s…"   5 hours ago          Up 5 hours          3306/tcp                                        204567103-testrail-mysql_1
b66b60d79e43        registry.gitlab.com/touchbit/image/testrail/web:latest         "nginx -g 'daemon of…"   5 hours ago          Up 5 hours          0.0.0.0:56321->80/tcp, 0.0.0.0:58749->443/tcp   204553690-testrail-web_1
033b1f46afa9        registry.gitlab.com/touchbit/image/testrail/fpm:latest         "docker-php-entrypoi…"   5 hours ago          Up 5 hours          9000/tcp                                        204553690-testrail-fpm_1
a8879c5ef941        mysql:5.7.22                                                   "docker-entrypoint.s…"   5 hours ago          Up 5 hours          3306/tcp                                        204553690-testrail-mysql_1
069954ba6010        registry.gitlab.com/touchbit/image/testrail/web:latest         "nginx -g 'daemon of…"   5 hours ago          Up 5 hours          0.0.0.0:32869->80/tcp, 0.0.0.0:16066->443/tcp   204553539-testrail-web_1
ed6b17d911a5        registry.gitlab.com/touchbit/image/testrail/fpm:latest         "docker-php-entrypoi…"   5 hours ago          Up 5 hours          9000/tcp                                        204553539-testrail-fpm_1
1a1eed057ea0        mysql:5.7.22                                                   "docker-entrypoint.s…"   5 hours ago          Up 5 hours          3306/tcp                                        204553539-testrail-mysql_1

Все задачи успешно завершены

Артефакты задачи содержат логи сервисов и тестов



Вроде все по красоте, но есть нюанс. Pipeline может быть принудительно отменен во время выполнения интеграционных тестов, и в этом случае запущенные контейнеры не будут остановлены. Время от времени нужно чистить раннер. К сожалению, задача на доработку в GitLab CE все еще в статусе Open


Но у нас добавлен запуск задачи по расписанию, и никто нам не запрещает ее запустить вручную.
Переходим в наш проект -> CI/CD -> Schedules и запускаем задачу Clean runner



Итого:


  • У нас один shell runner.
  • Конфликтов между задачами и окружением нет.
  • У нас параллельный запуск задач с интеграционными тестами.
  • Можно запускать интеграционные тесты как локально, так и в контейнере.
  • Логи сервисов и тестов собираются и прикрепляются к pipeline-задаче.
  • Есть возможность очистки раннера от старых docker-образов.

Время настройки — ~2 часа.
Вот, собственно, и все. Буду рад фидбэку.


P.S.
Особая благодарность freeseacher vvasilenok ivanych. Ваши коментарии оказались очень ценными в контектсе публикации.


К содержанию

Комментарии (13)


  1. Sovigod
    02.05.2019 09:32

    Я возможно не верно понял Makefile, но у вас в остановке контейнеров и их чистке нет фильтрации по CI_JOB_ID. т.е убиваются контейнеры из параллельных пайпов, которые возможно еще работают?


    1. OlegusTesterovichus Автор
      02.05.2019 09:47

      Все верно.
      Задача по расписанию на очистку раннера настроена на 5 утра. В 5 утра крайне низкая вероятность, что кто-то будет что-то пушить.
      Но, если возникла необходимость почистить стенд прямо сейчас, то да. Все запущенные контейнеры будут остановлены и выполняемые задачи с интеграционными тестами упадут. Но предполагается, что запускающий понимает последствия.
      Еще момент. Для очистки стенда, фильтрация по CI_JOB_ID и не предполагается. Мы же раннер чистим в принципе, а не от «ошметков» какой-либо конкретной задачи.


      1. Sovigod
        02.05.2019 10:11

        Ясно. Пропустил момент что вы чистите по расписанию, а не после сборки. А у вас места хватает тогда? У нас за рабочий день может быть до 100 сборок (тестируем каждый новый пуш коммитов во всех ветках). Если волумы не удалять сразу — за день гигов 100 мусора. И это с ограничением в 4 раннера.


        1. OlegusTesterovichus Автор
          02.05.2019 10:33

          Коммитов могло быть много, а пушей в репу вот не сильно много было. Чтоб 100 гигов за день, такого не помню.
          В моей практике мы делали максимально удобно для локального запуска окружения/тестов. Разработчики прежде чем пушить гоняли тесты у себя локально. Но тут повторюсь все должно быть максимально удобно. И собрать и тесты прогнать (быстро), и в случае ошибок максимально информативные логи посмотреть. Как оказалось, разработчику проще локально все прогнать и чуть-что логи грепнуть, чем по ссылкам GitLab маневрировать.


      1. 411
        03.05.2019 00:31

        А почему бы не фильтровать по дате запуска? Ну к примеру чистить только то, что живо более часа?

        А с отменой мы вроде с помощью trap справляемся вместо after_script, но надо посмотреть точнее, возможно ошибаюсь.


  1. gecube
    02.05.2019 11:17
    +1

    Почему не docker-runner и dind? Это решает проблему чистки раннера, а логи в виде артефактов так же можно сохранять и видеть в панели гитлаба.
    Почему docker-compose v3? Вы же наверняка swarm не используете — так и используйте тогда v2.4


  1. navstyachka
    02.05.2019 14:00

    Спасибо, очень интересно и полезно для новичка.


  1. leorush
    03.05.2019 11:24

    Действительно, почему не docker-runner и services?
    gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/ci/docker/using_docker_images.md#what-is-a-service
    Делаем свои образы с центральным логированием на основном, логи в артефактах забираем.
    И concurrent на одной машине без изоляции — плохо. Лично сталкивался с этим багом gitlab.com/gitlab-org/gitlab-ee/issues/2588
    Лучше сделать несколько раннеров, способных работать с одним инстансом системы.


  1. freeseacher
    05.05.2019 22:21
    +1

    Спасибо! Весьма полезно. А какую задачу вырешали выводя CI_JOB_ID в имя контейнера?
    И знали ли при -p ключ у docker-compose? Что бы можно было делать например так


      script:
        - docker-compose -f .docker/docker-compose.yml -p ${CI_COMMIT_REF_SLUG}-tests build tests
        - docker-compose -f .docker/docker-compose.yml -p ${CI_COMMIT_REF_SLUG}-tests up --exit-code-from tests tests
      after_script:
        - docker-compose -f .docker/docker-compose.yml -p ${CI_COMMIT_REF_SLUG}-tests down -v


    1. gecube
      06.05.2019 06:27

      Ключ -p — реальная находка :-)


  1. vvasilenok
    05.05.2019 22:40
    +1

    А почему не использовать COMPOSE_PROJECT_NAME=CI_JOB_ID, в этом случае у всех контейнеров и сетей будет уникальное имя?


  1. ivanych
    06.05.2019 00:09
    +1

    Там выше уже пару комментариев про изоляцию написали, но всё-таки вставлю свои более подробные пять копеек.

    В первую очередь мы делаем уникальные названия сервисов для CI. Одной из уникальных переменных в GitLab CI является переменная CI_JOB_ID. Если указать container_name со значением «service-${CI_JOB_ID:-local}»...


    Менять название контейнера, добавляя в него номер задания, не нужно. Изоляция одного инстанса от другого делается с помощью опции -p:

    docker-compose -p $CI_JOB_ID
    


    С этой опцией все сервисы, указанные в docker-compose.yml, будут запущены в изолированном окружении — инстансе. Каждому контейнеру инстанса будет автоматически добавлен префикс $CI_JOB_ID_ и все контейнеры инстанса будут запущены в автоматически созданной для них сети с таким же префиксом.

    Во вторую очередь мы делаем общую сеть для запускаемых сервисов. Это дает нам изоляцию на уровне сети при запуске нескольких тестовых окружений.


    Создавать сеть вручную тоже не нужно. Как написал выше — опция -p создаст для инстанса нужную сеть автоматически.

    # Останавливаем контейнеры и удаляем сеть
    docker-kill:
    docker-compose -f $${CI_JOB_ID:-.indirect}/docker-compose.yml kill


    Так останавливать инстанс не нужно. Вместо kill используйте down — эта команда удалит после себя мусор (контейнеры, сети и прочее) и дальнейшая очистка раннера будет не в пример проще.

    Мне сейчас не хочется поштучно пересматривать Ваши команды очистки, но с большой вероятностью все они (или большая часть) окажутся не нужны.


  1. OlegusTesterovichus Автор
    06.05.2019 03:09

    freeseacher vvasilenok ivanych плюсик вам в карму, добрые люди. Поправил и статью и свой gitlab-ci.