Как настроить среду тестирования непрерывной интеграции с Docker и Docker Compose в Ubuntu 16.04

Вступление

Continuous integration (CI) относится к практике, когда разработчики кодируютintegrate как можно чаще, и каждая фиксация проверяется до и после объединения в общий репозиторийautomated build.

CI ускоряет процесс разработки и сводит к минимуму риск возникновения критических проблем в производственной среде, но его нетривиально настроить; Автоматические сборки выполняются в другой среде, где установкаruntime dependencies и конфигурацияexternal services могут отличаться от вашей локальной среды и среды разработки.

Docker - это платформа для контейнеризации, цель которой - упростить проблемы стандартизации среды, чтобы можно было стандартизировать развертывание приложений (find out more about Docker). Для разработчиков Docker позволяет моделировать производственные среды на локальных машинах, запуская компоненты приложения в локальных контейнерах. Эти контейнеры легко автоматизировать с помощьюDocker Compose, независимо от приложения и базовой ОС.

В этом руководстве используется Docker Compose для демонстрации автоматизации рабочих процессов CI.

Мы создадим приложение Python Dockerized «Hello world» и тестовый скрипт Bash. Для запуска приложения Python потребуется два контейнера: один для самого приложения и контейнер Redis для хранилища, которое требуется как зависимость для приложения.

Затем тестовый сценарий будет Dockerized в своем собственном контейнере, а вся тестовая среда будет перемещена в файлdocker-compose.test.yml, чтобы мы могли убедиться, что мы запускаем каждое выполнение теста в новой и однородной среде приложения.

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

Таким образом, мы автоматизируем рабочие процессы CI независимо от тестируемого приложения и базовой инфраструктуры.

Предпосылки

Прежде чем начать, вам понадобится:

[[step-1 -—- create-the-quot-hello-world-quot-python-application]] == Шаг 1. Создайте приложение Python «Hello World»

На этом шаге мы создадим простое приложение Python в качестве примера типа приложения, которое вы можете протестировать с помощью этой настройки.

Создайте новый каталог для нашего приложения, выполнив:

cd ~
mkdir hello_world
cd hello_world

Отредактируйте новый файлapp.py с помощьюnano:

nano app.py

Добавьте следующий контент:

app.py

from flask import Flask
from redis import Redis




app = Flask(__name__)
redis = Redis(host="redis")




@app.route("/")
def hello():
    visits = redis.incr('counter')
    html = "

Hello World!

" \ "Visits: {visits}" \ "
" return html.format(visits=visits) if __name__ == "__main__": app.run(host="0.0.0.0", port=80)

Когда вы закончите, сохраните и выйдите из файла.

app.py - это веб-приложение на основеFlask, которое подключается к службе данных Redis. Строкаvisits = redis.incr('counter') увеличивает количество посещений и сохраняет это значение в Redis. Наконец, в HTML возвращается сообщениеHello World с количеством посещений.

В нашем приложении есть две зависимости,Flask иRedis, которые вы можете увидеть в первых двух строках. Эти зависимости должны быть определены до того, как мы сможем выполнить приложение.

Откройте новый файл:

nano requirements.txt

Добавьте содержимое:

requirements.txt

Flask
Redis

Когда вы закончите, сохраните и выйдите из файла. Теперь, когда мы определили наши требования, которые мы изложим позже вdocker-compose.yml, мы готовы к следующему шагу.

[[step-2 -—- dockerize-the-quot-hello-world-quot-application]] == Шаг 2 - Dockerize приложение «Hello World»

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

nano Dockerfile

Добавьте следующее содержание:

Dockerfile

FROM python:2.7


WORKDIR /app


ADD requirements.txt /app/requirements.txt
RUN pip install -r requirements.txt


ADD app.py /app/app.py


EXPOSE 80


CMD ["python", "app.py"]

Давайте проанализируем значение каждой строки:

  • FROM python:2.7: указывает, что наш образ приложения «Hello World» создан из официального образа Dockerpython:2.7

  • WORKDIR /app: устанавливает рабочий каталог внутри образа Docker на/app

  • ADD requirements.txt /app/requirements.txt: добавляет файлrequirements.txt в наш образ Docker

  • RUN pip install -r requirements.txt: устанавливает зависимости приложенияpip

  • ADD app.py /app/app.py: добавляет исходный код нашего приложения в образ Docker

  • EXPOSE 80: указывает, что наше приложение доступно через порт 80 (стандартный общедоступный веб-порт)

  • CMD ["python", "app.py"]: команда, запускающая наше приложение

