Compose项目简介
在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。Docker
开源项目Compose
专门负责实现对Docker
容器集群的快速编排,官方是这样定义的:Compose
是一个用于定义和运行多个Docker
容器的工具。使用Compose
,你可以使用YAML
文件来配置应用程序的服务。
Compose中两个重要概念:
- 服务:一个应用的容器,实际上可以包括若个运行相同镜像的容器实例;
- 项目:一组关联的应用容器组成的一个完整业务单元
Compose工具需要单独安装,具体安装办法就不说了,可以自行google。
Docker Compose示例
下面的示例将会在Docker Compose上构建一个简单的Python web应用程序,该程序使用Flask
框架,并在Redis
中维护一个计数器。虽然示例使用Python
,但是即使你不熟悉,照样也可以理解后面所讲的内容。
前提条件
确保你已经安装了Docker Engine
和Docker Compose
,你不需要安装Python
或Redis
,因为这两个都是由Docker
镜像提供的。
开始构建
1.创建一个工程目录
$ mkdir composetest
$ cd composetest
2.在你新创建的目录下,生成一个app.py
的文件,将下面的内容复制进去。
import time
import redis
from flask import Flask
app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)
def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)
@app.route('/')
def hello():
count = get_hit_count()
return 'Hello World! I have been seen {} times.\n'.format(count)
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True)
在这个例子中,redis
是应用程序网络上redis容器的主机名,这里使用Redis
的默认端口6379
。
3.在你当前目录下,生成Dockerfile
文件,并将下面内容复制进去。
FROM python:3.4-alpine
ADD . /code
WORKDIR /code
RUN pip install -r requirements.txt
CMD ["python", "app.py"]
通过上面Dockerfile构建的镜像,包含Python应用程序所需的所有依赖项,也包括Python本身。上面文件中每条指令的含义是:
- 以
Python3.4
镜像为基础镜像; - 添加当前目录
.
到镜像中的/code
路径; - 将
/code
设置为工作目录; - 安装
Python
的依赖项; - 设置容器的默认命令
python app.py
;
4.在当前目录下创建一个名为requirements.txt
的文件,用来配置安装Python
的依赖项,将下面内容复制到文件。
flask
redis
5.通过Compose文件来定义服务。同样在当前目录下创建一个docker-compose.yml
的文件,然后将下面的内容复制进去。
version: '3'
services:
web:
build: .
ports:
- "5000:5000"
redis:
image: "redis:alpine"
上面的Compose文件定义了两个服务,web
和redis
。首先看web
服务:
- 使用从当前目录中的
Dockerfile
文件构建的镜像 - 将容器上的公开端口5000转发到主机上的端口5000(Flask web服务器的默认端口是5000)
而redis
服务使用从Docker Hub
镜像仓库拉取的公共Redis
镜像。
6.使用Compose来创建和运行你的应用,在当前目录中使用命令docker-compose up
。然后你就可以看到如下的执行内容:
Creating network "composetest_default" with the default driver
Building web
Step 1/5 : FROM python:3.4-alpine
3.4-alpine: Pulling from library/python
8e3ba11ec2a2: Already exists
2baa13bb50be: Pull complete
94819cf8c320: Pull complete
fd37974ce96d: Pull complete
b7202c933744: Pull complete
Digest: sha256:f8c20ce4b774b816f3108ac6a9f08161c94824ec3626a3f93baffa2d3fecd02f
Status: Downloaded newer image for python:3.4-alpine
---> 73266cf72156
Step 2/5 : ADD . /code
---> d2739ab8a928
Step 3/5 : WORKDIR /code
---> Running in 37ed62ac8c11
Removing intermediate container 37ed62ac8c11
---> 25f7a4fbb7fa
Step 4/5 : RUN pip install -r requirements.txt
---> Running in 6f69dca0e3d9
Collecting flask (from -r requirements.txt (line 1))
Downloading https://files.pythonhosted.org/packages/7f/e7/08578774ed4536d3242b14dacb4696386634607af824ea997202cd0edb4b/Flask-1.0.2-py2.py3-none-any.whl (91kB)
Collecting redis (from -r requirements.txt (line 2))
Downloading https://files.pythonhosted.org/packages/3b/f6/7a76333cf0b9251ecf49efff635015171843d9b977e4ffcf59f9c4428052/redis-2.10.6-py2.py3-none-any.whl (64kB)
Collecting Werkzeug>=0.14 (from flask->-r requirements.txt (line 1))
Downloading https://files.pythonhosted.org/packages/20/c4/12e3e56473e52375aa29c4764e70d1b8f3efa6682bef8d0aae04fe335243/Werkzeug-0.14.1-py2.py3-none-any.whl (322kB)
Collecting click>=5.1 (from flask->-r requirements.txt (line 1))
Downloading https://files.pythonhosted.org/packages/34/c1/8806f99713ddb993c5366c362b2f908f18269f8d792aff1abfd700775a77/click-6.7-py2.py3-none-any.whl (71kB)
Collecting Jinja2>=2.10 (from flask->-r requirements.txt (line 1))
Downloading https://files.pythonhosted.org/packages/7f/ff/ae64bacdfc95f27a016a7bed8e8686763ba4d277a78ca76f32659220a731/Jinja2-2.10-py2.py3-none-any.whl (126kB)
Collecting itsdangerous>=0.24 (from flask->-r requirements.txt (line 1))
Downloading https://files.pythonhosted.org/packages/dc/b4/a60bcdba945c00f6d608d8975131ab3f25b22f2bcfe1dab221165194b2d4/itsdangerous-0.24.tar.gz (46kB)
Collecting MarkupSafe>=0.23 (from Jinja2>=2.10->flask->-r requirements.txt (line 1))
Downloading https://files.pythonhosted.org/packages/4d/de/32d741db316d8fdb7680822dd37001ef7a448255de9699ab4bfcbdf4172b/MarkupSafe-1.0.tar.gz
Building wheels for collected packages: itsdangerous, MarkupSafe
Running setup.py bdist_wheel for itsdangerous: started
Running setup.py bdist_wheel for itsdangerous: finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/2c/4a/61/5599631c1554768c6290b08c02c72d7317910374ca602ff1e5
Running setup.py bdist_wheel for MarkupSafe: started
Running setup.py bdist_wheel for MarkupSafe: finished with status 'done'
Stored in directory: /root/.cache/pip/wheels/33/56/20/ebe49a5c612fffe1c5a632146b16596f9e64676768661e4e46
Successfully built itsdangerous MarkupSafe
Installing collected packages: Werkzeug, click, MarkupSafe, Jinja2, itsdangerous, flask, redis
Successfully installed Jinja2-2.10 MarkupSafe-1.0 Werkzeug-0.14.1 click-6.7 flask-1.0.2 itsdangerous-0.24 redis-2.10.6
Removing intermediate container 6f69dca0e3d9
---> b0fd1432440e
Step 5/5 : CMD ["python", "app.py"]
---> Running in 4efeccdd4edb
Removing intermediate container 4efeccdd4edb
---> ae811597b7e9
Successfully built ae811597b7e9
Successfully tagged composetest_web:latest
WARNING: Image for service web was built because it did not already exist. To rebuild this image you must use `docker-compose build` or `docker-compose up --build`.
Pulling redis (redis:alpine)...
alpine: Pulling from library/redis
8e3ba11ec2a2: Already exists
baf0a0bb402f: Pull complete
3b0b05ea68b5: Pull complete
ba5ab541f6bf: Pull complete
cddd527d7b95: Pull complete
2ee1c014ab33: Pull complete
Digest: sha256:273023e79a025c089fbf1be0b41c99d68f064b80caf1fff069d2fa5d05a8d183
Status: Downloaded newer image for redis:alpine
Creating composetest_redis_1 ... done
Creating composetest_web_1 ... done
Attaching to composetest_redis_1, composetest_web_1
redis_1 | 1:C 10 Sep 06:00:42.812 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_1 | 1:C 10 Sep 06:00:42.812 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=1, just started
redis_1 | 1:C 10 Sep 06:00:42.812 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
redis_1 | 1:M 10 Sep 06:00:42.816 * Running mode=standalone, port=6379.
redis_1 | 1:M 10 Sep 06:00:42.817 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
redis_1 | 1:M 10 Sep 06:00:42.817 # Server initialized
redis_1 | 1:M 10 Sep 06:00:42.817 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
redis_1 | 1:M 10 Sep 06:00:42.818 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
redis_1 | 1:M 10 Sep 06:00:42.818 * Ready to accept connections
web_1 | * Serving Flask app "app" (lazy loading)
web_1 | * Environment: production
web_1 | WARNING: Do not use the development server in a production environment.
web_1 | Use a production WSGI server instead.
web_1 | * Debug mode: on
web_1 | * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
web_1 | * Restarting with stat
web_1 | * Debugger is active!
web_1 | * Debugger PIN: 236-932-282
Compose将拉取Redis
镜像,为你的代码构建镜像,并启动定义的服务。在这种情况下,代码在构建时被静态复制到镜像中。
假设你上面的服务是运行在111.1.2.3
,那么你在你的浏览器中输入http://111.1.2.3:5000/
,就可以在浏览器中看到Hello World! I have been seen 1 times.
。刷新一下浏览器页面,就会变成Hello World! I have been seen 2 times.
。
如果你是在本地运行,输入http://localhost:5000
,如果不起作用,可以试试http://0.0.0.0:5000
。如果你在Mac或Windows上运行Docker,那么可以使用命令docker-machine ip MACHINE_VM
获得你Docker主机的IP地址。接着在浏览器中打开http://获得的IP:5000
。
7.再切换到另一个终端窗口,输入命令docker image ls
。该命令会列出本地的镜像,从列表中我们可以看到
REPOSITORY TAG IMAGE ID CREATED SIZE
composetest_web latest e2c21aa48cc1 4 minutes ago 93.8MB
python 3.4-alpine 84e6077c7ab6 7 days ago 82.5MB
redis alpine 9d8fa9aa0e5b 3 weeks ago 27.5MB
8.在第二个终端中输入命令docker-compose down
来结束正在运行的服务,或者在原来的终端中键入CTRL+C
来停止应用程序。
9.添加Compose文件以添加数据卷,重新编辑docker-compose.yml
文件,为你的web
服务添加数据卷。
version: '3'
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
redis:
image: "redis:alpine"
新的卷将你主机上的项目目录(当前目录)安装到容器内的/code
,允许你动态修改代码,而无需重建镜像。
10.重新构建和运行app,在你项目目录下,输入docker-compose up
。
Recreating composetest_web_1 ...
Recreating composetest_web_1 ... done
Attaching to composetest_redis_1, composetest_web_1
redis_1 | 1:C 10 Sep 06:00:42.812 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
redis_1 | 1:C 10 Sep 06:00:42.812 # Redis version=4.0.11, bits=64, commit=00000000, modified=0, pid=1, just started
redis_1 | 1:C 10 Sep 06:00:42.812 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
redis_1 | 1:M 10 Sep 06:00:42.816 * Running mode=standalone, port=6379.
redis_1 | 1:M 10 Sep 06:00:42.817 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
redis_1 | 1:M 10 Sep 06:00:42.817 # Server initialized
redis_1 | 1:M 10 Sep 06:00:42.817 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
redis_1 | 1:M 10 Sep 06:00:42.818 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled.
redis_1 | 1:M 10 Sep 06:00:42.818 * Ready to accept connections
redis_1 | 1:M 10 Sep 07:00:43.044 * 1 changes in 3600 seconds. Saving...
redis_1 | 1:M 10 Sep 07:00:43.045 * Background saving started by pid 14
redis_1 | 14:C 10 Sep 07:00:43.050 * DB saved on disk
redis_1 | 14:C 10 Sep 07:00:43.050 * RDB: 0 MB of memory used by copy-on-write
redis_1 | 1:M 10 Sep 07:00:43.145 * Background saving terminated with success
web_1 | * Serving Flask app "app" (lazy loading)
web_1 | * Environment: production
web_1 | WARNING: Do not use the development server in a production environment.
web_1 | Use a production WSGI server instead.
web_1 | * Debug mode: on
web_1 | * Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
web_1 | * Restarting with stat
web_1 | * Debugger is active!
web_1 | * Debugger PIN: 236-932-282
在浏览器中刷新页面,可以看到以上次为基准,继续增加。
如果你的项目位于
Users
目录(cd ~
)之外,那么你需要共享你正在使用的Dockerfile
和卷的驱动或位置。如果得到运行时错误,指示未找到应用程序文件,拒绝数据卷的装入,或者服务无法启动,那么请尝试启用文件或驱动共享。在Windows
或mac
上,卷需要放在C:\Users
(Windows上)或/Users
(Mac)目录之外。
如果在比较旧的Windows操作系统上使用Oracle VirtualBox
,则可能会遇到上面的问题。
由于现在应用程序使用卷安装到容器中,因此你可以更改其代码并立即查看更改的结果而无需重建镜像。
11.不要停止镜像,然后在另外一个控制窗口中,改变app.py
文件的内容。将浏览器打印内容由Hello World!
变为Hello from Docker!
。保存后,在浏览器中刷新页面,就可以看到内容已经发生改变。
Hello from Docker! I have been seen 4 times.
12.如果你想在后台运行你的服务,通过传入参数-d
($ docker-compose up -d
)来实现。通过命令docker-compose ps
查看当前正在运行的服务。
Name Command State Ports
-------------------------------------------------------------------------------------
composetest_redis_1 docker-entrypoint.sh redis ... Up 6379/tcp
composetest_web_1 python app.py Up 0.0.0.0:5000->5000/tcp
docker-compose run
命令允许你运行一次性命令,例如,要查看web
服务可用的环境变量。
PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=4ba17b303aa5
TERM=xterm
LANG=C.UTF-8
GPG_KEY=97FC712E4C024BBEA48A61ED3A5CA953F73C700D
PYTHON_VERSION=3.4.9
PYTHON_PIP_VERSION=18.0
HOME=/root
注意:如果你使用docker-compose up -d
来启动服务,那么你停止服务需要使用命令docker-compose stop
。
你可以使用down
命令会完全删除容器,包括其中的卷等。使用参数--volumes
($ docker-compose down --volumes
)也可以删除Redis
容器使用的数据卷。
Stopping composetest_web_1 ... done
Stopping composetest_redis_1 ... done
Removing composetest_web_run_1 ... done
Removing composetest_web_1 ... done
Removing composetest_redis_1 ... done
Removing network composetest_default
讲到这里,你应该已经了解了Compose如何工作的基本知识。