多机Docker + InfiniBand 分布式运行实操手册

适用场景:两台主机,每台 8×V100;两台机器共享 /mnt;HostA 上已有可正常运行的 Docker 环境,希望迁移到 HostB,并使用 16 张 GPU 进行多机分布式运行,同时验证 NCCL 是否通过 InfiniBand 通信。


1. 当前环境信息

HostA

text 复制代码
IP: 192.168.206.140
GPU: 8 × V100
容器名: SD_jgy
原始镜像: sd_jgy:dt12_6

HostA 容器内已经看到:

text 复制代码
/sys/class/infiniband:
mlx5_0
mlx5_1

并且:

text 复制代码
mlx5_0: ACTIVE, InfiniBand
mlx5_1: ACTIVE, InfiniBand

需要进一步确认宿主机与容器看到的 HCA 数量是否一致,以及两个 HCA 的速率。

HostB

text 复制代码
IP: 192.168.205.32
GPU: 8 × V100

HostB 容器内已经看到:

text 复制代码
/sys/class/infiniband:
mlx5_0
mlx5_1
mlx5_2
mlx5_3

实际状态:

text 复制代码
mlx5_0: DOWN,   InfiniBand, 10 Gb/sec (4X SDR)
mlx5_1: DOWN,   InfiniBand, 10 Gb/sec (4X SDR)
mlx5_2: ACTIVE, InfiniBand, 100 Gb/sec (4X EDR)
mlx5_3: DOWN,   InfiniBand, 10 Gb/sec (4X SDR)

因此 HostB 当前应优先使用:

bash 复制代码
export NCCL_IB_HCA=mlx5_2

而不是把四个 HCA 全部交给 NCCL。


2. 整体思路

双机 16 卡并不是"一台 Docker 直接访问另一台机器的 GPU",而是:

text 复制代码
HostA:
  Docker 容器
  GPU rank 0~7

HostB:
  Docker 容器
  GPU rank 8~15

两个容器:
  使用相同代码
  使用兼容的 Python/CUDA/NCCL 环境
  通过 torch.distributed / NCCL 建立 world_size=16 的进程组

推荐流程:

text 复制代码
HostA 清理现有容器
        ↓
docker commit 生成新镜像
        ↓
docker save + zstd 写入共享 /mnt
        ↓
HostB docker load
        ↓
HostA / HostB 启动容器并暴露 GPU + IB
        ↓
检查 GPU / HCA / verbs
        ↓
检查两节点 TCP bootstrap 网络
        ↓
16 进程 torchrun + NCCL all_reduce
        ↓
查看 NCCL 日志是否出现 NET/IB

3. Docker 容器空间清理

3.1 查看容器大小

宿主机执行:

bash 复制代码
docker ps -s

最初 HostA 的结果:

text 复制代码
SIZE: 147GB
virtual: 218GB

清理之后:

text 复制代码
SIZE: 45.1GB
virtual: 116GB

说明容器可写层从 147GB 降到了 45.1GB。


3.2 查看容器内部根目录占用

进入容器:

bash 复制代码
docker exec -it SD_jgy bash

检查:

bash 复制代码
du -xhd1 / 2>/dev/null | sort -h

最初发现:

text 复制代码
/root 127G
/usr   23G
/opt   5.2G

因此继续排查:

bash 复制代码
du -xhd1 /root 2>/dev/null | sort -h

发现:

text 复制代码
/root/.cache         80G
/root/anaconda       30G
/root/.vscode-server 7.2G
/root/.npm           4.9G
/root/.lingma        1.5G

3.3 继续定位 .cache

bash 复制代码
du -xhd1 /root/.cache 2>/dev/null | sort -h

主要占用:

text 复制代码
/root/.cache/huggingface 66G
/root/.cache/uv          14G

由于模型权重已经确认不再需要,因此删除:

bash 复制代码
rm -rf /root/.cache
mkdir -p /root/.cache

删除后:

text 复制代码
/root: 127G → 47G

3.4 可清理的远程开发与 npm 缓存

在确认不需要这些远程编辑器服务状态后,可删除:

bash 复制代码
rm -rf /root/.vscode-server
rm -rf /root/.cursor-server
rm -rf /root/.cursor
rm -rf /root/.lingma
rm -rf /root/.npm

Codex 注意事项

通过以下命令确认 Codex 安装位置:

