Compose 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的快速编排。使用Dockerfile我们很容易定义一个单独的应用容器。然而在日常开发工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的多种数据库服务容器;再比如在分布式应用一般包含若干个服务,每个服务一般都会部署多个实例。如果每个服务都要手动启停,那么效率之低、维护量之大可想而知。这时候就需要一个工具能够管理一组相关联的的应用容器,这就是Docker Compose。
中文文档:https://yeasy.gitbook.io/docker_practice/compose
模板文件是使用 Compose 的核心,涉及到的指令关键字也比较多。下面主要列出几个常见&重要的模板指令,其他指令大家可以自行百度。
默认的模板文件名称为 docker-compose.yml,格式为 YAML 格式。
docker run -e
。你可以使用数组或字典两种格式。services:
mysql:
image: mysql:latest
ports:
- 3307:3306
environment: # 使用字典格式,类似于 docker run -e MYSQL_ROOT_PASSWORD=root
MYSQL_ROOT_PASSWORD: root
也可以使用数组格式:
services:
mysql:
image: mysql:latest
ports:
- 3307:3306
environment: # 使用数组格式
- MYSQL_ROOT_PASSWORD=root
services:
mysql:
image: mysql:latest
ports:
- 3307:3306
env_file: # 将比较重要的环境变量放在隐藏文件中
- ./.env # .开头的为隐藏文件
- ./apps/web.env
- /opt/secrets.env
services:
mysql:
image: mysql:latest
ports:
- 3307:3306
environment: # 使用字典格式,类似于 docker run -e MYSQL_ROOT_PASSWORD=root
MYSQL_ROOT_PASSWORD: root
volumes:
# 挂载绝对路径映射,没有这个路径的话会自动创建
- /root/docker/composetest/tomcat/app_data:/var/lib/mysql
# 或者使用相对路径映射,也会自动创建
- ./app_data:/var/lib/mysql
你还可以使用别名的方式挂载容器数据卷(可以跨多个服务并重用挂载卷,当然使挂载绝对路径或相对路径也可以重用挂载卷),但要注意一点,使用别名的方式挂载需要在顶级volumes关键字中声明挂载卷,否则启动会报错。
services:
mysql:
image: mysql:latest
ports:
- 3307:3306
environment:
MYSQL_ROOT_PASSWORD: root
volumes:
- my_app_data:/var/lib/mysql
web1:
volumes: # 重用my_app_data
- my_app_data:/var/lib/mysql
web2:
volumes: # 重用my_app_data
- my_app_data:/var/lib/mysql
volumes:
my_app_data:
services:
webapp:
build: ./ # 从当前目录下寻找Dockerfile文件
你也可以使用 context 指令指定 Dockerfile 所在文件夹的路径,使用 dockerfile 指令指定 Dockerfile 文件名,可以使用 args 指令指定构建镜像时往Dockerfile中传入的变量。
services:
webapp:
build:
context: ./dir
dockerfile: Dockerfile_flask
args:
buildno: 1
services:
webapp:
build: .
depends_on:
- db
- redis
redis:
image: redis:latest
db:
image: mysql:latest
services:
mysql:
image: mysql:latest
ports:
- 3307:3306
env_file: .env # 仅使用单个env文件
env_file: # 通过数组来使用多个env文件
- ./common.env
- ./apps/web.env
- /opt/secrets.env
环境变量文件中每一行必须符合格式,支持 # 开头的注释行。
# common.env: Set development environment
MYSQL_ROOT_PASSWORD=root
services:
webapp:
networks:
- flask-net
networks: # 在顶级networks关键字中需要声明,才会在启动时自动创建该网络,否则报错。
flask-net:
services:
tomcat:
image: tomcat:8.0
ports:
- "80:80" # 绑定容器的80端口到主机的80端口
- "9000:8080" # 绑定容器的8080端口到主机的9000端口
- "443" # 绑定容器的443端口到主机的任意端口,容器启动时随机分配绑定的主机端口号
services:
webapp:
networks:
- flask-net
restart: always
command: echo "hello world"
中文文档: https://yeasy.gitbook.io/docker_practice/compose/commands
docker-compose up -d · # 不写服务名,默认启动docker-compose.yml所有服务
docker-compose up -d 服务名 # 启动docker-compose.yml的对应服务
默认情况,如果服务容器已经存在,docker-compose up 将会尝试停止容器,然后重新创建(保持使用 volumes-from 挂载的卷),以保证新启动的服务匹配 docker-compose.yml 文件的最新内容。但是不会更新已经打好的镜像,如果镜像错误,不能通过 docker-compose up 更新镜像,只能先删除镜像。如果用户不希望容器被停止并重新创建,可以使用 docker-compose up --no-recreate。这样将只会启动处于停止状态的容器,而忽略已经运行的服务。如果用户只想重新部署某个服务,可以使用 docker-compose up --no-deps -d
docker-compose down · # 不写服务名,默认停止docker-compose.yml所有服务
docker-compose down 服务名 # 停止docker-compose.yml的对应服务
docker-compose exec 服务名 bash
docker-compose ps # 列出所有运行的服务
docker-compose ps -q # 只列出容器的ID信息
选项:
-q 只打印容器的 ID 信息。
docker-compose top
docker-compose top 服务名
docker-compose restart # 对整个项目操作,默认重启全部服务
docker-compose restart 服务名 # 只重启该服务
docker-compose restart -t 20 # 20s之后重启服务
docker-compose rm 服务名
docker-compose rm -f tomcat
start、stop
启停服务
pause、unpause
暂停、恢复服务
logs -f(实时)
查看所有服务容器,或指定服务容器的日志输出。默认情况下,docker-compose 将对不同的服务输出使用不同的颜色来区分。可以通过 --no-color 来关闭颜色。该命令在调试问题的时候十分有用。
docker-compose logs # 输出所有服务容器的日志
docker-compose logs 服务名 # 输出对应服务的日志
docker-compose logs -f 服务名 # 实时输出对应服务的日志
用docker部署一个flask应用:flask项目镜像用Dockerfile完成,使用docker-compose完成flaskapp,mysql,redis的编排。
Dockerfile:
FROM python:3.10.2-alpine
ENV APP_PATH=/apps
WORKDIR $APP_PATH
ADD . $APP_PATH
RUN pwd # /apps 已经切换到workdir了
RUN ls -a
RUN pip install -r flaskweb/requirements.txt # 所以这步直接在workdir下找txt就行
EXPOSE 8081
ENTRYPOINT ["python3"]
CMD ["flaskweb/start.py"]
docker-compose.yml:
version: '3.8'
services:
mysqldb:
image: mysql:latest
ports:
- 3306:3306
env_file:
- .env
volumes:
- /root/docker/composetest/20230603/mysql_data:/var/lib/mysql
networks:
- flask-net
flask_web:
build: .
depends_on:
- mysqldb
networks:
- flask-net
ports:
- 8080:8081
networks:
flask-net:
因为 flask_web 和 mysqldb 这两个服务用的都是同一个网络,所以容器之间访问可以不用写ip(防止容器销毁重新生成后flask代码还要适配新的ip),直接写服务名即可。
@app.route("/add")
def home():
connect = pymysql.connect(host="mysqldb", port=3306, user="root", password="123")
with connect as conn:
with conn.cursor() as cursor:
cursor.insert("INSERT INTO userinfo(uname, tel) VALUES ('zhangsan', 19725564581);")
return "add new user successful"