docker-compose
1. 介绍
一个项目一般会由多个应用服务组成。例如一个Django的web项目,由Django后端服务,数据库,uwsgi服务,nginx反向代理服务等组成。如果使用容器技术当然不会将所有的服务都部署到一个容器中,一般是一个独立的服务一个容器。因此上面的项目需要一个python环境的容器用来运行django后端服务和uwsgi服务,一个数据库容器,一个nginx容器。单独部署时,需要一个个手动部署,构建镜像,添加网络,以及各容器之间的依赖和通信等问题,非常繁琐。
docker-compose就是批量部署容器,并自动构建镜像,处理依赖和通信的工具。只需要在一个YAML文件中配置好应用程序的服务,然后通过docker-compose
命令就可以创建并启动配置中的所有服务。
使用docker-compose
有三个基本步骤:
- 在Dockerfile中定义好你的应用程序的环境,以便在任何地方它都可以复制。
- 在
docker-compose.ymal
中定义组成应用程序的服务,以便它们可以在一个独立的环境中一起运行。 - 运行
docker-compose up
,docker-compose
命令会启动并运行整个应用程序。
一个docker-compose.Yml
看起来是这样的:
version: "3.9" # optional since v1.27.0
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
- logvolume01:/var/log
links:
- redis
redis:
image: redis
volumes:
logvolume01: {}
2. 安装
Docker Compose依赖于Docker Engine来完成任何有意义的工作,所以请确保在本地或远程安装Docker Engine。
2.1 在windows和mac上安装
Docker Desktop for Mac和Windows 默认包括Compose命令。因此,Windows和Mac用户不需要单独安装Compose V2。
2.2 在liunx系统上安装
在Linux上,您可以从GitHub上的Compose存储库发布页面下载Docker Compose二进制文件,然后按照下面的步骤来安装。
注意:
对于alpine,需要以下依赖包:
py-pip
,python3-dev
,libffi-dev
,openssl-dev
,gcc
,libc-dev
,rust
,cargo
andmake
.
-
运行此命令下载Docker Compose的当前稳定版本:
sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
要安装不同版本的Compose,请将1.29.2替换为您想要使用的Compose版本。
-
添加执行权限
sudo chmod +x /usr/local/bin/docker-compose
-
测试安装是否成功
$ docker-compose --version docker-compose version 1.25.0
上面这种手动安装容易出现问题,推荐使用下面的pip
安装。
通过pip安装
Compose可以使用pip从pypi安装。如果您使用pip安装,我们建议您使用virtualenv,因为许多操作系统有与docker-compose依赖项冲突的python系统包。
pip install docker-compose
3. 基本使用
接下来我们通过运行一个简单的python web应用来学习docker-compose
命令。
3.1 第一步: 编写python程序
-
创建一个项目文件夹
mkdir composetest cd composetest
-
在项目目录下创建
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)
在上面的程序中,redis的主机名为
'redis'
,并使用默认端口6379
。 -
在你的项目目录中创建另一个名为
requirements.txt
的文件,并粘贴如下内容:flask redis
3.2 第二步:创建一个Dockerfile
在这个步骤中,我们会构建一个镜像。该映像包含Python应用程序所需的所有依赖项,包括Python本身。
在项目根目录创建文件Dockerfile
,内容如下:
# syntax=docker/dockerfile:1
FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]
这告诉Docker:
- 从Python 3.7映像开始构建映像。
- 将工作目录设置为/code。
- 设置flask命令使用的环境变量。
- 安装gcc和其他依赖项
- 复制requirements.txt并安装Python依赖项。
- 向映像添加元数据,以说明容器正在监听端口5000
- 复制项目当前目录到镜像的工作目录中
- 设置容器的默认运行命令为
flask run
3.3 第三步:在compose file中定义服务
在项目根目录中创建文件docker-compose.yml
,并在其中编写如下内容:
version: "3.9"
services:
web:
build: .
ports:
- "5000:5000"
redis:
image: "redis:alpine"
这个compose file定义了两个服务web
和redis
。
Web service
web 服务会使用项目当前目录下的dockerfile构建的镜像。 然后它将容器的5000端口绑定到主机的5000端口上。
redis service
redis服务使用从Docker Hub下载的公共redis镜像。
3.4 第四步:使用compose命令构建和运行应用
-
从项目目录,通过运行
docker-compose up
启动应用程序。$ docker-compose up Creating composetest_web_1 ... done Creating composetest_redis_1 ... done Attaching to composetest_redis_1, composetest_web_1 redis_1 | 1:C 14 Oct 2021 11:34:42.291 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo redis_1 | 1:C 14 Oct 2021 11:34:42.291 # Redis version=6.2.1, bits=64, commit=00000000, modified=0, pid=1, just started redis_1 | 1:C 14 Oct 2021 11:34:42.291 # 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 14 Oct 2021 11:34:42.291 * monotonic clock: POSIX clock_gettime redis_1 | 1:M 14 Oct 2021 11:34:42.292 * Running mode=standalone, port=6379. redis_1 | 1:M 14 Oct 2021 11:34:42.292 # Server initialized redis_1 | 1:M 14 Oct 2021 11:34:42.294 * Ready to accept connections web_1 | * Serving Flask app 'app.py' (lazy loading) web_1 | * Environment: production web_1 | WARNING: This is a development server. Do not use it in a production deployment. web_1 | Use a production WSGI server instead. web_1 | * Debug mode: off web_1 | * Running on all addresses. web_1 | WARNING: This is a development server. Do not use it in a production deployment. web_1 | * Running on http://192.168.80.3:5000/ (Press CTRL+C to quit)
compose下载了一个
Redis
镜像,为代码构建了一个镜像,并启动定义好的服务。在本例中,代码在构建时静态地复制到镜像中。 -
访问服务程序
在浏览器中输入
http://localhost:5000/
或者http://127.0.0.1:5000/
访问我们运行的web服务程序。 -
刷新页面
数字应该增加。
-
切换到另一个终端并输入
docker image ls
查询所有本地镜像 -
停止应用
直接在当前运行终端
Ctrl + C
,或者是再开启一个终端在项目目录下运行docker-compose down
关闭运行的应用。
3.5 第五步:添加挂载点
编辑docker-compose.yml
,给web服务添加挂载点。
version: "3.9"
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .:/code
environment:
FLASK_ENV: development
redis:
image: "redis:alpine"
volumes
键将主机上的项目目录(当前目录)挂载到容器内的/code中,并允许动态地修改代码,而不必重新构建映像。
environment
键设置FLASK_ENV
环境变量,该变量告诉flask以开发模式运行并在代码发送更改时重新加载。这种模式只能在开发中使用。
3.6 第六步:通过compose重新构建并运行应用
在项目目录下运行docker-compose up
使用更新后的compose文件重新构建并运行应用。
3.7 第七步:更新应用
因为现在使用卷将应用程序代码挂载到容器中,所以您可以对其代码进行更改并立即查看更改,而无需重新构建镜像。
修改app.py
中的返回问候语,例如:
return 'Hello from Docker! I have been seen {} times.\n'.format(count)
在浏览器中刷新应用程序。欢迎语应该更新,计数器应该仍然在增加。
3.8 第八步:实验一下其他命令
如果你想在后台运行你的服务,你可以将-d标志(用于“分离”模式)传递给docker-compose up
,并使用docker-compose ps来查看当前正在运行的服务:
docker-compose run
命令允许您为您的服务运行一次性命令。例如,要查看web服务可用的环境变量:
docker-compose run web env
Creating composetest_web_run ... done
PATH=/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOSTNAME=7929330f0f39
TERM=xterm
FLASK_ENV=development
LANG=C.UTF-8
GPG_KEY=0D96DF4D4110E5C43FBFB17F2D347EA6AA65421D
PYTHON_VERSION=3.7.10
PYTHON_PIP_VERSION=21.0.1
PYTHON_GET_PIP_URL=https://github.com/pypa/get-pip/raw/b60e2320d9e8d02348525bd74e871e466afdf77c/get-pip.py
PYTHON_GET_PIP_SHA256=c3b81e5d06371e135fb3156dc7d8fd6270735088428c4a9a5ec1f342e2024565
FLASK_APP=app.py
FLASK_RUN_HOST=0.0.0.0
HOME=/root
如果使用docker-compose up -d
命令启动服务,停止服务可以使用命令
docker-compose stop
也可以使用down
命令删除所有,完全删除容器。通过——volumes
来删除Redis容器使用的数据卷:
docker-compose down --volumes
这些就是docker-compose
的基本使用方法。
4. Compose file
Compose file是一个定义services
、networks
和volumes
的YAML文件。Compose file的默认路径是./docker-compose.yml
。yaml文件的后缀yml
和yaml
都支持。
下面介绍Compose file
中的常用指令。
version
指定compose file
的版本。
networks
创建网络。
services
定义服务程序,每个服务对应会创建一个容器。
build
配置构建。
-
设置为一个字符串,指定构建时的上下文路径:
version: "3.9" services: webapp: build: ./dir
-
设置为一个对象,在其中设置
context,Dockerfile,args
version: "3.9" services: webapp: build: context: ./dir dockerfile: Dockerfile-alternate args: buildno: 1
当同时设置build
和image
配置项时,Compose会使用image
中指定的webapp
和tag
来命名构建的图像:
build: ./dir
image: webapp:tag
command
覆盖容器默认的启动命令。
command: bundle exec thin -p 3000
也可以是一个列表
command: ["bundle", "exec", "thin", "-p", "3000"]
container_name
指定启动容器的名字
container_name: my-web-container
depends_on
表示服务之间的依赖关系。 服务依赖会导致以下行为:
Docker-compose up
按依赖顺序启动服务。 在下面的示例中,db
和redis
在web
之前启动。docker-compose up service
自动包括service
的依赖项。在下面的例子中,docker-compose up web
也创建并启动db
和redis
。docker-compose stop
按依赖顺序停止服务。在下面的例子中,web
在db
和redis
之前停止
version: "3.9"
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgres
在使用depends_on时需要注意:
depends_on
不会等待db
和redis
是“准备好”之后再启动web -只是等他们启动。如果需要等待服务就绪,请参阅控制启动顺序了解有关此问题和解决该问题的策略的更多信息。
entrypoint
覆盖容器默认的entrypoint
。
entrypoint: /code/entrypoint.sh
也可以写成列表的形式
entrypoint: ["php", "-d", "memory_limit=-1", "vendor/bin/phpunit"]
注意设置了entrypoint
后,不仅会覆盖服务镜像Dockerfile
中的ENTRYPOINT
指令还会忽略其中的CMD
指令。
environment
设置容器运行时的环境变量。你可以使用数组,也可以使用字典。 任何布尔值(true, false, yes, no)都需要用引号括起来,以确保它们不会被YML解析器转换为True
或False
。
environment:
RACK_ENV: development
SHOW: 'true'
SESSION_SECRET:
expose
暴露端口,但不映射到宿主机,只被连接的服务访问。只能指定内部端口。
expose:
- "3000"
- "8000"
image
指定容器启动的镜像。可以是镜像名,也可以是镜像ID的部分。
image: redis
image: ubuntu:18.04
image: a4bc65fd
如果镜像不存在compose会pull它。如果还制定了build
指令,将作为构建后的镜像的名字。
network_mode
设置网络模式。与docker客户端的--network
参数的取值一样。
network_mode: "bridge"
network_mode: "host"
network_mode: "none"
network_mode: "service:[service name]"
network_mode: "container:[container name/id]"
networks
配置容器连接的网络,引用顶级 networks 下的条目 。
services:
some-service:
networks:
- some-network
- other-network
ports
端口映射。
有三种格式:
- 指定宿主机和容器的端口(
HOST:CONTAINER
) - 仅仅指定容器的端口(映射宿主机一个随机端口)
- 指定宿主机的ip:端口和容器的端口,如果不指定宿主机的端口则随机映射一个端口。
ports:
- "3000"
- "3000-3005"
- "8000:8000"
- "9090-9091:8080-8081"
- "49100:22"
- "127.0.0.1:8001:8001"
- "127.0.0.1:5000-5010:5000-5010"
- "127.0.0.1::5000"
- "6060:6060/udp"
- "12400-12500:1240"
restart
设置重启策略。
no
是默认的重新启动策略,在任何情况下都不会重新启动容器。
当指定always
时,容器总是重新启动。
如果退出码指示一个on-failure
错误,on-failure
策略将重新启动容器。
设置为unless-stop
则除非容器被停止(手动或其他方式),否则该容器总是会重新启动。
restart: "no"
restart: always
restart: on-failure
restart: unless-stopped
volumes
挂着一个主机路径或者绑定一个命名卷到服务。
可以将主机路径挂载为单个服务的定义的一部分,不需要在顶级volumes
中定义它。
但是,如果您想跨多个服务重用卷,那么在顶级卷键中定义一个命名卷。
简单语法格式是:[SOURCE:]TARGET[:MODE]
。
SOURCE
可以是宿主机的路径或者是卷名TARGET
卷挂着的容器中的路径MODE
默认为rw
表示可读写,ro
表示只读
volumes:
# Just specify a path and let the Engine create a volume
- /var/lib/mysql
# Specify an absolute path mapping
- /opt/data:/var/lib/mysql
# Path on the host, relative to the Compose file
- ./cache:/tmp/cache
# User-relative path
- ~/configs:/etc/configs/:ro
# Named volume
- datavolume:/var/lib/mysql
更多信息详见官方文档
5. compose v2
新的compose V2版本支持将compose
命令作为docker cli
的一部分,也即是可以去掉docker-compose
命令中的-
,直接使用docker compose
命令。
v2版本的做了很多更新和优化,未来会取代v1版本。
1. 安装
1.1 在windows和mac上安装
Docker Desktop for Mac和Windows 3.2.1及以上版本包括新的Compose命令和Docker CLI。因此,Windows和Mac用户不需要单独安装Compose V2。
1.2 在linux上安装
直接通过从项目发布页面下载适合您系统的二进制文件并将其复制为$HOME/.docker/cli-plugins
目录下的docker-compose
文件。
- 运行以下命令下载Docker Compose的当前稳定版本:
mkdir -p ~/.docker/cli-plugins/
curl -SL https://github.com/docker/compose/releases/download/v2.0.1/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose
这个命令将为当前活动用户安装Compose V2到$HOME目录下。为系统上的所有用户安装Docker Compose,替换~/.docker/cli-plugins/
为/usr/local/lib/docker/cli-plugins
。
-
添加可执行权限
chmod +x ~/.docker/cli-plugins/docker-compose
-
测试是否安装成功
$ docker compose version Docker Compose version v2.0.1
欢迎来到testingpai.com!
注册 关于