bash 复制代码
which codex
which -a codex
npm root -g
npm ls -g @openai/codex --depth=0

本次环境输出:

text 复制代码
/usr/local/nvm/versions/node/v18.20.8/bin/codex
/usr/local/nvm/versions/node/v18.20.8/lib/node_modules
@openai/codex@0.130.0

因此:

text 复制代码
/root/.npm

只是 npm 缓存,可以删除。

不要误删:

text 复制代码
/usr/local/nvm/versions/node/v18.20.8/
/root/.codex

3.5 不要误删 Conda 主环境

当前 shell 中有:

text 复制代码
(parrot)

应先检查:

bash 复制代码
which python
conda info --envs

如果 parrot 位于:

text 复制代码
/root/anaconda/envs/parrot

那么:

text 复制代码
/root/anaconda

不能删除。

可以使用:

bash 复制代码
conda clean -a -y

清理包缓存,但不要直接删除整个 Conda 安装目录。


3.6 清理后的目录状态

最终容器中:

bash 复制代码
du -xhd1 / 2>/dev/null | sort -h

结果约为:

text 复制代码
/root 41G
/usr  23G
/opt  5.2G
/     71G

此时不建议继续盲删 /usr/opt/root/anaconda


4. docker commit、save、load 的关系

关系如下:

text 复制代码
运行中的容器
    │
    │ docker commit
    ▼
Docker 镜像
    │
    │ docker save
    ▼
tar / tar.zst 文件
    │
    │ docker load
    ▼
另一台机器上的 Docker 镜像
    │
    │ docker run
    ▼
新的运行容器

4.1 将容器保存为镜像

HostA:

bash 复制代码
docker commit SD_jgy sd_jgy:clean

作用:

text 复制代码
当前运行容器状态 → 新镜像 sd_jgy:clean

docker commit 本身没有百分比进度条。

可以在另一个终端观察:

bash 复制代码
watch -n 2 "docker images | grep sd_jgy"

或:

bash 复制代码
sudo iotop -oPa

4.2 压缩镜像到共享目录

创建目录:

bash 复制代码
mkdir -p /mnt/guoyong/image

执行:

bash 复制代码
docker save sd_jgy:clean \
  | zstd -T0 -3 \
  -o /mnt/guoyong/image/sd_jgy_clean.tar.zst

本次镜像原始数据约:

text 复制代码
117.6 GB

压缩结果约:

text 复制代码
51 GB

查看文件:

bash 复制代码
ls -lh /mnt/guoyong/image/sd_jgy_clean.tar.zst

检查压缩文件:

bash 复制代码
zstd -t /mnt/guoyong/image/sd_jgy_clean.tar.zst

4.3 为什么 docker save | zstd 很慢

该命令实际上同时进行:

text 复制代码
/var/lib/docker 读取约 116GB 镜像层
          ↓
docker save 顺序输出 tar stream
          ↓
zstd 多线程压缩
          ↓
持续写入共享 /mnt

瓶颈可能是:

text 复制代码
Docker 本地磁盘读取
zstd CPU 压缩
共享盘 /mnt 的写入带宽

查看文件增长:

bash 复制代码
watch -n 2 \
  "ls -lh /mnt/guoyong/image/sd_jgy_clean.tar.zst"

如果需要更快,可以将:

bash 复制代码
zstd -T0 -3

改为:

bash 复制代码
zstd -T0 -1

5. HostB 导入镜像与磁盘空间问题

HostB 导入:

bash 复制代码
zstd -dc /mnt/guoyong/image/sd_jgy_clean.tar.zst \
  | sudo docker load

注意不要写成:

bash 复制代码
sudo zstd -dc xxx | docker load

因为 sudo 只作用在管道左侧。


5.1 no space left on device

本次曾出现:

text 复制代码
Error processing tar file:
no space left on device

原因:

text 复制代码
51GB 是压缩文件大小
docker load 后需要把镜像层写入 Docker Root Dir
原始镜像约 116GB

查看 Docker Root Dir:

bash 复制代码
docker info | grep "Docker Root Dir"

查看其所在分区空间:

bash 复制代码
df -h /var/lib/docker

注意:

bash 复制代码
df -h /var/lib/docker

显示的是 /var/lib/docker 所在整个文件系统的容量,不是 Docker 目录自身大小。

例如:

text 复制代码
Size: 877G
Used: 508G
Avail: 333G
Mounted on: /

意思是:

