Статьи

Непрерывная интеграция и доставка с Docker

Непрерывная поставка — это снижение риска и повышение эффективности за счет создания надежного программного обеспечения в короткие итерации. Как говорит Мартин Фаулер , вы делаете непрерывную доставку, если:

  • Ваше программное обеспечение может быть развернуто в течение всего жизненного цикла.
  • Ваша команда считает приоритетным сохранение программного обеспечения доступным по сравнению с работой над новыми функциями.
  • Любой может получить быструю автоматическую обратную связь о готовности своих систем в любое время, когда кто-то вносит в них изменения.
  • Вы можете выполнить развертывание любой версии программного обеспечения в любой среде по запросу.

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

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

«Узнайте, как настроить конвейер непрерывной доставки с помощью Docker». — через @codeship

Нажмите, чтобы чирикать

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

Непрерывная интеграция с Docker

В качестве примера рассмотрим веб-сервер Hello World, написанный на Go . Вы можете найти весь код, использованный в этом примере, здесь: https://github.com/ContainerSolutions/cd-with-docker-tutorial

Настройка непрерывной интеграции состоит из:

  • выполнение юнит-тестов
  • создание образа Docker, который мы используем для создания нашего сервиса
  • запуск сборочного контейнера и компиляция нашего сервиса
  • создание образа Docker, который мы запускаем и разворачиваем
  • отправка окончательного образа в реестр Docker

Автоматизированное тестирование

Запуск тестов в этом примере так же тривиален, как и должно быть:

1
go test

Построение Docker image

Ядром интеграции единого сервиса является создание конечного артефакта — образа Docker в нашем случае.

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

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

Сборка исполняемого файла может быть частью единого процесса сборки образа Docker вместе с настройкой среды выполнения. Или мы можем разделить два. Имея все в одном процессе сборки, мы получили бы дополнительный контент (остатки процесса сборки) в нашей файловой системе образа Docker, даже если впоследствии мы очистим его в отдельных командах RUN в Dockerfile.

Некоторые люди используют трюки для создания, манипулирования и удаления ненужных вещей в одной команде RUN . Хотя это иногда удобно, я не могу рекомендовать это; на мой взгляд, это добавляет сложности Dockerfile. Конечно, есть ситуации, когда вы можете захотеть сохранить свои источники и все в конечном итоге артефакт.

Однако подход, который я рекомендую, заключается в создании отдельных Docker-файлов для «сборки» и «распространения». Используйте Dockerfile.build, чтобы выполнить тяжелую работу во время сборки программного обеспечения, и используйте Dockerfile.dist, чтобы создать распространяемый образ Docker, максимально легкий и чистый.

Ниже приводится Dockerfile.build . Как вы можете видеть, запустив файл сборки, мы создадим контейнер из образа golang, скомпилируем наш пример сервиса и выведем двоичный файл.

1
2
3
4
5
6
7
FROM golang:1.4
 
RUN mkdir -p /tmp/build
ADD hello-world.go /tmp/build/
WORKDIR /tmp/build
RUN go build hello-world.go
CMD tar -czf - hello-world

В Dockerfile.dist мы используем только этот двоичный файл и запускаем его во время выполнения:

1
2
3
4
5
FROM debian:jessie
 
RUN mkdir /app
ADD build.tar.gz /app/
ENTRYPOINT /app/hello-world

Наш скрипт build.sh — неотъемлемая часть нашего конвейера непрерывной интеграции — выглядит следующим образом:

1
2
3
4
# !/bin/sh
docker build -t hello-world-build -f Dockerfile.build .
docker run hello-world-build > build.tar.gz
docker build -t hello-world -f Dockerfile.dist .

Как видите, эти три простые команды Docker дают нам чистый небольшой образ Docker Hello-World, который готов к развертыванию и запуску по требованию. Как только оба изображения, использованные в предложениях FROM , извлекаются и кэшируются локально, наш процесс сборки займет считанные миллисекунды или самое большее несколько секунд с очень небольшим объемом ресурсов.

Хранение изображений Docker

После создания нашего артефакта процесса сборки мы хотим перенести его в Docker Registry, где он будет доступен для развертываний.

Обратите внимание, что правильная пометка изображений очень важна. Экосистемы Docker страдают от использования тега «последний». Если вы используете уникальный тег для каждого нового образа, то все версии вашего образа будут легко доступны для развертывания в будущем.

Мы можем выбрать, хотим ли мы использовать собственный реестр Docker или использовать Docker Hub . На Docker Hub вы можете хранить публичные или частные репозитории изображений. Это также первое место, где люди будут искать ваши изображения (если вы хотите, чтобы кто-нибудь их искал).

С другой стороны, ваш собственный реестр Docker дает вам полный контроль над хранением, производительностью и безопасностью ваших изображений. Более продвинутые настройки могут сочетать оба подхода.

Таким образом, вы можете пометить новое изображение соответствующим тегом и отправить его в общедоступный хаб (замените your_username и your_tag фактическими значениями):

1
2
3
# !/bin/sh
docker tag hello-world:latest your_username/hello-world:your_tag
docker push your_username/hello-world:your_tag

Контейнеры непрерывно доставляются

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

Способ развертывания приложений зависит от вашей инфраструктуры или поставщика облачных услуг. В настоящее время несколько облачных провайдеров поддерживают изображения Docker в своих API-интерфейсах ( например , Amazon EC2 Container Service , Digital Ocean или Giant Swarm ). Вы можете дополнительно использовать возможности контейнерных приложений с помощью инструментов абстракции ресурсов, таких как Apache Mesos (подробнее о запуске контейнеров в Mesos ) или Google Kubernetes, которые позволяют развертывать контейнеры и управлять ими по-своему.

В нашем примере Hello World удаленное развертывание означает удаленное выполнение следующей команды на целевом компьютере с установленным Docker:

1
2
3
# !/bin/sh
docker stop hello-production
docker run --rm -p 8000:80 --name hello-production hello-world

Помимо непрерывной доставки с докером

Использование контейнерного программного обеспечения по сути не означает, что кто-то внедряет микросервисы. Однако контейнеры поддерживают этот архитектурный шаблон, потому что они поощряют разработчиков разделять свои монолиты на основе разделения интересов.

Микросервисы также способствуют связи между контейнеризованными компонентами по простой сети, используя стандартизированные и легко заменяемые трубки. Чтобы узнать больше о микросервисах и о том, почему они могут быть хорошим архитектурным шаблоном для вашего программного проекта, я рекомендую создание микросервисов Сэма Ньюмана.

Трубопровод непрерывной доставки с контейнерным программным обеспечением также позволяет вам настроить новый тип среды тестирования; Подмножества (микро) сервисов развертываются в небольших кластерах, представляющих тестируемую систему, работающую с некоторыми частями, преднамеренно отключенными или отключенными.

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

«Непрерывная интеграция и доставка через Docker» — через @codeship

Нажмите, чтобы чирикать