Feature-спеки внутри Docker контейнера
Чистые функции хороши тем, что не нужно бояться что при вызове такой функции мы можем получить непредсказуемый результат. Функция просто делает свою работу, не оставляя никаких сайд-эффектов и при этом мы можем быть уверены что при тех же аргументах мы получим тот же результат, независимо от контекста. Docker контейнеры используют подобную идеологию - мы можем быть уверены что наш докер контейнер будет работать одинаково на любой хост-машине.
зачем?
Для меня основной причиной является изоляция внешних сервисов, используемых в приложении:
PostgreSQL
Elasticsearch
Chromedriver
- etc
Если версию Ruby можно достаточно удобно менеджить с помощью, например, rbenv
, то внешние для приложения сервисы не так удобно переключать между различными приложениями.
выносим приложение и сервисы в контейнер
Начнем с написания Dockerfile
. Для Rails
приложения нам понадобятся Ruby
+ PostgreSQL
клиент для подключения к базе данных + Node
и Yarn
для наших ассетов. Также потребуется установить bundler
для зависимостей.
FROM ruby:2.6.8-slim-buster
RUN apt-get update -qq && apt-get install -yq --no-install-recommends \
build-essential \
curl \
git \
gnupg2 \
shared-mime-info \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Add PostgreSQL to sources list
ARG PG_MAJOR
RUN curl -sSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \
&& echo 'deb http://apt.postgresql.org/pub/repos/apt/ buster-pgdg main' $PG_MAJOR > /etc/apt/sources.list.d/pgdg.list
# Add NodeJS to sources list
ARG NODE_MAJOR
RUN curl -sL https://deb.nodesource.com/setup_$NODE_MAJOR.x | bash -
# Add Yarn to the sources list
ARG YARN_VERSION
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
&& echo 'deb http://dl.yarnpkg.com/debian/ stable main' > /etc/apt/sources.list.d/yarn.list
# Install Dependencies
RUN apt-get update -qq && apt-get install -yq --no-install-recommends \
libpq-dev \
postgresql-client-$PG_MAJOR \
nodejs \
yarn=$YARN_VERSION-1 \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
RUN rm -f .bundle/config
RUN gem install bundler -v 1.17.3
RUN mkdir /app
WORKDIR /app
Зависимости и исходный код будет содержаться в волюмах, чтобы размер образа был меньше. Далее следует приступить к написанию docker-compose
для оркестрации нашего приложения и вспомогательных сервисов (база данных, Redis, Elasticsearch):
Из интересного:
- Мы открыли 4 000-ый порт в нашем приложении. Это нужно для
Rspec
+Capybara
тестов. Мы будем запускать сервер для тестов по этому порту. - У нас есть контейнер
chrome
в котором находится браузерchrome
дляfeature
тестов.
Интересные переменные окружения:
DATABASE_CLEANER_ALLOW_REMOTE_DATABASE_URL
- по умолчанию, в целях безопасностиdatabase_cleaner
не очищает базу данных если ее адрес резолвится за пределыlocalhost
-а, но с помощью этой переменной мы разраешаем такое поведение. Это допустимо, потому что данныйdocker-compose
будет использоваться исключительно для разработки и тестирования (+ внутриDocker
контейнеров)HUB_URL
- мы выносим наш браузер дляfeature
тестов в отдельный контейнер. Это адрес подключения к нашемуchrome
контейнеру дляcapybara
DATABASE_URL
- адрес нашей базы данныхREDIS_URL
- адрес дляRedis
. Аналогично сDATABASE_URL
.
Далее следует подготовить наш код к тому, что он будет работать внутри контейнера в dev и test окружении:
Sidekiq
может автоматически подключаться к нужному урлу если он задан в переменнойREDIS_URL
, поэтому дляSidekiq
ничего менять не нужно (link)- Нужно немного подправить
database.yml
:
- Далее подправить
cable.yml
дляActionCable
:
- Нужно также передать
capybara
что мы будем подключаться кChrome
который находится в другом контейнере + запускать тестовый сервер на том порту, который мы открыли вdocker-compose.yml
(4000):
Готово! Можем приступать к запуску наших контейнеров
запуск
- Сбилдим используемые образы командой
docker-compose build
- Установим фронтенд зависимости командой
docker-compose run --rm web yarn
- Установим бэкенд зависимости командой
docker-compose run --rm web bundle install
- Настроим базу данных для дев-окружения командой
docker-compose run --rm web bin/rails db:setup
- Настроим базу данных для тест-окружения командой
docker-compose run --rm -e RAILS_ENV=test web bin/rails db:test:prepare
- Запустим наш проект командой
docker-compose up -d
- Проверим тесты -
docker-compose exec -e RAILS_ENV=test web bin/rspec
Все, включая feature тесты должны работать внутри контейнеров. Пример проекта: link