导读 Docker现在越来越流行,但是真正在生产环境部署Docker还是个比较新的概念,还没有一个标准的流程。作者是ROR的程序员,作者结合平时的部署经验,联系Docker的特点,向大家分享了其在生产环境使用Docker部署应用程序的一个实践。

Docker是现在开发应用程序的不错选择;因为对于一个研发组来说,部署一个应用再也不用像以前那样繁琐的修改、设置配置文件了;因为对于Docker来说它“屏蔽”了应用程序的运行环境,不管你使用Mac、Linux还是Windows都能用相同的方式运行。

但是,当你使用Docker将应用部署到生产环境时,你会觉得Docker还是有些“弱”,至少从Ruby On Rails(ROR)的角度出发是这样的。当我查找与测试了很多不同的部署方法与Docker镜像后发现:确实没有一个确切而且标准的部署方案。在这篇文章中我会分享一种生产环境部署ROR应用的最佳实践。

标准

在实际操作之前,我们列举生产环境部署应用的标准:

  1. 易于使用:部署应用本身应该十分简单,不然部署新程序的过程会变得十分“恐怖”。
  2. 零服务中断:让我们面对它——零服务中断部署ROR应用程序已经成为当今的标准。
  3. 自动化部署:我更习惯把代码推送到代码仓库,然后使用Codeship这样的工具自动测试,测试通过后自动将代码部署到生产环境的服务器。我希望Docker能完成相同的工作。

    ## 操作就像之前我说过的,我希望部署过程越简单越好。如果你看过Docker:Part4这个视频,可能对以下命令有所熟悉,它启动了一个叫db的容器(跑postgres数据库),之后又启动了一个叫web的容器,最后将容器“web”跟容器“db”连接起来。

$ docker run -d --name db training/postgres
$ docker run -i -t --name web --link db:db -p 45000:80

当然如果你照着这么做来部署程序,当你敲了很多次这样的命令后,而且保证不遗漏的敲了很多次这种命令后,你会发现这是个“坑爹的”噩梦。这就是为什么会有Fig的原因。

FIG

如果你用Dockerfile来定义如何生成你的容器,那么Fig则可以帮你定义整个容器的运行框架。Fig将“添加数据卷(add volumes)”、“连接容器”(link container)与“映射端口”等操作都封装到一个YAML的描述文件中;如同前面提到的CodeTV中描述的那个操作在Fig中简化成如下形式:

web:
build: .
ports:
- "80:80"
links:
- db db:
image: postgres
ports:
- "5432" volumes:
- /etc/postgresql
- /var/log/postgresql
- /var/lib/postgresql

我在YAML中定义了两个容器:web与db;容器web生成自当前文件夹下的Dockerfile,向外暴露了80号端口,同时链接到了容器db。容器db生成自DockerHub的PostgreSQL镜像,向外暴露5432号端口。使用此YAML配置文件,fig可以用以下命令生成容器,然后依照配置文件的意图启动它们。

$ fig build
$ fig up -d

Fig会先启动被链接的容器db,这样容器web就不至于连不上数据库。-d参数表示以后台运行的方式启动容器,这样可以保证用户登出操作系统后,容器任然在运行。您可以登录Fig的官方网站获取更多的配置信息。

部署

现在我们可以很容易的启动一个Docker容器,但是怎么在生产环境下部署Docker容器呢?如果在生产环境下安装了Fig与Docker,我们所有要做的就是克隆之前的容器镜像,然后用相同的fig命令来启动容器。但是,现在的问题是如何更新线上运行的容器。

不幸的是,Fig可以非常优雅的启动一个容器,但是它并不擅长更新并重启服务。当然,你可以在代码仓库拉取程序的更新,然后重新运行以上的fig命令来达到这个目的;但是,在容器在更新代码,重新启动的过程中,就不能对外提供服务了。为了应对这种情况,我们使用原生的Docker命令,并引入Nginx做反向代理(注:软负载)来解决这个问题。

我们首先把容器监听的端口修改掉,因为Nginx需要监听80号端口。我们这么修改:

web:
build: .
ports:
- "8080:80"
links:
- db
...

通过修改Fig的配置文件,我们的web容器修改成监听8080号端口。而Nginx要配置成8080与8081端口的负载均衡;所以Nginx的配置如下:

upstream docker {
server 127.0.0.1:8080;
server 127.0.0.1:8081;
} server {
listen 80;
location / {
proxy_pass http://docker;
}
}

重启Nginx后,Nginx就开始在8080与8081号端口之间做反向代理(软负载);当其中任何一个端口失效后,Nginx将请求自动转发到另一个,直到失效后的端口恢复。这样,我们就能从Git中拉取更新,然后运行下面的命令将其启动:

$ docker run -d --name web1 --link codetvjournal_db_1:db -p 8081:80 codetvjournal_web:latest

当我们确定8081号端口的web1容器启动并服务正常后,我们就可以停止8080号端口的服务并开始为8080号端口服务进行更新了。我推荐使用原生的docker命令而不使用Fig来完成这个工作,因为这样可以避免干扰到正在运行的db容器(注:作者可能指的是之前写好的YAML,里面包含了启动db容器的配置)

我们可以用上述方法创建很多个web容器,只要保证它们占用的端口与容器名不同即可;同时使用Nginx在它们前端做负载即可实现不掉线的程序升级。

自动化

那么问题又来了,怎么将上述的更新流程自动化运行呢?有两个方式可以达到:

  1. 将容器更新、启停、切换等操作封装到一个单一的脚本中,这个脚本可以加入到传统的上线流程(注:新代码拉取,自动测试,自动部署的流程,作者称之为deployment pipeline)之后执行;
  2. 另一种方式是,使用类似Consul或者etcd等的发现服务来管理容器的更新,启停,与发现;这会更加“高大上”。

