Docker学习笔记(四):网络管理与容器操作
Docker
容器
限制容器对内存的使用
cgroup
cgroup 是 Linux 内核提供的一种资源隔离与限制机制,用于对进程组(Process Group)的硬件资源(如 CPU、内存、I/O 等)进行精细化管控。它的核心目标是:确保不同进程组公平使用系统资源,同时防止单个进程组过度占用资源导致系统不稳定,是容器技术(如 Docker、Kubernetes)、虚拟化及服务器资源管理的底层核心技术之一。
stress
可以使用 stress 工具来测试 CPU 和内存。
示例:创建一个基于 Ubuntu 的 stress 工 具镜像。
[root@docker ~]# vim Dockerfile
[root@docker ~]# cat Dockerfile
FROM ubuntu
MAINTAINER gaoqd "6946630@qq.com"
RUN apt-get -y update && apt-get -y install stress
ENTRYPOINT ["/usr/bin/stress"]# 使用Dockerfile构建镜像ubuntu-with-stress
[root@docker ~]# docker build -t ubuntu-with-stress .
一个 docker host 上会运行若干容器,每个容器都需要 CPU、内存和 IO 资源。对于 KVM,VMware 等 虚拟化技术,用户可以控制分配多少 CPU、内存资源给每个虚拟机。对于容器,Docker 也提供了类似的 机制避免某个容器因占用太多资源而影响其他容器乃至整个 host 的性能。
内存限额
与操作系统类似,容器可使用的内存包括两部分:物理内存和 swap。 Docker 通过下面两组参数来控制 容器内存的使用量。
- -m 或 --memory :设置内存的使用限额,例如 100M, 2G。
- –memory-swap :设置 内存+swap 的使用限额。
[root@docker ~]# docker run -m 200M --memory-swap=300M ubuntu
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
76249c7cd503: Already exists
Digest: sha256:9cbed754112939e914291337b5e554b07ad7c392491dba6daf25eef1332a22e8
Status: Downloaded newer image for ubuntu:latest# 其含义是允许该容器最多使用 200M 的内存和 100M 的 swap。输出说明:
系统提示本地没有找到 ubuntu:latest 镜像
开始从 Docker Hub 拉取最新的 Ubuntu 镜像
显示了镜像拉取的进度和摘要信息
最终提示镜像拉取成功
此时,Docker 会在后台创建并启动这个带有内存限制的 Ubuntu 容器。由于你没有指定交互参数(如 -it),容器在启动后可能会立即退出(因为没有前台进程运行)。
用ubuntu-with-stress镜像来学习如何为容器分配内存。该镜像可用于对容器执行压力测 试。
[root@docker ~]# docker run -it -m 200M --memory-swap=300M ubuntu-with-stress --vm 1 --vm-bytes 280M -v# -m 200M:容器物理内存上限 200MB
# --memory-swap=300M:物理内存 + 交换空间总上限 300MB(交换空间可用 100MB)
# -vm 1:启动 1 个内存压力测试进程
# --vm-bytes 280M:每个进程尝试分配 280MB 内存
# -v:显示详细调试信息
–vm 1 :启动 1 个内存工作线程。
–vm-bytes 280M :每个线程分配 280M 内存。
结果:
如果让工作线程分配的内存超过 300M,结果如下:
[root@docker ~]# docker run -it -m 200M --memory-swap=300M ubuntu-with-stress --vm 1 --vm-bytes 310M -v# 分配的内存超过限额,stress 线程报错,容器退出。
如果在启动容器时只指定 -m 而不指定 --memory-swap ,那么 --memory-swap 默认为 -m 的两倍, 比如:
[root@docker ~]# docker run -it -m 200M ubuntu-with-stress# 容器最多使用 200M 物理内存和 200M swap。
限制容器对CPU的使用
Docker 可以通过 -c 或 --cpu-shares 设置容器使用 CPU 的权重。如果不指定,默认值为 1024。
–cpu-shares 的值不能保证可以获得1个 vcpu 或者多少 GHz 的 CPU 资源,仅仅只是一个弹性的加权值。
默认情况下,每个 docker 容器的 cpu 份额都是1024。单独一个容器的份额是没有意义的,只有在同时 运行多个容器时,容器的 CPU 加权的效果才能体现出来。例如,两个容器A、B的 CPU 份额分别为1000 和500,在 CPU 进行时间片分配的时候,容器 A 比容器 B 多一倍的机会获得 CPU 的时间片,但分配的 结果取决于当时主机和其他容器的运行状态,实际上也无法保证容器A一定能获得 CPU 时间片。比如容 器A的进程一直是空闲的,那么容器B是可以获取比容器A更多的 CPU 时间片的。极端情况下,比如说主 机上只运行了一个容器,即使它的 CPU 份额只有 50,它也可以独占整个主机的 CPU 资源。
通过 cpu share 可以设置容器使用 CPU 的优先级。
比如在 host 中启动了两个容器:
docker run --name “container_A” -c 1024 ubuntu
docker run --name “container_B” -c 512 ubuntu
container_A 的 cpu share 1024,是 container_B 的两倍。当两个容器都需要 CPU 资源时, container_A 可以得到的 CPU 是 container_B 的两倍。
需要特别注意的是,这种按权重分配 CPU 只会发生在 CPU 资源紧张的情况下。如果 container_A 处于 空闲状态,这时,为了充分利用 CPU 资源,container_B 也可以分配到全部可用的 CPU。
基于ubuntu-with-stress:
启动 container_A,cpu share 为 1024
# 创建一个名为 container_A 的容器,并对其进行 CPU 压力测试
[root@docker ~]# docker run --name "container_A" -it -c 1024 ubuntu-with-stress --cpu 4 -v
stress: info: [1] dispatching hogs: 4 cpu, 0 io, 0 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 12000us
stress: dbug: [1] --> hogcpu worker 4 [7] forked
stress: dbug: [1] using backoff sleep of 9000us
stress: dbug: [1] --> hogcpu worker 3 [8] forked
stress: dbug: [1] using backoff sleep of 6000us
stress: dbug: [1] --> hogcpu worker 2 [9] forked
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogcpu worker 1 [10] forked# 新开一个窗口
[root@docker ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ce62082adbeb ubuntu-with-stress "/usr/bin/stress --c…" 20 seconds ago Up 20 seconds container_A
[root@docker ~]# cat /sys/fs/cgroup/cpu
cpu/ cpuacct/ cpu,cpuacct/ cpuset/
[root@docker ~]# cat /sys/fs/cgroup/cpu/docker/ce62082adbeb7b9a07c5cf2e27f918e76b3f87054fb09219554ccfb0384af44b/cpu.shares
1024# --name "container_A":为容器指定名称为 container_A
# -it:分配交互式终端
# -c 1024:设置容器的 CPU 权重为 1024
# ubuntu-with-stress:使用包含 stress 工具的 Ubuntu 镜像
# --cpu 4:启动 4 个 CPU 压力测试进程
# -v:显示 stress 工具的详细调试信息
查看top
再开一个窗口,启动 container_B,cpu share 为 512
[root@docker ~]# docker run --name "container_B" -it -c 512 ubuntu-with-stress --cpu 4 -vstress: info: [1] dispatching hogs: 4 cpu, 0 io, 0 vm, 0 hdd
stress: dbug: [1] using backoff sleep of 12000us
stress: dbug: [1] --> hogcpu worker 4 [7] forked
stress: dbug: [1] using backoff sleep of 9000us
stress: dbug: [1] --> hogcpu worker 3 [8] forked
stress: dbug: [1] using backoff sleep of 6000us
stress: dbug: [1] --> hogcpu worker 2 [9] forked
stress: dbug: [1] using backoff sleep of 3000us
stress: dbug: [1] --> hogcpu worker 1 [10] forked# -c(CPU 权重)1024(默认值)512权重比例为 2:1[root@docker ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fa23ad68bfb9 ubuntu-with-stress "/usr/bin/stress --c…" 14 seconds ago Up 13 seconds container_B
ce62082adbeb ubuntu-with-stress "/usr/bin/stress --c…" 2 minutes ago Up 2 minutes container_A
[root@docker ~]# cat /sys/fs/cgroup/cpu/docker/fa23ad68bfb9db2ce970bb24d7f0716ad18ad5f6589ff8d2ac4413bd85af51e8/cpu.shares
512# 实际效果
# 当 container_A 和 container_B同时运行且主机 CPU 资源紧张时(如主机 CPU 核心数 ≤ 8,两个容器共需 8 个核心):
# 两者的 CPU 时间片分配比例会接近其权重比 2:1(A 获得约 2/3,B 获得约 1/3)。
# 例如:若主机总 CPU 使用率为 100%(全部被两个容器占用),container_A 可能显示~67% 使用率,container_B 显示~33%。
查看top
container_A 消耗的 CPU 是 container_B 的两倍。
再开一个窗口
[root@docker docker]# docker stats
现在暂停 container_A:
[root@docker ~]# docker pause container_A
container_A
回到stats和top窗口看状态
top 显示 container_B 在 container_A 空闲的情况下能够用满整颗 CPU:
CPU 权重(-c
参数)的作用
Docker 中的 -c
(或 --cpu-shares
)参数用于设置 CPU 资源的相对权重,而非绝对限制:
- 权重值越高,在系统 CPU 资源紧张时,该容器能获得的 CPU 时间片比例越高
- 例如:如果容器 A 权重为 1024,容器 B 权重为 512,当两者都满负载时,A 会获得约 2/3 的 CPU 时间,B 获得约 1/3
- 若系统 CPU 资源充足(空闲),容器可以使用全部可用 CPU(不受权重限制)
总结
container_B
的 -c 512
与 container_A
的 -c 1024
形成了典型的 CPU 权重对比场景,直观展示了 Docker 如何通过 cgroup 的 cpu.shares
机制实现相对公平的资源分配。这种方式适合在多容器共享主机时,根据业务优先级分配 CPU 资源(如核心服务权重高,非核心服务权重低)。
export和import容器
export-导出容器文件系统
将容器导出为一个tar包,不管此时这个容器是否处于运行状态,都可以导出为文件。
示例:
# 创建容器httpd1用于测试
[root@docker ~]# docker run -d --name httpd1 httpd
Unable to find image 'httpd:latest' locally
latest: Pulling from library/httpd
396b1da7636e: Pull complete
40712a21826a: Pull complete
4f4fb700ef54: Pull complete
d2b1a5ae8cd3: Pull complete
7e8bbac53823: Pull complete
779ccd583397: Pull complete
Digest: sha256:3198c1839e1a875f8b83803083758a7635f1ae999f0601f30f2f3b8ce2ac99e3
Status: Downloaded newer image for httpd:latest
d6b7327099daad3bc89f67db53e87664fcf6d75d108d3c6184426957c71e2cc5# --name httpd1:指定容器名称为 httpd1[root@docker ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d6b7327099da httpd "httpd-foreground" About a minute ago Up About a minute 80/tcp httpd1
[root@docker ~]# docker export httpd1 -o myhttpd.tar
[root@docker ~]# ls
anaconda-ks.cfg Dockerfile myhttpd.tar# docker export:Docker 导出容器的命令,作用是将容器的文件系统快照导出为 tar 格式
# httpd1:要导出的容器名称
# -o myhttpd.tar:指定输出文件名为 myhttpd.tar(-o 是 --output 的简写)
import-导入为新镜像
将export导出的tar包导入为镜像
示例:
[root@docker ~]# docker import myhttpd.tar
sha256:a0a545135bacb60be6bdcef208d9a6c149f0d42cb964e7ab3de13a422e6c1a88[root@docker ~]# docker import myhttpd.tar myweb:v1
sha256:ea67fb2e875e8bbc4e412a68953b48ba5675e04fab1c329922c3946f17238540
docker save 和 docker export 对比:
docker save
和 docker export
都是 Docker 中用于导出镜像或容器文件的命令,但它们的作用对象、使用场景和输出内容有显著区别,具体对比如下:
作用对象
命令 | 作用对象 | 说明 |
---|---|---|
docker save | 镜像(Image) | 用于导出本地已存在的镜像(可包含多个镜像),保存镜像的完整分层信息。 |
docker export | 容器(Container) | 用于导出一个运行中或已停止的容器,保存的是容器当前的文件系统快照(合并为单层)。 |
输出内容
命令 | 输出特点 | 典型文件后缀 |
---|---|---|
docker save | 包含镜像的完整分层结构、元数据(如标签、历史记录、环境变量等),可复用分层。 | .tar |
docker export | 仅包含容器的文件系统内容(合并所有层为单层),不包含镜像元数据(如历史、标签)。 | .tar |
导入命令
命令 | 对应的导入命令 | 导入后产物 |
---|---|---|
docker save | docker load | 导入为镜像(保留分层和元数据,可直接运行 docker run )。 |
docker export | docker import | 导入为新镜像(仅包含文件系统,无历史记录,需重新指定标签等元数据)。 |
如何选择
- 若需迁移完整镜像(含版本历史、标签、环境变量等),使用
docker save
+docker load
。 - 若需捕获容器当前状态(如定制化配置后的文件系统),生成精简镜像,使用
docker export
+docker import
。
实现容器的底层技术
为了深入理解容器的特性,我们需要探讨其底层实现技术。其中,cgroup 和 namespace 是两种最核心的技术:cgroup 负责资源限额,namespace 实现资源隔离。
cgroup(Control Group)
cgroup 允许 Linux 操作系统对进程使用的 CPU、内存和 IO 资源进行限制。我们在使用容器时常用的 --cpu-shares
、-m
、--device-write-bps
等参数,本质上都是在配置 cgroup。
cgroup 的物理位置与验证
cgroup 相关配置文件位于 /sys/fs/cgroup
目录下。以 CPU 资源配置为例:
- 启动一个设置了
--cpu-shares=512
的容器 - 获取该容器的 ID
- 在
/sys/fs/cgroup/cpu/docker
目录中,系统会为每个容器创建以其长 ID 命名的专属目录 - 该目录下的
cpu.shares
文件中就保存着我们设置的 512 这个值
同理:
- 内存相关的 cgroup 配置位于
/sys/fs/cgroup/memory/docker
- 块设备 IO 相关的配置位于
/sys/fs/cgroup/blkio/docker
namespace
容器能拥有独立的文件系统、网卡等资源,仿佛是一个独立的计算机,这得益于 Linux 的 namespace 技术。namespace 管理着主机中全局唯一的资源,却能让每个容器感觉自己在独占使用这些资源,从而实现了容器间的资源隔离。
Linux 提供了六种 namespace,分别对应不同类型的资源隔离:
Mount namespace
使容器拥有独立的文件系统视图,容器内的 /
目录、mount
和 umount
操作仅在当前容器内生效,不会影响主机和其他容器。
UTS namespace
允许容器拥有自己的 hostname。默认情况下,容器的 hostname 是其短 ID,可通过 -h
或 --hostname
参数自定义。
IPC namespace
让容器拥有独立的共享内存和信号量,用于进程间通信,避免与主机和其他容器的 IPC 机制冲突。
PID namespace
实现了进程 ID 的隔离:
- 容器在主机中以进程形式运行,所有容器进程都隶属于 dockerd 进程
- 但在容器内部,
ps
命令只能看到容器自身的进程 - 容器内有独立的 PID 编号,容器中的 PID=1 进程并非主机的 init 进程
示例:
# 主机中查看容器
[root@docker ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a80f1f8b692c ubuntu "/bin/bash" 26 seconds ago Up 4 seconds interesting_davinci# 进入容器后查看进程
[root@docker ~]# docker exec -it a80f1f8b692c bash
root@a80f1f8b692c:/# ps axfPID TTY STAT TIME COMMAND17 pts/1 Ss 0:00 bash25 pts/1 R+ 0:00 \_ ps axf1 pts/0 Ss+ 0:00 /bin/bash
Network namespace
为容器提供独立的网络资源,包括网卡、IP 地址和路由表等。(详细内容将在网络章节展开)
User namespace
允许容器管理自己的用户系统,在容器内创建的用户不会在主机中出现,实现了用户层面的隔离。
小结
本章通过实践学习了容器的基本操作及状态转换,了解了限制容器 CPU、内存和 Block IO 的方法,重点掌握了容器的底层实现技术:
- cgroup:实现资源限额
- namespace:实现资源隔离
容器常用操作命令
命令 | 功能描述 |
---|---|
create | 创建容器 |
run | 运行容器 |
pause | 暂停容器 |
unpause | 取消暂停,继续运行容器 |
stop | 发送 SIGTERM 信号停止容器 |
kill | 发送 SIGKILL 信号强制停止容器 |
start | 启动容器 |
restart | 重启容器 |
attach | 连接到容器启动进程的终端 |
exec | 在容器中启动新进程(常用 -it 参数) |
logs | 显示容器启动进程的控制台输出(-f 参数可持续打印) |
rm | 从磁盘中删除容器 |
网络
none和host网络的适用场景
Docker 安装时会自动在 host 上创建三个网络,可以用 docker network ls 命令查看:
[root@docker ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
7ae6beb6c2fe bridge bridge local
8037f8eccbd4 host host local
b7b8e195eac6 none null local
none 网络
在 Docker 中,none
网络是一种特殊的网络模式,也被称为 “无网络” 模式。当容器使用 none
网络时,容器不会配置任何网络接口(除了回环接口 lo
),这意味着容器与外部网络(包括 Docker 主机以及其他容器)都无法直接通信。可以通过 --network=none 指定使用 none 网络。
[root@docker ~]# docker run -it --network=none busybox
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
80bfbb8a41a2: Pull complete
Digest: sha256:ab33eacc8251e3807b85bb6dba570e4698c3998eca6f0fc2ccb60575a563ea74
Status: Downloaded newer image for busybox:latest
/ # ifconfig
lo Link encap:Local Loopbackinet addr:127.0.0.1 Mask:255.0.0.0inet6 addr: ::1/128 Scope:HostUP LOOPBACK RUNNING MTU:65536 Metric:1RX packets:0 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:1000RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)/ # hostname
6dde17ba2898
/ ## --network=none:指定容器使用 none 网络模式(无网络模式)
# busybox:轻量级工具镜像,用于查看网络状态# 输出分析:
# 网络接口(ifconfig 命令):
# 容器内只有 回环接口(lo),没有任何用于外部通信的网络接口(如物理网卡、虚拟网卡 eth0 等)。
# 回环接口(lo)仅用于容器内部进程间通信,无法连接外部网络。
# 没有分配任何可用于外部通信的 IP 地址(除了本地回环地址 127.0.0.1)。
# 主机名(hostname 命令):
# 输出容器的随机 ID(6dde17ba2898),表明容器拥有独立的系统标识(与宿主机隔离),但因无网络,该标识无法通过网络被其他设备识别。
启动后,进入容器内部,使用 ifconfig
(或 ip addr
)命令查看网络接口,会发现只有回环接口 lo
,没有其他用于和外部通信的网络接口。
none
网络模式的核心特点
- 彻底的网络隔离:容器与宿主机、其他容器及外部网络完全断开,仅保留本地回环通信。
- 无自动网络配置:Docker 不会为容器分配 IP、配置路由或 DNS,所有网络设置需手动完成(如需联网)。
- 极高安全性:适合不需要网络的场景(如本地数据处理、加密运算),避免网络攻击面。
host 网络
在 Docker 中,host
网络模式是一种特殊的网络配置,它允许容器直接使用宿主机的网络栈,而不进行网络隔离。这意味着容器不会获得独立的网络命名空间(Network Namespace),而是与宿主机共享相同的 IP 地址、端口、路由表等网络资源。
[root@docker ~]# docker run -it --network=host busybox
/ # ip l
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq qlen 1000link/ether 00:0c:29:37:6a:32 brd ff:ff:ff:ff:ff:ff
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueuelink/ether 02:42:3f:2f:68:dd brd ff:ff:ff:ff:ff:ff
/ # hostname
docker# --network=host:指定容器使用宿主机的网络栈(host 网络模式)# 输出分析:
# 网络接口(ip l 命令):
# 容器内显示的网络接口(lo、ens160、docker0)与宿主机完全一致:
# lo:回环接口(所有系统都有)
# ens160:宿主机的物理网卡(容器直接共享)
# docker0:Docker 默认桥接网络接口(宿主机上的网络设备)
# 这证明 host 模式下,容器没有独立的网络命名空间,完全复用宿主机的网络接口。
# 主机名(hostname 命令):
# 输出 docker,与宿主机的主机名完全相同,进一步验证了容器与宿主机共享网络栈及系统标识。
host
模式的直观体现
- 无独立 IP:容器没有自己的 IP 地址(如默认桥接模式的
172.17.0.x
),直接使用宿主机的 IP。 - 端口直接共享:若在容器内启动一个服务(如
nc -l 8080
),无需端口映射,直接通过宿主机的8080
端口即可访问。 - 网络配置一致:容器内的路由表、DNS 配置等也与宿主机完全相同。
特点
- 无网络隔离:容器与宿主机共享网络栈,容器内的服务直接使用宿主机的 IP 地址和端口。
- 性能损耗低:由于省去了网络地址转换(NAT)和端口映射的开销,网络性能接近原生(适合对网络性能要求高的场景)。
- 端口冲突风险:容器内启动的服务若占用某个端口,会与宿主机或其他
host
模式容器的同端口服务冲突(需手动管理端口)。 - 跨平台限制:仅在 Linux 主机上完全支持,Windows 和 macOS 因 Docker 运行机制不同,
host
模式的行为会有差异(通常映射到虚拟机的网络)。
对比
特性 | none 网络模式 | host 网络模式 |
---|---|---|
网络接口 | 仅回环接口(lo ) | 共享宿主机所有网络接口 |
IP 地址 | 仅 127.0.0.1 (回环) | 共享宿主机 IP 地址 |
外部通信能力 | 无(完全隔离) | 与宿主机相同(直接联网) |
典型用途 | 本地数据处理、无网络需求的任务 | 高性能网络服务、需共享宿主机网络 |
brige网络
Docker 安装时会创建一个 命名为 docker0 的 linux bridge,实际上它是 Linux 的一个 bridge (网桥), 可以理解为一个软件交换机,它会在挂载到它的网口之间进行转发。如果不指定 --network ,创建的容 器默认都会挂到 docker0 上。
Docker 就创建了在主机和所有容器之间一个虚拟共享网络 当创建一个 Docker 容器的时候,同时会创建 了一对 veth pair 接口(当数据包发送到一个接口时,另外一个接口也可以收到相同的数据包), 这对接口
- 一端在容器内即 eth0
- 另一端在本地并被挂载到 docker0 网桥,名称以 veth 开头
通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。
示例:
# 配置yum源用于安装软件
[root@docker ~]# cd /etc/yum.repos.d/
[root@docker yum.repos.d]# vim cloud.repo
[root@docker yum.repos.d]# cat cloud.repo
[centos-openstack-victoria]
name=CentOS 8 - OpenStack victoria
baseurl=https://mirrors.aliyun.com/centos-vault/8-stream/cloud/x86_64/openstackvictoria/
enabled=1
gpgcheck=0[root@docker yum.repos.d]# yum clean all
20 files removed
[root@docker yum.repos.d]# yum makecache[root@docker yum.repos.d]# yum install -y bridge-utils[root@docker yum.repos.d]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242c1dda268 no# 当前 docker0 上没有任何其他网络设备,创建一个容器看有什么变化。
[root@docker yum.repos.d]# docker run -itd --name busybox1 busybox
Unable to find image 'busybox:latest' locally
latest: Pulling from library/busybox
80bfbb8a41a2: Pull complete
Digest: sha256:ab33eacc8251e3807b85bb6dba570e4698c3998eca6f0fc2ccb60575a563ea74
Status: Downloaded newer image for busybox:latest
33ce4b4d13e90965f00c8c0800dbcfb1d935bf5395042304bb541968c43c3d96
[root@docker yum.repos.d]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242c1dda268 no veth0205e26# 一个新的网络接口 veth0205e26 被挂到了 docker0 上, veth0205e26 就是新创建容器的虚拟网卡。# 新容器的配置
[root@docker yum.repos.d]# docker exec -it busybox1 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope hostvalid_lft forever preferred_lft forever
4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueuelink/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ffinet 172.17.0.2/16 brd 172.17.255.255 scope global eth0valid_lft forever preferred_lft forever
/ #
如何自定义容器网络
Docker 提供三种 user-defined 网络驱动:bridge, overlay 和 macvlan。overlay 和 macvlan 用于创建 跨主机的网络,
可通过 bridge 驱动创建类似前面默认的 bridge 网络,例如:
[root@docker ~]# docker network create --driver bridge my_net
7d268fd0e52a528d3f5e9157b878eb441e49c2b0e53fe253c30b364e15d4d7eb# 查看当前host的网络结构变化
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-7d268fd0e52a 8000.02426fd16fe1 no
docker0 8000.0242c1dda268 no veth0205e26
# 执行 docker network inspect 查看一下 my_net 的配置信息
[root@docker ~]# docker network inspect my_net
[{"Name": "my_net","Id": "7d268fd0e52a528d3f5e9157b878eb441e49c2b0e53fe253c30b364e15d4d7eb","Created": "2025-09-08T16:26:20.264735533+08:00","Scope": "local","Driver": "bridge","EnableIPv6": false,"IPAM": {"Driver": "default","Options": {},"Config": [{"Subnet": "172.18.0.0/16","Gateway": "172.18.0.1"}]},"Internal": false,"Attachable": false,"Ingress": false,"ConfigFrom": {"Network": ""},"ConfigOnly": false,"Containers": {},"Options": {},"Labels": {}}
]
172.18.0.0/16 是 Docker 自动分配的 IP 网段。也可以指定ip网段
指定ip网段
[root@docker ~]# docker network create --driver bridge --subnet 172.22.16.0/24 --gateway 172.22.16.1 my_net2
0bda1cbf58e0432df26896791e9cef598142494af941abd2b6d35a5a0961406b[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-0bda1cbf58e0 8000.0242cf26c94b no
br-7d268fd0e52a 8000.02426fd16fe1 no
docker0 8000.0242c1dda268 no veth0205e26[root@docker ~]# docker network inspect my_net2
[{"Name": "my_net2","Id": "0bda1cbf58e0432df26896791e9cef598142494af941abd2b6d35a5a0961406b","Created": "2025-09-08T16:29:28.58016471+08:00","Scope": "local","Driver": "bridge","EnableIPv6": false,"IPAM": {"Driver": "default","Options": {},"Config": [{"Subnet": "172.22.16.0/24","Gateway": "172.22.16.1"}]},"Internal": false,"Attachable": false,"Ingress": false,"ConfigFrom": {"Network": ""},"ConfigOnly": false,"Containers": {},"Options": {},"Labels": {}}
]
查看my_net2网卡
[root@docker ~]# ip a | grep br-0bda1cbf58e0
7: br-0bda1cbf58e0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group defaultinet 172.22.16.1/24 brd 172.22.16.255 scope global br-0bda1cbf58e0
容器要使用新的网络,需要在启动时通过 --network 指定:
[root@docker ~]# docker run -it --network=my_net2 --name busybox2 busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope hostvalid_lft forever preferred_lft forever
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueuelink/ether 02:42:ac:16:10:02 brd ff:ff:ff:ff:ff:ffinet 172.22.16.2/24 brd 172.22.16.255 scope global eth0valid_lft forever preferred_lft forever
/ # # ctrl+P + ctrl+q退出容器
# 如果是exit退出的话就会 brctl show看不到[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-0bda1cbf58e0 8000.0242cf26c94b no vethe99f91c
br-7d268fd0e52a 8000.02426fd16fe1 no
docker0 8000.0242c1dda268 no veth0205e26# my_net2上新增的接口br-0bda1cbf58e0连接容器busybox2
# 容器分配到的 IP 为 172.22.16.2。
也可以配置静态ip
[root@docker ~]# docker run -it --network=my_net2 --ip 172.22.16.8 --name busybox3 busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope hostvalid_lft forever preferred_lft forever
12: eth0@if13: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueuelink/ether 02:42:ac:16:10:08 brd ff:ff:ff:ff:ff:ffinet 172.22.16.8/24 brd 172.22.16.255 scope global eth0valid_lft forever preferred_lft forever
/ # [root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-0bda1cbf58e0 8000.0242cf26c94b no vethd98b1f3vethe99f91c
br-7d268fd0e52a 8000.02426fd16fe1 no
docker0 8000.0242c1dda268 no veth0205e26
容器之间的连通性
busybox2、busybox3 容器都挂在 my_net2 上,应该能够互通,可以验证一下:
# 登陆busybox2 ping busybox3
[root@docker ~]# docker exec -it busybox2 sh
/ # ifconfig eth0
eth0 Link encap:Ethernet HWaddr 02:42:AC:16:10:02inet addr:172.22.16.2 Bcast:172.22.16.255 Mask:255.255.255.0UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1RX packets:15 errors:0 dropped:0 overruns:0 frame:0TX packets:0 errors:0 dropped:0 overruns:0 carrier:0collisions:0 txqueuelen:0RX bytes:1226 (1.1 KiB) TX bytes:0 (0.0 B)/ # ping -c 3 172.22.16.8
PING 172.22.16.8 (172.22.16.8): 56 data bytes
64 bytes from 172.22.16.8: seq=0 ttl=64 time=0.134 ms
64 bytes from 172.22.16.8: seq=1 ttl=64 time=0.104 ms
64 bytes from 172.22.16.8: seq=2 ttl=64 time=0.121 ms--- 172.22.16.8 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.104/0.119/0.134 ms# ping my_net2网关地址
/ # ping -c 3 172.22.16.1
PING 172.22.16.1 (172.22.16.1): 56 data bytes
64 bytes from 172.22.16.1: seq=0 ttl=64 time=0.160 ms
64 bytes from 172.22.16.1: seq=1 ttl=64 time=0.095 ms
64 bytes from 172.22.16.1: seq=2 ttl=64 time=0.144 ms--- 172.22.16.1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.095/0.133/0.160 ms# busybox2 容器 ping buxybox1 容器
/ # ping -c 3 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes--- 172.17.0.2 ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss
/ ## 同一网络中的容器、网关之间都是可以通信的。
# 不同的网桥,不能通信
不同的网络加上路由可以通信
# 先查看路由表
[root@docker ~]# ip r
default via 192.168.108.2 dev ens160 proto static metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
172.18.0.0/16 dev br-7d268fd0e52a proto kernel scope link src 172.18.0.1 linkdown
172.22.16.0/24 dev br-0bda1cbf58e0 proto kernel scope link src 172.22.16.1
192.168.108.0/24 dev ens160 proto kernel scope link src 192.168.108.30 metric 100# 查看ip forwarding
[root@docker ~]# sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
# 也已经已起用# 条件满足为什么不能通行?
查看 iptables
[root@docker ~]# iptables-save
# Generated by iptables-save v1.8.5 on Mon Sep 8 16:58:15 2025
*filter
:INPUT ACCEPT [25962:47949738]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [14999:764562]
:DOCKER - [0:0]
:DOCKER-ISOLATION-STAGE-1 - [0:0]
:DOCKER-ISOLATION-STAGE-2 - [0:0]
:DOCKER-USER - [0:0]
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o br-0bda1cbf58e0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o br-0bda1cbf58e0 -j DOCKER
-A FORWARD -i br-0bda1cbf58e0 ! -o br-0bda1cbf58e0 -j ACCEPT
-A FORWARD -i br-0bda1cbf58e0 -o br-0bda1cbf58e0 -j ACCEPT
-A FORWARD -o br-7d268fd0e52a -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o br-7d268fd0e52a -j DOCKER
-A FORWARD -i br-7d268fd0e52a ! -o br-7d268fd0e52a -j ACCEPT
-A FORWARD -i br-7d268fd0e52a -o br-7d268fd0e52a -j ACCEPT
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i br-0bda1cbf58e0 ! -o br-0bda1cbf58e0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -i br-7d268fd0e52a ! -o br-7d268fd0e52a -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o br-0bda1cbf58e0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -o br-7d268fd0e52a -j DROP
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN
COMMIT
# Completed on Mon Sep 8 16:58:15 2025
# Generated by iptables-save v1.8.5 on Mon Sep 8 16:58:15 2025
*security
:INPUT ACCEPT [25962:47949738]
:FORWARD ACCEPT [6:504]
:OUTPUT ACCEPT [14999:764562]
COMMIT
# Completed on Mon Sep 8 16:58:15 2025
# Generated by iptables-save v1.8.5 on Mon Sep 8 16:58:15 2025
*raw
:PREROUTING ACCEPT [25971:47950494]
:OUTPUT ACCEPT [14999:764562]
COMMIT
# Completed on Mon Sep 8 16:58:15 2025
# Generated by iptables-save v1.8.5 on Mon Sep 8 16:58:15 2025
*mangle
:PREROUTING ACCEPT [25971:47950494]
:INPUT ACCEPT [25962:47949738]
:FORWARD ACCEPT [9:756]
:OUTPUT ACCEPT [14999:764562]
:POSTROUTING ACCEPT [15005:765066]
COMMIT
# Completed on Mon Sep 8 16:58:15 2025
# Generated by iptables-save v1.8.5 on Mon Sep 8 16:58:15 2025
*nat
:PREROUTING ACCEPT [7:524]
:INPUT ACCEPT [3:188]
:POSTROUTING ACCEPT [72:5306]
:OUTPUT ACCEPT [71:5222]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.22.16.0/24 ! -o br-0bda1cbf58e0 -j MASQUERADE
-A POSTROUTING -s 172.18.0.0/16 ! -o br-7d268fd0e52a -j MASQUERADE
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A DOCKER -i br-0bda1cbf58e0 -j RETURN
-A DOCKER -i br-7d268fd0e52a -j RETURN
-A DOCKER -i docker0 -j RETURN
COMMIT
# Completed on Mon Sep 8 16:58:15 2025
原因就在这里了:iptables DROP 掉了网桥 docker0 与 br-0bda1cbf58e0(my_net2) 之间双向的流 量。
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-0bda1cbf58e0 8000.0242cf26c94b no vethd98b1f3vethe99f91c
br-7d268fd0e52a 8000.02426fd16fe1 no
docker0 8000.0242c1dda268 no veth0205e26
所以为 busybox1 容器添加一块 my_net2的网卡就可以进行busybox1与busybox2 通信了。
可以通过 docker network connect 命令 实现。
[root@docker ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b82c2a1ccafc busybox "sh" 12 minutes ago Up 12 minutes busybox3
7defcefee85f busybox "sh" 18 minutes ago Up 18 minutes busybox2
33ce4b4d13e9 busybox "sh" About an hour ago Up About an hour busybox1
[root@docker ~]# docker network connect my_net2 busybox1# 在 httpd 容器中查看一下网络配置
[root@docker ~]# docker exec -it busybox1 sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00inet 127.0.0.1/8 scope host lovalid_lft forever preferred_lft foreverinet6 ::1/128 scope hostvalid_lft forever preferred_lft forever
4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueuelink/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ffinet 172.17.0.2/16 brd 172.17.255.255 scope global eth0valid_lft forever preferred_lft forever
14: eth1@if15: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueuelink/ether 02:42:ac:16:10:03 brd ff:ff:ff:ff:ff:ffinet 172.22.16.3/24 brd 172.22.16.255 scope global eth1valid_lft forever preferred_lft forever
/ # read escape sequence
[root@docker ~]# brctl show
bridge name bridge id STP enabled interfaces
br-0bda1cbf58e0 8000.0242cf26c94b no veth378ed6bvethd98b1f3vethe99f91c
br-7d268fd0e52a 8000.02426fd16fe1 no
docker0 8000.0242c1dda268 no veth0205e26# 容器中增加了一个网卡 eth1,分配了 my_net2 的 IP 172.22.16.3。现在 busybox2 应该能够访问busybox1 了
验证
[root@docker ~]# docker exec -it busybox2 sh
/ # ping -c 3 172.22.16.3
PING 172.22.16.3 (172.22.16.3): 56 data bytes
64 bytes from 172.22.16.3: seq=0 ttl=64 time=0.155 ms
64 bytes from 172.22.16.3: seq=1 ttl=64 time=0.107 ms
64 bytes from 172.22.16.3: seq=2 ttl=64 time=0.111 ms--- 172.22.16.3 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.107/0.124/0.155 ms# busybox 能够 ping 到 busybox2
ame bridge id STP enabled interfaces
br-0bda1cbf58e0 8000.0242cf26c94b no veth378ed6b
vethd98b1f3
vethe99f91c
br-7d268fd0e52a 8000.02426fd16fe1 no
docker0 8000.0242c1dda268 no veth0205e26
容器中增加了一个网卡 eth1,分配了 my_net2 的 IP 172.22.16.3。现在 busybox2 应该能够访问busybox1 了
验证```bash
[root@docker ~]# docker exec -it busybox2 sh
/ # ping -c 3 172.22.16.3
PING 172.22.16.3 (172.22.16.3): 56 data bytes
64 bytes from 172.22.16.3: seq=0 ttl=64 time=0.155 ms
64 bytes from 172.22.16.3: seq=1 ttl=64 time=0.107 ms
64 bytes from 172.22.16.3: seq=2 ttl=64 time=0.111 ms--- 172.22.16.3 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.107/0.124/0.155 ms# busybox 能够 ping 到 busybox2