[docker] docker compose

docker compose 是一个简化运行 docker 指令的工具,它可以部分代替 docker builddocker run 指令,但是无法取代 docker 指令,更不会取代容器和镜像。它可以运行单个或多个容器,通过运行 YAML 配置好的文件建造镜像和运行容器

不过 docker compose 有个缺点,它无法管理不同 hosts 上的容器——这个需要通过 类似于 docker swarm/kubernetes 这样的工具去进行管理

docker compose 文件

这里不会过多涉及 YAML/YML 的语法,下面分成一个个的 service,每个 service 是在 services 这个 key 下

不包含 service 具体实现的框架如下:

version: "3.8"
services:
  mongodb:
  backend:
  frontend:

volumes:
  data:
  logs:

命名规范——默认为 docker-compose.yaml,运行指令时需要在 docker-compose.yaml 同一个文件夹里运行

mongodb

mongodb:
  # container_name: mongodb
  image: "mongo"
  volumes:
    - data:/data/db
  # environment:
  #   # - MONGO_INITDB_ROOT_USERNAME=root
  #   MONGO_INITDB_ROOT_PASSWORD: root
  #   MONGO_INITDB_ROOT_USERNAME: root
  env_file:
    - ./env/mongo.env

backend

backend:
  # build: ./backend
  build:
    # should be the highest common parent level
    context: ./backend
    # can be omitted if the name is same as Dockerfile
    dockerfile: Dockerfile
  ports:
    - "80:80"
  volumes:
    - logs:/app/logs
    # can use relative path here
    - ./backend:/app
    - /app/node_modules
  env_file:
    - ./env/backend.env
  depends_on:
    - mongodb

frontend

frontend:
  build: ./frontend
  volumes:
    - ./frontend/src:/app/src
  ports:
    - "3000:3000"
  stdin_open: true
  tty: true
  depends_on:
    - backend

运行

讲配置之前先简单的提一下运行

up

安装最新版本的 docker 可以直接通过 docker compoe 去运行,如下面就是直接运行 docker compoe up 的结果:

docker compose up
[+] Running 1/0
 ✔ Container compose-mongodb-1  Created                                                                                                                    0.0s
Attaching to mongodb-1
# will hang here, but can stop using cmd+c
# run detached modedocker compose up -d
[+] Running 1/1
 ✔ Container compose-mongodb-1  Started                                                                                                                    0.0s
❯ docker compose down
[+] Running 2/2
 ✔ Container compose-mongodb-1  Removed                                                                                                                    0.1s
 ✔ Network compose_default      Removed

默认情况下 docker compoe up 不会在 detached 模式下运行,但是可以直接使用 cmd/ctrl+c 的方式去终结运行。一旦 docker compoe up 被终止,那么所有的容器就会进入终止状态:

[+] Stopping 1/2d with code 0
 ✔ Container compose-frontend-1  Stopped                                                                                                                   0.7s
[+] Stopping 3/3pose-backend-1   Stopping                                                                                                                  0.6s
 ✔ Container compose-frontend-1  Stopped                                                                                                                   0.7s
 ✔ Container compose-backend-1   Stopped                                                                                                                   0.7s
 ✔ Container compose-mongodb-1   Stopped                                                                                                                   0.1s
mongodb-1 exited with code 0
canceled
❯ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
❯ docker ps -a
CONTAINER ID   IMAGE              COMMAND                  CREATED          STATUS                     PORTS     NAMES
04fd7da5b373   compose-frontend   "docker-entrypoint.s…"   18 seconds ago   Exited (1) 7 seconds ago             compose-frontend-1
9ad9301633bd   compose-backend    "docker-entrypoint.s…"   18 seconds ago   Exited (1) 7 seconds ago             compose-backend-1
72c2fbe335e4   mongo              "docker-entrypoint.s…"   18 seconds ago   Exited (0) 6 seconds ago             compose-mongodb-1
9888e9d4cf74   mysql              "docker-entrypoint.s…"   2 days ago       Exited (0) 2 days ago                mysql

