docker-compose简单介绍

使用docker-compose可以很方便地把多个containers组织在一起,形成一个完整的功能单元。和kubernetes不同的是,docker-compose比较lightweight,更适合不考虑群集,只拆分功能单元的单机部署场景。本篇文章介绍docker-compose的基本使用方法。

首先可以从这里clone一个做好的例子:

这个sample project里面的内容如下:

$ cd composetest/
$ ls
Dockerfile         app.py             requirements.txt
README.md          docker-compose.yml

关于这个项目的具体细节,不是本文的重点,具体可以自己看这篇文档:

这个例子里面包含两个containers,一个是从项目里面的Dockerfile本地build出来的,另一个是直接从dockerhub上下载。这样等于展示全面docker-compose对容器的管理方式。两个容器定义在docker-compose.yml里面:

如上所示,我们定义了两个容器,分别是webredis。其中:

在实际使用docker-compose的时候,我们一般不会把一个需要build的容器和docker-compose.yml放在一起,而是各自build好,推送到dockerhub上,然后像例子里redis这个容器对应的image一样调用。这个例子里面只是为了展示docker-compose.yml对多种形式的containers的描述和支持能力。

那么使用docker-compose.yml来管理多个容器有什么好处呢?在这个例子里,我们可以看到以下几点好处:

总的来讲,docker-compose将多个containers组织成一个整体进行统一的管理。学习了基本概念,我们把clone下来的composetest项目跑起来,在项目里执行命令如下:

$ docker-compose up

上面的命令执行过程如下:

可以看到docker-compose首先build了web这个容器(build过程中首先pull了所需的image),然后把redis这个容器对应的image也pull下来,最后启动了两个containers。最后运行的状态如下:

此时我们可以使用docker命令查看容器的运行情况:

$ docker ps

命令执行结果如下:

可以看到启动的两个容器分别是composetest_redis_1composetest_web_1。此时我们登录到其中一个容器里面:

$ docker exec -it composetest_redis_1 sh

进入到容器里以后,使用docker-compose.yml里面配置的主机名字试试看:

从上面的执行过程可以看到,containers之间是可以通过hostname互相访问到的。这样我们在做项目的时候,在代码里就可以直接使用container的name,而不是需要实现知道container的ip地址。比如这个例子里面,web这个容器里的代码使用了redis这个container的name:

从上面的代码里可以看到,我们在app.py里面访问redis这个container的6379端口。我们可以回过头看一下docker-compose.yml的端口映射配置:

可以看到配置文件里面的5000端口是映射到host伤的,而webredis之间交换数据用的redis的6379端口并没有被映射出来,因为容器之间的端口在docker-compose的管理下,是互相开放的。这样整体只需要配置对外服务的端口就可以了。下面是在host上访问服务:

$ http http://localhost:5000
HTTP/1.0 200 OK
Content-Length: 39
Content-Type: text/html; charset=utf-8
Date: Mon, 08 Apr 2019 00:24:55 GMT
Server: Werkzeug/0.15.2 Python/3.4.10

Hello World! I have been seen 1 times.

可以看到,通过docker-compose,我们把两个容器按功能划分(一个是web服务,另一个是redis数据服务),它们两个内部协同工作,对外提供统一的服务端口,使用起来非常方便。

docker-compose管理的容器是无状态的

最后讲讲docker-compose的容器启停。在使用docker-compose管理容器的时候,有一点要注意:

我们可以做实验来验证这点。首先查看两个容器的id:

记录下上面两个容器的id,此时关掉容器:

$ docker-compose down

确认容器已经down掉:

此时使用docker-compose重新启动容器:

可以看到容器关停后重新启动的时候,不再需要重新pull image或者build本地container。这是因为本地的Dockerfile以及远程用到的image都没有发生变化。如果docker-compose检查到Dockerfile或者远程image的更新,是会重新触发build和pull image的动作的。此时查看新启动的容器:

可以看到此时两个容器的id和之前关掉之前的都不一样了。因此验证了 docker-compose每次启停容器都会销毁重建containers。所以,务必要把需要长久保持的数据保存在容器外的地方,比如映射到host的数据目录里去。具体配置参考docker-compose文档的volumes章节:

除了这篇文章里讲的内容,docker-compose还提供了很多丰富的配置能力,最后要说的一点是,docker-compose主要的适用场景还是一台机器的本地私有化部署。在云环境的分布式部署环境中,要使用kubernete这类分布式的管理工具,或者干脆使用混合云的方案,把负载平衡,运维管理等工作外包给混合云的提供商去解决。