目录

Docker - Compose

# 简介

Docker-compose 官网 (opens new window)

Docker-compose 指令地址 (opens new window)

Compose 项目是 Docker 官方的开源项目,负责实现对 Docker 容器集群的 快速编排。从功能上看,跟 OpenStack 中的 Heat 十分类似。

其代码目前在 https://github.com/docker/compose (opens new window) 上开源。

Compose 定位是「定义和运行多个 Docker 容器的应用(Defining and running multi-container Docker applications)」,其前身是开源项目 Fig。

在第一部分中的介绍,我们知道使用一个 Dockerfile 模板文件,可以让用户很方便的定义一个单独的应用容器。然而,在日常工作中,经常会碰到需要多个容器相互配合来完成某项任务的情况。例如要实现一个 Web 项目,除了 Web 服务容器本身,往往还需要再加上后端的数据库服务容器,甚至还包括负载均衡。

Compose 恰好满足了这样的需求。它允许用户通过一个单独的 docker-compose.yml 模板文件(HAML格式)来定义一组相关联的应用容器为一个项目(project)。

Compose 中有两个重要的概念:

  • 服务(service):一个应用的容器,实际上可以包括若干运行相同镜像的容器实例。

  • 项目( project):由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。

Compose 的默认管理对象是项目,通过子命令对项目中的一组容器进行便捷地生命周期管理。

Compose 项目由 Python 编写,实现上调用了 Docer 服务提供的 API 来对容器进行管理。因此,只要所操作的平台支持 Docker APl,就可以在其上利用 Compose 来进行编排管理。

笔记

Compose 就是一个 yml 文件,利用文件来替代 docker run 指令,大部分指令该指令存在的选项如 --name 等,Compose 都有。

2021-11-24 @Young Kbt

# docker-compose使用

相关概念

首先介绍几个术语:

  • 服务(service):一个服务就是一个应用容器,实际上可以运行多个相同镜像的实例
  • 项目(Project):由多个服务共同组成一个具有相同的业务逻辑单元,项目在 docker-compose.yml 里定义

使用 Compose 基本上是一个三步过程:

  1. 使用定义您的应用程序的环境,Dockerfile 以便它可以在任何地方复制。
  2. 定义组成您的应用程序的服务,docker-compose.yml 以便它们可以在隔离的环境中一起运行。
  3. 运行 docker compose upDocker compose command (opens new window)启动并运行你的整个应用程序。您也可以 docker-compose up 使用 docker-compose 二进制文件运行。

一个 docker-compose.yml 看起来像这样:

version: "3.9"  # 3.9 要求版本大于等于 v1.27.0
services:
  web:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/code
      - logvolume01:/var/log
    links:
      - redis
  redis:
    image: redis
volumes:
  logvolume01: {}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 安装与卸载

# 安装

  • Linux

    在 Linux 上的也安装十分简单,从官方 Gitub Release 处直接下载编译好的二进制文件即可。例如,在 Linux 64 位系统上直接下载对应的二进制包,

    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
    
    1

    要安装不同版本的 Compose,请替换 1.29.2 为您要使用的 Compose 版本。它将下载到 /usr/local/bin/ 目录。这是全局指令目录,建议放到这里。

  • 对二进制文件应用可执行权限:

    sudo chmod +x /usr/local/bin/docker-compose
    
    1
  • Mac、Windows

    Docker Desktop for Mac/Windows 自带 docker-compose 二进制文件,安装 Docker 之后可以直接使用。Compose 可以通过 Python 的包管理工具 pip 进行安装,也可以直接下载编译好的二进制文件使用,甚至能够直接在 Docker 容器中运行。

  • bash 命令补全

    sudo curl -L "https://raw.githubusercontent.com/docker/compose/1.29.2/contrib/completion/bash/docker-compose" > /etc/bash_completion.d/docker-compose
    
    1
  • 测试安装成功

    docker-compose -v
    # 或者
    docker-compose --version
    
    1
    2
    3

    如果提示权限不够,请先赋予权限

    sudo chmod +x /usr/local/bin/docker-compose
    
    1

# 卸载

如果是二进制包方式安装的,删除二进制文件即可。

sudo rm /usr/local/bin/docker-compose
1

如果您使用 pip 以下命令安装,则卸载 Docker Compose :

spip uninstall docker-compose
1

# Idea 工具

这里介绍使用 Idea 来操作 yml 文件,因为在 Linux 里,编写 yml 文件非常麻烦,要注意缩进两个空格,并非四个空格。

使用 Idea 工具连接 Linux:

image-20211124172551111

然后右侧弹出内容,点击 ... 进入配置:

