Более быстрые конвейеры CI/CD с Docker
Проблема
Одним из ключевых методов быстрого продвижения в разработке программного обеспечения является непрерывная поставка. Однако уход за агентами сборки — рутинная работа. Докер помогает в этом, сохраняя простой агент сборки и помещая все инструменты сборки в образ Docker. Однако это влечет за собой новую проблему — скорость. Создание зависимостей от нового агента сборки может занять довольно много времени, особенно в Java. В этой статье показано, как ускорить сборку с помощью некоторых функций Docker.
Чем отличается этот подход?
Используя систему слоев в Docker, мы можем отделить зависимости для нашего кода от части образа Docker, отличной от слоя, на котором находится код. Мы также можем использовать новую функцию в Docker, которая позволяет нам использовать ранее сохраненное изображение в качестве кэша слоев текущего изображения. Таким образом мы ускоряем сборку, когда изменился только код (а не зависимости).
Стек технологий
Мы рассмотрим примеры в
- Рубин
- Питон
- Ява
- JavaScript
Все будут использовать Docker, и мы добавим такие сервисы AWS, как CodePipeline, КодБилд а также Реестр эластичных контейнеров (ECR) в качестве простого примера того, как запустить конвейер сборки.
мельчайшие детали
Разные языки программирования имеют разные системы управления зависимостями пакетов:
Для целей установки зависимостей все они делают примерно одно и то же:
- посмотрите в файле конфигурации зависимости, которые вы объявили
- иди и найди пакеты для этих зависимостей в официальном репозитории
- загрузите их в свою локальную систему
- сделать их доступными для вашего кода
Например, если я хочу использовать Redux в своем приложении JS React, я могу yarn add react-redux
и я закончу с package.json
файл, содержащий ссылку на react-redux (а также локальную установку в моем node_modules). Поскольку я не хочу полагаться на то, что люди будут помнить о правильной установке при развертывании на серверах, я не храню все зависимости в git; я просто храню package.json
файл. Если кто-то получит мой код с GitHub, он сможет yarn install
и они получат избыточность (вместе со всеми остальными вещами в package.json
файл).
Вот проблема; загрузка и сборка этих зависимостей на сервере сборки часто занимает много времени. Даже если я установил их из предыдущей сборки, обычно масштабируют агенты сборки в периоды спроса, а затем уничтожают их позже для экономической эффективности. Это означает, что мои агенты сборки всегда новые и должны выполнять новые сборки.
Докер спешит на помощь
В Docker есть две полезные функции:
Если мы возьмем Java в качестве примера, мы можем использовать следующее Dockerfile.tests
для запуска наших тестов:
FROM openjdk:8-jdk-alpine
RUN apk update
RUN apk add maven
WORKDIR /opt/code
COPY ./pom.xml .
RUN mvn dependency:go-offline
COPY . .
Это означает, что зависимости приходят с RUN mvn dependency:go-offline
но остальная часть нашего кода приходит с COPY . .
(поэтому зависимости остаются на предыдущем уровне).
Затем мы можем предоставить конфигурацию CI, которая использует docker build
с --cache-from
чтобы убедиться, что нам нужно запускать уровень зависимостей только при изменении зависимостей.
В качестве примера опишем пару конфигураций CodeBuild. Если предположить, что у нас есть репозиторий ECR, настроенный по адресу 999999999.dkr.ecr.ap-southeast-2.amazonaws.com/some-img
мы можем настроить несколько шагов в CodePipeline:
- Шаг 1: получите исходный код из системы управления версиями (например, GitHub)
- Шаг 2: используйте стандартный контейнер CodeBuild для создания тестового образа докера.
- Шаг 3: используйте новый тестовый образ непосредственно в CodeBuild для запуска тестов.
Шаг 1
Создайте веб-перехватчик GitHub через CodePipeline. Это можно сделать в консоли, через кли или с CloudFormation
Шаг 2
это пример спецификация сборки который входит в ECR, извлекает последний тестовый образ, создает новый тестовый образ, используя последний в качестве кеша, и отправляет новый в ECR:
phases:
pre_build:
commands:
- $(aws ecr get-login --no-include-email --region ap-southeast-2)
- docker pull 999999999.dkr.ecr.ap-southeast-2.amazonaws.com/some-img:latest
build:
commands:
- docker build --tag 999999999.dkr.ecr.ap-southeast-2.amazonaws.com/some-img:latest --file Dockerfile-tests --cache-from 999999999.dkr.ecr.ap-southeast-2.amazonaws.com/some-img:latest .
post_build:
commands:
- docker push 999999999.dkr.ecr.ap-southeast-2.amazonaws.com/some-img:latest
Шаг 3
Спецификация сборки для запуска тестов на следующем шаге CodePipeline проста, если шаг настроен на использование 999999999.dkr.ecr.ap-southeast-2.amazonaws.com/some-img:latest
изображение, которое мы только что создали:
phases:
build:
commands:
- mvn test
Весь процесс аналогичен для других языков и систем управления пакетами. Просто поместите файл пакета и установите команды перед остальным кодом.
Рубин:
COPY ./Gemfile .
RUN bundle install
COPY . .
Питон:
COPY ./requirements.txt .
RUN pip install -r requirements.txt
COPY . .
JavaScript:
COPY ./package.json .
RUN yarn install
COPY . .
и т.п.
Заключительные мысли и следующие шаги
Это экономит много времени на поддержку агентов сборки и много времени на сборку. Он одинаково хорошо работает с любой другой системой сборки, которая может запускать док-контейнеры, например с БилдКайт. Если вам нужна помощь в настройке, обращайтесь.
Обо мне
Я главный инженер, с опытом программирования на Java, Python, Ruby, JavaScript и C#, со слабым знанием LabVIEW, C++, VisualBasic и ColdFusion. Я баловался Хаскеллом.
У меня есть большой опыт работы с AWS и некоторые знания в Azure и GCP.
Приложение — Технология, упомянутая в этом посте
Докер
Docker — это способ упаковки приложений в контейнер который включает все файлы, необходимые для запуска приложения, включая файлы операционной системы, но не ядро операционной системы. Напротив, виртуальная машина (ВМ) содержит ядро и виртуализированные аппаратные интерфейсы.
Веб-сервисы Амазонки
АВС — это облачные сервисы провайдер, где вычислительная мощность, сетевые и другие услуги предоставляются по запросу. Это позволяет использовать инфраструктуру как код и помогает командам тратить время на решение проблем клиентов, а не на обслуживание центров обработки данных.