0


Docker Compose 快速入门教程(看完解决大部分疑惑问题)

本教程只用来快速入门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 的安装

安装方式有两种:

  1. 第一种是直接独立安装docker-compose
  2. 第二种是基于docker enginedocker 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 filebuild属性。

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只读访问权限。
  • zSELinux 选项,指示绑定挂载主机内容在多个容器之间共享。
  • ZSELinux 选项,指示绑定挂载主机内容是私有的且不与其他容器共享。

后两个模式没用过,应该用得不多,这里也不做解释了。

如果想看更复杂的用法请参考官网。

简单的例子:

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参数和所有子命令导航

标签: docker 容器

本文转载自: https://blog.csdn.net/weixin_73227648/article/details/143995359
版权归原作者 我是小牛吗 所有, 如有侵权,请联系我们删除。

“Docker Compose 快速入门教程(看完解决大部分疑惑问题)”的评论:

还没有评论