image-20211124172925371

再次按下 OK 即可。

我是在 /opt/docker-compose 里进行操作:

image-20211124173043725

利用 Idea 可以实现从 Linux 系统里拉取文件(直接拖动到项目里,无法拖动到 Idea 界面外面)、创建文件,读写文件(双击会在 Idea 界面自动打开)等操作。

image-20211124173503422

# 模板文件

模板文件是使用 Compose 的核心,涉及到的指令关键字也比较多。但请不用担心,这里面大部分指令跟 docker run 相关参数的含义都是类似的。

首先这里说明一些,模板文件写好后是需要启动的,而启动的指令是 docker-compose up,如果打算后台启动,则是 docker-compose up -d,下面都是用到这个指令。如果想要详细了解更多指令,在 常用指令

默认的模板文件名称为 docker-compose.yml,格式为 YAML 格式。

version "3.0"

services:
  tomcat01:  # 服务名,唯一
    image: tomcat:8.5.73   # 启动的镜像
    ports:  # 端口映射,类似于 docker run 的 -p
      - 8080:8080
    volumes:  # 数据卷,类似于 ,类似于 docker run 的 -v
      - /data     # 匿名目录挂载
      - aa:/data   # 默认目录挂载
      - /opt/aa:   # 具体目录挂载
    networks:     # 网桥
      - kele

volumes:   # 声明服务用到的数据卷
  aa:    
    external: true   # 开启指定数据卷名,否则数据卷名的前缀是项目名
networks:   # 声明服务用到的网桥
  kele:
    external: true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

开头的 version 版本目前最高是 3.9。

注意每个服务都必须通过 image 指令指定镜像或 build 指令(需要 Dockerfile)等来自动构建生成镜像。

如果使用 build 指令,在 Dockerfile 中设置的选项例如:CND,EXPOSE,VOLUME,ENV 等)将会自动被获取,无需在 docker-compose.yml 中重复设置。

下面分别介绍各个指令的用法和例子。

每一个指令的例子都是独立的,没有关联,所以服务名可能重复,一个例子的容器信息不会出现在下一个例子中等等。所以是独立的!

# image

指定镜像名称或镜像 ID。如果镜像在本地不存在,Compose 将会尝试拉取这个镜像。

# 最新版
image: centos
# 版本号
image: centos:centos7
# 摘要
image: a4basdgv
1
2
3
4
5
6

例子 1:在 yml 文件里启动 tomcat 镜像

yml 文件内容:





 

version: "3.0"

services:
  tomcat01:  # 服务名,唯一
    image: tomcat:8.5.73
1
2
3
4
5

启动 yml 文件前,记得点击向上箭头在 IDEA 同步文件内容到 Linux。

启动 yml 文件的命令是 docker-compose up,如果后台启动,请加入 -d:docker-compose up -d


 




# 启动 yml 文件
docker-compose up -d

# 返回结果
Starting docker-compose_tomcat01_1 ... done
1
2
3
4
5

查看容器是否启动:






 

# 查看启动容器
docker ps

# 返回结果
CONTAINER ID   IMAGE           COMMAND             CREATED          STATUS          PORTS      NAMES
38c797769cc4   tomcat:8.5.73   "catalina.sh run"   56 seconds ago   Up 42 seconds   8080/tcp   docker-compose_tomcat01_1
1
2
3
4
5
6

容器启动成功,我们也可以看出容器的名字前缀都加上了 docker-compose,不再是 完全随机。

# ports

暴露端口信息,等价于 docker run -p

使用宿主端口∶容器端口(HOST:CONTAINER)格式,或者仅仅指定容器的端口(宿主将会随机选择端口)都可以。

ports:
  - "3000"
  - "8000:8000"
  - "80:80"
  - "127.0.0.1:8080:8080"
1
2
3
4
5

注意:当使用 HOST:CONTAINER 格式来映射端口时,如果你使用的容器端口小于 60 并且没放到引号里,可能会得到错误结果,因为 YAML 会自动解析 xx:yy 这种数字格式为 60 进制。为避免出现这种问题,建议数字串都采用引号包括起来的字符串格式。

例子 1:启动 tomcat,并指定两个映射端口

yml 文件内容:






 
 
 

version: "3.0"

services:
  tomcat01:  # 服务名,唯一
    image: tomcat:8.5.73
    ports:
    - "8081:8080"
    - "8082:8080"
1
2
3
4
5
6
7
8

启动 yml 文件,并验证是否启动:

# 启动 yml 文件
docker-compose up -d

# 返回结果
Starting docker-compose_tomcat01_1 ... done