Сохраните и выйдите из файла. Этот файлDockerfile содержит всю информацию, необходимую для создания основного компонента нашего приложения «Hello World».

Зависимость

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

Давайте создадим файлdocker-compose.yml, чтобы начать использовать Docker Compose.

Редактировать новый файл:

nano docker-compose.yml

Добавьте следующее содержание:

docker-compose.yml

web:
  build: .
  dockerfile: Dockerfile
  links:
    - redis
  ports:
    - "80:80"
redis:
  image: redis

Этот файл Docker Compose показывает, как локально раскрутить приложение «Hello World» в два контейнера Docker.

Он определяет два контейнера:web иredis.

  • web использует текущий каталог для контекстаbuild и строит наше приложение Python из только что созданного файлаDockerfile. Это локальное изображение Docker, которое мы создали только для нашего приложения Python. Он определяет ссылку на контейнерredis, чтобы иметь доступ к IP-адресу контейнераredis. Это также делает порт 80 общедоступным из Интернета, используя общедоступный IP-адрес вашего сервера Ubuntu.

  • redis выполняется из стандартного общедоступного образа Docker с именемredis.

Когда вы закончите, сохраните и выйдите из файла.

[[шаг-3 -—- deploy-the-quot-hello-world-quot-application]] == Шаг 3. Разверните приложение «Hello World»

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

Файлыdocker-compose.yml иDockerfile позволяют автоматизировать развертывание локальных сред, выполнив:

docker-compose -f ~/hello_world/docker-compose.yml build
docker-compose -f ~/hello_world/docker-compose.yml up -d

Первая строка создает образ нашего локального приложения из файлаDockerfile. Вторая строка запускает контейнерыweb иredis в режиме демона (-d), как указано в файлеdocker-compose.yml.

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

docker ps

Это должно показать два запущенных контейнера с именамиhelloworld_web_1 иhelloworld_redis_1.

Давайте проверим, что приложение запущено. Мы можем получить IP-адрес контейнераhelloworld_web_1, выполнив:

WEB_APP_IP=$(docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' helloworld_web_1)
echo $WEB_APP_IP

Убедитесь, что веб-приложение возвращает правильное сообщение:

curl http://${WEB_APP_IP}:80

Это должно вернуть что-то вроде:

Выход

Hello World!

Visits: 2

Количество посещений увеличивается каждый раз, когда вы достигаете этой конечной точки. Вы также можете получить доступ к приложению «Hello World» из браузера, посетив общедоступный IP-адрес вашего сервера Ubuntu.

Как настроить для вашего собственного приложения

Ключом к настройке вашего собственного приложения является помещение вашего приложения в собственный контейнер Docker и запуск каждой зависимости из своего собственного контейнера. Затем вы можете определить отношения между контейнерами с помощью Docker Compose, как показано в примере. Docker Compose более подробно рассматривается в этомDocker Compose article.

Другой пример того, как запустить приложение в нескольких контейнерах, можно найти в этой статье о запускеWordPress and phpMyAdmin with Docker Compose.

[[step-4 -—- create-the-test-script]] == Шаг 4 - Создайте тестовый сценарий

Теперь мы создадим тестовый скрипт для вашего приложения Python. Это будет простой скрипт, который проверяет HTTP-вывод приложения. Сценарий является примером типа теста, который вы, возможно, захотите выполнить в рамках процесса развертывания непрерывной интеграции.

Редактировать новый файл:

nano test.sh

Добавьте следующее содержание:

test.sh

sleep 5
if curl web | grep -q 'Visits: '; then
  echo "Tests passed!"
  exit 0
else
  echo "Tests failed!"
  exit 1
fi

test.sh проверяет базовое подключение к Интернету нашего приложения «Hello World». Он использует cURL для получения количества посещений и отчетов о том, был ли тест пройден или нет.

[[step-5 -—- create-the-testing-environment]] == Шаг 5. Создание среды тестирования.

Чтобы протестировать наше приложение, нам нужно развернуть среду тестирования. И мы хотим убедиться, что она идентична реальной среде приложения, которую мы создали вStep 3.

Во-первых, нам нужно Dockerize наш скрипт тестирования, создав новый файл Dockerfile. Редактировать новый файл:

nano Dockerfile.test

Добавьте следующее содержание:

Dockerfile.test

FROM ubuntu:xenial


RUN apt-get update && apt-get install -yq curl && apt-get clean


WORKDIR /app


ADD test.sh /app/test.sh


CMD ["bash", "test.sh"]

Dockerfile.test расширяет официальный образubuntu:xenial для установки зависимостиcurl, добавляетtests.sh в файловую систему образа и указывает командуCMD, которая выполняет тестовый сценарий с Баш.

Как только наши тесты Dockerized, они могут выполняться реплицируемым и независимым способом.

Следующий шаг - связать наш тестовый контейнер с нашим приложением «Hello World». Здесь Docker Compose снова приходит на помощь. Редактировать новый файл:

nano docker-compose.test.yml

Добавьте следующее содержание:

docker-compose.test.yml

sut:
  build: .
  dockerfile: Dockerfile.test
  links:
    - web
web:
  build: .
  dockerfile: Dockerfile
  links:
    - redis
redis:
  image: redis

Вторая половина файла Docker Compose развертывает основное приложениеweb и его зависимостьredis так же, как и предыдущий файлdocker-compose.yml. Это часть файла, определяющая контейнерыweb иredis. Единственное отличие состоит в том, что контейнерweb больше не предоставляет порт 80, поэтому приложение не будет доступно через общедоступный Интернет во время тестов. Итак, вы можете видеть, что мы создаем приложение и его зависимости точно так же, как в реальном развертывании.

Файлdocker-compose.test.yml также определяет контейнерsut (названный в честьsystem under tests), который отвечает за выполнение наших интеграционных тестов. Контейнерsut определяет текущий каталог как наш каталогbuild и указывает наш файлDockerfile.test. Он связывается с контейнеромweb, поэтому IP-адрес контейнера приложения доступен нашему сценариюtest.sh.

Как настроить для вашего собственного приложения

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

Если у вас есть дополнительные тесты для запуска вашего приложения, вы можете создать для них дополнительные файлы Docker, аналогичные файлуDockerfile.test, показанному выше.

Затем вы можете добавить дополнительные контейнеры под контейнеромsut в файлеdocker-compose.test.yml, ссылаясь на дополнительные файлы Docker.

[[step-6 -—- test-the-quot-hello-world-quot-application]] == Шаг 6. Протестируйте приложение «Hello World»

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

docker-compose -f ~/hello_world/docker-compose.test.yml -p ci build

Эта команда создает локальные образы, необходимыеdocker-compose.test.yml. Обратите внимание, что мы используем-f для указания наdocker-compose.test.yml и-p для указания имени конкретного проекта.

Теперь раскрутите свою свежую среду тестирования, выполнив:

docker-compose -f ~/hello_world/docker-compose.test.yml -p ci up -d
OutputCreating ci_redis_1
Creating ci_web_1
Creating ci_sut_1

Проверьте вывод контейнераsut, выполнив:

docker logs -f ci_sut_1

Выход

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    42  100    42    0     0   3902      0 --:--:-- --:--:-- --:--:--  4200
Tests passed!

И, наконец, проверьте код выхода контейнераsut, чтобы проверить, прошли ли ваши тесты:

docker wait ci_sut_1

Выход

0

После выполнения этой команды значение$? будет0, если тесты пройдены. В противном случае наши тесты приложений не пройдены.

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

Это оно! Мы успешно провели наш тест в новой среде, идентичной нашей производственной среде.

Заключение

Благодаря Docker и Docker Compose мы смогли автоматизировать сборку приложения (Dockerfile), развертывание локальной среды (docker-compose.yml), создание тестового образа (Dockerfile.test) и выполнение (интеграционные) тесты (docker-compose.test.yml) для любого приложения.

В частности, преимущества использования файлаdocker-compose.test.yml для тестирования заключаются в том, что процесс тестирования:

  • Automatable: способ, которым инструмент выполняетdocker-compose.test.yml, не зависит от тестируемого приложения

  • Light-weight: сотни внешних сервисов могут быть развернуты на одном хосте, имитируя сложные (интеграционные) тестовые среды

  • Agnostic: избегайте привязки к поставщику CI, и ваши тесты могут работать в любой инфраструктуре и на любой ОС, которая поддерживает Docker.

  • Immutable: тесты, проходящие на вашем локальном компьютере, пройдут через ваш инструмент CI

В этом руководстве показан пример тестирования простого приложения «Hello World».

Теперь пришло время использовать ваши собственные файлы приложения, Dockerize ваши собственные тестовые сценарии приложений и создать свои собственныеdocker-compose.test.yml для тестирования вашего приложения в свежей и неизменной среде.

Related