部署 生产环境使用 Docker 部署 Rails 应用 Puma 和 Sidekiq

embbnux · 发布于 2016年5月23日 · 最后由 uestc_bird 回复于 2017年2月06日 · 2389 次阅读
15999

有幸拿到docker beta的测试资格, 在Mac OSX下使用docker更加方便好玩了。这篇博文介绍如何在生产环境也就是线上利用docker实现快速部署以及横向扩展,为大规模负载均衡做准备。这里使用一个docker容器来跑rails应用,另一个容器来跑异步队列sidekiq等服务, 数据库和redis使用RDS和云redis,直接使用docker镜像的数据库也可以。

本文原文出处: 生产环境使用docker部署rails应用puma和sidekiq

一、生产环境使用docker前准备

首先你的web应用要足够干净,rails也好,nodejs也一样,不依赖于本地的任何东西,应该是一个docker镜像pull下来,加上一些环境变量等配置就能直接跑起来。

  1. 数据库url可配置,可以连接远程数据库,或者连接其他数据库容器
  2. redis也应该是远程连接可配置, redis独立出去,异步队列像sidekiq的也可以在单独容器里跑了,因为一个docker容器只支持一直进程跑,所以server和队列是分开的,通过redis通讯。
  3. 只处理动态流量,静态资源请走CDN, 图片的上传也不是储存在本地磁盘的, 图片的上传可以上传到容器再由容器传到云存储服务器,或者直接由客户端上传到云存储服务器,数据库里只存图片的地址就可以。

二、配置生产环境Dockerfile

首先讲一些我的工程目录结构,主要就是rails的结构,这里只列出关键的文件目录结构:

|__ app
|__ config
|__ |__ puma_docker.rb
|__ |__ database.yml
|__ |__ redis.yml
|__ |__ sidekiq.yml
|__ public
|
|__ Dockerfile
|__ Gemfile
|__ Gemfile.lock

Dockerfile原则应该是只添加有需要的:

##########################################
# Dockerfile for rails app with puma and sidekiq postgres
# Author: Embbnux Ji
# HomePage: www.embbnux.com
##########################################

FROM ruby:2.3.1

MAINTAINER Embbnux embbnux@embbnux.com
RUN apt-get update && apt-get install -y build-essential libssl-dev libpq-dev libxml2-dev libxslt1-dev nodejs git imagemagick libbz2-dev libjpeg-dev libevent-dev libmagickcore-dev libffi-dev libglib2.0-dev zlib1g-dev libyaml-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*

ENV APP_HOME /app

RUN mkdir -p $APP_HOME
WORKDIR $APP_HOME

COPY Gemfile $APP_HOME/
COPY Gemfile.lock $APP_HOME/

RUN bundle install

COPY . $APP_HOME

RUN bundle exec rake assets:precompile RAILS_ENV=production

EXPOSE 8080
CMD ["bundle", "exec", "puma", "-C", "config/puma_docker.rb"]

三、配置rails工程

我的rails是使用puma来作为web服务器的,docker自然也一样,所以app容器默认是执行puma启动server的命令,对外输出接口为8080, 使用nginx代理流量到这个服务端口即可。 puma这里需要配置为暴露8080端口:

# puma_docker.rb:

threads 4, 16
workers 1
environment 'production'
bind 'tcp://0.0.0.0:8080'
preload_app!

on_worker_boot do
  ActiveSupport.on_load(:active_record) do
    ActiveRecord::Base.establish_connection
  end
end

数据库配置:

# database.yml:

default: &default
  adapter: postgresql
  encoding: unicode
  pool: 5
  timeout: 5000

production:
  <<: *default
  pool: 10
  database: <%= ENV["DATABASE"] %>
  host: <%= ENV['DATABASE_HOST'] %>
  username: <%= ENV["DATAUSER"] %>
  password: <%= ENV["DATAPASSWD"] %>

redis的配置也一样,redis的地址用环境变量代替: ENV["REDIS_URL"]

四、使用远程仓库自动构建

我这边采取的远程仓库方案是Github加Docker Hub,实现代码更新自动构建镜像,方法很简单,就是使用docker hub的自动构建功能,关联github仓库即可。需要在工程根目录下有一个Dockerfile. 这样git push代码后过几分钟镜像就会被自动构建完成。 也可以使用docker hub的webhook功能实现构建完成自动部署,这个我暂时没测试。

五、部署docker镜像到生产环境

docker镜像的部署很简单,直接pull下来跑就可以了。这里为了演示, 数据库和redis也用一个单独的docker容器来跑,模拟远程连接,云储存用docker的volume功能实现,具体如下:

# 下载redis镜像
docker pull redis
# 下载postgres镜像
docker pull postgres
# 下载已经自动构建完成的app镜像
docker pull embbnux/app
# 后台运行redis容器
docker run --name app_redis -d redis
# 后台运行postgres容器, 指定用户名密码
docker run --name app_postgres -e POSTGRES_PASSWORD=password -e POSTGRES_USER=user -e POSTGRES_DB=app_db -d postgres
# 后台运行app容器, 环境变量使用.env.docker文件传入, 映射容器的8080端口到本地的8080端口
docker run --env-file ./.env.docker --link app_redis:redis --link app_postgres:postgres -v /var/www/public/uploads:/app/public/public -v /var/log/app:/app/log --name app_web -p 127.0.0.1:8080:8080 -d embbnux/app
# 上传assets文件到cdn
# docker run --env-file ./.env.docker --link app_redis:redis --link app_postgres:postgres --name app_assets --rm embbnux/app rake cdn:upload_assets
# 运行sidekiq容器
docker run --env-file ./.env.docker --link app_redis:redis --link app_postgres:postgres -v /var/www/public/uploads:/app/public/public -v /var/log/app:/app/log --name app_sidekiq -d embbnux/app bundle exec sidekiq -C config/sidekiq.yml

环境变量文件如下:

# .env.docker
RAILS_ENV=production
SECRET_KEY_BASE=1237293729347238719422b4e25fe42a311bc4e5ffb242397934cbad3adabfbcfae4b431a5029ad6486bce777382470327493287402
DATABASE_HOST=app_postgres
DATABASE=app_db
DATAUSER=user
DATAPASSWD=password
REDIS_URL=redis://app_redis:6379

以后升级代码,只需要把app pull下来跑就可以了, 多机器部署建议用capistrano等工具。 在开发环境使用docker快速构建rails开发环境可以看之前的博客。

本文原文出处,Embbnux博客,生产环境使用docker部署rails应用puma和sidekiq.欢迎转载,转载请注明原文出处,并保留原文链接

共收到 14 条回复
26677

正好用到了。。。学习了

13229

赞,按LZ教程操作了一遍确实不错。如果是国内下载docker镜像慢的话可以跑下面的命令设置:

pinata get daemon | jq -cm '."registry-mirrors" = ["https://XXXXX.mirror.aliyuncs.com"]' | pinata set daemon -

镜像加速可以用阿里云的 (https://dev.aliyun.com/search.html),也可以用网易。

27

uploads 和 logs 目录挂载,我觉得可以写进 Dockerfile 里

11562

学习了. 支持. 我之前研究了自发现服务. 然后感觉用起来就省很多事情了.

23412

有配合jenkins使用的教程吗?

26123

谢谢楼主分享,学到了新知识

24405
# 后台运行redis容器
docker run --name app_redis -d redis
# 后台运行p