Как создавать образы Docker в конвейере GitLab CI
Одним из распространенных вариантов использования конвейеров CI является создание образов Docker, которые вы будете использовать для развертывания своего приложения. GitLab CI — отличный выбор для этого, так как он поддерживает интегрированную службу прокси-сервера, что означает более быстрые конвейеры, и встроенный реестр для хранения ваших созданных образов.
В этом руководстве мы покажем вам, как настроить сборки Docker, которые используют обе вышеуказанные функции. Шаги, которые вам нужно предпринять, немного различаются в зависимости от типа исполнителя GitLab Runner, который вы будете использовать для своего пайплайна. Ниже мы рассмотрим исполнителей Shell и Docker.
Сборка с помощью Shell Executor
Если вы используете исполняющую оболочку, убедитесь, что у вас установлен Docker на компьютере, на котором находится исполняющая программа. Исполнитель работает, выполняя обычные команды оболочки, используя двоичный файл docker
на хосте Runner.
Перейдите в репозиторий Git для проекта, для которого вы хотите создать образы. Создайте файл .gitlab-ci.yml
в корне репозитория. Этот файл определяет конвейер GitLab CI, который будет запускаться при отправке изменений в ваш проект.
Добавьте в файл следующее содержимое:
stages: - build docker_build: stage: build script: - docker build -t example.com/example-image:latest . - docker push example.com/example-image:latest
Этой упрощенной конфигурации достаточно, чтобы продемонстрировать основы конвейерной сборки образов. GitLab автоматически клонирует ваш репозиторий Git в среду сборки, поэтому запуск docker build
будет использовать Dockerfile
вашего проекта и сделает содержимое репозитория доступным в качестве контекста сборки.
После завершения сборки вы можете docker отправить
образ в свой реестр. В противном случае он был бы доступен только для локальной установки Docker, на которой была запущена сборка. Если вы используете частный реестр, сначала запустите docker login
, чтобы предоставить правильные данные аутентификации:
script:
- docker login -u $DOCKER_REGISTRY_USER -p $DOCKER_REGISTRY_PASSWORD
Определите значения двух переменных учетных данных, выбрав «Настройки» > «CI/CD» > «Переменные» в веб-интерфейсе GitLab. Нажмите синюю кнопку «Добавить переменную», чтобы создать новую переменную и присвоить ей значение. GitLab сделает эти переменные доступными в среде оболочки, используемой для запуска вашего задания.
Создание с помощью Docker Executor
Исполнитель Docker GitLab Runner обычно используется для обеспечения абсолютно чистой среды для каждого задания. Задание будет выполняться в изолированном контейнере, поэтому двоичный файл docker
на хосте Runner будет недоступен.
Исполнитель Docker предлагает две возможные стратегии для создания образа: либо использовать Docker-in-Docker, либо привязать сокет Docker хоста к среде сборки Runner. Затем вы используете официальный образ контейнера Docker в качестве образа вашего задания, делая команду docker
доступной в вашем сценарии CI.
Докер-в-Докере
Использование Docker-in-Docker (DinD) для создания образов дает вам полностью изолированную среду для каждого задания. Процесс Docker, выполняющий сборку, будет дочерним элементом контейнера, который GitLab Runner создает на хосте для выполнения задания CI.
Вам необходимо зарегистрировать исполнитель GitLab Runner Docker с включенным привилегированным режимом, чтобы использовать DinD. Добавьте флаг --docker-privived
при регистрации бегуна:
sudo gitlab-runner register -n
--url https://example.com
--registration-token $GITLAB_REGISTRATION_TOKEN
--executor docker
--description "Docker Runner"
--docker-image "docker:20.10"
--docker-volumes "/certs/client"
--docker-privileged
В конвейере непрерывной интеграции добавьте образ docker:dind
в качестве службы. Это делает Docker доступным в виде отдельного образа, связанного с образом задания. Вы сможете использовать команду docker
для создания образов с использованием экземпляра Docker в контейнере docker:dind
.
services: - docker:dind docker_build: stage: build image: docker:latest script: - docker build -t example-image:latest .
Использование DinD дает вам полностью изолированные сборки, которые не могут влиять ни друг на друга, ни на ваш хост. Основным недостатком является более сложное поведение кэширования: каждое задание получает новую среду, в которой ранее созданные слои не будут доступны. Вы можете частично решить эту проблему, попытавшись получить предыдущую версию вашего образа перед сборкой, а затем использовать флаг сборки --cache-from
, чтобы сделать слои извлеченного изображения доступными в качестве источника кеша:
docker_build: stage: build image: docker:latest script: - docker pull $CI_REGISTRY_IMAGE:latest || true - docker build --cache-from $CI_REGISTRY_IMAGE:latest -t $CI_REGISTRY_IMAGE:latest .
Гнездо для крепления
Установка сокета Docker вашего хоста в среду вашего задания является альтернативным вариантом, когда вы используете исполнителя Docker. Это обеспечивает бесшовное кэширование и избавляет от необходимости добавлять службу docker:dind
в конфигурацию CI.
Чтобы настроить это, зарегистрируйте свой Runner с флагом docker-volumes
, который привязывает сокет Docker хоста к /var/run/docker.sock
внутри контейнеров заданий:
sudo gitlab-runner register -n
--url https://example.com
--registration-token $GITLAB_REGISTRATION_TOKEN
--executor docker
--description "Docker Runner"
--docker-image "docker:20.10"
--docker-volumes /var/run/docker.sock:/var/run/docker.sock
Теперь задания, запускаемые с образом docker
, смогут использовать двоичный файл docker
как обычно. Операции фактически будут выполняться на вашем хост-компьютере, становясь родственными контейнеру задания, а не дочерними.
Это фактически похоже на использование исполнителя оболочки с установкой Docker на вашем хосте. Изображения будут храниться на хосте, что упрощает использование обычного кэширования слоя docker build
.
Хотя этот подход может привести к более высокой производительности, меньшей конфигурации и отсутствию ограничений DinD, он имеет свои уникальные проблемы. Наиболее важными среди них являются последствия для безопасности: задания могут выполнять произвольные команды Docker на вашем хосте Runner, поэтому вредоносный проект в вашем экземпляре GitLab может запускать docker run -it malware-image:latest
или docker rm -f $ (docker ps -a)
с разрушительными последствиями.
GitLab также предупреждает, что привязка сокетов может вызвать проблемы при одновременном выполнении заданий. Это происходит, когда вы полагаетесь на контейнеры, создаваемые с определенными именами. Если два экземпляра задания выполняются параллельно, второй завершится ошибкой, так как имя контейнера уже существует на вашем хосте.
Вместо этого вам следует рассмотреть возможность использования DinD, если вы ожидаете, что любая из этих проблем будет проблематичной. Хотя DinD больше не рекомендуется, он может иметь больше смысла для общедоступных экземпляров GitLab, которые выполняют параллельные задания CI.
Отправка изображений в реестр GitLab
Проекты GitLab имеют встроенный реестр, который вы можете использовать для хранения своих образов. Вы можете просмотреть содержимое реестра, перейдя в Packages & Registries > Container Registry на боковой панели вашего проекта. Если вы не видите эту ссылку, включите реестр, выбрав «Настройки»> «Основные»> «Видимость, проект, функции и разрешения» и активировав переключатель «Реестр контейнеров».
GitLab автоматически устанавливает переменные среды в ваших заданиях CI, что позволяет вам ссылаться на реестр контейнеров вашего проекта. Настройте раздел script
, чтобы войти в реестр и отправить свое изображение:
script: - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY - docker build -t $CI_REGISTRY_IMAGE:latest . - docker push $CI_REGISTRY_IMAGE:latest
GitLab создает безопасный набор учетных данных для каждого из ваших заданий CI. Переменная среды $CI_JOB_TOKEN
будет содержать маркер доступа, который задание может использовать для подключения к реестру в качестве пользователя gitlab-ci-token
. URL-адрес сервера реестра доступен как $CI_REGISTRY
.
Последняя переменная, $CI_REGISTRY_IMAGE
, предоставляет полный путь к реестру контейнеров вашего проекта. Это подходящая основа для ваших тегов изображений. Вы можете расширить эту переменную для создания вложенных репозиториев, таких как $CI_REGISTRY_IMAGE/production/api:latest
.
Другие клиенты Docker могут извлекать образы из реестра, аутентифицируясь с помощью токена доступа. Вы можете сгенерировать их на экране «Настройки» > «Токены доступа» вашего проекта. Добавьте область read_registry
, затем используйте отображаемые учетные данные для входа в docker
в реестр вашего проекта.
Использование прокси-сервера зависимостей GitLab
Прокси-сервер зависимостей GitLab обеспечивает уровень кэширования для исходных изображений, которые вы извлекаете из Docker Hub. Это помогает вам оставаться в пределах ограничений скорости Docker Hub, извлекая содержимое изображений только тогда, когда они действительно изменились. Это также повысит производительность ваших сборок.
Прокси-сервер зависимостей активируется на уровне группы GitLab, выбрав «Настройки» > «Пакеты и реестры» > «Прокси-сервер зависимостей». После его включения добавьте к ссылкам на изображения в файле .gitlab-ci.yml
префикс $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX
, чтобы получить их через прокси-сервер:
docker_build: stage: build image: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/docker:latest services: - name: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/docker:dind alias: docker
Вот и все! GitLab Runner автоматически входит в реестр прокси-серверов зависимостей, поэтому вам не нужно вручную вводить свои учетные данные.
Теперь GitLab будет кэшировать ваши изображения, повышая производительность и устойчивость к перебоям в работе сети. Обратите внимание, что определение services
также пришлось скорректировать — переменные среды не работают со встроенной формой, использовавшейся ранее, поэтому необходимо указать полное имя
изображения, а затем команда псевдоним
для ссылки в разделе script
.
Хотя мы уже настроили прокси для образов, непосредственно используемых на этапах нашей работы, требуется дополнительная работа, чтобы добавить поддержку базового образа в Dockerfile
для сборки. Обычная инструкция вроде этой не пройдет через прокси:
FROM ubuntu:latest
Чтобы добавить эту последнюю часть, используйте аргументы сборки Docker, чтобы сделать URL-адрес прокси-сервера зависимостей доступным при пошаговом прохождении Dockerfile:
ARG GITLAB_DEPENDENCY_PROXY
FROM ${GITLAB_DEPENDENCY_PROXY}/ubuntu:latest
Затем измените команду docker build
, чтобы определить значение переменной:
script: > - docker build --build-arg GITLAB_DEPENDENCY_PROXY=${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX} -t example-image:latest .
Теперь ваш базовый образ также будет загружаться через прокси-сервер зависимостей.
Краткое содержание
Сборки образов Docker легко интегрируются в конвейеры GitLab CI. После первоначальной настройки Runner команды docker build
и docker push
в разделе script
вашего задания — это все, что вам нужно для создания образа с Dockerfile
в вашем репозитории. Встроенный реестр контейнеров GitLab предоставляет вам личное хранилище для образов вашего проекта.
Помимо базовых сборок, стоит интегрировать прокси-сервер зависимостей GitLab, чтобы повысить производительность и избежать превышения ограничений скорости Docker Hub. Вы также должны проверить безопасность своей установки, оценив, позволяет ли выбранный вами метод ненадежным проектам запускать команды на вашем хосте Runner. Хотя у Docker-in-Docker есть свои проблемы, он является самым безопасным подходом, когда ваш экземпляр GitLab общедоступен или используется большой базой пользователей.