# 查看启动的容器
docker ps

# 返回结果
CONTAINER ID   IMAGE           COMMAND             CREATED         STATUS         PORTS                                                                                  NAMES
c06c886ec78b   tomcat:8.5.73   "catalina.sh run"   7 seconds ago   Up 6 seconds   0.0.0.0:8081->8080/tcp, 0.0.0.0:8082->8080/tcp, :::8081->8080/tcp, :::8082->8080/tcp   docker-compose_tomcat01_1
1
2
3
4
5
6
7
8
9
10
11
12

# container_name

指定容器名称。默认将会使用 项目名称_服务名称_序号 这样的格式,等价于 docker run --name

container_name: docker-web-container  # 相当于 run 的 --name
1

注意:指定容器名称后,该服务将无法进行拓展(scale),因为 Docker 不允许多个容器具有相同的名称。

例子 1:启动 tomcat,指定容器名字

yml 文件内容:






 

version: "3.0"

services:
  tomcat01:  # 服务名,唯一
    image: tomcat:8.5.73
    container_name: tomcat01
1
2
3
4
5
6

启动 yml 文件,并查看容器是否启动:












 

# 启动 yml 文件
docker-compose up -d

# 返回结果
Starting tomcat01 ... done

# 查看启动容器
docker ps

# 返回结果
CONTAINER ID   IMAGE           COMMAND             CREATED         STATUS         PORTS      NAMES
777df200aa36   tomcat:8.5.73   "catalina.sh run"   3 seconds ago   Up 2 seconds   8080/tcp   tomcat01
1
2
3
4
5
6
7
8
9
10
11
12

如果容器已经在运行,则使用 yml 文件启动时,会将运行的容器停止,然后以新的 yml 文件配置重新启动。

# volumes

数挥卷所挂载路径设置。可以设置为宿主机路径(HOST:CONTAIMER)或者数据卷名称(VOLUNME:CONTATNER),并且可以设置访问模式(HOST:CONTAINER:ro)。该指令中路径支持相对路径,等价于 docker run -v

volumes:
  - /usr/local/tomcat   # 匿名目录挂载
  - aa:/usr/local/tomcat   # 默认目录挂载
  - /opt/aa:/usr/local/tomcat   # 具体目录挂载
  - ~/configs:/usr/local/tomcat:ro   # 指定容器的只读权限
1
2
3
4
5

如果是默认目录挂载,必须在文件中声明数据卷。






 
 


 
 

version "3.0"

services:
  tomcat01:  # 服务名,唯一
    image: tomcat:8.5.73
    volumes: 
      - aa:/usr/local/tomcat

# 必须在这里进行声明,否则报错
volumes:
  aa:
1
2
3
4
5
6
7
8
9
10
11

但是默认目录挂载生成数据卷名会加上项目名。如上方文件生成的数据卷名叫:docker-compose_aa,注意不是服务名,是项目名(yml 文件所在的目录名)。

如果不想要加上项目名,则加上 external 为 true。












 

version "3.0"

services:
  my_src:
    image: tomcat:8.5.73
    volumes: 
      - aa:/usr/local/tomcat

# 必须在这里进行声明,否则报错
volumes:
  aa:  # 声明数据卷名
    external: true  # 确认使用指定的数据卷名,前缀不会加上项目名
1
2
3
4
5
6
7
8
9
10
11
12

加入 external 为 true 又引起新的问题:如果该数据卷名不存在,则会报错,它不会主动创建不存在的数据卷,所以需要先手动创建数据卷。

例子 1:不加 external 为 true 的默认目录挂载

yml 文件内容:







 
 

version: "3.0"

services:
  tomcat01:  # 服务名,唯一
    image: tomcat:8.5.73
    container_name: tomcat01
    volumes:
    - tomcat:/usr/local/tomcat
1
2
3
4
5
6
7
8

如果直接启动 yml 文件,它会报错,知道为什么吗?

之前说过,使用 volumes 必须要进行声明,否则会报错:

ERROR: Named volume "tomcat:/usr/local/tomcat:rw" is used in service "tomcat01" but no declaration was found in the volumes section.
1

所以正确的 yml 文件内容:(声明数据卷)










 
 

version: "3.0"

services:
  tomcat01:  # 服务名,唯一
    image: tomcat:8.5.73
    container_name: tomcat01
    volumes:
    - tomcat:/usr/local/tomcat

volumes:  # 声明数据卷
  tomcat:
1
2
3
4
5
6
7
8
9
10
11

查看容器是否启动:

# 查看容器
docker ps

