一、关于虚拟化、容器化

1.1 虚拟化

虚拟化是工作在硬件层,提供一整套“虚拟的”硬件接口(装过黑苹果的,改配置文件时一定深有体会)。这一套提供”虚拟硬件接口“的软件,叫做 HYPERVISOR

HYPERVISOR 有两种类型,一种是工作在宿主机之上,即作为一款应用程序,比如常用的 VMWare WorkStation、VMWare Fusion、Virtual Box 等;另一种是工作在硬件上,作为一款系统软件,对硬件资源进行分配,在这种工作方式下没有真正的宿主机,所有虚拟机都直接在硬件上工作

1.2 容器化

在硬件层之上,便是操作系统层、函数层(系统调用、glibc等)、应用层。我们的容器化,就是作用在操作系统层(lxc),或者应用层(docker)

容器化依赖于 Linux 的 namespace 和 cgroups(c 代表 control 的意思)。namespace 负责完成资源的隔离,比如文件系统、共享内存、进程id等等;cgroups 负责完成资源上限的约束,使得容器不会过度占用主机资源

早期的 Docker 基于 lxc。所谓 lxc,就是 Linux Contianer 的意思。

lxc 工作在操作系统层,让各个容器和宿主机共用一个内核(对于 Linux 来说,发行版之间虽然千差万别,但是都用的是一个 Linux 内核,不过在新旧、补丁上有些许不同),完成在操作系统上的虚拟化,更形象的:

Libraries
shared kernel
-------  ^ lxc container
lxc
glibc、Libraries...
------------------------------ ^ user space
System Call Interface
...
------------------------------ ^ kernel space

这样,通过 namespace 和 cgroup ,lxc就可以将一个内核,“虚拟化”为多个内核供给 lxc 容器使用。相比与模拟硬件的虚拟化,lxc 使用的容器化跳过了内核的初始化等流程,快捷、轻量的多

Docker 现在做的是应用层的虚拟化,即:只打包一个应用和他所需要的所有运行时环境,不打包完整的的系统。这意味着 Docker 更加轻量快捷专一

1.3 namespace

Docker 各个容器资源的隔离,是基于 Linux 原生提供的能力,namespace 就是将主机名、进程 pid、网络端口、文件系统隔离开来的。

首先认识以下命令:

dd if=/dev/zero of=test.img bs=1k count=1024 conv=sync # 从 Linux 只会输出空文件的特殊设备 /dev/zero 读取1024 * 1k 的数据到 test.img,不做缓存
mkfs -t ext4 test.img # 将test.img 格式化为ext4文件系统
mkdir -p /data/test # 创建挂载点
mount test.img /data/test # 将格式化的文件系统挂载到 /data/test,所谓挂载其实就是给文件系统创建一个入口
df -h # 带有 kb mb gb 单位的显示磁盘信息

unshare 是 Linux 提供给我们的创建新进程的命令,可以指定要隔离哪些资源,比如

  1. -p,隔离进程 pid,这种情况建议搭配 --mount-proc、–fork 使用。新的进程默认会使用 unshare 的进程作为父进程,但是它又不属于新的 namespace,所以 cannot allocate memory,需要 --fork 创建新的进程作为父进程;/proc/PID 存放着 PID 进程的各种信息,如果想要依赖于 /proc 的命令也正常隔离信息,就需要完成文件系统中 /proc 的隔离,Linux 特意提供了 --mount-proc 来隔离 /proc 下的进程信息。整条命令实例:unshare --fork -p --mount-proc /bin/bash
  2. -u,隔离主机名
  3. -m,不共享 mount 挂载空间,即隔离后挂载的文件系统不可见

1.4 cgroup

cgroup 意为 controll group,可以限制分配给一个进程的资源。不过在实操前需要认识两个命令:

1.4.1 pidstat

是 sysstat 提供的命令之一,格式为 pidstat <option> [时间间隔] [次数],option 常见选项有:

  1. -u,查看 cpu 资源
  2. -d,查看磁盘 IO
  3. -r,查看内存
  4. -C,通过命令而不是 pid 筛选进程
  5. -l,显示命令时完整显示
  6. -p,通过进程 pid 筛选,ALL 表示全部

