使用 React 前端应用程序将 Ruby on Rails 容器化可以显著改善您的开发工作流程和部署过程。通过为您的应用程序创建标准化环境,您可以确保在开发、测试、生产的不同阶段,甚至不同系统之间保持一致的行为。事实上,它旨在最大限度地减少与系统差异相关的问题。本指南将引导您完成让您的 Rails 和 React 应用程序在 Docker 容器中顺利运行的基本步骤。
Docker 确保应用程序无论部署在何处(无论是在开发人员的机器、测试环境还是生产服务器上)都以相同的方式运行。这种一致性是通过容器化所有依赖项和配置来实现的。
Docker 容器包含应用程序运行所需的所有依赖项。这意味着系统库的变化或不同系统上缺少的依赖项不会影响应用程序的功能。
Docker 容器彼此独立运行,并且与主机系统隔离。这种隔离可防止同一系统上不同应用程序及其依赖项之间发生冲突。
Docker 化涉及两个关键概念:镜像和容器。镜像是容器的蓝图,包含创建容器所需的所有信息,包括依赖项和部署配置。容器是镜像的运行时实例,由镜像本身、执行环境和运行时指令组成。总体而言,Docker 为软件的运输建立了标准。
用一个简单的类比来解释 Docker:将容器想象成院子里的集装箱,将图像想象成放置在这些集装箱内的物品,将运输船想象成运行容器的系统。
无论何时设置和构建应用程序,某些环境配置都是必需的。例如,如果系统上没有安装 Ruby 环境,则无法运行 Rails 应用程序。同样,如果没有Node.js
,则无法运行 React 应用程序,如果没有npm
或Yarn
等 Node 包管理器,则无法安装 React 包。
由于容器与用户系统隔离运行,我们将使所有这些包在我们的容器中可用,就像我们直接在我们的系统上构建它一样,因此,容器将作为一个独立的系统,就像虚拟机一样。docker 和虚拟机之间存在差异,但这个例子只是为了进一步解释。
现在,让我们继续将 Rails 应用程序 docker 化。为此,我们将需要 Rails 应用程序中的三个文件: Dockerfile
、 docker-compose.yml
和bin/docker-entrypoint
。让我们详细检查每个文件。
Dockerfile
是创建 Docker 容器的蓝图。它包含 Docker 用于构建映像的一系列指令,然后可以使用这些指令运行容器。让我们分解 Ruby on Rails 和 React 应用程序的Dockerfile
:
ARG RUBY_VERSION=3.1.4 FROM ruby:$RUBY_VERSION
ARG RUBY_VERSION=3.1.4
:定义一个名为RUBY_VERSION
的构建参数,默认值为3.1.4
。这可以在构建时被覆盖。
FROM ruby:$RUBY_VERSION
:使用由RUBY_VERSION
指定的版本的ruby
基础镜像。这将使用 Ruby 运行时设置容器。正如我之前提到的,要运行 Rails 应用程序,您需要安装 Ruby。RUN apt-get update -qq && \ apt-get install -y build-essential libvips bash bash-completion libffi-dev tzdata postgresql curl && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* /usr/share/doc /usr/share/man
apt-get update -qq
:从存储库更新软件包列表,使用-qq
进行静默输出。
apt-get install -y
... :安装各种软件包: build-essential
:构建软件的基本软件包(如 GCC)。
libvips
:图像处理库。
bash
, bash-completion
:Bash shell 及其自动完成功能。
libffi-dev
:外部函数接口库。
tzdata
:时区数据。
postgresql
:PostgreSQL 数据库客户端。
curl
:从 URL 传输数据的工具。
apt-get clean
:清理检索到的包文件的本地存储库。
rm -rf /var/lib/apt/lists/ /usr/share/doc /usr/share/man
:删除软件包列表和文档以减小图像大小。 RUN curl -fsSL https://deb.nodesource.com/setup_current.x | bash - && \ apt-get install -y nodejs && \ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ apt-get update && \ apt-get install -y yarn
curl -fsSL https://deb.nodesource.com/setup_current.x | bash -
:下载并运行 NodeSource 安装脚本来安装 Node.js。
apt-get install -y nodejs
:安装 Node.js。
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
:添加 Yarn GPG 密钥来验证其软件包。
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list
:将 Yarn 的存储库添加到源列表中。
apt-get update && apt-get install -y yarn
:更新包列表并安装 Yarn。ENV NODE_OPTIONS=--openssl-legacy-provider
ENV NODE_OPTIONS=--openssl-legacy-provider
:设置环境变量以启用对 Node.js 的旧版 OpenSSL 支持。WORKDIR /rails
WORKDIR /rails
:将后续指令的工作目录设置为/rails
。ARG RAILS_ENV ENV RAILS_ENV=$RAILS_ENV
ARG RAILS_ENV
:定义一个名为RAILS_ENV
的构建参数,用于指定 Rails 环境(如development
、 test
、 production
)。
ENV RAILS_ENV=$RAILS_ENV
:将环境变量RAILS_ENV
设置为构建参数的值。 COPY Gemfile Gemfile.lock ./ RUN bundle install
COPY Gemfile Gemfile.lock ./
:将Gemfile
和Gemfile.lock
复制到工作目录。
RUN bundle install
:安装Gemfile
中指定的 Ruby 宝石。COPY package.json yarn.lock ./ RUN yarn install --frozen-lockfile
COPY package.json yarn.lock ./
:将package.json
和yarn.lock
复制到工作目录。
RUN yarn install --frozen-lockfile
:使用 Yarn 安装前端依赖项,确保它使用yarn.lock
中的精确版本。COPY . .
COPY . .
:将所有应用程序代码复制到工作目录。RUN bundle exec bootsnap precompile --gemfile app/ lib/
RUN bundle exec bootsnap precompile --gemfile app/ lib/
:预编译 Bootsnap 缓存,以加快 Rails 应用程序的启动时间。Bootsnap 是一个通过缓存昂贵的计算来加快 Ruby 和 Rails 启动时间的 gem。RUN if [ "$RAILS_ENV" = "production" ]; then \ SECRET_KEY_BASE=1 bin/rails assets:precompile; \ fi
RUN if [ "$RAILS_ENV" = "production" ]; then
... :仅当RAILS_ENV
设置为production
时才有条件地运行资产预编译。此步骤对于为生产环境准备资产至关重要。COPY bin/docker-entrypoint /rails/bin/ RUN chmod +x /rails/bin/docker-entrypoint
COPY bin/docker-entrypoint /rails/bin/
:将自定义入口点脚本复制到容器。
RUN chmod +x /rails/bin/docker-entrypoint
:使入口点脚本可执行。ENTRYPOINT ["/rails/bin/docker-entrypoint"] EXPOSE 5000 // you can use any port of your choice CMD ["./bin/rails", "server"]
ENTRYPOINT ["/rails/bin/docker-entrypoint"]
:设置容器启动时将运行的入口点脚本。此脚本通常设置环境、准备数据库并启动应用程序。
EXPOSE 5000
:表示容器监听 5000 端口,这是一个文档功能,并不发布端口。
CMD ["./bin/rails", "server"]
:指定容器启动时默认运行的命令,即启动Rails服务器。 docker-compose.yml
文件用于定义和运行多容器 Docker 应用程序。它允许您在单个文件中配置应用程序的服务、网络和卷。在本例中,我们将使用两个服务。以下是 Rails 应用程序的docker-compose.yml
文件:
db
) codedb: image: postgres:14.2-alpine container_name: demo-postgres-14.2 volumes: - postgres_data:/var/lib/postgresql/data command: "postgres -c 'max_connections=500'" environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} ports: - "5432:5432"
image: postgres:14.2-alpine
:指定用于此服务的 Docker 映像。在本例中,它是基于 Alpine Linux 发行版的 PostgreSQL 14.2 映像。Alpine 映像以体积小而闻名,这有助于降低整体映像大小。
container_name: demo-postgres-14.2
:将容器命名为demo-postgres-14.2
。此名称用于在命令和日志中引用容器。
volumes
: postgres_data:/var/lib/postgresql/data:
将命名卷postgres_data
挂载到容器内的/var/lib/postgresql/data
。此目录是 PostgreSQL 存储其数据的地方,确保数据库数据在容器重启之间保持不变。
command: "postgres -c 'max_connections=500'"
:覆盖 PostgreSQL 映像的默认命令。它使用配置选项启动 PostgreSQL,以将最大连接数增加到 500。
environment
: POSTGRES_DB: ${POSTGRES_DB}
:使用环境变量POSTGRES_DB
设置要创建的默认数据库的名称。
POSTGRES_USER: ${POSTGRES_USER}
:使用POSTGRES_USER
环境变量设置访问 PostgreSQL 数据库的默认用户名。
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
:使用POSTGRES_PASSWORD
环境变量设置默认用户的密码。
ports
:"5432:5432"
:将主机上的端口 5432 映射到容器中的端口 5432。这允许通过端口 5432 访问主机上的 PostgreSQL。demo-web
) codedemo-web: build: context: . args: - RAILS_ENV=${RAILS_ENV} command: "./bin/rails server -b 0.0.0.0" environment: - RAILS_ENV=${RAILS_ENV} - POSTGRES_HOST=${POSTGRES_HOST} - POSTGRES_DB=${POSTGRES_DB} - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - RAILS_MASTER_KEY=${RAILS_MASTER_KEY} volumes: - .:/rails - app-storage:/rails/storage depends_on: - db ports: - "3000:3000"
build:
context: .
:指定 Docker 镜像的构建上下文。在本例中, .
指的是当前目录。这意味着 Docker 将使用当前目录中的 Dockerfile 来构建镜像。args
: RAILS_ENV=${RAILS_ENV}
:将RAILS_ENV
构建参数传递给 Docker 构建过程,允许您指定 Rails 环境(如development
、 test
或production
)。
command: "./bin/rails server -b 0.0.0.0"
:覆盖 Docker 镜像的默认命令。启动 Rails 服务器并将其绑定到所有网络接口 ( 0.0.0.0
),这对于从容器外部访问服务是必需的。
environment:
RAILS_ENV=${RAILS_ENV}
:使用RAILS_ENV
环境变量设置容器内的 Rails 环境。
POSTGRES_HOST=${POSTGRES_HOST}
:设置 PostgreSQL 主机地址。
POSTGRES_DB=${POSTGRES_DB}
:设置数据库名称。
POSTGRES_USER=${POSTGRES_USER}
:设置 PostgreSQL 用户。
POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
:设置 PostgreSQL 用户密码。
RAILS_MASTER_KEY=${RAILS_MASTER_KEY}
:设置 Rails 主密钥,用于加密凭证和其他机密。
volumes
:
.:/rails
:将当前目录( docker-compose.yml
文件所在的目录)挂载到容器内的/rails
。这样您就可以在主机上编辑文件,并将这些更改反映在容器内。
app-storage:/rails/storage
:将命名卷app-storage
挂载到容器内的/rails/storage
。这通常用于存储 Rails 特定文件,例如日志、上传和缓存文件。
depends_on
:
db
:确保demo-web
服务在启动前等待db
服务准备就绪。Docker Compose 根据此设置处理启动服务的顺序。 ports:
"3000:3000"
:将主机上的端口 3000 映射到容器中的端口 3000。这样你就可以通过端口 3000 访问主机上的 Rails 应用程序。codevolumes: postgres_data: app-storage:
postgres_data
:定义一个命名卷postgres_data
,由db
服务用来保存 PostgreSQL 数据。app-storage
:定义一个命名卷app-storage
,由demo-web
服务用来保存特定于应用程序的数据,例如上传和日志。 bin/docker-entrypoint
脚本是 Docker 设置的关键部分。它在容器启动时执行,通常处理环境设置、数据库准备以及启动主应用程序之前所需的其他初始化任务。以下是bin/docker-entrypoint
脚本示例以及每个部分的详细说明:
bashCopy code#!/bin/bash set -e
#!/bin/bash
:此行指定应使用 Bash shell 运行脚本。
set -e
:如果任何命令返回非零退出代码,则指示脚本立即退出。这有助于确保如果任何步骤失败,脚本将停止执行,从而可以防止后续步骤在无效状态下运行。
有条件的数据库创建或迁移
# If running the rails server then create or migrate existing database if [ "${*}" == "./bin/rails server" ]; then ./bin/rails db:create ./bin/rails db:prepare fi
"${*}"
) 是否为./bin/rails server
。 *
是一个特殊参数,它保存传递给脚本的所有位置参数。
./bin/rails 数据库
:如果满足条件,此命令将尝试创建数据库。它相当于运行rails db:create
,按照数据库配置文件 ( config/database.yml
) 中的定义设置数据库。
./bin/rails 数据库
:此命令将运行rails db:prepare
,以确保数据库已设置并迁移。如果数据库不存在,它将创建数据库;如果数据库已创建,它将运行迁移。这是rails db:create
和rails db:migrate
的组合。
bashCopy codeexec "${@}"
exec "${@}"
:这会将当前 shell 进程替换为作为参数传递给脚本的命令。 @
符号包含传递给脚本的所有位置参数。例如,如果使用./bin/rails server
调用脚本,则此行实际上会将./bin/rails server
作为容器的主进程运行。精心编写的Dockerfile
对于为 Ruby on Rails 和 React 应用程序创建可靠且一致的环境至关重要。通过定义基础映像、设置环境变量和安装依赖项,您可以确保应用程序在各种环境中顺利运行。
Docker 不仅简化了您的开发流程,还提高了生产中应用程序的可靠性。虽然还有一些需要优化的地方,但这只是对如何将 Rails 应用程序 docker 化的一般概述。
Dockerfile
、 docker-compose.yml
和bin/docker-entrypoint
的完整脚本ARG RUBY_VERSION=3.1.4 FROM ruby:$RUBY_VERSION # Install dependencies RUN apt-get update -qq && \ apt-get install -y build-essential libvips bash bash-completion libffi-dev tzdata postgresql curl && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* /usr/share/doc /usr/share/man # Install Node.js and Yarn RUN curl -fsSL https://deb.nodesource.com/setup_current.x | bash - && \ apt-get install -y nodejs && \ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \ echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \ apt-get update && \ apt-get install -y yarn # Set environment variable to enable legacy OpenSSL support ENV NODE_OPTIONS=--openssl-legacy-provider # Rails app lives here WORKDIR /rails # Set environment variable for the build ARG RAILS_ENV ENV RAILS_ENV=$RAILS_ENV # Install application gems COPY Gemfile Gemfile.lock ./ RUN bundle install # Install frontend dependencies COPY package.json yarn.lock ./ RUN yarn install --frozen-lockfile # Copy application code COPY . . # Precompile bootsnap code for faster boot times RUN bundle exec bootsnap precompile --gemfile app/ lib/ # Precompiling assets for production without requiring secret RAILS_MASTER_KEY RUN if [ "$RAILS_ENV" = "production" ]; then \ SECRET_KEY_BASE=1 bin/rails assets:precompile; \ fi # Entrypoint prepares the database. COPY bin/docker-entrypoint /rails/bin/ RUN chmod +x /rails/bin/docker-entrypoint # Use an absolute path for the entry point script ENTRYPOINT ["/rails/bin/docker-entrypoint"] # Start the server by default, this can be overwritten at runtime EXPOSE 5000 CMD ["./bin/rails", "server"]
services: db: image: postgres:14.2-alpine container_name: demo-postgres-14.2 volumes: - postgres_data:/var/lib/postgresql/data command: "postgres -c 'max_connections=500'" environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} ports: - "5432:5432" demo-web: build: context: . args: - RAILS_ENV=${RAILS_ENV} command: "./bin/rails server -b 0.0.0.0" environment: - RAILS_ENV=${RAILS_ENV} - POSTGRES_HOST=${POSTGRES_HOST} - POSTGRES_DB=${POSTGRES_DB} - POSTGRES_USER=${POSTGRES_USER} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - RAILS_MASTER_KEY=${RAILS_MASTER_KEY} volumes: - .:/rails - app-storage:/rails/storage depends_on: - db ports: - "3000:3000" volumes: postgres_data: app-storage:
#!/bin/bash set -e # If running the rails server then create or migrate existing database if [ "${*}" == "./bin/rails server" ]; then ./bin/rails db:create ./bin/rails db:prepare fi exec "${@}"