text 复制代码
根分区 / 总容量 877G
整个根分区已使用 508G
还剩 333G

5.2 查看 Docker 自身实际占用

bash 复制代码
sudo du -h --max-depth=1 /var/lib/docker \
  2>/dev/null | sort -h

本次结果:

text 复制代码
75G /var/lib/docker
75G /var/lib/docker/overlay2

Docker 统计:

bash 复制代码
sudo docker system df

曾显示:

text 复制代码
Images       28.29GB
Containers   10.04GB

dudocker system df 不完全一致是正常的,因为 overlay2、层存储与逻辑镜像统计方式不同。


5.3 删除 HostB 无用停止容器

本次删除了多个 Exited 容器:

bash 复制代码
sudo docker rm -f \
  0c32d3900cc7 \
  ea299c60a5bd \
  876eb50eddcf \
  fa0c2a8ae631 \
  6999d3521863

清理后根分区:

text 复制代码
Used: 798G → 508G
Avail: 43G → 333G

释放约 290GB。

进一步可检查:

bash 复制代码
sudo docker image prune -af
sudo docker builder prune -af

执行前应确认没有需要保留的镜像。


6. HostA / HostB Docker 启动方式

推荐两台机器启动同一镜像。

例如:

bash 复制代码
sudo docker run -dit \
  --name sd_jgy_16gpu \
  --gpus all \
  --runtime=nvidia \
  --net=host \
  --ipc=host \
  --shm-size=64g \
  --ulimit memlock=-1 \
  --ulimit stack=67108864 \
  --privileged \
  -v /dev/infiniband:/dev/infiniband \
  -v /mnt:/mnt \
  -v /mnt/guoyong/SD_DockerShared:/workspace \
  -w /workspace \
  sd_jgy:clean \
  /sbin/init

进入:

bash 复制代码
sudo docker exec -it sd_jgy_16gpu bash

6.1 --net host-p 的关系

旧命令类似:

bash 复制代码
-p 50022:22
--net host

使用:

bash 复制代码
--net=host

后,容器共享宿主机网络栈,Docker 端口映射通常没有必要,因此:

bash 复制代码
-p 50022:22

可以删除。


7. 判断容器是否看到 IB

7.1 检查 RDMA 设备节点

bash 复制代码
ls /dev/infiniband

例如 HostB:

text 复制代码
issm0
issm1
issm2
issm3
rdma_cm
umad0
umad1
umad2
umad3
uverbs0
uverbs1
uverbs2
uverbs3

如果 /dev/infiniband 不存在,容器通常无法使用 RDMA verbs。


7.2 检查 HCA

bash 复制代码
ls /sys/class/infiniband

HostA:

text 复制代码
mlx5_0
mlx5_1

HostB:

text 复制代码
mlx5_0
mlx5_1
mlx5_2
mlx5_3

7.3 检查状态、链路类型和速率