1.4.2 stress

可以对磁盘、内存、cpu 等造成压力,语法为:

root@DESKTOP-OFM10JG:~# stress --help
`stress' imposes certain types of compute stress on your system

Usage: stress [OPTION [ARG]] ...
 -q, --quiet        be quiet
 -t, --timeout N    timeout after N seconds
     --backoff N    wait factor of N microseconds before work starts
 -c, --cpu N        spawn N workers spinning on sqrt()
 -i, --io N         spawn N workers spinning on sync()
 -m, --vm N         spawn N workers spinning on malloc()/free()
     --vm-bytes B   malloc B bytes per vm worker (default is 256MB)
     --vm-stride B  touch a byte every B bytes (default is 4096)
     --vm-hang N    sleep N secs before free (default none, 0 is inf)
     --vm-keep      redirty memory instead of freeing and reallocating
 -d, --hdd N        spawn N workers spinning on write()/unlink()
     --hdd-bytes B  write B bytes per hdd worker (default is 1GB)

Example: stress --cpu 8 --io 4 --vm 2 --vm-bytes 128M --timeout 10s

1.4.3 通过 cgroup 操作 cpu 限制

基于 cgroupv2

  1. 进入 cgroup 的内存控制目录 /sys/fs/cgroup,创建测试文件夹 test_cpu

  2. 系统为我们做好了初始化,这里我们关注两个文件,cgroup.procs 和 cpu.max

    root@DESKTOP-OFM10JG:/sys/fs/cgroup/test_cpu# ls
        cgroup.controllers      cgroup.stat.local       cpu.stat.local       memory.max           memory.swap.events
        cgroup.events           cgroup.subtree_control  cpu.weight           memory.min           memory.swap.high
        cgroup.freeze           cgroup.threads          cpu.weight.nice      memory.numa_stat     memory.swap.max
        cgroup.kill             cgroup.type             io.pressure          memory.oom.group     memory.swap.peak
        cgroup.max.depth        cpu.idle                memory.current       memory.peak          pids.current
        cgroup.max.descendants  cpu.max                 memory.events        memory.pressure      pids.events
        cgroup.pressure         cpu.max.burst           memory.events.local  memory.reclaim       pids.events.local
        cgroup.procs            cpu.pressure            memory.high          memory.stat          pids.max
        cgroup.stat             cpu.stat                memory.low           memory.swap.current  pids.peak
    
  3. 控制 cpu 使用率,cpu使用率 的计算公式cfs_quota_us/cfs_period_us,其中

    • cfs_quota_us 表示一个 cpu 带宽,单位为微秒。系统 cpu 总带宽,默认为 100000
    • cfs_period_us,cgroup 用来限制 cpu 带宽,单位为微妙,最小为 1000
  4. 在 cpu.max,中,将 max 设置为 30000

  5. 开启 stress,进行 cpu 压力

root@DESKTOP-OFM10JG:~# stress -c 1
stress: info: [1600] dispatching hogs: 1 cpu, 0 io, 0 vm, 0 hdd
  1. 使用 pidstat 进行资源监视
root@DESKTOP-OFM10JG:~# pidstat -C stress -u 1 1000
Linux 6.18.33.2-microsoft-standard-WSL2 (DESKTOP-OFM10JG)       07/28/26        _x86_64_        (12 CPU)

11:05:44      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
11:05:45        0      1601  100.00    0.00    0.00    0.00  100.00     2  stress

11:05:45      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
11:05:46        0      1601  100.00    0.00    0.00    0.00  100.00     2  stress

11:05:46      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
11:05:47        0      1601  100.00    0.00    0.00    0.00  100.00     2  stress
  1. 将 stress 进程加入 cgroup 控制的进程中(cgroup.procs)
root@DESKTOP-OFM10JG:/sys/fs/cgroup/test_cpu# echo 1601 > cgroup.procs
  1. 可以发现,stress 的 cpu 使用率受到控制
11:06:08      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
11:06:09        0      1601  100.00    0.00    0.00    0.00  100.00     2  stress

11:06:09      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
11:06:10        0      1601  100.00    0.00    0.00    0.00  100.00     2  stress

11:06:10      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
11:06:11        0      1601   92.00    0.00    0.00    7.00   92.00     2  stress

11:06:11      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
11:06:12        0      1601   30.00    0.00    0.00   70.00   30.00     2  stress

11:06:12      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
11:06:13        0      1601   30.00    0.00    0.00   70.00   30.00     2  stress

11:06:13      UID       PID    %usr %system  %guest   %wait    %CPU   CPU  Command
11:06:14        0      1601   30.00    0.00    0.00   70.00   30.00     2  stress

二、Docker 使用

2.1 基础命令

2.1.1 docker run

docker run 用来创建(如果本地没有该容器)并开启容器。docker run 可以认为是 Docker 最核心的操作之一,参数如下

  • -d,在后台运行
  • -i + -t,两者通常搭配使用,前者表示交互式运行,后者表示分配一个伪终端给容器(即能够通过 CLI 交互)
  • --rm,当前 shell 关闭时,删除容器
  • -P 以及 -p,端口映射,后者指定 主机端口:容器端口,前者随机映射
  • -m,指定容器内存上限
  • -v,类似于端口映射,不过这里映射的是文件系统
  • --name=...,指定容器名称
  • -e user_name=...,指定环境变量

2.1.2 docker images

查看本地所有的镜像

2.1.3 docker ps

查看由镜像创建的容器,会展示运行信息。-q 表示只展示 containerid,可以用来批量清除 docker rm $(docker ps -aq)

2.1.4 docker save && docker load

将指定镜像保存为 .tar 文件,例如:

docker save -o ubuntu.tar ubuntu;
docker load -i ubuntu.tar

这样,只需要传递打包后的文件,就可以把容器从一个主机传到另一个主机了(当然 docker hub 也可以)。

在不允许联网的情况下,也可以通过 scp 将打包的镜像文件通过 ssh 协议传输给另一台机器,例如

ssh ubuntu.tar user@ip:directory

2.1.5 docker cp

在宿主机和容器之间拷贝文件,格式为 宿主机目录 容器名称:容器目录

2.1.6 docker port

查看某个容器的端口映射

2.1.7 docker tag

给一个镜像打上标签表明归属于远端那个仓库,后续可以通过 docker push 完成镜像的推送。远端存储镜像时,一方面会进行压缩,另一方面对于已经存在的镜像不会重复存储

2.1.8 docker commit

从某个容器中制作出来新的镜像

2.1.9 docker import/export

将容器制作为 tar 包,导入。与 save/load 相比,export/import 操作的是容器而不是镜像,不保留 layer 等镜像元信息,因此 save/load 使用的更多

2.1.10 docker stats/docker top

前者实时查看容器的资源占用, 后者通过 ps 的方式查看(比如 docker top nginx_test aux)

常见问题

  1. docker create 和 docker start 和 docker run 的区别
    docker create 是从镜像创建一个容器,但是并不启动;docker start 是启动一个已经创建好的容器,可以是 docker stop 结束运行的容器,也可以是刚刚通过 docker create 创建的容器;docker run 是创建并启动一个容器(如果本地镜像的话会从 docker 仓库拉取)
  2. docker export 和 docker save
    docker save 是对镜像文件操作,打包成 tar 文件,同时保存镜像源信息(如 layer 信息和历史记录),相对更大一些,通过 tar 文件导入搭配 docker load;docker export 是对容器操作,直接把这份容器形成 tar 文件,不再保留镜像元信息和联合文件系统每一层的信息,所以相对更小,搭配 docker import 导入

2.2 什么是镜像

镜像,本质上是一个只读文件,其中是一个文件系统,我们叫做 联合文件系统

联合文件系统 中是若干层文件系统,本身是只读的,但在创建镜像时,可以有只读、读写、写出的权限。创建镜像时,由底层向上,每一层文件系统都挂载在上一层并彻底覆盖上一层的可见性。

这里的每一层文件系统,我们都叫做 layer

2.3 什么是容器

如果把镜像比作一个 C++ 中的模板或者类定义的话,那么容器就是一个 实例化对象。他是可修改的,为应用提供一个可供操作的运行时环境。

容器的状态一共有以下几种

  • Created,初创状态
  • Running,运行中
  • Paused,暂停
  • Stopped,终止状态
  • Deleted,删除状态

使用 docker pull 下载镜像后,进入初创状态

使用 docker run 运行容器,进入运行状态(如果本地没有,就先拉取,随后立即进入运行状态)

使用 docker stop 停止容器运行,进入终止状态

使用 docker pause 暂停容器运行,使用 docker unpause 恢复容器运行

使用 docker rm 删除容器,进入删除状态

OOM(Out of Memory)

前面我们说过,在 Linux 中,容器使用 namespace 做资源隔离,用 cgroup 做资源上限限制。当容器中内存资源到达上限之后(上限通过 docker run 的 -m 参数指定,或者是 docker create),宿主机操作系统就会杀死相应容器进程(每个容器都有一个 init 进程,当它被杀死或退出时,就是一个容器退出了)

如果没有指定 -m,那么容器就没有内存资源上限;如果指定了 -m 并且设置 --oom-kill-disable ,内存资源沾满后,就不会杀死容器,但也不会分配更多资源,这个容器进入类似挂起状态

2.3 存储卷

Docker 这种通过 namespace 隔离出资源的处理方式,一旦在容器出现故障无法继续使用后,里面存储的数据就很难恢复了。其实 Docker 的容器化更加适合无状态的处理应用。从宿主机到容器我们可以使用 docker cp,但是每一次手动做很麻烦;而且对于我们使用 mysql、redis 这里存储类应用的镜像的话,从容器到宿主机的文件交流也比较难以实现。

举个例子,我们的容器其实是我们建在地面上的小木屋,而我们的被映射的宿主机路径,就是一个地下室。当有一天地面上挂了台风摧毁了地面上的小木屋(容器由于某些原因崩溃),我们的地下室是不受影响的,我们在地下室内的物品(我们存储在映射文件路径中的数据)也是不受影响的。而我们创建存储卷的行为,就是获取这个打开地下室门的钥匙

2.3.1 管理卷

Volume 卷操作

  1. docker volume create,创建卷
  2. docker volume inspect,查看详细卷信息,比如挂载点、创建时间等
  3. docker volume prune,清除掉不使用的卷
  4. docker volume rm,删除某个卷
  5. docker volume ls,列出所有卷

通过 -v 或者 --mount 绑定卷

  1. -v my_vol:/app,将前面创建的卷 my_vol 绑定到容器的 /app 目录

  2. --mount type=volue,src=my_vol,dst=/app,将前面创建的卷 my_vol 绑定到容器的 /app 目录,type有 bindvolumetmpfs

    • volume,docker 自动管理数据卷,容器停止时数据依然存在,默认位置在 /var/lib/docker,可以共享
    • bind,绑定卷,可以自己指定绑定位置,数据也立即同步,但是注意权限问题,可以共享
    • tmpfs,在内存中临时的数据存储区域,容器停止即销毁
    • volume、bind、tmpfs,都会覆盖容器目的目录的内容(不是删除),但是有一些区别:volume,首次空卷挂载的时候,会复制容器目录中的内容;bind 不会进行复制,并且会直接显示宿主机相应目录的内容;tmpfs 会直接进行覆盖,而且总是空的,容器关闭后临时文件系统的内容会被清除

绑定 tmpfs 临时文件系统

  1. --tmpfs /app
  2. --mount type=tmpfs,dst=/app

2.3.2 Mysql 灾难恢复

mysql 的持久化文件存放在 /var/lib/mysql,因此,只要我们保证 mysql 的持久化未见不丢失,就能够保证数据的安全性。

  1. 创建 mysql 容器,并设置挂载卷,将持久化数据放到宿主机文件系统
05:58:10 root@DESKTOP-OFM10JG ~ → docker run -it -d --name=mysql_test -e MYSQL_ROOT_PASSWORD=123456 -v /data/mysql:/var/lib/mysql mysql
621ec938cfbdbb0fe96ccbcb232d11df36f286b831a1c565a5ef00b264f489d5
  1. 创建数据库、表,插入数据
ysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.005 sec)

mysql> create database test;
Query OK, 1 row affected (0.008 sec)

mysql> use test
Database changed
mysql> create table testTB(
    -> id int primary key,
    -> name varchar(30)
    -> );
Query OK, 0 rows affected (0.016 sec)

mysql> insert into testTB(id, name) values(1, "wjl");
Query OK, 1 row affected (0.003 sec)
  1. 假设接下来遇到灾难事件,比如机房停电或者其它故障,最后直接导致原来的镜像无法使用。停止并删除容器
07:42:35 root@DESKTOP-OFM10JG ~ → docker stop mysql_test;
mysql_test
07:42:43 root@DESKTOP-OFM10JG ~ → docker rm mysql_test
mysql_test
  1. 开始灾难恢复,重新创建 mysql 容器并以相同的方式设置挂载卷
07:42:46 root@DESKTOP-OFM10JG ~ → docker run -it -d --name=mysql_test -e MYSQL_ROOT_PASSWORD=123456 -v /data/mysql:/var/lib/mysql mysql
6d78a61b1c982f9ef732e099ea34c89c13a7522e5c1198fdbf90c2ce259ea244
  1. 再次进入容器,发现数据仍然存在
07:42:57 root@DESKTOP-OFM10JG ~ → docker exec -it mysql_test mysql -uroot -p
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+
5 rows in set (0.003 sec)

mysql> use test
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> select*from testTB;
+----+------+
| id | name |
+----+------+
|  1 | wjl  |
+----+------+
1 row in set (0.001 sec)

mysql>

三、docker 网络

3.1 CNM

docker 网络设计采用的规范是 CNM,即 Container Network Model,主要有三个部分:endpoint、network、sandbox

  • endpoint,是网络的接口,负责让一个容器能够接入一个网络
  • network,docker 内部的虚拟子网,使得网络的参与者能够进行通信
  • sandbox,提供网络协议栈,如端口、ip 路由表、套接字等

3.2 常见网络类型

3.2.1 bridge 网络

搭建一个 Linux 网桥,参与网桥的容器都可以进行通信,当只是需要一个主机上的多个 docker 容器进行之间通信时,就可以使用 bridge 网络

当创建容器没有指定所属网络,比如 docker run --network=...,就会将其加入名为 bridge 的默认网络,其对应名为 docker0 的 linux 网桥

对于自定义的 bridge 网络,docker 支持 dns 解析,即可以直接通过主机名获得 ip

自定义网络支持dns解析
09:51:14 root@DESKTOP-OFM10JG ~ → docker exec -it busybox_1 hostname
f802210b1443
09:51:17 root@DESKTOP-OFM10JG ~ → docker exec -it busybox_2 hostname
e0b68d857d64
09:51:29 root@DESKTOP-OFM10JG ~ → docker exec -it busybox_2 ping f802210b1443 -c 10
PING f802210b1443 (172.18.0.5): 56 data bytes
64 bytes from 172.18.0.5: seq=0 ttl=64 time=0.233 ms

3.2.2 host 网络

直接共享宿主机的网络资源,如 ip 地址,以宿主机的身份使用网络,不会额外虚拟出网卡、ip 等,例如下面使用 --network=host 使用 host 网络创建的 busybox 容器,使用的网络资源就同宿主机

对于需要直接与外界主机通信的容器,使用 host 网络比 bridge 合适,因为不存在端口转发的性能消耗;但是 host 网络也容易出现端口占用的问题

root@DESKTOP-R88A08G:/home/diinki/docker# docker exec -it busyboxhost ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet 10.255.255.254/32 brd 10.255.255.254 scope global lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc mq qlen 1000
    link/ether 00:50:56:c0:00:01 brd ff:ff:ff:ff:ff:ff

root@DESKTOP-R88A08G:/home/diinki/docker# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet 10.255.255.254/32 brd 10.255.255.254 scope global lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host proto kernel_lo
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST> mtu 1500 qdisc mq state DOWN group default qlen 1000
    link/ether 00:50:56:c0:00:01 brd ff:ff:ff:ff:ff:ff

3.2.3 container 网络

也是直接使用别人的网络资源,但是不是宿主机而是其他容器,是一种介于 host 和 bridge 之间的状态:依赖的容器与被依赖的容器之间不存在网络隔离,但是与其他容器之间存在;但是当被依赖的容器关闭时,使用 container 网络的容器又将失去网络连接

3.2.4 none 网络

不配置网络,直接从网络隔离

3.2.5 overlay 网络

将多个 Docker 守护进程连接在一起,使集群服务能够相互通信。当我们需要运行在不同 Docker 主机上的容器进行通信时,或者当多个应用程序使用集群服务协同工作时,覆 盖网络是最佳选择。

不给容器配置网络,这种情况下只具有 lo 本地环回

四、Docker compose 容器编排

4.1 基本格式

version: "3.8"
services: # 服务,可以存在多个
  servicename: # 服务名称,也是内部 bridge 网络可以使用的 DNS name,不是集群模式时相当于 docker run 时指定的名称
    image: # 镜像的名字
    command: # 可选,如果设置,覆盖容器启动的默认命令
    environment: # 环境变量,等价于 docker run 中通过 -e 设置
    volumes: # 可选,等价于 docker run 中 -v 绑定数据卷
    networks: # 可选,等价于 docker run 中 --network 指定网络
    ports: # 可选,等价于 docker run 中通过 -p 进行端口映射
    build: # 构建目录
    depends_on: #服务依赖配置
    env_file: # 环境变量文件
  # ...
volumes: # 可选,等价于 docker volumes create
networks: # 可选,等价于 docker network create

4.2 案例:nginx、mysql、redis

services:
    web:
      image: nginx:latest
      ports:
        - "80:80"
      volumes: 
        - "/data/nginx-home:/usr/share/nginx/html"
      networks:
        - mynetwork
      depends_on:
        db: 
          condition: service_healthy
        redis: 
          condition: service_healthy
    db:
      image: mysql:latest
      ports:
        - "3306:3306"
      volumes:
        - "/data/mysql-home:/var/lib/mysql"
      networks:
        - mynetwork
      environment:
        - MYSQL_ROOT_PASSWORD=123456
      healthcheck:
        test: mysql -uroot -p123456 -e "select 1"
        interval: 10s
        timeout: 5s
        retries: 10
    redis:
      image: redis:latest
      ports:
        - "6379:6379"
      networks:
        - mynetwork
      healthcheck:
        test: redis-cli ping
        interval: 10s
        timeout: 5s
        retries: 5
networks:
  mynetwork:

4.3 docker compose 常见问题

  1. docker compose up/run/start 的区别

    • up,会创建并启动 compose 文件中的所有内容,并创建 docker 卷、network 等内容;如果没有 -d,会直接在前台运行并输出日志,若指明了 -d,那么当容器全部启动后,compose 进城退出

    • run,运行指定的服务,对于该服务创建临时容器;对于依赖的服务也会启动,如果还没有创建容器,那么会创建依赖服务的容器(不是临时的)

    • start,不会创建容器,只是启动已经处于停止状态的服务容器

  2. 怎样创建一个 compose 文件的多个副本?

    • docker compose 通过 project name 来区分资源,比如容器名、网络名、volume 名

    • 也可以指定环境变量 COMPOSE_PROJECT_NAME,直接使用 docker compose up 即可创建

    • 通过 -p 指定 project name,即可创建多个副本,比如

docker compose -p project1 up -d
docker compose -p project2 up -d  
  1. 启动顺序可以指定吗?

    • 可以,通过 depend_on 指定依赖的容器,并且可以配合 health_check 等待制定容器正常可用后再创建
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