有幸拿到docker beta的测试资格, 在Mac OSX下使用docker更加方便好玩了。这篇博文介绍如何在生产环境也就是线上利用docker实现快速部署以及横向扩展,为大规模负载均衡做准备。这里使用一个docker容器来跑rails应用,另一个容器来跑异步队列sidekiq等服务, 数据库和redis使用RDS和云redis,直接使用docker镜像的数据库也可以。
个人原创,版权所有,转载请注明原文出处,并保留原文链接:
https://www.embbnux.com/2016/05/22/rails_use_puma_sidekiq_deploy_with_docker_on_production/
一、生产环境使用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 [email protected] 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开发环境可以看之前的博客。