有幸拿到docker beta的测试资格, 在Mac OSX下使用docker更加方便好玩了。这篇博文介绍如何在生产环境也就是线上利用docker实现快速部署以及横向扩展,为大规模负载均衡做准备。这里使用一个docker容器来跑rails应用,另一个容器来跑异步队列sidekiq等服务, 数据库和redis使用RDS和云redis,直接使用docker镜像的数据库也可以。
一、生产环境使用docker前准备
首先你的web应用要足够干净,rails也好,nodejs也一样,不依赖于本地的任何东西,应该是一个docker镜像pull下来,加上一些环境变量等配置就能直接跑起来。
- 数据库url可配置,可以连接远程数据库,或者连接其他数据库容器
- redis也应该是远程连接可配置, redis独立出去,异步队列像sidekiq的也可以在单独容器里跑了,因为一个docker容器只支持一直进程跑,所以server和队列是分开的,通过redis通讯。
- 只处理动态流量,静态资源请走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.欢迎转载,转载请注明原文出处,并保留原文链接