使用 Docker Compose 将 Ruby on Rails 应用程序容器化以进行开发
简介 如果您正在积极开发应用程序,使用Docker可以简化您的工作流程以及将应用程序部署到生产的过程。在开发中使用容器具有以下好处: 环境是一致的,这意味着你可以为你的项目选择你想要的语言和依赖项,而不用担心系统冲突。 环境被隔离,更容易解决问题和加入新的团队成员。 环境是可移植的,允许您打包并与他人共享您的代码。 本教程将向您展示如何使用 Docker 为Ruby on Rails应用程序设置开
简介
如果您正在积极开发应用程序,使用Docker可以简化您的工作流程以及将应用程序部署到生产的过程。在开发中使用容器具有以下好处:
-
环境是一致的,这意味着你可以为你的项目选择你想要的语言和依赖项,而不用担心系统冲突。
-
环境被隔离,更容易解决问题和加入新的团队成员。
-
环境是可移植的,允许您打包并与他人共享您的代码。
本教程将向您展示如何使用 Docker 为Ruby on Rails应用程序设置开发环境。您将为应用程序本身、PostgreSQL数据库、Redis和Sidekiq服务创建多个容器 - 使用Docker Compose。该设置将执行以下操作:
-
将宿主机上的应用程序代码与容器内的代码同步,方便开发过程中的更改。
-
在容器重新启动之间保留应用程序数据。
-
配置 Sidekiq 工作人员以按预期处理作业。
在本教程结束时,您将拥有一个在 Docker 容器上运行的鲨鱼信息应用程序:
先决条件
要遵循本教程,您将需要:
-
运行 Ubuntu 18.04 的本地开发机器或服务器,以及具有
sudo
权限和活动防火墙的非 root 用户。有关如何设置这些设置的指导,请参阅此初始服务器设置指南。 -
Docker 安装在您的本地机器或服务器上,按照如何在 Ubuntu 18.04上安装和使用 Docker 的步骤 1 和 2。
-
Docker Compose 安装在您的本地计算机或服务器上,按照如何在 Ubuntu 18.04上安装 Docker Compose 的第 1 步。
第 1 步 - 克隆项目并添加依赖项
我们的第一步是从DigitalOcean 社区 GitHub 帐户克隆rails-sidekiq存储库。此存储库包含如何将 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
gem添加到项目的依赖项中,这些依赖项在其 Gemfile 中列出。使用nano
或您喜欢的编辑器打开该文件进行编辑:
nano Gemfile
在主项目依赖项(在开发依赖项之上)的任何位置添加 gem:
~/rails-docker/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
gem,因为我们不会再使用它了:
~/rails-docker/Gemfile
. . .
# Use sqlite3 as the database for Active Record
# gem 'sqlite3'
. . .
最后把development
下面的spring-watcher-listen
gem注释掉:
~/rails-docker/Gemfile
. . .
gem 'spring'
# gem 'spring-watcher-listen', '~> 2.0.0'
. . .
如果我们不禁用这个 gem,我们将在访问 Rails 控制台时看到持续的错误消息。这些错误消息源于这个 gem 有 Rails 使用listen
来监视开发中的变化,而不是轮询文件系统的变化。因为这个 gem 监视项目的根目录,包括node_modules
目录,所以它会抛出有关正在监视哪些目录的错误消息,从而使控制台混乱。但是,如果您担心节省 CPU 资源,则禁用此 gem 可能对您不起作用。在这种情况下,将 Rails 应用程序升级到 Rails 6 可能是个好主意。
完成编辑后保存并关闭文件。
准备好项目存储库,将pg
gem 添加到 Gemfile 并注释掉spring-watcher-listen
gem,您就可以配置应用程序以使用 PostgreSQL。
第 2 步 - 配置应用程序以使用 PostgreSQL 和 Redis
要在开发中使用 PostgreSQL 和 Redis,我们需要执行以下操作:
-
将应用程序配置为使用 PostgreSQL 作为默认适配器。
-
使用我们的数据库用户名和密码以及 Redis 主机将
.env
文件添加到项目中。 -
创建
init.sql
脚本为数据库创建sammy
用户。 -
为 Sidekiq 添加一个初始化程序以便它可以与我们的容器化
redis
服务一起使用。 -
将
.env
文件和其他相关文件添加到项目的gitignore
和dockerignore
文件中。 -
创建数据库种子,以便我们的应用程序在启动时有一些记录供我们使用。
首先,打开位于config/database.yml
的数据库配置文件:
nano config/database.yml
目前,该文件包括以下default
个设置,这些设置在没有其他设置的情况下应用:
~/rails-docker/config/database.yml
default: &default
adapter: sqlite3
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
timeout: 5000
我们需要更改这些以反映我们将使用postgresql
适配器这一事实,因为我们将使用 Docker Compose 创建一个 PostgreSQL 服务来保存我们的应用程序数据。
删除将 SQLite 设置为适配器的代码并将其替换为以下设置,这将适当地设置适配器以及连接所需的其他变量:
~/rails-docker/config/database.yml
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 数据库配置,使该部分如下所示:
~/rails-docker/config/database.yml
. . .
development:
<<: *default
. . .
最后,删除production
和test
环境的database
设置:
~/rails-docker/config/database.yml
. . .
test:
<<: *default
production:
<<: *default
. . .
这些对我们默认数据库设置的修改将允许我们使用.env
文件中定义的环境变量动态设置我们的数据库信息,这些文件不会提交给版本控制。
完成编辑后保存并关闭文件。
请注意,如果您从头开始创建 Rails 项目,您可以使用rails new
命令设置适配器,如步骤 3ofHow To Use PostgreSQL with Your Ruby on Rails Application on Ubuntu 18.04中所述。这会将您的适配器设置为config/database.yml
并自动将pg
gem 添加到项目中。
现在我们已经引用了环境变量,我们可以使用我们的首选设置为它们创建一个文件。以这种方式提取配置设置是应用程序开发的12 因素方法的一部分,该方法定义了分布式环境中应用程序弹性的最佳实践。现在,当我们将来设置生产和测试环境时,配置我们的数据库设置将涉及创建额外的.env
文件并在我们的 Docker Compose 文件中引用适当的文件。
打开一个.env
文件:
nano .env
将以下值添加到文件中:
~/rails-docker/.env
DATABASE_NAME=rails_development
DATABASE_USER=sammy
DATABASE_PASSWORD=shark
DATABASE_HOST=database
REDIS_HOST=redis
除了设置我们的数据库名称、用户和密码之外,我们还为DATABASE_HOST
设置了一个值。值database
是指我们将使用 Docker Compose 创建的database
PostgreSQL 服务。我们还设置了一个REDIS_HOST
来指定我们的redis
服务。
完成编辑后保存并关闭文件。
要创建sammy
数据库用户,我们可以编写一个init.sql
脚本,然后我们可以在数据库容器启动时将其挂载到数据库容器中。
打开脚本文件:
nano init.sql
添加以下代码以创建具有管理权限的sammy
用户:
~/rails-docker/init.sql
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
的值:
~/rails-docker/config/initializers/sidekiq.rb
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
添加一个条目:
~/rails-docker/.gitignore
yarn-debug.log*
.yarn-integrity
.env
完成编辑后保存并关闭文件。
接下来,我们将创建一个.dockerignore
文件来设置不应复制到容器中的内容。打开文件进行编辑:
.dockerignore
将以下代码添加到文件中,这会告诉 Docker 忽略一些我们不需要复制到容器中的内容:
~/rails-docker/.dockerignore
.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
也添加到该文件的底部:
~/rails-docker/.dockerignore
. . .
yarn-error.log
coverage/
.env
完成编辑后保存并关闭文件。
作为最后一步,我们将创建一些种子数据,以便我们的应用程序在启动时有一些记录。
在db
目录中为种子数据打开一个文件:
nano db/seeds.rb
将以下代码添加到文件中以创建四个演示鲨鱼和一个示例帖子:
~/rails-docker/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。
第 3 步 — 编写 Dockerfile 和入口点脚本
您的 Dockerfile 指定创建应用程序容器时将包含的内容。使用 Dockerfile 可以定义容器环境并避免依赖项或运行时版本的差异。
遵循这些关于构建优化容器的指南,我们将通过使用Alpine base并尝试总体上最小化我们的镜像层来使我们的镜像尽可能高效。
在当前目录中打开一个 Dockerfile:
nano Dockerfile
Docker 镜像是使用一系列相互构建的分层镜像创建的。我们的第一步是为我们的应用程序添加_base image_,这将构成应用程序构建的起点。
将以下代码添加到文件中以添加Ruby alpine 映像作为基础:
~/rails-docker/Dockerfile
FROM ruby:2.5.1-alpine
alpine
镜像源自 Alpine Linux 项目,将帮助我们减小镜像大小。有关alpine
映像是否适合您的项目的更多信息,请参阅Docker Hub Ruby 映像页面的 Image Variants 部分下的完整讨论。
在开发中使用alpine
时需要考虑的一些因素:
-
减小图像大小将减少页面和资源加载时间,特别是如果您还将卷保持在最低限度。这有助于使您在开发中的用户体验快速且接近于您在非容器化环境中本地工作时的体验。
-
开发和生产映像之间的平等有助于成功部署。由于团队经常选择在生产中使用 Alpine 图像以获得速度优势,因此使用 Alpine 基础进行开发有助于在转移到生产时解决问题。
接下来,设置一个环境变量,指定Bundler版本:
~/rails-docker/Dockerfile
. . .
ENV BUNDLER_VERSION=2.0.2
这是我们为避免环境中可用的默认bundler
版本与需要 Bundler 2.0.2 的应用程序代码之间的版本冲突而采取的步骤之一。
接下来,将与应用程序一起使用所需的包添加到 Dockerfile:
~/rails-docker/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
版本:
~/rails-docker/Dockerfile
. . .
RUN gem install bundler -v 2.0.2
此步骤将保证我们的容器化环境与该项目的Gemfile.lock
文件中的规范之间的一致性。
现在为容器上的应用程序设置工作目录:
~/rails-docker/Dockerfile
. . .
WORKDIR /app
复制您的Gemfile
和Gemfile.lock
:
~/rails-docker/Dockerfile
. . .
COPY Gemfile Gemfile.lock ./
将这些文件作为一个独立步骤复制,后跟bundle install
,这意味着每次更改应用程序代码时都不需要重新构建项目 gem。这将与我们将包含在 Compose 文件中的 gem 卷一起使用,在重新创建服务但项目 gem 保持不变的情况下,它将把 gem 挂载到您的应用程序容器中。
接下来,设置nokogiri
gem 构建的配置选项:
~/rails-docker/Dockerfile
. . .
RUN bundle config build.nokogiri --use-system-libraries
. . .
此步骤使用我们在上面的RUN apk add…
步骤中添加到应用程序容器的libxml2
和libxslt
库版本](https://nokogiri.org/tutorials/installing_nokogiri.html#install-with-system-libraries)构建nokigiri
[。
接下来,安装项目 gem:
~/rails-docker/Dockerfile
. . .
RUN bundle check || bundle install
该指令在安装之前检查 gem 是否尚未安装。
接下来,我们将使用我们的 JavaScript 包和依赖项重复我们对 gems 使用的相同过程。首先我们将复制包元数据,然后我们将安装依赖项,最后我们将应用程序代码复制到容器映像中。
要开始使用 Dockerfile 的 Javascript 部分,请将主机上当前项目目录中的package.json
和yarn.lock
复制到容器中:
~/rails-docker/Dockerfile
. . .
COPY package.json yarn.lock ./
然后用yarn install
安装所需的包:
~/rails-docker/Dockerfile
. . .
RUN yarn install --check-files
该指令包含一个带有yarn
命令的--check-files
标志,该功能可确保未删除任何以前安装的文件。与我们的 gems 一样,当我们编写 Compose 文件时,我们将使用一个卷来管理node_modules
目录中的包的持久性。
最后,复制其余的应用程序代码并使用入口点脚本启动应用程序:
~/rails-docker/Dockerfile
. . .
COPY . ./
ENTRYPOINT ["./entrypoints/docker-entrypoint.sh"]
使用入口点脚本允许我们将容器作为可执行文件运行。
最终的 Dockerfile 将如下所示:
~/rails-docker/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
将以下代码添加到文件中:
rails-docker/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
shell 快速失败,如果脚本后面有任何问题。接下来,脚本会检查tmp/pids/server.pid
是否不存在,以确保在我们启动应用程序时不会发生服务器冲突。最后,脚本使用bundle exec rails s
命令启动 Rails 服务器。我们在此命令中使用-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:
~/rails-docker/entrypoints/sidekiq-entrypoint.sh
#!/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 文件中定义服务了。
第 4 步 — 使用 Docker Compose 定义服务
使用 Docker Compose,我们将能够运行我们的设置所需的多个容器。我们将在主文件docker-compose.yml
中定义 Compose services。 Compose 中的服务是一个正在运行的容器,并且服务定义(您将包含在docker-compose.yml
文件中)包含有关每个容器映像将如何运行的信息。 Compose 工具允许您定义多个服务来构建多容器应用程序。
我们的应用程序设置将包括以下服务:
-
应用程序本身
-
PostgreSQL 数据库
-
雷迪斯
-
西底家
我们还将绑定挂载作为我们设置的一部分,以便我们在开发期间所做的任何代码更改都将立即与需要访问此代码的容器同步。
请注意,我们_不_定义test
服务,因为测试超出了本教程和系列的范围,但您可以按照我们在此处使用的sidekiq
服务的先例来进行。
打开docker-compose.yml
文件:
nano docker-compose.yml
首先,添加应用服务定义:
~/rails-docker/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
app
服务定义包括以下选项:
-
build
:这定义了 Compose 构建应用程序映像时将应用的配置选项,包括context
和dockerfile
。如果您想使用Docker Hub等注册表中的现有映像,则可以使用image
指令代替,其中包含有关您的用户名、存储库和映像标签的信息。 -
context
:这定义了映像构建的构建上下文——在本例中,是当前项目目录。 -
dockerfile
:这将您当前项目目录中的Dockerfile
指定为 Compose 将用于构建应用程序映像的文件。 -
depends_on
:这首先设置database
和redis
容器,以便它们在app
之前启动并运行。 -
ports
:这会将主机上的端口3000
映射到容器上的端口3000
。 -
volumes
:我们在这里包括两种类型的坐骑: -
第一个是bind mount,将我们宿主机上的应用代码挂载到容器上的
/app
目录。这将有助于快速开发,因为您对主机代码所做的任何更改都将立即填充到容器中。 -
第二个是一个名为的卷,
gem_cache
。当bundle install
指令在容器中运行时,它会安装项目 gems。添加此卷意味着如果您重新创建容器,gems 将被挂载到新容器中。此挂载假定项目没有任何更改,因此如果您_do_ 在开发中对项目 gem 进行更改,您需要记住在重新创建应用程序服务之前删除此卷。 -
第三卷是
node_modules
目录的命名卷。与其将node_modules
挂载到主机上,否则会导致开发中的包差异和权限冲突,此卷将确保此目录中的包被持久化并反映项目的当前状态。同样,如果您修改项目的节点依赖项,您将需要删除并重新创建此卷。 -
env_file
:这告诉 Compose 我们希望从位于构建上下文中的名为.env
的文件中添加环境变量。 -
environment
:使用此选项允许我们设置非敏感环境变量,将有关 Rails 环境的信息传递给容器。
接下来,在app
服务定义下方,添加以下代码来定义您的database
服务:
~/rails-docker/docker-compose.yml
. . .
database:
image: postgres:12.1
volumes:
- db_data:/var/lib/postgresql/data
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
与app
服务不同,database
服务直接从Docker Hub拉取一个postgres
镜像。请注意,我们也在此处固定版本,而不是将其设置为latest
或不指定它(默认为latest
)。这样,我们可以确保此设置适用于此处指定的版本,并避免因破坏图像代码更改而出现意外。
我们还包括一个db_data
卷,它将在容器启动之间保存我们的应用程序数据。此外,我们已将init.sql
启动脚本挂载到容器上的相应目录docker-entrypoint-initdb.d/
中,以创建我们的sammy
数据库用户。映像入口点创建默认的postgres
用户和数据库后,它将运行在docker-entrypoint-initdb.d/
目录中找到的任何脚本,您可以将其用于必要的初始化任务。有关更多详细信息,请查看PostgreSQL 映像文档的 Initialization scripts 部分
接下来,添加redis
服务定义:
~/rails-docker/docker-compose.yml
. . .
redis:
image: redis:5.0.7
与database
服务一样,redis
服务使用来自 Docker Hub 的映像。在这种情况下,我们不会持久化 Sidekiq 作业缓存。
最后,添加sidekiq
服务定义:
~/rails-docker/docker-compose.yml
. . .
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
服务,因此将是最后启动的。此外,它使用entrypoint
将覆盖 Dockerfile 中设置的入口点。这个entrypoint
设置指向entrypoints/sidekiq-entrypoint.sh
,其中包括启动sidekiq
服务的相应命令。
作为最后一步,在sidekiq
服务定义下方添加卷定义:
~/rails-docker/docker-compose.yml
. . .
volumes:
gem_cache:
db_data:
node_modules:
我们的顶级卷键定义了卷gem_cache
、db_data
和node_modules
。当 Docker 创建卷时,卷的内容存储在由 Docker 管理的主机文件系统/var/lib/docker/volumes/
的一部分中。每个卷的内容都存储在/var/lib/docker/volumes/
下的目录中,并被挂载到使用该卷的任何容器中。这样,即使我们删除并重新创建database
服务,我们的用户将创建的鲨鱼信息数据将保留在db_data
卷中。
完成的文件将如下所示:
~/rails-docker/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
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:
完成编辑后保存并关闭文件。
编写好服务定义后,您就可以启动应用程序了。
第 5 步 — 测试应用程序
准备好docker-compose.yml
文件后,您可以使用docker-compose up
命令创建服务并为数据库播种。您还可以通过使用docker-compose down
停止和删除容器并重新创建它们来测试您的数据是否会持续存在。
首先,构建容器镜像并通过运行带有-d
标志的docker-compose up
创建服务,这将在后台运行容器:
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
路线:
为了验证应用程序是否正常工作,我们可以向其添加一些演示信息。点击新鲨鱼。由于项目的身份验证设置,系统将提示您输入用户名 (sammy) 和密码 (shark)。
在 New Shark 页面上,在 Name 字段中输入“Mako”,在 Facts 字段中输入“Fast”。
点击 Create Shark 按钮来创建鲨鱼。创建鲨鱼后,单击站点导航栏上的 Home 以返回主应用程序登录页面。我们现在可以测试 Sidekiq 是否正常工作。
点击**哪些鲨鱼处于危险之中?**按钮。由于您还没有上传任何濒临灭绝的鲨鱼,这将带您到endangered``index
视图:
点击 Import Endangered Sharks 以导入鲨鱼。您将看到一条状态消息,告诉您鲨鱼已被导入:
您还将看到导入的开始。刷新页面以查看整个表格:
多亏了 Sidekiq,我们大批量上传濒临灭绝的鲨鱼已经成功,没有锁定浏览器或干扰其他应用程序功能。
单击页面底部的 Home 按钮,您将返回应用程序主页面:
从这里,再次单击哪些鲨鱼处于危险之中?。您将再次看到上传的鲨鱼。
现在我们知道我们的应用程序工作正常,我们可以测试我们的数据持久性。
回到你的终端,输入以下命令来停止和移除你的容器:
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
使用docker-compose exec
和bundle exec rails console
打开app
容器上的 Rails 控制台:
docker-compose exec app bundle exec rails console
在提示符下,检查数据库中的last
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
服务可以访问保存的数据。如果您通过访问localhost:3000/sharks
或http://your_server_ip:3000/sharks
直接导航到index``shark
页面,您还将看到显示的记录:
您濒临灭绝的鲨鱼也将出现在localhost:3000/endangered/data
或http://your_server_ip:3000/endangered/data
视图中:
您的应用程序现在在启用了数据持久性和代码同步的 Docker 容器上运行。您可以继续在主机上测试本地代码更改,这将同步到您的容器,这要归功于我们定义为app
服务的一部分的绑定挂载。
结论
按照本教程,您已经使用 Docker 容器为 Rails 应用程序创建了开发设置。通过提取敏感信息并将应用程序的状态与代码解耦,您使您的项目更加模块化和可移植](https://12factor.net/config)。您还配置了一个样板文件docker-compose.yml
,您可以根据开发需求和要求的变化对其进行修改。
在开发过程中,您可能有兴趣了解有关为容器化和Cloud Native工作流设计应用程序的更多信息。有关这些主题的更多信息,请参阅为 Kubernetes 架构应用程序和为 Kubernetes 现代化应用程序。或者,如果您想投资 Kubernetes 学习序列,请查看Kubernetes for Full-Stack Developers 课程。
要了解有关应用程序代码本身的更多信息,请参阅本系列中的其他教程:
-
如何构建 Ruby on Rails 应用程序
-
如何为 Ruby on Rails 应用程序创建嵌套资源
-
如何向 Ruby on Rails 应用程序添加刺激
-
如何将引导程序添加到 Ruby on Rails 应用程序
-
如何将 Sidekiq 和 Redis 添加到 Ruby on Rails 应用程序
更多推荐
所有评论(0)