Оригинал: How to Create a CI/CD Pipeline with Docker
Перевод для канала Мы ж программист
Конвейеры CI/CD автоматизируют задачи сборки, тестирования и развертывания в рамках жизненного цикла поставки программного обеспечения (SDLC). CI/CD является важной частью DevOps, поскольку помогает повысить производительность доставки, обеспечивая при этом соблюдение стандартов качества.
Настройка конвейера часто пересекается с использованием платформ контейнеризации, таких как Docker. Контейнеры – это изолированные, эфемерные среды, которые имеют два основных преимущества для CI/CD: возможность безопасно выполнять задания конвейера и упаковывать создаваемые приложения.
В этой статье мы обсудим, как объединить Docker и CI/CD для достижения максимального эффекта.
Что такое CI/CD?
Конвейеры непрерывной интеграции (CI) и непрерывной доставки (CD) автоматизируют процесс переноса изменений кода из разработки в производственную среду. Ручное выполнение заданий по сборке, тестированию и развертыванию отнимает много времени и чревато ошибками; использование CI/CD позволяет не отвлекаться на разработку, гарантируя, что весь код пройдет необходимые проверки.
Успешное внедрение CI/CD зависит от быстроты, простоты, безопасности и масштабируемости конвейеров. Важно спроектировать среду выполнения заданий таким образом, чтобы она соответствовала этим требованиям, поскольку в противном случае могут возникнуть узкие места и неэффективность. Одним из способов достижения этой цели является использование контейнеров Docker для выполнения заданий.
Использование Docker для CI/CD
Docker – самая популярная платформа для контейнеризации. Изолированность и масштабируемость контейнеров делают их пригодными для решения множества задач, связанных с развертыванием приложений и SDL.
В контексте CI/CD Docker используется двумя основными способами:
- Использование Docker для запуска заданий конвейера CI/CD – ваша платформа CI/CD создает новый контейнер Docker для каждого задания в конвейере. Сценарий задания выполняется внутри контейнера, обеспечивая изоляцию каждого задания, что помогает предотвратить возникновение нежелательных побочных эффектов и проблем с безопасностью.
- Использование конвейера CI/CD для сборки и развертывания образов Docker – задание в рамках конвейера CI/CD используется для сборки обновленного образа Docker после внесения изменений в исходный код. Собранный образ может быть развернут на производстве в последующем задании.
Эти взаимодействия между Docker и CI/CD-серверами не являются взаимоисключающими: многие проекты используют Docker для запуска своих CI/CD-заданий и собирают Docker-образы в этих заданиях. Такой рабочий процесс обычно осуществляется с помощью Docker-in-Docker, когда экземпляр демона Docker запускается внутри контейнера, в котором выполняется задание CI/CD. Вложенный демон Docker позволяет успешно выполнять такие операции, как docker build и docker push, которые требует сценарий задания. Включение Docker-in-Docker может потребовать специальной настройки в заданиях CI/CD, в зависимости от используемой платформы.
Пример: Как построить CI/CD-конвейер с помощью Docker
Чтобы проиллюстрировать два способа использования Docker в CI/CD, мы создадим простой CI/CD-конвейер GitLab.
Конвейер будет выполнять задание, которое запускается внутри контейнера Docker; это контейнерное задание будет использовать Docker-in-Docker для создания Docker-образа нашего приложения и отправки его в реестр образов, предоставляемый GitLab. Этот конвейер обеспечит автоматическую и последовательную перестройку образа при каждом новом коммите в репозиторий.
Следующие шаги специфичны для GitLab, но общая схема похожа и на другие инструменты CI/CD.
1. Подготовка GitLab CI/CD
Чтобы следовать этому руководству, вам понадобится новый проект, подготовленный либо на GitLab.com, либо на вашем собственном экземпляре GitLab. По умолчанию GitLab.com запускает ваши задания в виде контейнеров Docker на эфемерных виртуальных машинах, поэтому для контейнеризации конвейеров не требуется никаких дополнительных настроек.
Если вы используете свой собственный экземпляр GitLab, вам следует подключить GitLab Runner, использующий исполнитель Docker – подробные инструкции по настройке можно найти в документации. Для целей этого руководства runner должен быть настроен на поддержку заданий без тега.
2. Создайте Dockerfile
Создав проект, клонируйте его на своей машине, а затем сохраните следующий пример Dockerfile в корневой каталог проекта:
FROM httpd:alpine
RUN echo "<h1>Hello World</h1>" > /usr/local/apache2/htdocs/index.htm
Затем используйте Git, чтобы закоммитить ваш файл и загрузить его в GitLab:
$ git add .
$ git commit -m "Add Dockerfile"
$ git push
Этот Dockerfile настраивает образ, который будет создан для нашего приложения в рамках конвейера CI/CD.
3. Создание конфигурации CI/CD-конвейера GitLab
Теперь вы можете настроить CI/CD-конвейер на сборку образа при фиксации новых изменений в вашем репозитории.
Конвейеры GitLab настраиваются с помощью YAML-файла .gitlab-ci.yml
, расположенного в корневом каталоге вашего репозитория. Следующая конфигурация конвейера использует Docker-in-Docker для сборки образа из вашего Docker-файла внутри Docker-контейнера, в котором выполняется задание. Затем образ будет отправлен в экземпляр GitLab Container Registry вашего проекта, который включен по умолчанию.
stages:
- build
variables:
DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
build:
image: docker:25.0
stage: build
services:
- docker:25.0-dind
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build -t $DOCKER_IMAGE .
- docker push $DOCKER_IMAGE
Несколько моментов:
- Задания GitLab CI/CD запускаются с предопределенными переменными, которые можно использовать для аутентификации в различных компонентах GitLab в вашем проекте. Здесь автоматически сгенерированные переменные
$CI_REGISTRY_USER
и$CI_REGISTRY_PASSWORD
используются для аутентификации в реестре контейнеров вашего проекта с помощью командыdocker login
. - Переменная
$CI_REGISTRY_IMAGE
содержит URL-адрес образа, которое должно использоваться для хранения образов в Container Registry вашего проекта. В нашей пользовательской переменной$DOCKER_IMAGE
эта переменная комбинируется с SHA коммита, который выполняет конвейер, чтобы получить окончательный тег, который будет присвоен созданному образу. Это гарантирует, что при каждом коммите будет создаваться образ с отдельной меткой. - Поле
image
в определении заданияbuild
определяет образ Docker, который будет использоваться для выполнения задания – в данном случае docker:25.0, чтобы был доступен Docker CLI. Поскольку требуется функциональность Docker-in-Docker (DinD), образ DinD также упоминается в качестве сервиса для задания (service for the job). Это механизм GitLab, который позволяет сетевым приложениям (в данном случае демону Docker) запускаться в другом контейнере, но получать доступ из контейнера задания. Это необходимо, поскольку GitLab переопределяет точку входа контейнера задания для запуска вашего сценария, поэтому демон Docker не будет запускаться в контейнере задания.
Скопируйте файл конвейера, сохраните как .gitlab-ci.yml
и закомитьте в ваш репозиторий. После того, как вы загрузите изменения в GitLab, перейдите на страницу Build > Pipelines в web UI — вы должны увидеть ваш первый конвейер запущенным:

Подождите, пока конвейер завершится, затем нажмите на зеленую галочку в колонке Stages, чтобы просмотреть журнал сборки:

Из журнала видно, что для выполнения задания используется Docker, поэтому ваш скрипт выполняется в контейнере. GitLab выбирает образ docker:25.0
, указанный в файле конфигурации вашего конвейера, затем запускает службу DinD, чтобы демон Docker был доступен. Затем, следуя инструкциям вашего скрипта, образ будет собран и помещен в Container Registry вашего проекта.
3. Посмотрите на ваш образ
Зайдите на страницу Deploy > Container Registry в интерфейсе GitLab, чтобы увидеть свой свежезагруженный образ.

Изображение помечается уникальным SHA вашего последнего коммита. Теперь вы можете вносить изменения в свой проект, отправлять их на GitLab, а ваш конвейер CI/CD будет автоматически собирать обновленный образ.
Хотя это всего лишь простой пример, он показывает наиболее распространенный способ совместного использования CI/CD и Docker. Для вашей платформы CI/CD может потребоваться конфигурация конвейера, отличная от показанной здесь, но вы все равно должны быть в состоянии достичь эквивалентного результата.
Лучшие практики для CI/CD в Docker
Хотя конвейеры CI/CD и контейнеры Docker хорошо дополняют друг друга, все же существует несколько подводных камней, с которыми вы можете столкнуться при их объединении.
Вот несколько лучших практик Docker CI/CD, которые позволят повысить производительность, безопасность и масштабируемость:
- Остерегайтесь рисков, связанных с использованием Docker-in-Docker. Docker-in-Docker требует использования привилегированного режима. Это означает, что root в контейнере заданий фактически является root и на вашем хосте, что позволяет злоумышленнику, имеющему доступ к файлу конфигурации вашего конвейера, определить задание, использующее конфиденциальные привилегии.
- Блокируйте Docker-ориентированные среды сборки. Поскольку привилегированный режим небезопасен, следует ограничить CI/CD-среды известными пользователями и проектами. Если это невозможно, то вместо Docker можно попробовать использовать отдельный сборщик образов, например Buildah, чтобы исключить риск. Кроме того, настройка Docker-in-Docker без рута может уменьшить некоторые (но не все) проблемы безопасности, связанные с привилегированным режимом.
- Запускайте задания CI/CD параллельно для повышения производительности. Правильная настройка платформы CI/CD для параллельного выполнения заданий позволит сократить продолжительность конвейера и повысить пропускную способность. Контейнеризация означает, что все задания будут выполняться в собственном изолированном окружении, что снижает вероятность возникновения побочных эффектов при их одновременном выполнении.
- Контролируйте использование ресурсов и масштабирование конвейера. Активный CI/CD-сервер, на котором одновременно выполняется множество заданий, может испытывать высокую нагрузку на ресурсы. Выполнение заданий в контейнерах упрощает масштабирование на дополнительные хосты, поскольку вам не нужно вручную копировать окружение сборки на каждую машину-исполнитель.
- Корректно настраивайте кэш сборок и постоянное хранилище. Использование Docker-in-Docker не позволяет эффективно использовать кэш сборок Docker, поскольку каждое задание создает свой собственный контейнер, не имея доступа к кэшу, созданному предыдущим заданием. Настройка сборки на использование ранее созданных образов в качестве кэша повысит эффективность и производительность.
Использование управляемой платформы CI/CD
Выбор управляемой CI/CD-платформы избавит вас от хлопот, связанных с настройкой и масштабированием конвейеров. Spacelift – это специализированная CI/CD-платформа для сценариев IaC. Она выходит за рамки той поддержки, которую предлагает обычная бэкенд-система. Spacelift обеспечивает свободу разработчиков, поддерживая множество IaC-провайдеров, систем контроля версий и конечных точек публичного облака с точными ограждениями для универсального контроля.
Вместо того чтобы вручную поддерживать серверы сборки, вы можете просто подключить платформу к своим репозиториям. Затем вы можете тестировать и применять изменения в инфраструктуре непосредственно из ваших запросов на сборку. Это устраняет накладные расходы на администрирование и обеспечивает простой доступ разработчиков к самообслуживанию в рамках определенных политикой ограждений.
Ключевые моменты
CI/CD и контейнеры – две ключевые технологии в современном жизненном цикле разработки программного обеспечения. В сочетании они становятся еще лучше: правильно настроенные среды Docker обеспечивают изоляцию и безопасность для ваших заданий CI/CD, а также являются идеальным местом для создания образов Docker, необходимых вашим приложениям .