部署 Docker 部署多站点、镜像与代码分离实践

pinewong · 2016年06月17日 · 最后由 pinewong 回复于 2016年07月30日 · 6481 次阅读

前言

Docker 为部署提供了便捷,能让新手快速部署复杂的服务器环境,并把环境保存下来。网上有许多 Docker 实践,本文实践的是如何利用 Docker 容器封装一个与代码配置分离的服务器环境,每次修改配置只需重启容器,无需重新建立镜像,并简单实现了多个站点部署。选择部署的环境是 Rails,基础镜像选用集成服务器环境的 phusion/passenger-ruby22,数据库选用 postgres

实践过程

环境介绍

为了突出重点,部署没有涉及 mina 以及 puma 相关配置

apps                    # 服务器工作空间目录
|__ deploy                 # 部署配置文件目录
|__ |__ Dockerfile
|__ |__ docker.sh         # 容器每次启动运行都会执行该脚本
|__ |__ docker-link.sh     # 通过该文件使得容器启动执行脚本与镜像隔离,后面有文件内容
|__ |__ nginx.conf
|__ |__ nginx-env.conf
|__ |__ database.yml
|__ |__ secrets.yml
|__ |__ ...ddjh
|__ site_a                   # 网站源码目录
|__ site_b
|__ ...

上述目录结构需要事先在服务器中搭建好,我的操作步骤是建立在/home 目录下建立好 apps 目录后,在我们的工作目录 apps 里 git clone 相关网站;deploy 部署目录含相关服务器和密钥配置,下方写好后通过 scp 命令上传

文件

Dockerfile

# 以phusion/passenger-ruby22镜像为基础
FROM phusion/passenger-ruby22

# 设置项目目录
VOLUME ['/home/apps']
WORKDIR /home/apps

# 设置容器运行执行命令
CMD ["/sbin/my_init"]

# 开放80端口
EXPOSE 80

# 设置时区
RUN echo "Asia/Shanghai" > /etc/timezone
RUN dpkg-reconfigure -f noninteractive tzdata

# 设置当前环境变量
ENV HOME /root

# 设置rails环境为生产环境
ENV RAILS_ENV production

# 启动nginx
RUN rm -f /etc/service/nginx/down

# 增加初始化运行脚本
RUN mkdir -p /etc/my_init.d
COPY docker-link.sh /etc/my_init.d/docker-link.sh
RUN chmod +x /etc/my_init.d/docker-link.sh

# 修改国内源
RUN gem sources -r https://rubygems.org/ -a https://gems.ruby-china.org/
RUN bundle config mirror.https://rubygems.org https://gems.ruby-china.org
# RUN gem sources -r https://rubygems.org/ -a http://mirrors.aliyun.com/rubygems/
# RUN bundle config mirror.https://rubygems.org http://mirrors.aliyun.com/rubygems

# 清楚产生的缓存文件
RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

docker-link.sh (使得执行脚本可以在镜像建立后自定义)

#!/bin/bash

bash /home/apps/deploy/docker.sh

docker.sh

#!/bin/bash

echo '/*** 变量配置---------------:';
workdir='/home/apps';           # 工作空间目录,需要与Dockerfile文件的项目目录对应
# workdir='/var/www/apps';      # 其他类似工作空间目录
deployname='deploy';            # 部署目录名
sitearr=('site_a' 'site_b');            # 配置所有项目名


echo '/*** 配置nginx---------------:';
rm /etc/nginx/sites-enabled/default;
cp ${workdir}/${deployname}/nginx.conf /etc/nginx/sites-enabled/nginx.conf;

echo '/*** 添加环境文件---------------:';
cp ${workdir}/${deployname}/nginx-env.conf /etc/nginx/main.d/nginx-env.conf;

echo '/*** 遍历每个项目执行操作---------------:';
for site in ${sitearr[@]};
do
    echo "/*** ${site}配置---------------:";
    cd ${workdir}/${site};
    bundle install;
    rake assets:precompile;
    rake db:create;
    rake db:migrate;
    rake db:seed;
done

nginx.conf (site_a, site_b 根据自己需求修改)

# site_a
server {
    listen 80;
    root /home/apps/site_a/public;
    server_name site_a.urlis.cn;

    # 开启passenger
    passenger_enabled on;
    passenger_user root;
    client_max_body_size 20M;
    passenger_max_request_queue_size 0;
}

# site_b
server {
    listen 80;
    root /home/apps/site_b/public;
    server_name site_b.urlis.cn;

    # 开启passenger
    passenger_enabled on;
    passenger_user root;
    client_max_body_size 20M;
    passenger_max_request_queue_size 0;
}

nginx-env.conf

# 暴露服务端口 这个示例中只有postgres服务,因此我们只需要暴露这个端口即可
env POSTGRES_PORT_5432_TCP_ADDR;
env POSTGRES_PORT_5432_TCP_PORT;

database.yml (主要为 production 的 host 和 port 项目,需要与 nginx-env.conf 文件对应)

production:
  <<: *default
  database: site_production
  host:     <%= ENV['POSTGRES_PORT_5432_TCP_ADDR'] || 'localhost' %>
  port:     <%= ENV['POSTGRES_PORT_5432_TCP_PORT'] || '5432' %>

步骤

1. 在服务器上部署好目录结构后,添加需要部署的网站源码 (这步在目录介绍中就可以完成)

local$ ssh user@server;
server$ mkdir -p /home/apps;
server$ cd /home/apps;
server$ git clone https://github.com/pinewong/site_a;
server$ git clone https://github.com/pinewong/site_b;
...

2. scp 上传 deploy 部署配置目录 (本地机操作)

local$ scp -r deploy user@server:/home/apps

3. 建立部署镜像并启动

server$ cd /home/apps/deploy
server$ docker pull postgres; docker pull phusion/passenger-ruby22;
server$ docker rm -f postgres; docker run --name postgres -p 5432:5432 -d postgres;
server$ docker rmi -f pinewong/passenger-ruby22; docker build -t pinewong/passenger-ruby22 .;
server$ docker rm -f web; docker run --name web --link postgres -v /home/apps:/home/apps -p 80:80 -d pinewong/passenger-ruby22;
server$ docker logs -f web;

最后等待终端的 log 日志输出,查看之前编写的 docker.sh 脚本执行情况。如果顺利,最后 nginx 服务器会启动成功。 以后有新项目上线测试时,只需要在服务器工作目录 clone 源码,然后添加 deploy/nginx.conf 配置,deploy/docker.sh 的 sitearr 数组变量值添加新项目名称,最后重启容器 (docker restart web)。 另外以后当修改配置文件,或新增 gem 时,也只需要执行容器容器命令

文章参考:gameFu's Blog

pinewong [该话题已被删除] 提及了此话题。 07月08日 10:46

这个好像不支持 Rails5 吧?我试了一下没成功诶

#2 楼 @jimmy0017 如果全部按文章操作,Docker 封装的环境是 Ruby2.2, Rails 版本是 4.2, 是不支持 Rails5.0 项目。 如果要部署的都是 Rails5.0 项目,可以更换 Docker 基础 Image. 如果想多个版本 Rails 项目并存,这个实践就不适合了。

pinewong 关闭了讨论。 09月21日 13:38
pinewong 重新开启了讨论。 09月21日 13:38
需要 登录 后方可回复, 如果你还没有账号请 注册新账号