Если вы активно занимаетесь разработкой приложений, использование Docker может упростить ваш рабочий процесс и процесс развертывания вашего приложения в продакшен. Работа с контейнерами в процессе разработки предоставляет следующие преимущества:
Это обучающее руководство поможет вам научиться настраивать среду разработки для приложений Ruby on Rails с использованием Docker. Мы создадим контейнеры для самого приложения, базы данных PostgreSQL, Redis и службы Sidekiq с помощью Docker Compose. Настройка обеспечит следующее:
После изучения данного руководства у вас будет рабочее приложение с информацией об акулах, работающее на контейнерах Docker:
Для данного обучающего руководства вам потребуется следующее:
sudo
и активный брандмауэр. Дополнительную информацию о настройке этих параметров см. в руководстве по первоначальной настройке сервера.Прежде всего мы клонируем репозиторий rails-sidekiq из учетной записи сообщества DigitalOcean на GitHub. Этот репозиторий содержит код установки, описанный в обучающем руководстве Добавление Sidekiq и Redis в приложение Ruby on Rails, где объясняется процедура добавления Sidekiq в существующий проект Rails 5.
Клонируйте репозиторий в директорию rails-docker
:
- git clone https://github.com/do-community/rails-sidekiq.git rails-docker
Перейдите в директорию rails-docker
:
- cd rails-docker
В этом обучающем руководстве мы будем использовать базу данных PostgreSQL. Для работы с PostgreSQL вместо SQLite 3 нам потребуется добавить зависимость pg
в список зависимостей проекта в файле Gemfile. Откройте этот файл в nano
или другом текстовом редакторе по вашему выбору:
- nano Gemfile
Добавьте зависимость в любое место в списке основных зависимостей проекта (над зависимостями разработки):
. . .
# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.1.0', require: false
gem 'sidekiq', '~>6.0.0'
gem 'pg', '~>1.1.3'
group :development, :test do
. . .
Также можно выделить зависимость sqlite
как комментарий, поскольку мы больше не будем ее использовать:
. . .
# Use sqlite3 as the database for Active Record
# gem 'sqlite3'
. . .
Наконец, мы превратим в комментарий зависимость spring-watcher-listen
в разделе development
:
. . .
gem 'spring'
# gem 'spring-watcher-listen', '~> 2.0.0'
. . .
Если мы не отключим эту зависимость, мы будем постоянно получать сообщения об ошибке при доступе к консоли Rails. Эти сообщения об ошибке связаны с тем, что с этой зависимостью Rails использует listen
для отслеживания изменений разработки, а не запрашивает изменения в файловой системе. Поскольку эта зависимость следит за корневой директорией проекта, включая директорию node_modules
, она выводит сообщения об ошибке, связанные с отслеживаемыми директориями, засоряя ими консоль. Если вам требуется экономить ресурсы процессора, отключение этой зависимости может вам не подойти. В этом случае имеет смысл обновить приложение Rails до версии Rails 6.
Сохраните и закройте файл после завершения редактирования.
Мы подготовили репозиторий проекта, добавили зависимость pg
в файл Gemfile и выделили зависимость spring-watcher-listen
как комментарий. Теперь мы можем перейти к настройке приложения для работы с PostgreSQL.
Для работы с PostgreSQL и Redis во время разработки нам потребуется следующее:
.env
с именем пользователя и паролем базы данных и хостом Redis.init.sql
для создания пользователя sammy
для базы данных.redis
в контейнере..env
и другие требуемые файлы в файлы gitignore
и dockerignore
нашего проекта.Откройте файл конфигурации базы данных в директории config/database.yml
:
- nano config/database.yml
В этом файле содержатся следующие параметры по умолчанию
, которые применяются при отсутствии других настроек:
default: &default
adapter: sqlite3
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
timeout: 5000
Нам нужно изменить их и указать, что мы используем адаптер postgresql
, поскольку мы будем создавать службу PostgreSQL с помощью Docker Compose для постоянного хранения данных нашего приложения.
Удалите код, задающий SQLite в качестве адаптера, и замените его следующими настройками, которые будут задавать адаптер и другие переменные, необходимые для подключения:
default: &default
adapter: postgresql
encoding: unicode
database: <%= ENV['DATABASE_NAME'] %>
username: <%= ENV['DATABASE_USER'] %>
password: <%= ENV['DATABASE_PASSWORD'] %>
port: <%= ENV['DATABASE_PORT'] || '5432' %>
host: <%= ENV['DATABASE_HOST'] %>
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
timeout: 5000
. . .
Затем мы изменим настройки среды development
, которую будем использовать в данном примере.
Удалите существующую конфигурацию базы данных SQLite, чтобы раздел выглядел следующим образом:
. . .
development:
<<: *default
. . .
Удалите параметры database
для сред production
и test
:
. . .
test:
<<: *default
production:
<<: *default
. . .
Эти изменения параметров базы данных по умолчанию помогут нам динамически настраивать информацию базы данных с помощью переменных среды из файлов .env
, для которых не будет применяться контроль версий.
Сохраните и закройте файл после завершения редактирования.
Следует отметить, что при создании проекта Rails с нуля можно задать адаптер с помощью команды rails new
, как описано в шаге 3 обучающего руководства Использование PostgreSQL с приложением Ruby on Rails в Ubuntu 18.04. Эта команда задаст адаптер в файле config/database.yml
и автоматически добавит зависимость pg
в наш проект.
Мы уже разместили ссылку на переменные среды, и теперь нам нужно создать для них файл с предпочитаемыми настройками. Такое извлечение параметров конфигурации является частью 12-факторного подхода к разработке приложений, который определяет лучшие практики обеспечения надежности приложений в распределенных средах. При будущей настройке рабочей среды и среды тестирования для изменения настроек базы данных потребуется создание дополнительных файлов .env
и размещение ссылок на соответствующие файлы в наших файлах Docker Compose.
Откройте файл .env
:
- nano .env
Добавьте в файл следующие значения:
DATABASE_NAME=rails_development
DATABASE_USER=sammy
DATABASE_PASSWORD=shark
DATABASE_HOST=database
REDIS_HOST=redis
В дополнение к настройке имени базы данных, имени пользователя и пароля мы также зададим значение DATABASE_HOST
. Значение database
относится к службе database
PostgreSQL, которую мы создадим с помощью Docker Compose. Также мы задаем REDIS_HOST
для определения службы redis
.
Сохраните и закройте файл после завершения редактирования.
Чтобы создать пользователя базы данных sammy
, мы можем написать скрипт init.sql
для последующего монтирования в контейнер базы данных при его запуске.
Откройте файл скрипта:
- nano init.sql
Добавьте следующий код для создания пользователя sammy
с привилегиями администратора:
CREATE USER sammy;
ALTER USER sammy WITH SUPERUSER;
Этот скрипт создаст соответствующего пользователя базы данных и предоставит ему привилегии администратора.
Задайте в скрипте подходящие разрешения:
- chmod +x init.sql
Далее мы настроим Sidekiq для работы с нашей службой redis
в контейнере. Мы можем добавить инициализатор в директорию config/initializers
, где Rails ищет параметры конфигурации после загрузки структур и надстроек. Этот инициализатор будет задавать значение для хоста Redis.
Откройте файл sidekiq.rb
для указания этих настроек:
- nano config/initializers/sidekiq.rb
Добавьте в файл следующий код, чтобы задать значения REDIS_HOST
и REDIS_PORT
:
Sidekiq.configure_server do |config|
config.redis = {
host: ENV['REDIS_HOST'],
port: ENV['REDIS_PORT'] || '6379'
}
end
Sidekiq.configure_client do |config|
config.redis = {
host: ENV['REDIS_HOST'],
port: ENV['REDIS_PORT'] || '6379'
}
end
Как и наши параметры конфигурации базы данных, они позволяют выполнять динамическую настройку параметров хоста и портов, заменяя соответствующие значения во время исполнения без изменения кода приложения. В дополнение к REDIS_HOST
мы задаем значение по умолчанию для REDIS_PORT
, если оно больше нигде не задано.
Сохраните и закройте файл после завершения редактирования.
Чтобы важные данные приложения не копировались в систему контроля версий, мы можем добавить .env
в файл .gitignore
нашего проекта, указывая Git, какие файлы нашего проекта нужно игнорировать. Откройте файл для редактирования:
- nano .gitignore
Добавьте в конце файла запись для .env
:
yarn-debug.log*
.yarn-integrity
.env
Сохраните и закройте файл после завершения редактирования.
Далее мы создадим файл .dockerignore
и зададим, что не следует копировать в наши контейнеры. Откройте файл для редактирования:
- .dockerignore
Добавьте в файл следующий код, предписывающий Docker игнорировать элементы, которые мы не хотим копировать в наши контейнеры:
.DS_Store
.bin
.git
.gitignore
.bundleignore
.bundle
.byebug_history
.rspec
tmp
log
test
config/deploy
public/packs
public/packs-test
node_modules
yarn-error.log
coverage/
Добавьте .env
в конец файла:
. . .
yarn-error.log
coverage/
.env
Сохраните и закройте файл после завершения редактирования.
На последнем шаге нам потребуется создать исходные данные, чтобы у нашего приложения было несколько записей для работы сразу после запуска.
Откройте файл для исходных данных в директории db
:
- nano db/seeds.rb
Добавьте в файл следующий код для создания четырех демонстрационных акул и одного образца сообщения:
# Adding demo sharks
sharks = Shark.create([{ name: 'Great White', facts: 'Scary' }, { name: 'Megalodon', facts: 'Ancient' }, { name: 'Hammerhead', facts: 'Hammer-like' }, { name: 'Speartooth', facts: 'Endangered' }])
Post.create(body: 'These sharks are misunderstood', shark: sharks.first)
Исходные данные создадут четыре акулы и одно сообщение, связанное с первой акулой.
Сохраните и закройте файл после завершения редактирования.
Мы настроили приложение для работы с PostgreSQL и создали переменные среды. Теперь мы готовы к написанию файла Dockerfile для нашего приложения.
Файл Dockerfile указывает, что будет включено в контейнер приложения при его создании. Использование Dockerfile позволяет определить среду контейнера и избежать расхождений с зависимостями и версиями модуля исполнения.
Следуя этим указаниям по построению оптимизированных контейнеров, мы сделаем наш образ максимально эффективным, используя базовый образ Alpine и постаравшись минимизировать количество уровней образа.
Откройте файл Dockerfile в текущей директории:
- nano Dockerfile
Образы Docker создаются с использованием последовательности многослойных образов, накладывающихся друг поверх друга. Вначале мы добавим базовый образ нашего приложения, который станет начальной точкой сборки приложения.
Добавьте в файл следующий код, чтобы добавить образ Ruby alpine как базовый:
FROM ruby:2.5.1-alpine
Образ alpine
является производным проекта Alpine Linux, и это помогает уменьшить размер образа. Дополнительную информацию о том, подходит ли образ alpine
для вашего проекта, можно найти в обсуждении в разделе Image Variants на странице образа Ruby на Docker Hub.
При использовании alpine
для разработки нужно учитывать ряд факторов:
Далем мы зададим переменную среды, которая будет указывать версию Bundler:
. . .
ENV BUNDLER_VERSION=2.0.2
Это один из шагов, которые мы предпримем для предотвращения конфликтов версий между версией bundler
по умолчанию в нашей среде и кодом нашего приложения, для которого требуется версия Bundler 2.0.2.
Затем следует добавить в Dockerfile пакеты, необходимые для работы с приложением:
. . .
RUN apk add --update --no-cache \
binutils-gold \
build-base \
curl \
file \
g++ \
gcc \
git \
less \
libstdc++ \
libffi-dev \
libc-dev \
linux-headers \
libxml2-dev \
libxslt-dev \
libgcrypt-dev \
make \
netcat-openbsd \
nodejs \
openssl \
pkgconfig \
postgresql-dev \
python \
tzdata \
yarn
Это пакеты nodejs
, yarn
и другие. Поскольку наше приложение обслуживает ресурсы с помощью webpack, нам нужно добавить пакеты Node.js и Yarn для надлежащей работы приложения.
Следует помнить, что образ alpine
является минимальным: мы перечислили не все пакеты, которые вам можно или нужно будет установить в среде разработки при контейнеризации вашего приложения.
Далее следует установить подходящую версию bundler
:
. . .
RUN gem install bundler -v 2.0.2
Этот шаг гарантирует паритет контейнеризованной среды и спецификаций в файле Gemfile.lock
нашего проекта.
Теперь настройте рабочую директорию для приложения на контейнере:
. . .
WORKDIR /app
Скопируйте файлы Gemfile
и Gemfile.lock
:
. . .
COPY Gemfile Gemfile.lock ./
Копирование этих файлов — отдельный шаг, после которого выполняется команда bundle install
. Благодаря этому зависимости проекта не нужно будет воссоздавать каждый раз при внесении изменений в код приложения. Это работает в сочетании с объемом зависимостей, который мы включаем в наш файл Compose, монтирующий зависимости в контейнер приложений, когда производится воссоздание службы, но зависимости остаются без изменений.
Далее мы установим параметры конфигурации для сборки зависимостей nokogiri
:
. . .
RUN bundle config build.nokogiri --use-system-libraries
. . .
На этом шаге выполняется сборка nokogiri
с версиями библиотек libxml2
и libxslt
, которые мы добавили в контейнер приложений на шаге RUN apk add…
выше.
Далее мы установим зависимости проекта:
. . .
RUN bundle check || bundle install
Эта команда перед установкой зависимостей проверяет, не были ли они уже установлены.
Далее мы повторяем эту же процедуру для пакетов и зависимостей JavaScript. Сначала мы копируем метаданные пакета, затем устанавливаем зависимости, а в заключение копируем код приложения в образ контейнера.
Чтобы начать работать с разделом Javascript в нашем файле Dockerfile, нужно скопировать файлы package.json
и yarn.lock
из текущей директории проекта на хосте в контейнер:
. . .
COPY package.json yarn.lock ./
Затем мы установим требуемые пакеты с помощью команды yarn install
:
. . .
RUN yarn install --check-files
Эта команда включает флаг --check-files
с командой yarn
так, чтобы ранее установленные файлы не удалялись. Как и в случае с зависимостями, мы будем управлять состоянием постоянного хранения пакетов в директории node_modules
при написании файла Compose.
В заключение мы скопируем остальной код приложения и запустим приложение с помощью скрипта точки входа:
. . .
COPY . ./
ENTRYPOINT ["./entrypoints/docker-entrypoint.sh"]
Использование скрипта точки входа позволяет запускать контейнер как исполняемый файл.
Итоговый файл Dockerfile будет выглядеть следующим образом:
FROM ruby:2.5.1-alpine
ENV BUNDLER_VERSION=2.0.2
RUN apk add --update --no-cache \
binutils-gold \
build-base \
curl \
file \
g++ \
gcc \
git \
less \
libstdc++ \
libffi-dev \
libc-dev \
linux-headers \
libxml2-dev \
libxslt-dev \
libgcrypt-dev \
make \
netcat-openbsd \
nodejs \
openssl \
pkgconfig \
postgresql-dev \
python \
tzdata \
yarn
RUN gem install bundler -v 2.0.2
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle config build.nokogiri --use-system-libraries
RUN bundle check || bundle install
COPY package.json yarn.lock ./
RUN yarn install --check-files
COPY . ./
ENTRYPOINT ["./entrypoints/docker-entrypoint.sh"]
Сохраните и закройте файл после завершения редактирования.
Далее мы создадим директорию entrypoints
для скриптов точек входа:
- mkdir entrypoints
В этой директории будут храниться основной скрипт точки входа и скрипт для нашей службы Sidekiq.
Откройте файл скрипта точки входа приложения:
- nano entrypoints/docker-entrypoint.sh
Добавьте в файл следующий код:
#!/bin/sh
set -e
if [ -f tmp/pids/server.pid ]; then
rm tmp/pids/server.pid
fi
bundle exec rails s -b 0.0.0.0
Первая важная строка — это строка set -e
, которая предписывает оболочке выполнения скрипта /bin/sh
быстро прекратить работу при обнаружении любых проблем со скриптом. Далее скрипт проверяет отсутствие tmp/pids/server.pid
для предотвращения конфликтов с сервером при запуске приложения. В заключение скрипт запускает сервер Rails с помощью команды bundle exec rails s
. Мы используем с этой командой опцию -b
для привязки сервера ко всем IP-адресам, а не только к адресу localhost
по умолчанию. При таком вызове сервер Rails перенаправляет входящие запросы на IP-адрес контейнера, а не на адрес localhost
по умолчанию.
Сохраните и закройте файл после завершения редактирования.
Создайте исполняемый скрипт:
- chmod +x entrypoints/docker-entrypoint.sh
Далее мы создадим скрипт для запуска службы sidekiq
, который будет обрабатывать наши задания Sidekiq. Дополнительную информацию об использовании Sidekiq в этом приложении можно найти в обучающем руководстве Добавление Sidekiq и Redis в приложение Ruby on Rails.
Откройте файл скрипта точки входа Sidekiq:
- nano entrypoints/sidekiq-entrypoint.sh
Добавьте в файл следующий код для запуска Sidekiq:
#!/bin/sh
set -e
if [ -f tmp/pids/server.pid ]; then
rm tmp/pids/server.pid
fi
bundle exec sidekiq
Этот скрипт запускает Sidekiq в контексте комплекта нашего приложения.
Сохраните и закройте файл после завершения редактирования. Сделайте его исполняемым:
- chmod +x entrypoints/sidekiq-entrypoint.sh
Со скриптами точки входа и файлом Dockerfile мы готовы определять службы в файле Compose.
С помощью Docker Compose мы сможем запустить несколько контейнеров, необходимых для нашего приложения. Мы определим службы Compose в основном файле docker-compose.yml
. Служба в Compose — это запущенный контейнер, а определения служб, которые вы будете добавлять в ваш файл docker-compose.yml
, содержат информацию о том, как будет запускаться образ каждого контейнера. Compose позволяет вам определять различные службы для создания приложений с несколькими контейнерами.
Установка приложения предусматривает следующие службы:
Также мы добавим привязку монтирования, чтобы любые изменения кода при разработке немедленно синхронизировались с контейнерами, которым требуется доступ к этому коду.
Обратите внимание, что мы не определяем службу test
, поскольку в настоящем обучающем руководстве и серии материалов не описывается тестирование, но вы можете использовать для ее определения процедуру, аналогичную приведенной здесь для службы sidekiq
.
Откройте файл docker-compose.yml
:
- nano docker-compose.yml
Добавьте определение службы приложения:
version: '3.4'
services:
app:
build:
context: .
dockerfile: Dockerfile
depends_on:
- database
- redis
ports:
- "3000:3000"
volumes:
- .:/app
- gem_cache:/usr/local/bundle/gems
- node_modules:/app/node_modules
env_file: .env
environment:
RAILS_ENV: development
Определение службы приложения
включает следующие параметры:
build
: это определение параметров конфигурации, включая context
и dockerfile
, которые будут применяться при создании образа приложения Compose. Если вы хотите использовать существующий образ из реестра, например, из Docker Hub, вы можете использовать инструкцию image
с информацией об имени пользователя, репозитория и теге образа.context
: это определение контекста сборки для сборки образа, в этом случае текущая директория проекта.dockerfile
: данный параметр определяет Dockerfile
в текущей директории проекта в качестве файла, который Compose будет использовать для сборки образа приложения.depends_on
: настраивает контейнеры database
и redis
первыми, чтобы они запускались до приложения
.ports
: сопоставляет порт 3000
хоста с портом 3000
контейнера.volumes
: мы используем два типа монтирования:
/app
в контейнере. Это упрощает быструю разработку, поскольку любые изменения, которые вы вносите в код хоста, будут немедленно добавлены в контейнер.gem_cache
. При запуске команды bundle install
в контейнере она устанавливает зависимости проекта. Добавление этого тома означает, что при воссоздании контейнера зависимости монтируются в новый контейнер. Такое монтирование предполагает отсутствие изменений в проекте, поэтому если вы вносите изменения в зависимости проекта во время разработки, этот том нужно удалить до воссоздания службы приложения.node_modules
. Поскольку монтирование node_modules
на хост может привести к расхождениям с пакетом и конфликтам при разработке, этот том обеспечивает постоянство пакетов в данной директории и их соответствие текущему состоянию проекта. Если вы измените зависимости Node проекта, этот том нужно удалить и воссоздать.env_file
: указывает Compose, что мы хотим добавить переменные среды из файла .env
в контексте сборки.environment
: данная опция позволяет установить некритичную переменную среды, передавая информацию о среде Rails в контейнер.Добавьте под определением службы app
следующий код для определения службы database
:
. . .
database:
image: postgres:12.1
volumes:
- db_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
В отличие от службы app
, служба database
извлекает образ postgres
непосредственно из Docker Hub. Здесь мы также закрепляем версию, а не устанавливаем последнюю
версию и не указываем конкретную версию (по умолчанию — последнюю
). Так мы обеспечим работу этой системы с указанными здесь версиями и сможем избежать непредвиденных сюрпризов при нарушениях изменений кода образа.
Также мы добавляем здесь том db_data
, который сохраняет в постоянном виде данные приложения в промежутках между запуском контейнеров. Также мы смонтировали скрипт пуска init.sql
в соответствующую директорию контейнера docker-entrypoint-initdb.d/
для создания нашего пользователя базы данных sammy
. Когда точка входа образа создает пользователя и базу данных postgres
по умолчанию, она выполняет все скрипты из директории docker-entrypoint-initdb.d/
, которые можно использовать для выполнения необходимых задач по инициализации. Более подробную информацию можно найти в разделе Скрипты инициализации в документации по образам PostgreSQL.
Затем следует добавить определение службы redis
:
. . .
redis:
image: redis:5.0.7
Как и служба database
, служба redis
использует образ из Docker Hub. В этом случае мы не сохраняем кэш заданий Sidekiq.
В заключение следует добавить определение службы sidekiq
:
. . .
sidekiq:
build:
context: .
dockerfile: Dockerfile
depends_on:
- app
- database
- redis
volumes:
- .:/app
- gem_cache:/usr/local/bundle/gems
- node_modules:/app/node_modules
env_file: .env
environment:
RAILS_ENV: development
entrypoint: ./entrypoints/sidekiq-entrypoint.sh
Наша служба sidekiq
напоминает службу app
в некоторых отношениях. В частности, она использует тот же контекст сборки и образ, те же переменные среды и тома. Однако она зависит от служб app
, redis
и database
и поэтому запускается в последнюю очередь. Кроме того, она использует точку входа
, заменяющую заданную в Dockerfile. Этот параметр точки входа
указывает на файл entrypoints/sidekiq-entrypoint.sh
, который включает команду для запуска службы sidekiq
.
На заключительном шаге мы добавим определения томов под определением службы sidekiq
:
. . .
volumes:
gem_cache:
db_data:
node_modules:
Наш ключ томов верхнего уровня определяет тома gem_cache
, db_data
и node_modules
. Когда Docker создает тома, содержимое тома сохраняется в части файловой системы хоста, /var/lib/docker/volumes/
, а данным процессом управляет Docker. Содержимое каждого тома сохраняется в директории /var/lib/docker/volumes/
и монтируется в любой контейнер, который использует том. Таким образом, данные информации об акулах, которые будут добавлять наши пользователи, будут сохраняться в томе db_data
даже при удалении и последующем восстановлении службы database
.
Итоговый файл будет выглядеть примерно так:
version: '3.4'
services:
app:
build:
context: .
dockerfile: Dockerfile
depends_on:
- database
- redis
ports:
- "3000:3000"
volumes:
- .:/app
- gem_cache:/usr/local/bundle/gems
- node_modules:/app/node_modules
env_file: .env
environment:
RAILS_ENV: development
database:
image: postgres:12.1
volumes:
- db_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
redis:
image: redis:5.0.7
sidekiq:
build:
context: .
dockerfile: Dockerfile
depends_on:
- app
- database
- redis
volumes:
- .:/app
- gem_cache:/usr/local/bundle/gems
- node_modules:/app/node_modules
env_file: .env
environment:
RAILS_ENV: development
entrypoint: ./entrypoints/sidekiq-entrypoint.sh
volumes:
gem_cache:
db_data:
node_modules:
Сохраните и закройте файл после завершения редактирования.
Когда ваши определения службы будут записаны, вы сможете запустить приложение.
Имея в распоряжении файл docker-compose.yml
, вы можете создать ваши службы с помощью команды docker-compose up
и создать исходные записи базы данных. Также вы можете проверить сохранение данных, останавливая работу контейнеров и удаляя их с помощью docker-compose down
, а затем воссоздавая их.
Во-первых, необходимо выполнить сборку образов и создать службы, запустив docker-compose up
с флагом -d
, который будет запускать контейнеры в фоновом режиме:
- docker-compose up -d
Вы увидите сообщение, подтверждающее успешное создание служб:
OutputCreating rails-docker_database_1 ... done
Creating rails-docker_redis_1 ... done
Creating rails-docker_app_1 ... done
Creating rails-docker_sidekiq_1 ... done
Также вы можете получить более подробную информацию о процессах запуска, отобразив вывод журнала из служб:
- docker-compose logs
Если запуск был выполнен корректно, вы должны увидеть примерно следующее:
Outputsidekiq_1 | 2019-12-19T15:05:26.365Z pid=6 tid=grk7r6xly INFO: Booting Sidekiq 6.0.3 with redis options {:host=>"redis", :port=>"6379", :id=>"Sidekiq-server-PID-6", :url=>nil}
sidekiq_1 | 2019-12-19T15:05:31.097Z pid=6 tid=grk7r6xly INFO: Running in ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux-musl]
sidekiq_1 | 2019-12-19T15:05:31.097Z pid=6 tid=grk7r6xly INFO: See LICENSE and the LGPL-3.0 for licensing details.
sidekiq_1 | 2019-12-19T15:05:31.097Z pid=6 tid=grk7r6xly INFO: Upgrade to Sidekiq Pro for more features and support: http://sidekiq.org
app_1 | => Booting Puma
app_1 | => Rails 5.2.3 application starting in development
app_1 | => Run `rails server -h` for more startup options
app_1 | Puma starting in single mode...
app_1 | * Version 3.12.1 (ruby 2.5.1-p57), codename: Llamas in Pajamas
app_1 | * Min threads: 5, max threads: 5
app_1 | * Environment: development
app_1 | * Listening on tcp://0.0.0.0:3000
app_1 | Use Ctrl-C to stop
. . .
database_1 | PostgreSQL init process complete; ready for start up.
database_1 |
database_1 | 2019-12-19 15:05:20.160 UTC [1] LOG: starting PostgreSQL 12.1 (Debian 12.1-1.pgdg100+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
database_1 | 2019-12-19 15:05:20.160 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432
database_1 | 2019-12-19 15:05:20.160 UTC [1] LOG: listening on IPv6 address "::", port 5432
database_1 | 2019-12-19 15:05:20.163 UTC [1] LOG: listening on Unix socket "/var/run/postgresql/.s.PGSQL.5432"
database_1 | 2019-12-19 15:05:20.182 UTC [63] LOG: database system was shut down at 2019-12-19 15:05:20 UTC
database_1 | 2019-12-19 15:05:20.187 UTC [1] LOG: database system is ready to accept connections
. . .
redis_1 | 1:M 19 Dec 2019 15:05:18.822 * Ready to accept connections
Также вы можете проверить состояние ваших контейнеров с помощью docker-compose ps
:
- docker-compose ps
Вы получите вывод, указывающий, что ваши контейнеры запущены:
Output Name Command State Ports
-----------------------------------------------------------------------------------------
rails-docker_app_1 ./entrypoints/docker-resta ... Up 0.0.0.0:3000->3000/tcp
rails-docker_database_1 docker-entrypoint.sh postgres Up 5432/tcp
rails-docker_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp
rails-docker_sidekiq_1 ./entrypoints/sidekiq-entr ... Up
Далее создайте базу данных, создайте для нее исходные записи и выполните миграцию с помощью следующей команды docker-compose exec
:
- docker-compose exec app bundle exec rake db:setup db:migrate
Команда docker-compose exec
позволяет запускать команды в службах. Здесь мы используем ее для запуска команд rake db:setup
и db:migrate
в контексте нашего приложения для создания базы данных, создания исходных записей и проведения миграции. Команда docker-compose exec
полезна для проведения миграции с базой данных, используемой для разработки.
После запуска этой команды вы увидите следующий экран:
OutputCreated database 'rails_development'
Database 'rails_development' already exists
-- enable_extension("plpgsql")
-> 0.0140s
-- create_table("endangereds", {:force=>:cascade})
-> 0.0097s
-- create_table("posts", {:force=>:cascade})
-> 0.0108s
-- create_table("sharks", {:force=>:cascade})
-> 0.0050s
-- enable_extension("plpgsql")
-> 0.0173s
-- create_table("endangereds", {:force=>:cascade})
-> 0.0088s
-- create_table("posts", {:force=>:cascade})
-> 0.0128s
-- create_table("sharks", {:force=>:cascade})
-> 0.0072s
Оставив службы работать, откройте в браузере адрес localhost:3000
или http://your_server_ip:3000
. Вы увидите стартовую страницу, которая будет выглядеть примерно так:
Теперь мы можем протестировать сохранение данных. Создайте новую акулу, нажав кнопку Get Shark Info, после чего откроется путь sharks/index
:
Чтобы убедиться в работе приложения, добавим в него примеры данных. Нажмите New Shark. Вам будет предложено ввести имя пользователя (sammy) и пароль (shark) в связи с параметрами аутентификации проекта.
На странице New Shark введите Mako в поле Name и Fast в поле Facts.
Нажмите кнопку Create Shark для создания акулы. После создания акулы нажмите Home на панели навигации сайта, чтобы вернуться на главную страницу приложения. Теперь мы можем протестировать работу Sidekiq.
Нажмите кнопку Which Sharks Are in Danger? Поскольку вы еще не выгрузили акул, находящихся под угрозой вымирания, сейчас откроется экран endangered
index
:
Нажмите Import Endangered Sharks для импорта акул. Вы увидите сообщение о состоянии, где будет указано, что акулы были импортированы:
Также вы увидите начало импорта. Обновите страницу, чтобы увидеть таблицу целиком:
Благодаря Sidekiq пакетная выгрузка акул, находящихся под угрозой вымирания, была проведена успешно без блокировки браузера и без помех для работы других приложений.
Нажмите кнопку Home внизу страницы, чтобы вернуться на главную страницу приложения:
Далее нажмите Which Sharks Are in Danger? еще раз. Вы снова увидите список выгруженных акул.
Теперь мы знаем, что наше приложение работает хорошо и можем протестировать сохранение данных.
Введите на терминале следующую команду для остановки и удаления контейнеров:
- docker-compose down
Обратите внимание, что мы не используем параметр --volumes
и поэтому наш том db_data
не удаляется.
Следующая информация подтверждает, что ваши контейнеры и сеть были удалены:
OutputStopping rails-docker_sidekiq_1 ... done
Stopping rails-docker_app_1 ... done
Stopping rails-docker_database_1 ... done
Stopping rails-docker_redis_1 ... done
Removing rails-docker_sidekiq_1 ... done
Removing rails-docker_app_1 ... done
Removing rails-docker_database_1 ... done
Removing rails-docker_redis_1 ... done
Removing network rails-docker_default
Повторно создайте контейнеры:
- docker-compose up -d
Откройте консоль Rails в контейнере app
с помощью команд docker-compose exec
и bundle exec rails console
:
- docker-compose exec app bundle exec rails console
Проверьте в командной строке последнюю
запись Shark в базе данных:
- Shark.last.inspect
Вы увидите только что созданную запись:
IRB session Shark Load (1.0ms) SELECT "sharks".* FROM "sharks" ORDER BY "sharks"."id" DESC LIMIT $1 [["LIMIT", 1]]
=> "#<Shark id: 5, name: \"Mako\", facts: \"Fast\", created_at: \"2019-12-20 14:03:28\", updated_at: \"2019-12-20 14:03:28\">"
Вы можете проверить сохранение акул из списка Endangered
с помощью следующей команды:
- Endangered.all.count
IRB session (0.8ms) SELECT COUNT(*) FROM "endangereds"
=> 73
Ваш том db_data
был успешно смонтирован в воссозданную службу database
, благодаря чему служба app
смогла получить доступ к сохраненным данным. Если вы перейдете напрямую на страницу index
shark
по адресу localhost:3000/sharks
или http://your_server_ip:3000/sharks
, вы также увидите эту запись:
Находящиеся под угрозой исчезновения виды акул также можно будет посмотреть на экране localhost:3000/endangered/data
или http://your_server_ip:3000/endangered/data
:
Ваше приложение сейчас запущено в контейнерах Docker с сохранением данных и активацией синхронизации кода. Далее вы можете протестировать локальные изменения кода на вашем хосте, который будет синхронизирован с контейнером благодаря привязке монтирования, определенной в рамках службы app
.
В этом обучающем руководстве вы создали систему разработки приложений Rails с использованием контейнеров Docker. Вы сделали проект более модульным и портативным посредством извлечения важной информации и отсоединения состояния приложения от кода. Вы также настроили шаблонный файл docker-compose.yml
, который вы можете изменять в зависимости от потребностей разработки и изменений требований.
В процессе разработки вы можете захотеть узнать больше о проектировании приложений для контейнеризованных рабочих процессов и процессов Cloud Native. Дополнительную информацию по этим темам вы можете посмотреть в статьях Разработка архитектуры приложений для Kubernetes и Модернизация приложений для Kubernetes. Если вы предпочитаете пройти обучение по Kubernetes, ознакомьтесь с нашим учебным планом по Kubernetes для комплексной разработки.
Чтобы узнать больше о коде приложения, ознакомьтесь с другими обучающими руководствами этой серии:
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!