docker-compose是Docker官方提供的开源项目,负责实现对Docker容器集群的快速编排。
docker容器本身占用资源极少,所以docker官方建议我们每一个容器只运行一个服务,即将每个服务单独的分割开来。但是如果分隔开来的话,就需要启动多个容器,如果遇到迁移、重启等操作,就需要花费很多时间,所以docker官方又提供了docker-compose工具,支持用户按照一定的业务规则批量管理容器。
Compose允许用户通过一个单独的
docker-compose.yml
模板文件来定义一组相关的应用容器
为一个项目。即可以非常容易地用一个配置文件定义一个多容器,然后使用一条指令安装应用的所有依赖,完成多个容器的构建,解决了容器与容器之间如何管理编排的问题。
macOS、Windows系统使用的Docker Desktop默认已经安装。可以通过docker-compose version
查看安装的版本。
具体的安装可以根据官方教程来:Install Docker Compose-Overview
也可以网上找具体的教程,这里不具体展示了。
想要了解docker-compose,则需要了解docker中镜像、容器之间的使用,特别是需要了解docker run命令。
刚开始可能对docker-compose的不太了解,我们可以先简单的认为docker-compose是对docker run命令的解析。
首先可以先了解下docker部署mysql的操作(相关步骤可以参考:docker常用应用部署,我们按照这个示例来讲如何使用docker-compose实现mysql的部署。
官方给出使用docker-compose的3个步骤:
我们可以先看步骤2、3(步骤1后面再涉及),从步骤2来看,我们需要有个docker-compose.yml
文件。docker-compose.yml对docker run命令的解析说明如下:
docker run命令如下:
docker run -id --name=test_mysql -p 3307:3306 \
-v $PWD/conf:/etc/mysql/conf.d \
-v $PWD/logs:/logs \
-v $PWD/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=wenxiaoba \
mysql:latest
以下是解析的docker-compose.yml(yaml文件的具体语法参考:YAML 入门教程):
# 确认使用docker-compose项目的版本号
version: "3.8"
services: # 服务群,即一组容器,容器的信息都在services下定义
regx_mysql: # 如果下一层没有设置container_name,则docker-compose会根据该名称按照规则生成容器的容器名称
container_name: test_mysql # 定义容器名称
image: mysql:latest # 生成容器时使用的镜像
ports:
- 3307:3306 # 指定端口映射,相当于docker run -p参数
volumes: # 相当于docker run -v参数
- ./conf:/etc/mysql/conf.d
- ./logs:/logs
- ./data:/var/lib/mysql
environment: # 相当于docker run -e参数
- "MYSQL_ROOT_PASSWORD=wenxiaoba"
解析说明:
镜像名称:版本号
(没有版本号的话,默认是latest)主机(宿主)端口:容器端口
,相当于docker run -p参数宿主机路径:容器路径
,相当于docker run -v参数远程连接mysql,连接成功
docker-compose up命令会获取当前目录下的docker-compose.yml文件(文件名称与后缀是固定的,除非使用docker-compose命令时加上-f选项),根据docker-compose.yml的内容,按照规则去启动容器
docker-compose.yml文件中定义了一组容器的信息,定义了:version(已弃用)、services(必需)、networks、volumes、configs和secrets
docker version
获取到docker-compose.yml模板官网示例:
services:
frontend:
image: awesome/webapp
ports:
- "443:8043"
networks:
- front-tier
- back-tier
configs:
- httpd-config
secrets:
- server-certificate
backend:
image: awesome/database
volumes:
- db-data:/etc/data
networks:
- back-tier
volumes:
db-data:
driver: flocker
driver_opts:
size: "10GiB"
configs:
httpd-config:
external: true
secrets:
server-certificate:
external: true
networks:
# The presence of these objects is sufficient to define them
front-tier: {}
back-tier: {}
docker-compose.yml基本包含了容器群的基本信息。services的下一层是容器,services字段下的每一个键值对都表示一个容器,键会被按照规则定义为容器的名称,值则为容器的配置信息。如模板中,services下有frontend、backend共2个键值对,即表示会生成2个容器,容器名称会涉及到“frontend”和“backend”;frontend层下内容,则表示了frontend容器的配置(比如根据哪个镜像生成、端口映射、数据卷配置、网络配置等),backend层下的内容,表示了backend容器的配置。
关于模板全部的字段,可以看docker官方教程Compose specification
中文译本可以参考:Compose 模板文件
容器的一些需要注意的配置字段下面具体介绍下。
在本章的 简单入门 示例中,我们介绍了如何用镜像去使用docker-compose。实际使用中,经常是使用dockerfile文件去生成容器的,build字段就是docker-compose工具支持dockerfile文件去生成镜像。
build:在通过docker-compose启动容器之前,会先根据dockerfile构建镜像,然后根据构建的镜像启动容器
格式:
services:
webapp:
build:
context: ./dir
dockerfile: Dockerfile-alternate
args:
buildno: 1
我们以docker镜像构建的tomcat镜像dockerfile为例,使用docker-compose命令启动容器
编辑dockerfile文件(tomcat_dockerfile):
FROM tomcat:jre17-temurin
MAINTAINER wenxiaoba
RUN cp -r webapps.dist/* webapps/
RUN rm ./webapps/ROOT/index.jsp
RUN echo "Welcomo to Tomcat Docker
---by wenxiaoba, create in docker-compose with dockerfile">./webapps/ROOT/index.html
WORKDIR /usr/local/tomcat
EXPOSE 8080
编辑docker-compose.yml文件:
services:
regx_tomcat:
build:
context: ./
dockerfile: tomcat_dockerfile
ports:
- "8080:8080"
**注意:**相关文件最好放在同一个目录下,方便管理、操作和引用
访问主机的8080端口:
command:覆盖容器启动后默认执行的命令。相当于docker run命令末尾的command命令
container_name:指定docker-compose启动的容器的容器名称,相当于docker run --name参数。如果未设置的话,容器名称默认将会使用 项目名称_服务名称_序号 这样的格式。不建议使用container_name指令
格式:
container_name: xxxx
注意:由于Docker不允许容器名称重复,所以如果指定了容器名称,则docker-compose up启动容器时,若容器名称重复,会导致启动失败,其他人使用docker-compose.yml启动容器时也会遇到这种问题,所以不推荐使用container_name指令
depends_on:设置在当前容器启动前需要先启动的容器,即根据容器的依赖设置启动顺寻。
示例:
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgres
在该示例中,web容器会在redis、db容器启动后再启动
注意:当前容器不会等待被依赖服务【完全启动】后才启动,一般是在快【完全启动】时启动
environment:用来给容器启动指定环境变量,相当于docker run -e参数
有2种格式:
environment:
变量名1: 值1
变量名2: 值2
...
或:
environment:
- 变量名1=值1
- "变量名2=值2" # 对于yaml文件来说,双引号加不加都是被识别成字符串
示例:
services:
regx_mysql:
container_name: test_mysql
image: mysql:latest
ports:
- 3307:3306
volumes:
- ./conf:/etc/mysql/conf.d
- ./logs:/logs
- ./data:/var/lib/mysql
environment:
- "MYSQL_ROOT_PASSWORD=wenxiaoba"
在此示例中,设置MYSQL_ROOT_PASSWORD为wenxiaoba(即mysql的root用户密码)
env_file:用来给容器启动指定环境变量文件,相当于docker run -e参数。
与environment区别:
- environment指定变量
- env_file是指定到变量文件,在指定的变量文件中定义具体变量
格式:
# 单个变量文件
env_file: 变量文件路径
# 多个变量文件
env_file:
- 变量文件路径1
- 变量文件路径2
- 变量文件路径3
变量文件格式如下(#
开头的为注释行,一行定义一个变量,变量定义格式为变量名=值
):
# 注释的内容
变量名1=值1
变量名2=值2
...
在当前目录的.env文件中设置内容如下:
MYSQL_ROOT_PASSWORD=wenxiaob
docker-compose.yml文件内容如下:
services:
regx_mysql:
image: mysql:latest
ports:
- 3306:3306
volumes:
- ./data:/var/lib/mysql
env_file: .env
远程连接mysql成功
environment的变量及其对应的值是在docker-compose.yml中明文显示的,如果有涉及到比较私密的数据,就不宜分享出去了,所以,如果有私密的数据,则使用env_file,到时候env_file指向的变量可以根据情况进行分享,且变量文件的文件名可以使用.
开头,这样会被识别为隐藏文件(虽然ls -a还是能识别,但是好歹比明文显示在docker-compose.yml中的要好一丢丢)
expose:指定构建镜像过程容器暴露的端口号,不建议使用
格式:
expose:
- "3000"
- "8000"
有需要时,镜像中就有指定暴露的端口号(如dockerfile),docker-compose.yml文件一般不指定。
image:指定创建容器的镜像
格式:
image: mysql # 如果只有名称,则默认版本号是latest
image: centos:7 # 指定centos,版本7的镜像
image: a4bc65fd # 根据镜像id指定镜像(不推荐,镜像id只是本系统唯一,在其他系统可能不存在)
示例:
networks:指定容器使用的网桥,相当于docker run --network。(如果多个容器使用同一个网桥,则容器之间可以通过容器名通讯,具体内容可以查阅:Docker:网络模式详解和尚硅谷2022版Docker实战教程(docker教程天花板)
示例:
services:
container1:
networks:
- some-network
- other-network
container2:
networks:
- other-network
networks:
some-network:
other-network:
该示例中,创建了2个networks,container1和container2可以通过通过网桥other-network进行通讯,container1可以通过some-network根其他容器通讯。
ports:指定宿主机和容器的端口映射,相当于docker run -p
示例:
services:
regx_mysql:
container_name: test_mysql
image: mysql:latest
ports:
- 3307:3306 # 宿主机的3307端口与容器的3306端口映射
volumes:
- ./data:/var/lib/mysql
environment:
- "MYSQL_ROOT_PASSWORD=wenxiaoba"
volumes:指定宿主机和容器的端口映射,相当于docker run -p
格式:
volumes:
- 宿主机路径(绝对路径|相对路径):容器路径(绝对路径)
- 宿主机路径2:容器路径2
如果想挂载数据卷容器,则services下的容器volumes字段中,:
前为数据卷容器名称,且与services同一层级定义volumes,声明数据卷容器。
宿主机路径的数据卷本章一开始的示例有介绍到,这里只说明下数据卷容器的使用
restart: always:指定docker容器总是运行,即保持容器始终运行,相当于docker run --restart=always
示例:
services:
regx_mysql:
container_name: test_mysql
image: mysql:latest
restart: always # 保持当前容器始终运行
ports:
- 3307:3306
volumes:
- ./data:/var/lib/mysql
environment:
- "MYSQL_ROOT_PASSWORD=wenxiaoba"
docker-compose命令的基本使用格式是:
docker-compose [-f=…] [options] [COMMAND] [ARGS…]
- -f,–file:指定使用的compose模板文件,默认为docker-compose.yml,-f可以指定文件(文件名可以不是docker-compose.yml)
- -p,–project-name:指定项目名称,默认是将
docker-compose命令说明教程包含了docker-compose的命令说明,重点关注up、down,其他的使用docker原生命令也可以达到
格式为: docker-compose up [options] [SERVICE…]
描述:该命令会自动完成包括构建镜像、(重新)创建容器、启动容器,并关联相关内容等一系列操作。
- 默认情况下,启动的容器都在前台,控制台会打印容器的输出信息,可以方便调试,·Ctrl-C`会停止所有容器
- 如果需要再后台启动容器,可以使用
-d
选项,即docker-compose up -d
,推荐生产环境使用-d
选项- 默认情况下,若项目所在容器已经存在,
docker-compose up
会将项目已有容器停止,再重新创建(但保持volumes-from挂载的数据卷【数据非常重要】),以保证新启动的服务匹配 docker-compose.yml 文件的最新内容- –force-recreate:强制重新创建容器,不能与 --no-recreate 同时使用。
- –no-recreate:如果容器已经存在了,则不重新创建,不能与 --force-recreate 同时使用。
- –no-deps:不启动服务所链接的容器(比如depends_on字段指向的容器)。
- 单独启动某个容器:
- 包含链接的容器(depends_on字段等):docker-compose up -d 服务名称
- 只有指定的容器:docker-compose up --no-deps -d 服务名称
注意:这里的服务名称是指services下一层的键名
格式:docker-compose down
描述:停止up命令所启动的容器,并移除网络(network)
格式:docker-compose exec 服务名称
进入指定的STATUS为UP的容器(非UP的进不了)
格式:docker-compose ps
列出当前docker-compose.yml所运行的服务
格式:docker-compose restart [服务名称]
根据当前docker-compose.yml重启已存在的容器(不创建,只重启)
在docker-compose.yml有定义,但是系统中不存在的容器,restart并不会创建并启动,restart只是重启已存在的在docker-compose.yml中有定义的容器
格式:docker-compose rm [服务名称]
根据当前服务名称删除对应的容器(容器必须是非UP状态)
格式:docker-compose logs [-f] [服务名称]
查看整个项目中所有(或某个)服务的运行日志
关于docker-compose.yml(-f参数的话可以是其他名称),模板字段的冒号:
后面必须有个空格,否则会被识别成字符串,比如image:redis
会被识别字符串”image:redis“,所以英文冒号后面记得加个空格