# 返回结果
CONTAINER ID   IMAGE           COMMAND             CREATED         STATUS         PORTS      NAMES
c8acd0e644ef   tomcat:8.5.73   "catalina.sh run"   4 seconds ago   Up 2 seconds   8080/tcp   tomcat01
1
2
3
4
5
6

查看数据卷是否会自动创建:



































 

# 查看数据卷
docker volume ls

# 返回结果
DRIVER    VOLUME NAME
local     docker-compose_tomcat

# 查看数据卷的宿主机位置
docker volume inspect docker-compose_tomcat 

# 返回结果
[
    {
        "CreatedAt": "2021-11-24T18:26:33+08:00",
        "Driver": "local",
        "Labels": {
            "com.docker.compose.project": "docker-compose",
            "com.docker.compose.version": "1.29.2",
            "com.docker.compose.volume": "tomcat"
        },
        "Mountpoint": "/var/lib/docker/volumes/docker-compose_tomcat/_data",
        "Name": "docker-compose_tomcat",
        "Options": null,
        "Scope": "local"
    }
]

# 进入数据卷的目录
cd /var/lib/docker/volumes/docker-compose_tomcat/_data

# 查看目录内容
ls

# 返回结果
bin  BUILDING.txt  conf  CONTRIBUTING.md  lib  LICENSE  logs  native-jni-lib  NOTICE  README.md  RELEASE-NOTES  RUNNING.txt  temp  webapps  webapps.dist  work
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

证明了创建的数据卷名带有项目名(yml 文件所在的目录名),并且说明了:默认目录挂载方式,容器的挂载目录内容覆盖了宿主机的挂载内容。

如果不想数据卷名带有项目名(yml 文件所在的目录名),请添加 external 为 true,看例子 2。

例子 2:加 external 为 true 的默认目录挂载

yml 文件:












 

version: "3.0"

services:
  tomcat01:  # 服务名,唯一
    image: tomcat:8.5.73
    container_name: tomcat01
    volumes:
    - tomcat:/usr/local/tomcat

volumes:
  tomcat:
    external: true
1
2
3
4
5
6
7
8
9
10
11
12

如果直接启动 yml 文件,它会报错,知道为什么吗?

前面说过,虽然此时的数据卷确实叫做 tomcat 而不是带有项目名,但是目前的 tocmat 数据卷就不存在,而 external 为 true 时,不会创建不存在的数据卷名。所以我们必修先创建数据卷:

docker volume create tomcat
1

启动 yml 文件














 

# 启动 yml 文件
docker-compose up -d

# 返回结果
Recreating tomcat01 ... done

# 进入数据卷目录
cd /var/lib/docker/volumes/tomcat/_data

# 查看目录内容
ls

# 返回结果
bin  BUILDING.txt  conf  CONTRIBUTING.md  lib  LICENSE  logs  native-jni-lib  NOTICE  README.md  RELEASE-NOTES  RUNNING.txt  temp  webapps  webapps.dist  work
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# networks

配置容器连接的网络,等价于 docker run --network

  • 利用 docker run 启动的容器,默认网桥名为 bridge
  • 利用 yml 文件启动的容器,默认网桥名为 docker-compose_default
version "3.0"

services:
  some-service:
    networks:
     - some-network
     - other-network

# 必须在这里进行声明,否则报错
networks:
  some-network
  other-network
1
2
3
4
5
6
7
8
9
10
11
12

volumes 一样:

  • 创建的网桥名默认加上项目名(yml 文件所在的目录名),如果不想加上项目名,请添加 external 为 true
  • 使用网桥需要进行声明,否则报错
  • 如果添加 external 为 true,该网桥必须先存在,否则报错,它不会主动创建不存在的网桥
version "3.0"

services:
  some-service:
    networks:
     - some-network
     - other-network

# 必须在这里进行声明,否则报错
networks:
  some-network  # 网桥名不加上项目名
    external:
      true
  other-network   # 这个网桥名会带有项目名前缀
1
2
3
4
5
6
7
8
9
10
11
12
13
14

例子 1:容器有两个网桥,一个网桥使用带有项目名,一个不带有项目名

yml 文件内容:







 
 
 

 
 
 
 
 

version: "3.0"

services:
  tomcat01:  # 服务名,唯一
    image: tomcat:8.5.73
    container_name: tomcat01
    networks:
      - kele
      - bing

networks:
  kele:
    external: 
      true
  bing:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

不演示 kele 网桥不存在报错的问题了,直接创建 kele 网桥:


 








 

# 创建网桥
docker network create kele

# 查看网桥
docker network ls