bash 复制代码
for hca in /sys/class/infiniband/*; do
  echo "==== $(basename $hca) ===="
  for p in $hca/ports/*; do
    echo -n "state: "
    cat $p/state

    echo -n "phys_state: "
    cat $p/phys_state 2>/dev/null

    echo -n "link_layer: "
    cat $p/link_layer

    echo -n "rate: "
    cat $p/rate
  done
done

判断标准:

text 复制代码
state: 4: ACTIVE
link_layer: InfiniBand

才表示链路处于可用状态。


8. 如何判断 HostA HCA 数量差异是宿主机还是 Docker 问题

HostA 容器里目前只看到:

text 复制代码
mlx5_0
mlx5_1

HostB 容器里看到四个:

text 复制代码
mlx5_0
mlx5_1
mlx5_2
mlx5_3

不能直接判断是 Docker 问题。

需要宿主机和容器对比。


8.1 HostA 宿主机检查

退出容器,在 HostA 宿主机执行:

bash 复制代码
ls /sys/class/infiniband
ls /dev/infiniband

再检查:

bash 复制代码
for hca in /sys/class/infiniband/*; do
  echo "==== $(basename $hca) ===="
  for p in $hca/ports/*; do
    echo -n "state: "
    cat $p/state

    echo -n "link_layer: "
    cat $p/link_layer

    echo -n "rate: "
    cat $p/rate
  done
done

查看 PCIe 设备:

bash 复制代码
lspci | grep -Ei "Mellanox|ConnectX|InfiniBand|MT"

判断:

text 复制代码
宿主机 2 个,容器 2 个
→ HostA 本身只暴露 2 个 HCA,Docker 没问题

宿主机 4 个,容器 2 个
→ Docker 设备暴露不完整

宿主机 4 个,但只有部分 ACTIVE
→ 只能使用 ACTIVE 的 HCA

8.2 查看容器启动参数

bash 复制代码
sudo docker inspect <container_name> \
  --format 'Privileged={{.HostConfig.Privileged}} NetworkMode={{.HostConfig.NetworkMode}}'

查看设备:

bash 复制代码
sudo docker inspect <container_name> \
  --format '{{json .HostConfig.Devices}}'

9. 查看 GPU 与 IB HCA 拓扑关系

最重要命令:

bash 复制代码
nvidia-smi topo -m

重点看:

text 复制代码
GPU0~GPU7
mlx5_0
mlx5_1
...

拓扑距离常见含义:

text 复制代码
PIX  同一 PCIe Switch
PXB  跨多个 PCIe Bridge
PHB  跨 Host Bridge
NODE 同一 NUMA node
SYS  跨 CPU socket / UPI/QPI

一般距离大致:

text 复制代码
PIX < PXB < PHB < NODE < SYS

查看 GPU PCI 地址:

bash 复制代码
nvidia-smi \
  --query-gpu=index,name,pci.bus_id \
  --format=csv

查看 HCA PCI 路径:

bash 复制代码
for hca in /sys/class/infiniband/*; do
  echo "$(basename $hca)"
  readlink -f $hca/device
  echo -n "numa_node="
  cat $hca/device/numa_node
done

如果系统有:

bash 复制代码
ibdev2netdev

执行:

bash 复制代码
ibdev2netdev

可以查看:

text 复制代码
mlx5_X port Y → Linux netdev

10. HostA 单节点 IB 健康检查

HostA 单独可以验证:

text 复制代码
IB HCA 存在
verbs 设备存在
端口 ACTIVE
链路类型是 InfiniBand
驱动和 sysfs 正常

但单机不能证明:

text 复制代码
HostA ↔ HostB 的 IB 网络一定互通

检查:

bash 复制代码
ls /dev/infiniband
ls /sys/class/infiniband

然后:

bash 复制代码
for hca in /sys/class/infiniband/*; do
  echo "==== $(basename $hca) ===="
  for p in $hca/ports/*; do
    cat $p/state
    cat $p/phys_state 2>/dev/null
    cat $p/link_layer
    cat $p/rate
    cat $p/lid 2>/dev/null
  done
done

如果安装了工具:

bash 复制代码
ibv_devinfo
rdma link

11. 两节点 TCP bootstrap 互通测试

HostA:

text 复制代码
192.168.206.140

HostB:

text 复制代码
192.168.205.32

两者不在同一个 /24 网段,但本次已经验证 HostB 可以 ping HostA:

bash 复制代码
ping -c 3 192.168.206.140

结果:

text 复制代码
0% packet loss
RTT 约 0.2~0.35 ms

这只证明:

text 复制代码
TCP/IP 路由可达

不证明 NCCL 数据路径一定使用 IB。


11.1 端口连通测试

HostA:

bash 复制代码
python -m socketserver 29500

HostB:

bash 复制代码
python - <<'PY'
import socket

s = socket.create_connection(
    ("192.168.206.140", 29500),
    timeout=5,
)

print("connect ok")
s.close()
PY

12. 16 卡 torchrun + NCCL all_reduce 测试

创建共享脚本:

bash 复制代码
cat > /mnt/guoyong/test_dist_16gpu.py <<'PY'
import os
import socket

import torch
import torch.distributed as dist


dist.init_process_group(backend="nccl")

rank = dist.get_rank()
world_size = dist.get_world_size()
local_rank = int(os.environ["LOCAL_RANK"])

torch.cuda.set_device(local_rank)

# correctness test
x = torch.tensor(
    [rank],
    dtype=torch.float32,
    device="cuda",
)

dist.all_reduce(
    x,
    op=dist.ReduceOp.SUM,
)

# larger communication tensor
y = torch.ones(
    256 * 1024 * 1024 // 4,
    dtype=torch.float32,
    device="cuda",
)

y *= rank

dist.all_reduce(
    y,
    op=dist.ReduceOp.SUM,
)

torch.cuda.synchronize()

print(
    f"host={socket.gethostname()} "
    f"rank={rank} "
    f"local_rank={local_rank} "
    f"world_size={world_size} "
    f"sum_rank={x.item()} "
    f"y0={y[0].item()}"
)

dist.barrier()
dist.destroy_process_group()
PY

正确结果:

text 复制代码
world_size=16
sum_rank=120
y0=120.0

因为:

text 复制代码
0 + 1 + ... + 15 = 120

13. HostA torchrun 启动模板

HostA:

bash 复制代码
export MASTER_ADDR=192.168.206.140
export MASTER_PORT=29500

export NCCL_DEBUG=INFO
export NCCL_DEBUG_SUBSYS=INIT,NET
export NCCL_IB_DISABLE=0

# 根据 HostA 实际 ACTIVE HCA 调整
export NCCL_IB_HCA=mlx5_0,mlx5_1

# 填写 192.168.206.140 对应的 Linux 网络接口
export NCCL_SOCKET_IFNAME=enp1s0f0

torchrun \
  --nnodes=2 \
  --nproc_per_node=8 \
  --node_rank=0 \
  --master_addr=$MASTER_ADDR \
  --master_port=$MASTER_PORT \
  /mnt/guoyong/test_dist_16gpu.py \
  2>&1 | tee /tmp/nccl_hostA.log

14. HostB torchrun 启动模板

HostB 先确认:

bash 复制代码
ip -br addr

找到:

text 复制代码
192.168.205.32

对应的接口名。

然后:

bash 复制代码
export MASTER_ADDR=192.168.206.140
export MASTER_PORT=29500

export NCCL_DEBUG=INFO
export NCCL_DEBUG_SUBSYS=INIT,NET
export NCCL_IB_DISABLE=0

# HostB 当前只有 mlx5_2 ACTIVE
export NCCL_IB_HCA=mlx5_2

# 替换为 HostB 上 192.168.205.32 对应的接口
export NCCL_SOCKET_IFNAME=<HOSTB_NETDEV>

torchrun \
  --nnodes=2 \
  --nproc_per_node=8 \
  --node_rank=1 \
  --master_addr=$MASTER_ADDR \
  --master_port=$MASTER_PORT \
  /mnt/guoyong/test_dist_16gpu.py \
  2>&1 | tee /tmp/nccl_hostB.log

启动顺序建议:

text 复制代码
先启动 HostA
再启动 HostB

HostA 会等待 HostB 加入 rendezvous。


15. 如何确认 NCCL 真的走 IB

测试完成后:

HostA:

bash 复制代码
grep -E \
  "NET/IB|NET/Socket|mlx5|Using network|Bootstrap" \
  /tmp/nccl_hostA.log

HostB:

bash 复制代码
grep -E \
  "NET/IB|NET/Socket|mlx5|Using network|Bootstrap" \
  /tmp/nccl_hostB.log

判断:

text 复制代码
看到 NET/IB
看到具体 mlx5_X
→ NCCL 数据路径使用 RDMA/InfiniBand

只看到 NET/Socket
→ NCCL 通过 TCP Socket 通信

注意:

text 复制代码
ping 通 ≠ NCCL 使用 IB

真正应以 NCCL 日志为准。


16. 当前最合理的 NCCL HCA 配置

根据目前已知状态:

HostA

当前容器看到:

text 复制代码
mlx5_0 ACTIVE InfiniBand
mlx5_1 ACTIVE InfiniBand

可先使用:

bash 复制代码
export NCCL_IB_HCA=mlx5_0,mlx5_1

但应先在宿主机确认 HCA 数量、状态和速率是否与容器一致。

HostB

只有:

text 复制代码
mlx5_2 ACTIVE 100 Gb/sec EDR

因此使用:

bash 复制代码
export NCCL_IB_HCA=mlx5_2

17. 常见误区

误区 1:ip addr 没有 ib0 就说明不能用 IB

不一定。

真正 RDMA 数据通信可以通过:

text 复制代码
mlx5_X verbs device

完成。

是否有 ib0 主要涉及 IPoIB 接口。


误区 2:NCCL_SOCKET_IFNAME 决定 IB 数据链路

不完全正确。

例如:

bash 复制代码
export NCCL_SOCKET_IFNAME=enp1s0f0
export NCCL_IB_HCA=mlx5_2

可以理解为:

text 复制代码
enp1s0f0
→ bootstrap / socket 初始化网络

mlx5_2
→ NCCL RDMA 数据通道

最终仍要看 NCCL 日志。


误区 3:HostA 和 HostB 的 HCA 名必须一致

不要求。

HostA 可以:

bash 复制代码
export NCCL_IB_HCA=mlx5_0,mlx5_1

HostB 可以:

bash 复制代码
export NCCL_IB_HCA=mlx5_2

NCCL_IB_HCA 是本地设备选择。


误区 4:Docker 里看到 HCA 就一定能通信

不一定。

必须同时满足:

text 复制代码
/dev/infiniband 可见
/sys/class/infiniband 可见
端口 ACTIVE
link_layer 为 InfiniBand
两节点 Fabric 互通
NCCL verbs 后端可用

18. 推荐后续验证顺序

严格按以下顺序:

text 复制代码
1. HostA 宿主机检查 HCA 数量、ACTIVE 状态、速率
2. HostA 容器与宿主机对比
3. HostB 容器确认 mlx5_2 ACTIVE 100Gb/s
4. 两边确认 8 张 GPU
5. 两边确认 /dev/infiniband
6. 检查 HostA:29500 端口互通
7. 运行 world_size=16 的 all_reduce
8. 检查 sum_rank=120
9. 检查 NCCL 日志出现 NET/IB
10. 再运行正式 HunyuanDiT / xDiT / DiT 推理程序

19. 一组最小排障命令

GPU

bash 复制代码
nvidia-smi -L
nvidia-smi topo -m

网络接口

bash 复制代码
ip -br addr
ip route

IB HCA

bash 复制代码
ls /sys/class/infiniband
ls /dev/infiniband

IB 状态

bash 复制代码
for hca in /sys/class/infiniband/*; do
  echo "==== $(basename $hca) ===="
  for p in $hca/ports/*; do
    cat $p/state
    cat $p/link_layer
    cat $p/rate
  done
done

RDMA 工具

bash 复制代码
ibv_devinfo
rdma link
ibdev2netdev

Docker

bash 复制代码
docker ps -s
docker system df
docker info | grep "Docker Root Dir"
sudo du -h --max-depth=1 /var/lib/docker | sort -h

NCCL

bash 复制代码
export NCCL_DEBUG=INFO
export NCCL_DEBUG_SUBSYS=INIT,NET

日志判断:

bash 复制代码
grep -E \
  "NET/IB|NET/Socket|mlx5|Using network|Bootstrap" \
  /tmp/nccl_hostA.log

20. 最终建议

对于以后换机器,建议将整个环境拆成四层管理:

text 复制代码
Docker 镜像
→ 只保存系统库、CUDA/NCCL、Conda/Python 环境

/mnt/models
→ 模型权重

/mnt/workspace
→ 项目代码

/mnt/results
→ 实验结果

避免再把以下内容长期堆积到容器 writable layer:

text 复制代码
/root/.cache/huggingface
/root/.cache/uv
/root/.npm
/root/.vscode-server
/root/.cursor-server
模型权重
数据集
大日志
实验输出

这样后续 Docker 镜像会更容易迁移,也更利于双机或多机部署。

相关推荐
java_logo1 小时前
Docker 部署 WPS 在线办公套件,浏览器即可编辑 Word、Excel、PPT
docker·word·wps·wps部署教程·wps免费版·轩辕镜像·docker部署教程
AI服务老曹2 小时前
Docker部署AI视频分析平台项目实战记录
人工智能·docker·音视频
AndrewHZ2 小时前
【LLM技术全景】混合精度与分布式训练:训练大模型的工程奥秘
人工智能·分布式·深度学习·算法·ai·语言模型·llm
留不住的何止是时间2 小时前
关于docker构建镜像build指令的注意事项
运维·docker·容器
ffqws_10 小时前
Redis 分布式锁:基于 Redisson 的实现与面试高频问答
redis·分布式·面试
小兔崽子去哪了16 小时前
Docker 删除镜像后磁盘空间没有释放?
后端·docker·容器
六bring个六16 小时前
open Harmony中分布式软总线的学习任务清单
分布式·学习·c/c++·open harmony
wuqingshun31415916 小时前
说一下 Kafka 中关于事务消息的实现?
分布式·kafka
Zhu75818 小时前
在Docker环境部署ApacheGuacamole,对接PG数据库
数据库·docker·容器