[docker] docker compose
docker compose
是一个简化运行 docker 指令的工具,它可以部分代替 docker build
和 docker 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 mode
❯ docker 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 去实现
这里的实现方法有两种:
-
直接指定 Dockerfile 所在的文件夹地址
这里可以使用相对路径,所以注释掉的代码用的是
build: ./backend
这种情况下 compose 会自动寻找该目录下的
Dockerfile
文件去运行 -
使用更细节的配置
这里提到的是
context
和dockerfile
context
是当前 container 的作用域,也就是说 Dockerfile 中所有会涉及到的文件——如COPY
操作所需要的文件都应存在于当前作用域,不然可能会导致 build 失败dockerfile
则是Dockerfile
的名称,默认情况下为Dockerfile
ports
即端口,可以暴露和 map 多个端口
环境参数
这里实现的方法有两种:
-
直接写
这里也有两种实现方法:
- MONGO_INITDB_ROOT_USERNAME=root
MONGO_INITDB_ROOT_PASSWORD: root
二者不可通用
两个都是 YAML 的语法,这里不多赘述
-
配置一个环境变量的文件
主流还是搭配一个
.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