所以,使用Docker在生产环境中部署服务不像你想象中那么容易。我推荐大家试试上面所说的方法;同时分享你自己的实践经验给大家,这会帮助大家一同使用Docker。Docker还是个很年轻的产品,同时又是个非常热门的产品,它肯定会在未来不断的演化升级。

在生产环境使用Docker部署应用的更多相关文章

  1. .NET持续集成与自动化部署之路第三篇——测试环境到生产环境的一键部署策略(Windows)

    Jenkins测试环境到生产环境的一键部署策略(Windows) 一.前言     前面我们已经初步实现了开发集成环境.测试环境的持续集成(自动化构建.自动化测试.自动化部署).但生产环境自动化部署迟 ...

  2. 云计算之路-阿里云上-2017年最错误的选择: 生产环境使用 docker swarm

    2017年12月29日 10:18 ~ 11:00 左右,由于整个 docker swarm 集群宕机,造成我们迁移至 .net core 跑在 docker swram 上的所有站点无法正常访问,由 ...

  3. ionic框架前端生产环境的简单部署

    1. 效果对比 1.1 开发环境 css+js+lib文件大小为好多M :) 1.2 部署环境(生产环境) css+js+lib文件大小约为800K 文件大小:好多M–>800K(多少自己试下) ...

  4. 生产环境中CentOS7部署NET Core应用程序

    NET Core应用程序部署至生产环境中(CentOS7) 阅读目录 环境说明 准备你的ASP.NET Core应用程序 安装CentOS7 安装.NET Core SDK for CentOS7. ...

  5. redis的生产环境中的部署?

    使用的是redis cluster 10台机器,5台机器部署了redis主实例,另外5台机器部署了redis 的从实例,每个主实例挂了一个从实例,5个节点对外提供读写服务,每个节点的读写高峰qps可能 ...

  6. Linux系统 Centos7 环境基于Docker部署Rocketmq服务

    消息队列 基本概述 MQ,Message Queue,基于TCP协议构建的简单协议,区别于具体的通信协议. 基于通信协议定义和抽象的更高层次的通信模型,一般都是生产者和消费者模型,又或者说服务端和客户 ...

  7. Linux Centos7 环境基于Docker部署Zookeeper服务搭建实战

    配置Zookeeper安装目录 在宿主机配置zookeeper安装目录:/docker/develop/zookeeper 并且在文件夹创建 data 和logs 目录: mkdir -p /dock ...

  8. Linux Centos7 环境搭建Docker部署Zookeeper分布式集群服务实战

    Zookeeper完全分布式集群服务 准备好3台服务器: [x]A-> centos-helios:192.168.19.1 [x]B-> centos-hestia:192.168.19 ...

  9. 一次生产环境的docker MySQL故障

    问题 昨天下午本来要去吃下午茶,然后前端小伙伴突然说接口怎么崩了,我登上sentry一看,报错了 (2005, "Unknown MySQL server host 'mysql' (-3) ...

随机推荐

  1. sql server T-SQL 基础

    SQL语言按照用途可以分为如下3类: ①DDL(Data Definition Language)  数据定义语言: 定义修改和删除数据库.表.索引和视图等 ②DML(Data Manipulatio ...

  2. 4、面向对象以及winform的简单运用(继承与多态、命名空间与类库)

    继承 继承既子类与父类之间的关系.子类是父类的一种特例,子类拥有父类所没有的功能. 子类与父类之间的相互赋值——例: Parent p; Son c = new Son(); p = c; //正确, ...

  3. 阿里百川IMSDK--自定义群聊界面

    // 获取群对象 YWTribe *tribe = [self.tribesArray objectAtIndex:indexPath.row]; // 发起群聊 UIViewController * ...

  4. Java 缓存技术

    以下仅是对map对方式讨论.没有对点阵图阵讨论.作缓存要做以下2点:  1:清理及更新缓存时机的处理: . 虚拟机内存不足,清理缓存 .. 缓存时间超时,或访问次数超出, 启动线程更新 2:类和方法的 ...

  5. Java集合类: Set、List、Map、Queue使用

    目录 1. Java集合类基本概念 2. Java集合类架构层次关系 3. Java集合类的应用场景代码 1. Java集合类基本概念 在编程中,常常需要集中存放多个数据.从传统意义上讲,数组是我们的 ...

  6. Spring监听器配置

    使用spring框架时如果同时使用org.springframework.web.util.Log4jConfigListener监听器,那么在web.xml中的监听器的注册顺序为org.spring ...

  7. POJ1651Multiplication Puzzle(矩阵链乘变形)

    Multiplication Puzzle Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8040   Accepted: ...

  8. jmap命令详解

    1.命令基本概述 Jmap是一个可以输出所有内存中对象的工具,甚至可以将VM 中的heap,以二进制输出成文本.打印出某个java进程(使用pid)内存内的,所有‘对象’的情况(如:产生那些对象,及其 ...

  9. linux磁盘空间清理

    由于当初安装系统设计不合理,有些分区的过小,以及网络通讯故障等造成日志文件速度增长等其他原因都可以表现为磁盘空间满,造成无法读写磁盘,应用程序无法执行等.下面就给你支几招(以/home空间满为例): ...

  10. yii增删改查

     一.查询数据集合     1.$admin=Admin::model()->findAll($condition,$params);//该方法是根据一个条件查询一个集合,如: findAll( ...