在 Docker 中使用 PostgreSQL 部署仅 Ruby on Rails API 应用程序
项目链接:https://github.com/Joker666/rails-api-docker
Docker允许将应用程序或服务及其所有依赖项打包到单个映像中,然后可以将其托管到不同的平台上,例如Docker Hub或 Github Container Registry。这些图像可以拉取并与队友共享,以便于开发或使用 Kubernetes 等容器编排工具部署到生产环境。
当我们查看当前的开发状态时,关于如何安装和配置应用程序及其所有依赖项的安装说明层出不穷。即使这样它也不起作用,Ruby 版本不匹配或某些依赖项的版本升级破坏了安装。这就是 Docker 派上用场的地方,一次创建的镜像,只要安装了 Docker,就可以在任何平台上运行。今天我们将在 Docker 中部署一个 Ruby on Rails 应用程序。
准备
我们需要在系统中安装一些工具来开始 Rails 开发
-
红宝石 2.7
-
导轨 6.0
-
码头工人
安装这些之后,让我们生成我们的仅 API 项目
rails new docker-rails \
--database=postgresql \
--skip-action-mailbox \
--skip-action-text \
--skip-spring -T \
--skip-turbolinks \
--api
进入全屏模式 退出全屏模式
由于我们正在创建仅 API 项目,因此我们跳过了一些 Rails Web 特定工具的安装,例如action-text或turbolinks。我们确保有--api标志来创建仅 API 的 Rails 项目。
制作API
我们将制作两个 API。作者和文章
rails g resource Author name:string --no-test-framework
rails g resource Article title:string body:text author:references --no-test-framework
进入全屏模式 退出全屏模式
让我们在Author模型中添加has_many宏
# app/models/author.rb
class Author < ApplicationRecord
has_many :articles
end
进入全屏模式 退出全屏模式
并用一些种子数据填充数据库。先安装faker
bundle add faker
进入全屏模式 退出全屏模式
然后做bundle install然后更新seeds文件
# db/seeds.rb
require 'faker'
Author.delete_all
Article.delete_all
10.times do
Author.create(name: Faker::Book.unique.author)
end
50.times do
Article.create({
title: Faker::Book.title,
body: Faker::Lorem.paragraphs(number: rand(5..7)),
author: Author.limit(1).order('RANDOM()').first # sql random
})
end
进入全屏模式 退出全屏模式
现在,我们没有运行 PostgreSQL,因此我们无法运行迁移或种子数据。当我们在 docker 中部署时,我们会这样做。现在让我们更新控制器文件
# app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
before_action :find_article, only: :show
def index
@articles = Article.all
render json: @articles
end
def show
render json: @article
end
private
def find_article
@article = Article.find(params[:id])
end
end
# app/controllers/author_controller.rb
class AuthorsController < ApplicationController
before_action :find_author, only: :show
def index
@authors = Author.all
render json: @authors
end
def show
render json: @author
end
private
def find_author
@author = Author.find(params[:id])
end
end
进入全屏模式 退出全屏模式
让我们在路由前加上api
Rails.application.routes.draw do
scope :api do
resources :articles
resources :authors
end
end
进入全屏模式 退出全屏模式
我们现在都准备好达到一些终点了。
进入码头
要构建一个 docker 镜像,我们必须写一个Dockerfile。什么是Dockerfile?Dockerfile是捆绑所有依赖项的位置,并在构建映像之前编写要执行的其他命令或步骤。有用于 Ruby 的内置图像。我们将从 Ruby 2.7 的图像开始。让我们先写Dockerfile,然后我们将解释那里发生了什么。
FROM ruby:2.7
RUN apt-get update -qq && apt-get install -y postgresql-client
# throw errors if Gemfile has been modified since Gemfile.lock
RUN bundle config --global frozen 1
WORKDIR /app
COPY Gemfile Gemfile.lock ./
RUN bundle install
COPY . .
ENTRYPOINT ["./entrypoint.sh"]
EXPOSE 3000
# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]
进入全屏模式 退出全屏模式
所以我们从 Ruby 2.7 预构建的镜像开始,然后将 PostgreSQL 客户端安装到系统中,这是一个基于 Debian 的系统,所以我们使用apt-get。接下来,我们冻结捆绑配置,这实际上有助于我们在 dockerized 系统和主机上保持一致性系统。如果修改了Gemfile但我们没有运行bundle install,这就是它会抛出错误的地方
现在我们将 docker 系统中的工作目录设置为/app。我们将Gemfile和Gemfile.lock复制到 docker 的app目录并在 docker 中运行bundle install。在bundle install完成后,我们将所有文件从主机系统复制到 docker 系统。
之后,我们执行一个 shell 脚本,我们很快就会回来,然后我们公开端口 3000 并启动将它绑定到 0.0.0.0 的 rails 服务器。
entrypoint.sh文件
#!/bin/bash
set -e
if [ -f tmp/pids/server.pid ]; then
rm tmp/pids/server.pid
fi
exec "$@"
进入全屏模式 退出全屏模式
这有助于修复特定于 Rails 的问题,该问题会在某个 server.pid 文件预先存在时阻止服务器重新启动,这需要在每次 docker 启动时运行。
我们完成了 docker 文件。现在让我们构建它。
docker build -t rails-docker .
进入全屏模式 退出全屏模式
这将构建图像并拉取所有依赖项并将其保存为标签rails-docker:latest
现在,我们可以运行这个镜像,但这不一定对我们有帮助,因为我们还需要运行 PostgreSQL。我们可以使用本地安装的数据库,但在这里我们将在 docker 中运行数据库。
环境设置
让我们在目录的根目录下添加.env文件
DBHOST=localhost
DBUSER=postgres
DBPASS=password
进入全屏模式 退出全屏模式
这本质上是我们将用 docker 覆盖的数据库环境变量。
现在,让我们更新 config 中的database.yml文件,以便 Rails 应用程序可以从环境变量中读取以连接到 PostgreSQL。
# config/database.yml
default: &default
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
development:
<<: *default
database: docker_rails_development
username: <%= ENV['DBUSER'] %>
password: <%= ENV['DBPASS'] %>
host: <%= ENV['DBHOST'] %>
进入全屏模式 退出全屏模式
Docker 组合
Docker compose 是一种方便的方式,可以将所有 docker 镜像编写为相互依赖的服务,并在一个内部网络中运行,它们可以在其中相互通信。我们将在 docker-compose 中将 PostgreSQL 作为服务运行,以及我们刚刚构建的 Rails API 映像
version: '3.8'
services:
web:
build: .
image: rails-docker
restart: "no"
environment:
- DBHOST=postgresql
- DBUSER=postgres
- DBPASS=password
ports:
- 3000:3000
depends_on:
- postgresql
postgresql:
image: postgres
restart: "no"
ports:
- 5432:5432
environment:
POSTGRES_DB: docker_rails_development
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
volumes:
- postgresdb:/var/lib/postgresql/data/
volumes:
postgresdb:
进入全屏模式 退出全屏模式
所以这里有两个服务。在postgresql服务中,我们使用的是官方的postgresql镜像,并为环境变量传递一些值,并将内部5432端口暴露给主机。我们用它添加一个 docker 卷,以便它在那里存储数据,并且数据可以在重启后继续存在。
web服务,运行我们刚刚为 API 构建的镜像,并且依赖于postgresql服务。这意味着postgresql服务需要首先启动并运行,web服务才能开始运行。这很酷。由于我们在postgresql服务中指定了POSTGRES_DB环境,如果第一次运行 PostGreSQL 服务器时数据库不存在,就会创建数据库。太好了,现在让我们运行服务。
docker-compose -f docker-compose.yml up --build
进入全屏模式 退出全屏模式
如果它们尚未构建,这将首先构建图像,然后运行它们。我们会看到两个图像都在控制台中运行。现在让我们进行迁移和播种。
使用ctrl+c停止服务并运行
docker-compose run web rails db:migrate
docker-compose run web rails db:seed
进入全屏模式 退出全屏模式
这将从web服务容器内部运行 rails 命令。我们现在已经填充了数据。
现在让我们再次运行服务
docker-compose up
进入全屏模式 退出全屏模式
让我们打一些端点来检查
curl localhost:3000/api/authors
[
{
"id":1,
"name":"Lakendra Bergnaum",
"created_at":"2020-11-24T13:25:29.507Z",
"updated_at":"2020-11-24T13:25:29.507Z"
},
...
]
进入全屏模式 退出全屏模式
当然,它会从 API 中获取作者并在控制台中打印。如果点击articles端点,它也会打印文章。
结论
如果您是第一次使用 docker,那么需要掌握很多知识。但是我们介绍了如何在 Docker 中部署仅 Rails API 的应用程序以及 PostgreSQL。这是构建很棒的东西的一个很好的起点。
资源
-
https://dev.to/forksofpower/build-a-json-api-spec-compliant-api-with-rails-6-and-fastjsonapi-b19
-
https://docs.docker.com/compose/rails/
更多推荐
所有评论(0)