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
里面:
如上所示,我们定义了两个容器,分别是web
和redis
。其中:
web
这个容器是从本地的Dockerfile
在本地build而来。redis
这个容器是从dockerhub
里面pull的redis:alpine
。
在实际使用docker-compose
的时候,我们一般不会把一个需要build的容器和docker-compose.yml
放在一起,而是各自build好,推送到dockerhub
上,然后像例子里redis
这个容器对应的image一样调用。这个例子里面只是为了展示docker-compose.yml
对多种形式的containers的描述和支持能力。
那么使用docker-compose.yml
来管理多个容器有什么好处呢?在这个例子里,我们可以看到以下几点好处:
- 两个容器之间的网络是相互透明的,不再需要为了容器之间的通信打开端口映射。
- 两个容器之间可以使用host名来通信。
- 容器之间的拓扑关系统一在
docker-compose.yml
当中配置与管理。 docker-compose
负责管理容器的启动的先后顺序(参考文档:Control startup and shutdown order in Compose)。
总的来讲,docker-compose
将多个containers组织成一个整体进行统一的管理。学习了基本概念,我们把clone下来的composetest
项目跑起来,在项目里执行命令如下:
$ docker-compose up
上面的命令执行过程如下:
可以看到docker-compose
首先build了web
这个容器(build过程中首先pull了所需的image),然后把redis
这个容器对应的image也pull下来,最后启动了两个containers。最后运行的状态如下:
此时我们可以使用docker
命令查看容器的运行情况:
$ docker ps
命令执行结果如下:
可以看到启动的两个容器分别是composetest_redis_1
和composetest_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伤的,而web
与redis
之间交换数据用的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
管理容器的时候,有一点要注意:
docker-compose
每次启停会使用images建立新的containers(containers是无状态的)。
我们可以做实验来验证这点。首先查看两个容器的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
这类分布式的管理工具,或者干脆使用混合云的方案,把负载平衡,运维管理等工作外包给混合云的提供商去解决。