# 返回结果(部分)
NETWORK ID     NAME                     DRIVER    SCOPE
6a9007e442ce   bridge                   bridge    local
28f389726875   docker-compose_default   bridge    local
922ea0d2e922   kele                     bridge    local
1
2
3
4
5
6
7
8
9
10
11

启动 yml 文件:





 








 



# 启动 yml 文件
docker-compose up -d

# 返回结果
Creating network "docker-compose_bing" with the default driver
Creating tomcat01 ... done

# 查看网桥
docker network ls

# 返回结果(部分)
NETWORK ID     NAME                     DRIVER    SCOPE
6a9007e442ce   bridge                   bridge    local
6f723cfea57c   docker-compose_bing      bridge    local
28f389726875   docker-compose_default   bridge    local
922ea0d2e922   kele                     bridge    local
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

可以看到,yml 文件启动容器的默认网桥是 docker-compose_bing,而指定的 bing 网桥带有项目名(yml 文件所在的目录名):docker-compose_bing

# build

指定 Dockerfile 所在文件夹的路径(可以是绝对路径,或者相对 docker-compose.yml 文件的路径),Compose 将会利用它自动构建这个镜像,然后使用这个镜像,等价于 docker build

version "3.0"

services:
  tomcat01:
    build: ./dir  # 当前目录下的 dir 目录为上下文目录(Dockerfile 所在的目录)
1
2
3
4
5
  • 使用 context 指令指定 Dockerfile 所在文件夹的路径

  • 使用 dockerfile 指令指定 Dockerfile 文件名

  • 使用 arg 指令指定构建镜像时的变量,等价 docker build --build-arg,即给 ARG 变量传参

version "3.0"

services:
  tomcat01:   # 服务名,唯一
    build:
      context: /xxx   # 上下文命令:Dockerfile 所在的目录
      dockerfile: Dockerfile-otherName    # 默认叫 Dockerfile,如果是其他名,这里设置 
      args:       # 给 ARG 变量传参
        变量名:
1
2
3
4
5
6
7
8
9

例子 1:创建一个 Dockerfile 文件,并构建

