本教程只用来快速入门docker compose,至于后续的高阶用法,如涉及到环境变量,很复杂的命令行参数(简单的命令行用法我会提)等,这里不再提,如果我个人有兴致,我会再出一次Docker Compose进阶教程。
Docker Compose官网:https://docs.docker.com/compose/
时间:2024年11月18日22:25:01
Docker Compose是什么
Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务
即:原本使用 docker 的时候,可能面临许多问题(尽管 docker 本身已经是一个非常优秀的工具了),比如无法修改正在运行的容器的配置,想在另一台服务器启动相同的容器的时候需要重新编写命令,某些容器之间有依赖关系时需要以正确的顺序去依次启动容器,等等一系列问题,而 docker-compose 就可以很完美的解决这些问题,只需要正确的编写
<font style="color:rgb(51, 51, 51);">compose-file.yaml</font>
文件,然后去运行 compose 命令即可
Docker Compose 的安装
安装方式有两种:
- 第一种是直接独立安装
docker-compose
- 第二种是基于
docker engine
和docker cli
安装docker compose plugin
,两种方式命令有略微差别(一丢丢,无伤大雅)
我这里选择第二种方式,因为我已经安装过
docker engine
和
docker cli
了,所以我选择不再独立安装
docker-compose
,而且经过查询后有种说法是
docker compose plugin
的性能会更好一些,因为和
docker engine
关系更紧密
# 以ubtuntu24.04为例sudoapt-get update
sudoapt-getinstall docker-compose-plugin
安装后使用以下命令检查是否安装成功:
docker compose version
# 如果使用第一种方式安装,则用docker-compose --version
如果安装成功则会出现类似:
Docker Compose version v2.29.7
的字样
Docker-compose-file.yaml 的编写
首先就是需要遵循yaml的格式要求:https://www.runoob.com/w3cnote/yaml-intro.html > > 文件规范的官网:https://docs.docker.com/reference/compose-file/ 参考性还是非常高的 >
具体我们分成六部分来讲:··
version 和 name 顶级属性
https://docs.docker.com/reference/compose-file/version-and-name/
- version
首先! 在目前官网的介绍中,已经将
version
弃用了! 但是不可避免有些老一点的版本还是会用到这个值的,所以我还是介绍一下这个是干嘛的! 但是既然官网都已经表明弃用了,所以我还是建议大家不要去写这个值!
version
表明当前
compose-file.yaml
文件用的是第几版的
docker-compose规范
! 如果使用的是新版的编写规范,但是却声明了较旧的
version
值,会导致那些新版本才出现的语法会出现警告! 如果不写这个
version
值则默认使用最新的
docker-compose规范
!
- name
该值用来表明项目的名字,至于这个名字有什么用,目前我能体验的就是将启动后的容器用更好的标识区分开来(这个值官方有尝试说明他的作用,举例了三种,但是太高深了,目前我没理解明白和体验到)。
name
的规范只能包含小写字母、十进制数字、破折号和下划线,并且必须以小写字母或十进制数字开头。如果不声明
name
的话,默认会用该yaml文件所在的目录作为
name
的值。
举个简单的例子:
~/study-docker-compose/docker-compose.yaml
效果:
在项目中执行
docker compose -f docker-compose.yaml up
后运行情况
帮我们创建的容器长这样:
可见,指定了
name
属性后,帮我们创建的容器格式叫做:
**name-服务id-容器id**
(后面我们可以自定义容器的名字,会覆盖掉这里的默认行为,但那都是后话了,我们这里只简单的提一嘴。有容器id的原因是我们可能一下子启动好几个该容器,所以docker会自动帮我们编码)
PS: 其实name属性不仅会影响到容器的名字,还有可能影响到挂载卷名和网络名,比如:
挂载卷在yaml中设置的名字叫做customVolume,那他运行后创建的可能就是
name_customVolume
自定义网络在yaml中设置的名字叫做customNetwork,那他运行后创建的可能就是
name_customNetwork
所有设置name属性的方式和其对应的优先级
设置
name
的方式有很多,官方官网给出了5种可能的情况,并为他们设置了优先级:
我们这里来简单的提一嘴除了第二种以外的几条(第二种涉及到环境变量了,太复杂了,如果后面我确实需要用到了,我会过来补档的)
第一条:涉及到
docker compose
的命令行语法了,这里贴一个官方链接docker compose 命令行 教程,这个链接里面有
docker compose命令的参数
和
docker compose 子命令
的教程,里面有提到,在启动yaml文件的时候
-p
参数可以直接以最高优先级设置
name
属性,即项目的名字。
第三条:如果yaml文件中有
name
属性,则会使用该属性的值作为项目名字。如果使用
docker compose
一下子使用
-f
参数启动了多个yaml文件,这会涉及到docker compose 多yaml文件 合并规范,里面有提出,如果有多个yaml文件,多个文件中重复设置的属性,前面文件设置的属性会被后面文件重复的属性所覆盖。所以第三条后半句的意思就是,如果启动时带有多个设置了
name
属性的yaml文件,会以最后一个设置
name
属性的yaml文件的
name
属性为主。
第四条:刚开始我看这一条没看懂是什么意思,感觉和第三条重复了,但是经过查询后发现,这里的意思是。如果yaml文件中没设置
name
属性值,则会以该yaml文件所在的目录为项目的名字,如果启动时带有多个未设置
name
属性的yaml文件,那么会以第一个yaml文件所在的目录的名字为项目名。
第五条:这句话的意思是如果直接使用
docker compose up
启动的时候,没有通过
-f
参数去指定具体的yaml文件,也就是让
docker compose up
以本目录下
docker-compose.yaml
文件所在的目录为项目名。(其实我认为和第四条重了)
services 顶级属性
官网链接:https://docs.docker.com/reference/compose-file/services/
这里要讲的东西还是非常多的!但是我们只挑出一些我们经常用到的来讲,那些不经常用到的东西,后来我们需要的时候再去官网去查就行了!
编写services这一层,其实就是将原本的
docker run
命令拆成配置文件的过程。
一个简单的例子
举个例子,我需要用wordpress和mysql镜像去搭建一个博客,原本的docker命令创建是这样的:
# wordpress依赖mysql,所以先通过命令创建mysql容器,再创建wordpress容器
docker run -d -p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=root \# -e 配置容器内环境变量
-e MYSQL_DATABASE=wordpress \
-v mysql-data:/var/lib/mysql \
-v /app/myconf:/etc/mysql/conf.d \
--restart always --name mysql \
--network blog \
mysql:8.3.0
docker run -d 8001:80 \
-e WORDPRESS_DB_HOST=mysql \# 因为和mysql处于同一个网络中,所以可以直接通过容器名进行访问
-e WORDPRESS_DB_USER=root \
-e WORDPRESS_DB_PASSWORD=root \
-e WORDPRESS_DB_NAME=wordpress \
-v wordpress:/var/www/html \
--restart always --name wordpress-app \
--network blog \
wordpress:latest
现在我们要用docker compose,那就需要把他变现到yaml配置文件中,上面这行命令最终变现后的结果为:
services:mysql:container_name: mysql # container_name属性,可以覆盖docker compose默认设置的容器名image: mysql:8.3.0 # 使用的镜像ports:# 映射端口,可以映射多个-"3306:3306"environment:# 配置环境变量- MYSQL_ROOT_PASSWORD=root
- MYSQL_DATABASE=wordpress
volumes:# 配置挂载卷,有两种写法,这里采用的是简略版写法- mysql-data:/var/lib/mysql
- /app/myconf:/etc/mysql/conf.d
restart: always # 设置重启方式networks:# 设置要加入网络- blog
wordpress:image: wordpress
ports:-"8001:80"environment:- WORDPRESS_DB_HOST=mysql
- WORDPRESS_DB_USER=root
- WORDPRESS_DB_PASSWORD=root
- WORDPRESS_DB_NAME=wordpress
volumes:- wordpress:/var/www/html
restart: always
networks:- blog
depends_on:# 依赖关系,wordpress容器需要在mysql容器创建后再创建- mysql
volumes:mysql-data:# 这里可以对mysql-data容器卷进行更详细的配置# 但是我们用不到这些配置,所以这里让mysql-data这个容器卷出现一次代表创建了这么一个容器卷就行了wordpress:# 同上networks:blog:# 这里也是可以对blog这个网络进行一些详细的配置# 但是我们同样目前也用到这些配置,所以这里让blog这个网络出现一次代表创建了这么一个网络就行了
关于例子细节和小总结
如果入门的话还是非常的简单的,但是如果要讲细节还需要去官网看详细。
从上面我们可以注意到:
services
属性下的每一个一级属性直接就是每一个服务。然后这个属性名就是服务的id。- 对于每个服务,我们又可以对其进行详细配置,就像用docker命令的参数一样对服务容器进行配置。
然后下面我们将挑一些比较重要的属性讲一讲。讲解的顺序按照属性的字典序。
annotation
这个属性是给容器添加注释的,他不会给容器造成实质性的作用,有两种语法,分别是:
annotations:com.example.foo: this is a test container
annotations:- com.example.foo=this is a test container
一般是用不到的,因为可以直接看yaml文件中的注释,但是避免有些时候容器太多,翻yaml文件也翻半天,而且可能有些人在yaml中不写注释。
写了这个以后通过
docker inspect <容器ID或容器名称>
可以打印出对应容器的信息,里面可以看到注释的内容。指的一提的是,docker好像原生并没有给容器添加注解的参数,但是有类似的
label
参数,不过使用起来好像还是有些许区别的,而且
compose
本身也会用
label
给容器添加很多信息,但是这里不再对
label
做出讲解,感兴趣的话自行搜索,或者我后面感兴趣的话会专门针对
label
再讲一下。
举例子:
# 运行命令
docker inspect <容器ID或容器名称>| grep -i -A 2 annotations
# 打印结果"Annotations":{"com.example.foo":"this is a test container"},
container_name
这个属性是指定容器的名字的,原本容器创建的时候compose
会有默认的规则去生成名字,我之前也提到过。如果使用了container_name
属性会导致原本声明容器名的默认规则失效。值的一提的是,手动指定了容器名以后就无法再使用scale
属性了,尝试这么做会报错!
depends_on
有时候我们会遇到一个容器必须在另一个容器启动起来后再启动。之前使用docker的命令行的时候,我们是手动控制命令执行的顺序来解决的,现在,用depends_on
这个属性来解决这个问题。
有两种语法格式 - 长语法 和 简洁语法
- 简洁语法
直接声明依赖启动的服务即可,例如,
web
服务需要在
redis
和
db
创建后启动。
services:web:build: .
depends_on:- db # 直接以数组的格式声明依赖的服务即可- redis
redis:image: redis
db:image: postgres
值得一提的是,在利用
docker compose down
删除容器的时候,会按照和
depends_on
相反的顺序去删除容器。比如在上面的例子中,删除的顺序就是先删除
web
后删除
db
和
redis
。
- 长语法
有长语法的原因是允许用户去配置简洁语法所无法配置的选项,不过一般是用不到长语法的。但是还是可以提一下,多出的配置项有:
restart
:设置为
true
的时候,会导致在配置了该属性的依赖服务更新的时候,重启本服务。
condition
:用来设置满足依赖关系的条件,有三个可以设置的值。
service_started
:短语法默认就是这个属性。代表在依赖服务启动后再创建启动该容器。
service_healthy
: 代表在依赖服务启动并通过“健康检查”后再创建启动该容器。
<font style="color:rgb(0, 0, 0);">service_completed_successfully</font>
: 代表在依赖服务正式启动并且运行完成(退出代码为0)后再创建启动该容器。(ps:该项通常用于一些用来进行数据迁移的服务,或者一些用于初始化的服务)
我们还是以web和redis与db之间的关系来用长语法举个例子:
services:web:build: .
depends_on:db:condition: service_healthy
restart:trueredis:condition: service_started
redis:image: redis
db:image: postgres
enviroment
该属性用来设置容器内的环境变量,有两种语法格式,一种是映射格式,另一种是数组格式
- 映射格式
environment:RACK_ENV: development
SHOW:"true"USER_INPUT:
- 数组格式
environment:- RACK_ENV=development
- SHOW=true
- USER_INPUT
值得一提的是,compose还提供了通过
env_file
的形式去设置容器的环境变量,但是他涉及到了
.env
文件和其对应的语法,形式上复杂了很多,这里不再详细讲解,而且
environment
也可以和这种方式联动,比如:在
environment
中仅仅声明变量但是并没有赋值,这样子会让compose去尝试通过在指定的
.env
文件中去找其对应的值,如果找不到则丢弃该环境变量。
build
这个东西太复杂了,涉及到很多东西,就连普通的docker命令我也只是docker build
命令简单的配合docker file
文件去创建项目的镜像而已。这里我们同样讲如何利用docker file
和build
属性。
在
build
属性的子属性中我只介绍两个属性,一般也就用到这两个,分别是
context
和
dockerfile
- context
context
属性用来指定dockerfile的目录的路径,支持相对路径。
- dockerfile
dockerfile
用于指定dockerfile的目录,支持相对路径,是相对于
context
所指定的路径而言的。
一个简单的例子:
name: test
services:hello:build:context: ./ddf
dockerfile: dockerfile
这样子就会帮我们根据本项目目录下的
ddf/dockerfile
文件去构建一个镜像,然后再根据这个镜像去启动容器,构建的镜像的根据默认规则叫做
项目名-服务id
,后面我会讲如何修改这个镜像的名字。
image
image
属性干的内容非常的简单,就是指明构建容器要使用哪个镜像(或者给本地构建的镜像改名字)。
但是有一些点需要注意,如果
**image**
属性和
**build**
属性都同时存在,根据
pull_policy
属性的默认规则,会默认先看云端docker仓库中是否有和
image
属性对应的镜像,如果有则直接拉取云端镜像并使用,如果云端没有,那么会尝试通过
build
属性的内容通过本地dockerfile文件构建一个本地的镜像,然后这个本地镜像的名字和
**image**
属性所指定的镜像一样(这样也可以另外达到修改本地构建的镜像的名字的效果)
一个简单的例子:
name: test
services:hello:build:context: ./ddf
dockerfile: dockerfile
image: lihaotian-hello # 云端肯定没有这个镜像,因为是我自己取的名字
可以看到我们通过
build
属性本地构建的容器的名字确实因为
image
属性而发生了改变。
pull_policy
这个属性用来指定docker compose
拉取镜像的规则。
这个属性可以设定的值四个,分别是
always
,
never
,
missing
,
build
。
compose默认是
always
,也就是始终尝试从注册表中拉取镜像,不管本地是否有镜像的缓存。
never
则是只会在本地寻找镜像。
missing
则是在本地没有镜像的时候,才会尝试去远程仓库中拉取镜像。
build
在官网说的太浅了,我猜测应该是每次都会尝试重新构建镜像,不管本地是否有镜像。
restart
就和通过命令行设置一样,compose同样提供了几个可选的值。
no
:默认重启策略。在任何情况下它都不会重新启动容器。
always
:该策略始终重新启动容器,直到将其删除。
on-failure[:max-retries]
:如果退出代码指示错误,该策略将重新启动容器。 (可选)可以在后面加参数来限制 Docker 守护进程最大尝试重新启动的次数。
unless-stopped
:无论退出代码如何,策略都会重新启动容器,但在服务停止或删除时停止重新启动。(PS:我个人认为
unless-stopped
和
always
是没区别的)
一个简单的例子:
restart:"no"restart: always
restart: on-failure
restart: on-failure:3restart: unless-stopped
ports
只说简单用法,以字符串数组的形式去声明要映射的端口。格式为[主机端口:]服务端口
。
可以指定单个端口,也可以指定一个范围的端口。
如果不指定主机端口的话,则服务端口会自动分配给主机任意未分配使用的端口。不过我们一般都手动指定。
如果想看更复杂的用法请参考官网。
一个简单的例子:
ports:-"3000"-"3000-3005"-"8000:8000"-"9090-9091:8080-8081"-"8000-9000:80"
sacle
设置一次启动多少个服务。如果设置了scale
则不能使用container_name
,原因很简单,之前我们说过container_name
会修改compose默认的服务命名规则,导致compose无法给服务名自动添加服务id
,从而导致compose无法批量启动服务。
networks
只说简单用法,直接以数组的形式声明要把该服务连接到哪些网络中去。连接到的这些网络必须在networks
顶级属性中定义过!
如果想看更复杂的用法请参考官网。
简单的例子:
services:some-service:networks:- some-network
- other-network
# networks顶级属性中必须定义上面services中出现的网络networks:some-network:other-network:
network_mode
一般用不到这个,但是还是提一嘴。可选的值有四个,分别是none
关闭所有网络, host
设置服务的网络模式是主机模式, 剩下的service:{name}
, container:{name}
我就不解释了,因为我也没用过。
为什么我要说这个用的不多,因为我们后面会说到
networks
,这个属性是自定义网络,我们在学docker的时候就知道,容器一旦设置了自定义网络,那么就无法再使用网络模式了,也就是
networks
和
network_mode
冲突。因此,设置
network_mode
后,不允许使用
networks
属性,并且 Compose 会拒绝任何包含这两个属性的 Compose 文件!
volumes
只说简单用法,直接以数组的形式声明挂载卷的形式。具体的格式为VOLUME:CONTAINER_PATH[:ACCESS_MODE]
。使用到的挂载卷必须在volumes
顶级属性中定义过!
volume
:可以是主机路径,也可以是具体卷名称。
CONTAINER_PATH
:安装卷的容器中的路径。
ACCESS_MODE
(可选):
rw
读写访问。如果未指定,则这是默认值。ro
只读访问权限。z
SELinux 选项,指示绑定挂载主机内容在多个容器之间共享。Z
SELinux 选项,指示绑定挂载主机内容是私有的且不与其他容器共享。
后两个模式没用过,应该用得不多,这里也不做解释了。
如果想看更复杂的用法请参考官网。
简单的例子:
services:some-service:volumes:- mysql-data:/var/lib/mysql
- /app/myconf:/etc/mysql/conf.d
# volumes顶级属性中必须定义上面services中出现的具体卷名volumes:mysql-data:
networks顶级属性
目前仅需要知道如何创建一个自定义网络即可。如果有遇到进阶用法,我会在这里补充。
https://docs.docker.com/reference/compose-file/networks/
一个简单的例子:
services:frontend:image: example/webapp
networks:- front-tier
- back-tier
networks:front-tier:# 这里出现一次自定义网络名就相当于定义了一个自定义网络# 这里原本肯定可以对自定义网络再进行详细的配置# 但是目前我用不到,所以没有对networks的子属性再进行详细的讲解了back-tier:
值的一提的是,我之前说过,项目目录的名字会影响到最后创建的网络名(即
项目名_自定义网络名
),如果不想受到这个的限制,则可以使用
networks
下的子属性
name
。
volumes顶级属性
目前仅需要知道如何创建一个具名挂载卷即可。如果有遇到进阶用法,我会在这里进行补充。
https://docs.docker.com/reference/compose-file/volumes/
一个简单的例子:
services:backend:image: example/database
volumes:- db-data:/etc/data
backup:image: backup-service
volumes:- db-data:/var/lib/backup/data
volumes:db-data:# 这里出现一次具名挂载卷就相当于定义了一个具名挂载卷# 这里原本肯定可以对挂载卷再进行详细的配置# 但是目前我用不到,所以没有对volumes的子属性再进行详细讲解了
值的一提的是,我之前说过,项目目录的名字会影响到最后创建的具体卷名(即
项目名_具体卷名
),如果不想受到这个的限制,则可以使用
volumes
下的子属性
name
。
Docker compose 常用命令
docker compose 参数
我只讲我用过的,或者用的较多的。
https://docs.docker.com/reference/cli/docker/compose/
上面的这个链接里有docker compose下的所有参数和其子命令,里面可以看到很多之前用过的参数,比如
-f
指定yaml文件,
-p
指定项目名等。
这里我为什么要把
docker compose
参数单独拎出来说?因为接下来就会讲很多
docker compose
的子命令,如:
docker compose up
等,他们也是有参数的,他们的参数需要跟在他们后面,如
docker compose up
这个子命令有一个参数叫做
--no-recreate
,那么他应该这么加:
docker compose -p project_name up --no-recreate
。
docker compose up
https://docs.docker.com/reference/cli/docker/compose/up/
启动应用程序。它会创建和启动定义在
docker-compose.yml
文件中的所有服务,并将所有服务的容器输出出来。如果想细化到一个服务的子集去输出,则可以在
up
后面加上
--attach
参数去指定。
docker compose up <service>
可以单独启动某个服务。
注意不是
container_name
,而是
service_name
!(这里有点像consul或者nacos那味,体会一下,容器可能有很多个,但是都是一个服务)。
如果启动过服务的容器后,服务的配置,也就是yaml文件发生变化,这时再次使用
docker compose up
命令会自动检测那些服务的配置发生了改变,然后对于那些配置发生了变化的服务进行重新创建,停掉的服务重新启动,没有变化的服务则不会重新创建。但是如果加了
--no-recreate
参数,则再次使用该命令只会重新创建启动那些停止了的容器,正在运行的容器则不会重新构建,无论他的配置是否发生变化。如果加了
--force-recreate
参数,则再次使用该命令的时候,无论服务的配置是否发生变化,Compose 都会尝试重新创建启动所有服务!
重新创建服务的过程会保留原来已安装的卷,所以不用担心数据问题。
docker compose down
https://docs.docker.com/reference/cli/docker/compose/down/
停止并移除应用程序的所有容器、网络和卷。
使用该命令的时候,会停掉并删除所有程序的容器,在yaml文件中定义的网络。默认网络(如果有使用)。
但是不会删除定义的外部网络和所有卷(为了数据嘛,可以理解)。
值的一提的是,默认也不会删除匿名卷,但是因为后续再次通过
docker compose up
启动服务的时候,是无法使用之前的匿名卷的,所以如果要在更新后还继续使用之前的数据,请使用具名挂载卷。
docker compose version
查看当前docker compose的版本。
docker compose ps
列出正在运行的容器。
docker compose logs
查看应用程序的日志输出。
docker compose build
构建在 docker-compose.yml
文件中定义的服务。如果你修改了 Dockerfile 或应用程序代码,需要重新构建镜像。
docker compose stop
停止运行中的应用程序,但不会移除容器。
docker compose start
启动停止的应用程序。
docker compose restart
重新启动应用程序的容器。
docker compose exec
在指定的服务容器内执行命令。例如,docker-compose exec app bash
可以在 app
服务容器内打开一个 Bash 终端。
docker compose pull
拉取定义在 docker-compose.yml
文件中的所有服务所需的镜像,但不会启动容器。
学习过程所有用到的参考链接
ChatGPT [这里不得不感谢AI帮我引出了很多知识]
yaml教学
dockerfile语法
docker compose yaml 文件语法规范导航页
version和name顶级元素
compose yaml中项目名称的作用以及设置项目名称的几种方法
运行docker compose命令时同时指定多个yaml文件时的合并规则 ①
运行docker compose命令时同时指定多个yaml文件时的合并规则 ②
services顶级属性下的所有子属性
networks顶级属性
volumes顶级属性
docker compose参数和所有子命令导航
版权归原作者 我是小牛吗 所有, 如有侵权,请联系我们删除。