添加 -d flag 可以在 detached 模式下运行 docker compose

down

docker compose down 可以用来终止并清理所有通过 docker-compose.yaml 管理的容器,如:

docker ps -a
CONTAINER ID   IMAGE              COMMAND                  CREATED          STATUS                     PORTS     NAMES
04fd7da5b373   compose-frontend   "docker-entrypoint.s…"   18 seconds ago   Exited (1) 7 seconds ago             compose-frontend-1
9ad9301633bd   compose-backend    "docker-entrypoint.s…"   18 seconds ago   Exited (1) 7 seconds ago             compose-backend-1
72c2fbe335e4   mongo              "docker-entrypoint.s…"   18 seconds ago   Exited (0) 6 seconds ago             compose-mongodb-1
9888e9d4cf74   mysql              "docker-entrypoint.s…"   2 days ago       Exited (0) 2 days ago                mysql
❯ docker compose down
[+] Running 4/4
 ✔ Container compose-frontend-1  Removed                                                                                                                   0.0s
 ✔ Container compose-backend-1   Removed                                                                                                                   0.0s
 ✔ Container compose-mongodb-1   Removed                                                                                                                   0.0s
 ✔ Network compose_default       Removed                                                                                                                   0.1s
❯ docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED      STATUS                  PORTS     NAMES
9888e9d4cf74   mysql     "docker-entrypoint.s…"   2 days ago   Exited (0) 2 days ago             mysql

network

默认情况下所有 docker-compose 中管理的容器都会在同一个 docker network 中,没有特殊需求可以不用配置

build 镜像

默认情况下,如果 docker-compose.yaml 文件中有配置的话,那么 docker compsoe 指令会在找不到所需的镜像这一情况下自动 build

如果想要强制 docker compose 去重新 build 镜像,可以使用 build 这个 arg

docker compose build
[+] Building 1.4s (17/17) FINISHED                                                                                                         docker:desktop-linux
 => [backend internal] load .dockerignore                                                                                                                  0.0s
 => => transferring context: 68B                                                                                                                           0.0s
 => [backend internal] load build definition from Dockerfile                                                                                               0.0s
 => => transferring dockerfile: 202B                                                                                                                       0.0s
 => [frontend internal] load metadata for docker.io/library/node:latest                                                                                    1.1s
 => [frontend 1/5] FROM docker.io/library/node@sha256:162d92c5f1467ad877bf6d8a098d9b04d7303879017a2f3644bfb1de1fc88ff0                                     0.0s
 => [backend internal] load build context                                                                                                                  0.0s
 => => transferring context: 924B                                                                                                                          0.0s
 => CACHED [frontend 2/5] WORKDIR /app                                                                                                                     0.0s
 => CACHED [backend 3/5] COPY package.json .                                                                                                               0.0s
 => CACHED [backend 4/5] RUN npm install                                                                                                                   0.0s
 => CACHED [backend 5/5] COPY . .                                                                                                                          0.0s
 => [backend] exporting to image                                                                                                                           0.0s
 => => exporting layers                                                                                                                                    0.0s
 => => writing image sha256:0b50e06210a6786efef5e4b403eed36760a9fac59a81b75c5b0ba0070918c0e6                                                               0.0s
 => => naming to docker.io/library/compose-backend                                                                                                         0.0s
 => [frontend internal] load build definition from Dockerfile                                                                                              0.0s
 => => transferring dockerfile: 147B                                                                                                                       0.0s
 => [frontend internal] load .dockerignore                                                                                                                 0.0s
 => => transferring context: 70B                                                                                                                           0.0s
 => [frontend internal] load build context                                                                                                                 0.0s
 => => transferring context: 4.31kB                                                                                                                        0.0s
 => CACHED [frontend 3/5] COPY package.json .                                                                                                              0.0s
 => CACHED [frontend 4/5] RUN npm install                                                                                                                  0.0s
 => CACHED [frontend 5/5] COPY . .                                                                                                                         0.0s
 => [frontend] exporting to image                                                                                                                          0.0s
 => => exporting layers                                                                                                                                    0.0s
 => => writing image sha256:98fe0b6f0a0f89aa2c1b36a7a1c54006e5dd0f522209a4d59f2cf768a14c911a                                                               0.0s
 => => naming to docker.io/library/compose-frontend                                                                                                        0.0s