首先创建一个 Dockerfile 文件,添加内容:(内容较少,这里只是演示 yml 文件进行构建,详细 Dockfile 内容请看:Docker - Dockerfile

FROM tomcat:8.5.73

ARG ARGS

RUN echo $ARGS
1
2
3
4
5

yml 文件内容:






 
 
 
 

version: "3.0"

services:
  container_name: tomcat01   #  容器名
  tomcat01:  # 服务名,唯一
    build:
      context: ./   # 指定上下文目录:Dockerfile 所在的目录
      args:
        ARGS: hello docker
1
2
3
4
5
6
7
8
9

启动 yml 文件,查看镜像是否生成和启动:









 






 

# 启动 yml 文件
docker-compose up -d

# 查看镜像
docker images

# 返回结果
REPOSITORY                TAG       IMAGE ID       CREATED        SIZE
docker-compose_tomcat01   latest    39e47af1a1c1   3 hours ago    249MB

# 查看运行的容器
docker ps

# 返回结果
CONTAINER ID   IMAGE                     COMMAND             CREATED         STATUS         PORTS      NAMES
c7f73ee44c49   docker-compose_tomcat01   "catalina.sh run"   2 minutes ago   Up 2 minutes   8080/tcp   tomcat01
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

可以看出,镜像名也是基于项目名(yml 文件所处的目录名)而命名的。

args 是否生效呢,请看构建过程图例:

image-20211124205401613

# depends_on

解决容器的依赖、启动先后的问题。

version "3.0"

services:
  服务名1:   
    image: 服务 1 镜像
    depends_on:
      - 服务名 2
      - 服务名 3
      
  服务名2:
    image: 服务 2 镜像
    
  服务名3:
    image: 服务 3 镜像
1
2
3
4
5
6
7
8
9
10
11
12
13
14

服务 1 启动前,先等服务 2 和服务 3启动后自己再启动。

注意: 服务 1 不会等待服务 2 和服务 3 「完全启动」之后才启动,两个服务启动过半即可。depends_on 必须是服务名

例子 1:先启动 redis、es 再启动 tomcat

yml 文件内容:





 
 
 
 
 
 
 
 
 

version "3"

services:
  tomcat:
    depends_on:
      - db
      - redis
      
  redis:
    image: redis
    
  es:
    image: elasticsearch
1
2
3
4
5
6
7
8
9
10
11
12
13

# environment

设置环境变量。你可以使用数组或字典两种格式。

只给定名称的变量会自动获取运行 Compose 主机上对应变量的值,可以用来防止泄露不必要的数据。

有两种形式:

  • key: value
  • - key=value
# 形式 1
environment:
  RACK_ENV: development
  SESSION_SECRET: 123456

# 形式 2
environment:
  - RACK_ENV=development
  - SESSION_SECRET=123456
1
2
3
4
5
6
7
8
9

如果变量名称或者值中用到 true | false,yes | no 等表达 布尔 含义的词汇,最好放到引号里 (如 "true" | "false"),避免 YAML 自动解析某些内容为对应的布尔语义。这些特定词汇,包括:

y|Y|yes|Yes|YES|n|N|no|No|NO|true|True|TRUE|false|False|FALSE|on|On|ON|off|Off|OFF
1

例子 1:启动 MySQL 时,需要密码

我们都知道,启动 MySQL 镜像,需要给 MySQL 密码,否则报错。给定密码格式 docker run -e MYSQL_ROOT_PASSWORD=密码 mysql

yml 文件内容:







 


version: "3.0"

services:
  container_name: tomcat01   #  容器名
  tomcat01:  # 服务名,唯一
    image: mysql:8.0.27   # 启动的 MySQL 镜像
    environment:
      MYSQL_ROOT_PASSWORD: 123456   # 假设这是 MySQL 密码
1
2
3
4
5
6
7
8

# env_file

从文件中获取环境变量,可以为单独的文件路径或列表。其实就是把上面的 environment 变量(数据库密码)放到一个 .env 文件里,然后引用这个文件(就相当于引用变量)

如果通过 docker-compose -f FILE 方式来指定 Compose 模板文件,则 env_file 中变量的路径会基于模板文件路径。

如果镜像自带的变量名称与 environment 指令冲突,则按照惯例,以后者为准。

两种形式:

  • 单文件: .env
  • 多文件:- .env、- .env
# 单文件
env_file: .env

# 多文件
env_file:
  - ./common.env
  - ./apps/web.env
  - /opt/secrets.env
1
2
3
4
5
6
7
8

环境变量文件中有一个必须符合格式,支持 # 开头的注释行,且内容格式是 key=value

# common.env: Set development environment
PROG_ENV=development
1
2

例子 1:在 mysql.env 文件里加上 MySQL 密码

mysql.env 文件内容:(先创建 touch mysql.env

# 这是一个 MySQL 环境变量文件
MYSQL_ROOT_PASSWORD=123456
1
2

yml 文件内容:






 
 

version: "3.0"

services:
  tomcat01:  # 服务名,唯一
    image: mysql:8.0.27   # 启动的 MySQL 镜像
    env_file:
      - ./mysql.env   # 存放 MySQL 密码的 .env 文件
1
2
3
4
5
6
7

# command

覆盖容器启动后默认执行的命令,等价于 docker run 镜像 command 的 command。

command: echo "hello docker"
1

例子 1:启动 redis,开启 AOP 持久化

我们知道,启动 redis 持久化的 docker 指令是:docker run redis redis-server --appendonly yes

yml 文件内容:











 




version: "3.0"

services:
  redis:   # 服务名,唯一
    image: redis  
    container_name: redis
    ports:    # 映射端口
      - "6379:6379"
    volumes:     # 数据卷
      - redisData:/data
    command: "redis-server --appendonly yes"    # 启动容器执行的命令
    
volumes:   # 声明数据卷
  redisData:
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# healthcheck

通过命令检查容器是否健康运行。

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost"] # 发生请求
  interval: 1m30s   # 发送请求时间
  timeout: 10s  # 超时时间
  retries: 3  # 重试次数
1
2
3
4
5

例子 1:启动 tomcat,并不断检测检测健康运行







 
 
 
 
 

version: "3.0"

services:
  mysql01:  # 服务名,唯一
    image: mysql:8.0.27   # 启动的 MySQL 镜像
    container_name: mysql
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"] # 发生请求
      interval: 1m30s   # 发送请求时间  
      timeout: 10s  # 超时时间
      retries: 3  # 重试次数
1
2
3
4
5
6
7
8
9
10
11

启动后,Docker 每隔 1 分 30 秒发送一次 curl -f http://localhost 的 CMD 请求,如果 10 秒内不响应,则重试 3 次。

# sysctls

用来配置容器中系统内部参数﹒并不是必须有些服务启动受容器内操作系统参数限制可能会无法启动必须通过修改容器中参数才能启动。

sysctls:  
  net.core.somaxconn: 1024
  net.ipv4.tcp_syncookies: 0

# 必须在这里进行声明,否则报错
sysctls:
  - net.core.somaxconn: 1024
  - net.ipv4.tcp_syncookies: 0
1
2
3
4
5
6
7
8

必须声明。

例子 1:

yml 文件内容:







 
 
 


 
 
 

version: "3.0"

services:
  mysql01:  # 服务名,唯一
    image: mysql:8.0.27   # 启动的 MySQL 镜像
    container_name: mysql
    sysctls:  
      net.core.somaxconn: 1024
      net.ipv4.tcp_syncookies: 0

# 必须在这里进行声明,否则报错
sysctls:
  - net.core.somaxconn: 1024
  - net.ipv4.tcp_syncookies: 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# ulimits

指定容器的 ulimits 限制值。

例如,指定最大进程数为 65535,指定文件句柄数为 20000 (软限制,应用可以随时修改,不能超过硬限制)和 40000 (系统硬限制,只能 root 用户提高)。

ulimits:
  nproc: 65535
  nofile:
    soft: 20000
    hard: 40000
1
2
3
4
5

例子 1:

yml 文件内容:







 
 
 
 
 

version: "3.0"

services:
  mysql01:  # 服务名,唯一
    image: mysql:8.0.27   # 启动的 MySQL 镜像
    container_name: mysql
    ulimits:
    nproc: 65535
    nofile:
      soft: 20000
      hard: 40000
1
2
3
4
5
6
7
8
9
10
11

# 模板文件参考

version: "3.0"

services:
  
  tomcat01:  # 服务名,唯一
    container_name: tomcat01  # 相当于 run 的 --name
    image: tomcat:8.5.73   # 启动镜像,相当于 run image
    ports:  # 用来完成 host 与容器的端口映射关系,相当于 run -p
      - "8080:8080"
    volumes:  # 完成宿主机与容器中目录数据卷共享相当于 run -v
    # - /root/apps:/usr/local/tomcat/webapps  # 使用具体目录挂载
      - tomcat01:/usr/local/tomcat  # 使用默认目录挂载
    networks:    # 代表当前服务使用哪个网络桥,相当于 run --network
      - kele
  
  tomcat02:  # 服务名,唯一
    container_name: tomcat02  # 容器名
    image: tomcat:8.5.73    # 镜像
    ports:     # 映射端口
      - "8081:8080"
    volumes:  # 宿主机和容器的数据卷共享
      - tomcat02:/usr/local/tomcat  # 使用默认目录挂载
    networks:   # 代表当前服务使用哪个网络桥
      - kele

  tomcat03:
    build:   # 构建模式,相当于 docker build 
      context: ./    # 指定上下文的路径:Dockerfile 所在的目录
      args:   # 传参,相当于 docker build --build-arg
        ARGS: hello docker     
  
  mysql:
    image: mysql:8.0.27
    container_name: mysql
    ports:
      - "3307:3306"
    volumes:
      - mysqlData:/var/lib/mysql
      - mysqlConf:/etc/myconf
    environment:
      - MYSQL_ROOT_PASSWORD=123456
    networks:
      - kele
  
  redis:
    image: redis:5.0.10
    container_name: redis
    ports:
      - "6379:6379"
    volumes:
      - redisData:/data
    networks:
      - bing
    command: "redis-server --appendonly yes"  # run 镜像之后来覆盖容器内默认命令
    
volumes:   # 声明上面的服务所使用的自带创建的数据卷名
  tomcat01:   # 声明指令的数据卷名,compose 自带创建该卷,但是会加入项目名作为前缀
    external:  # 使用自定义数据卷名
      true    # 代表确认使用指定的数据卷名,注意:一旦使用外部自定义数据卷名,启动服务前必须手动创建 
  tomcat02:
  mysqlData:
  mysqlConf:
  redisData:
    
networks:   # 声明服务用到的网桥
  kele:    # 定义上面的服务用到的网桥,默认创建时 bridge
    external:    
      true    # 使用外部指定的网桥,注意:启动前网桥必须存在
  bing:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

# 常用指令

# 模板指令和常用指令的区别

  • 模板指令:用来书写在 docker-compose.yml 文件中指令称之为模板指令用来为服务进行服务的
  • 常用指令:用来对整个 docker-compose.yml 对应的这个项目操作

# 命令对象格式

对于 Compose 来说,大部分命令的对象既可以是项目本身,也可以指定为项目中的服务或者容器。如果没有特别的说明,命令对象将是项目,这意味着项目中所有的服务都会受到命令影响。

执行 docker-compose [COMMAND] --help 或者 docker-compose help [CONMAND] 可以查看具体某个命令的使用格式。

docker-compose 命令的基本的使用格式是:

docker-compose [-f=<arg> ......] [options] [COMMAND] [ARGS ......]
1

# 命令选项

-f <模板文件名>
--file <模板文件名>
指定使用的 Conpose 模板文件,默认为 docker-compose.yml,可以多次指定
-p <项目名>
--project-name 项目名
指定项目名称,默认将使用所在目录名称作为项目名
--x-networking 使用 Docker 的可拔插网络后端特性
--x-network-driver <驱动名> 指定网络后端的驱动,默认为 bridge
--verbose 输出更多调试信息
-v
--version
打印版本并退出

例子 1:假设不叫 docker-compose.yml 文件,叫 kele.yml 文件,启动它

docker-compose -f kele.yml up
1

例子 2:虽然 docker-compose.yml 文件在 aa 目录下,但是我希望项目名不叫 aa 名,而是叫 bb,启动它

docker-compose -P bb up
1

# up

启动 yml 文件里的单个/所有服务,如果不指定服务 id,默认启动所有服务。

格式:docker-compose up [options] [ service ... ]

docker-compose up [options] [ service .. . ]

# 后台启动
docker-compose up -d [ service ...]

# 指定 yml 文件所在的目录启动
docker-compose -f <文件路径> up
1
2
3
4
5
6
7
  • 该命令十分强大,它将尝试自动完成包括构建镜像,(重新)创建服务,启动服务,并关联服务相关容器的一系列操作

  • 链接的服务都将会被自动启动,除非已经处于运行状态

  • 可以说,大部分时候都可以直接通过该命令来启动一个项目

  • 默认情况,docker-compose up 启动的容器都在前台,控制台将会同时打印所有容器的输出信息,可以很方便进行调试

  • 当通过 Ctrl-C 停止命令时,所有容器将会停止

  • 如果使用 docker-compose up -d,将会在后台启动并运行所有的容器。一般推荐生产环境下使用该选项

  • 默认情况,如果服务容器已经存在,docker-compose up 将会尝试停止容器,然后重新创建(保持使用 volumes-from 挂载的卷),以保证新启动的服务匹配 docker-compose.yml 文件的最新内容

# down

此命令将会停止 up 命令启动的单个/所有服务,并移除自己创建的网络,但不会移除数据卷。

格式:docker-compose down [ service ...]

docker-compose down [ service ...]
1

# exec

进入指定的服务,使用的是服务 id,并非容器 id。

格式:docker-compose exec [ service ] [窗口命令]

docker-compose exec [ service ] [窗口命令]
1

# ps

列出项目中目前的单个/所有服务,如果不指定服务 id,默认列出所有服务。

格式:docker-compose ps [options] [ service ...]

docker-compose ps [options] [ service ...]
1

选项:

  • -q:只打印容器的 ID 信息。

# restart

重启项目中的单个/所有服务,如果不指定服务 id,默认重启所有服务。

格式:docker-compose restart [options] [ service ...]

docker-compose restart [options] [ service ...]
1

选项:

  • 简写:-t,完整 --timeout 时间数:重启前停止容器的超时(默认为 10 秒)

# rm

删除单个/所有(停止状态的)服务,如果不指定服务 id,默认删除所有服务。推荐先执行 docker-compose stop 指令来停止容器给再删除。

格式:docker-compose rm [options] [ service ...]

docker-compose rm [options] [ service ...]
1

选项:

  • 简写 -f、完整 --force:强制直接删除,包括运行状态的容器,一般尽量不要使用该选项
  • -v:删除容器所挂载的数据卷,同样慎用

# start

启动已经存在的单个/所有服务。

格式:docker-compose start [service ...]

docker-compose start [service ...]
1

# stop

停止已经处于运行状态的单个/所有服务,但不会删除它,如果不指定服务 id,默认停止所有服务。通过 docker-compose start 可以再次启动这些容器。

格式:docker-compose stop [options] [ service ...]

docker-compose stop [options] [ service ...]
1

选项:

  • 简写:-t,完整 --timeout 时间数:停止容器时候的超时(默认为 10 秒)

# top

查看单个/所有服务内运行的进程。

格式:docker-compose top [ service ...]

docker-compose top [ service ...]
1

# pause

暂停单个/所有服务。

格式:docker-compose pause [ service ...]

docker-compose pause [ service ...]
1

# unpause

恢复处于暂停状态的单个/所有服务。

格式:docker-compose unpause [ service ...]

docker-compose unpause [ service ...]
1

# logs

查看单个/所有服务的日志信息。

格式:docker-compose logs [ service ...]

docker-compose logs [ service ...]
1
更新时间: 2024/01/17, 05:48:13
最近更新
01
JVM调优
12-10
02
jenkins
12-10
03
Arthas
12-10
更多文章>