⚠️:docker compose build 不会运行容器,只会重新 build 镜像

配置

接下来补充一下配置的内容

version

这部分可以通过官方文档查看:Compose file versions and upgrading

具体还是要看用的是什么 docker engine,大多数情况下可以使用 3.8,即 docker engine 19.03.0+

目前我的版本是:

docker engine --version
Docker version 24.0.7, build afdd53b

虽然本机上安装的不是最新的版本,不过只差了 3 个 minor 版本,也可以看到大多数情况下用 3.8 就够了

services

services 下面列举的是一个个单独的 service,service 可以理解成容器的具体描述,即一个容器应当如何配置和如何运行

以上面列举的配置为例,mongodb 指的就是当前 service 的名称,并不是容器的名称。比如说 service 的名称是 frontend,但是 docker 容器的名称为 compose-frontend-1

在 docker swarm 的情况下——我们项目用的是 Kubernetes,所以我应该不会设计 swarm,service 指的是不同的东西

volumes

本片配置中,volumes 出现在两个地方,一个和 services 平级,一个在单独的 service 里

和 services 平级的 volumes 是整个 compose 文件中所有出现过的命名卷及其配置——本片配置出现的都是极简配置。和 services 平级的 volumes 并不是强制要求定义的,不过一般来说被认为是个 good practice

在单独的 service 中的 volumes 则是当前容器会使用的 volume,包含 bind mounts,anonymous volume 和 named volume

image

这是在当前 service 使用的是别人已经实现好的 image 的情况下使用

如上面实现的 mongodb,我这里没有 load 其他的数据看不需要额外的 Dockerfile 去实现,所以直接使用 image 即可

build

这是在需要 tailor 别人实现的 image,添加自己的代码

前后端有自己实现的代码,需要运行 Dockerfile 去 build 镜像,这里就会使用 build 去实现

这里的实现方法有两种:

  1. 直接指定 Dockerfile 所在的文件夹地址

    这里可以使用相对路径,所以注释掉的代码用的是 build: ./backend

    这种情况下 compose 会自动寻找该目录下的 Dockerfile 文件去运行

  2. 使用更细节的配置

    这里提到的是 contextdockerfile

    context 是当前 container 的作用域,也就是说 Dockerfile 中所有会涉及到的文件——如 COPY 操作所需要的文件都应存在于当前作用域,不然可能会导致 build 失败

    dockerfile 则是 Dockerfile 的名称,默认情况下为 Dockerfile

ports

即端口,可以暴露和 map 多个端口

环境参数

这里实现的方法有两种:

  1. 直接写

    这里也有两种实现方法:

    • - MONGO_INITDB_ROOT_USERNAME=root
    • MONGO_INITDB_ROOT_PASSWORD: root

    二者不可通用

    两个都是 YAML 的语法,这里不多赘述

  2. 配置一个环境变量的文件

    主流还是搭配一个 .env 文件,如 mongo.env 的内容为:

    MONGO_INITDB_ROOT_PASSWORD=root
    MONGO_INITDB_ROOT_USERNAME=root
    

depends_on

这是在有依赖关系的时候使用,如后端项目依赖于 mongodb 实现,那么后端的 depends_on 就是 mongodb

这个会和优先级/排序有关系,可以被依赖的容器存在,但是无法完全保证被依赖的项目一定会初始完毕。要保证被依赖的容器已经成功初始化,可以被连接,还需要使用其他的工具辅助

container_name

容器最终会使用的名称,可选

项目比较小/简单的时候用不用都可以,当然,用了更具有指向性

stdin_open & tty

就是 -it,进入 interact mode 和 teletypewriter

04-29 15:11