数据卷&&网络

8335 字
42 分钟
数据卷&&网络

数据卷&&网络#

[TOC]


数据卷#

Terminal window
1.让容器的"数据进行持久化",说白了,就是让容器的数据不丢失
2.数据卷技术,本质上是把宿主机(Linux)的目录,挂载(映射)到容器内部
3.容器之间也是可以进行数据共享
4.可以指定一个宿主机的路径,也可以使用存储卷进行管理
========================================
1)镜像准备
[root@Docker ~]# docker images | grep nginx
nginx:latest 7f0adca1fc6c
2)ro映射
[root@Docker ~]# ll /data/index
ls: cannot access '/data/index': No such file or directory
# 刚开始,宿主机也没有这个目录
[root@Docker ~]# docker run -d --name web -p 81:80 -v /data/index:/usr/share/nginx/html/:ro --restart unless-stopped nginx
--restart: # 为了能够让数据卷持久化挂载
-v: # 前面是宿主机目录,后面是容器目录
'都可以没有,会自动创建'
✅️属于指定路径挂载!
:ro # 以只读的方式进行挂载
'默认给rw'
[root@Docker ~]# ll /data/index
total 0
# 现在有了,会自动创建
[root@Docker ~]# docker exec -it web /bin/bash
root@54cce6d13894:/# curl localhost
<title>403 Forbidden</title>
# 403,这里是因为主页缺失!
root@54cce6d13894:/# cd /usr/share/nginx/html/
root@54cce6d13894:/usr/share/nginx/html# ls
root@54cce6d13894:/usr/share/nginx/html#
'里面没有默认主页!'
✅️覆盖行为
原本是有默认主页的,只是被覆盖隐藏了
取而代之的是宿主机目录下的内容
'相当于是把宿主机的目录挂载到容器里面了'
⚠️原文件并没有被删除,一旦你取消挂载,原文件就会重新出现
🌿这里是指定的宿主机路径,如果是数据卷--->有一个初始化机制✅️
# 会进行复制而并非覆盖!!!
root@54cce6d13894:/usr/share/nginx/html# echo "<h1>kpyun<h1/>" > index.html
bash: index.html: Read-only file system
# 想要手动给个主页,被警告权限拒绝!
🌿因为这里实际上是宿主机的目录,我们是:ro只读,没有权限!
[root@Docker ~]# echo "<h1>kpyun<h1/>" > /data/index/index.html
# 给个主页
[root@Docker ~]# curl localhost:81
<h1>kpyun<h1/>
[root@Docker ~]# docker inspect web -f {{.Mounts}}
[{bind /data/index /usr/share/nginx/html ro false rprivate}]
# 但是总觉得怪怪的!
[root@Docker ~]# docker inspect web | grep -A 8 Mounts
"Mounts": [
{
"Type": "bind",
"Source": "/data/index",
"Destination": "/usr/share/nginx/html",
"Mode": "ro",
"RW": false,
"Propagation": "rprivate"
}
✅️ 这样子显示出来就更加清晰了!
[root@Docker ~]# docker exec -it web /bin/bash
root@54cce6d13894:/# cat /usr/share/nginx/html/index.html
<h1>kpyun<h1/>
# 一模一样
[root@Docker ~]# docker rm -f web
# 即使把这个容器删除了,我们宿主机的文件依旧保留
[root@Docker ~]# cat /data/index/index.html
<h1>kpyun<h1/>
3)rw映射
[root@Docker ~]# docker run -d --name web02 -p 81:80 -v /data/index:/usr/share/nginx/html/:rw --restart unless-stopped nginx
# 这次换了一个容器,但依旧是那个容器卷:rw权限
[root@Docker ~]# curl localhost:81
<h1>kpyun<h1/>
# 拉取页面直接就拉取成功了!
[root@Docker ~]# docker exec -it web02 /bin/bash
root@b3a1c588cd4d:/# cd /usr/share/nginx/html/
root@b3a1c588cd4d:/usr/share/nginx/html# cat index.html
<h1>kpyun<h1/>
root@b3a1c588cd4d:/usr/share/nginx/html# echo oldboy > index.html
'修改默认主页'
root@b3a1c588cd4d:/usr/share/nginx/html# curl localhost
oldboy
✅️成功拉取到了 :rw ---> 可读写 "默认不写就是它"
4)多个数据卷
[root@Docker ~]# docker run -d --name web03 -p 82:80 -v /data/index:/usr/share/nginx/html/:rw -v /oldboy:/kpyun --restart unless-stopped nginx
'挂载多个容器卷'
[root@Docker ~]# ll -d /oldboy/
drwxr-xr-x 2 root root 6 Apr 21 08:30 /oldboy/
# 凭空创建
[root@Docker ~]# docker exec -it web03 /bin/bash
root@bf9cc775e720:/# ls -d -lh /kpyun/
drwxr-xr-x 2 root root 6 Apr 21 00:30 /kpyun/
# 也是自动创建
root@bf9cc775e720:/# echo 111 >/kpyun/test.md
root@bf9cc775e720:/# exit
exit
[root@Docker ~]# cat /oldboy/test.md
111
# 数据同步

—volumes-from#

image-20260421093045376
image-20260421093045376

Terminal window
[root@Docker ~]# docker run -d --name web04 -p 83:80 --volumes-from web03 --restart unless-stopped nginx
'--volumes-from'
# 覆盖了原本的文件
[root@Docker ~]# curl localhost:83
oldboy
# 依旧拉取到它
'此时,宿主机和父容器和子容器实现数据同步'
[root@Docker ~]# docker rm -f web03
web03
'即使把父容器删除了,子容器依旧可以拉取到'
[root@Docker ~]# curl localhost:83
oldboy
'本质上拉取的还是宿主机的文件'
[root@Docker ~]# cat /data/index/index.html
oldboy
[root@Docker ~]# docker exec -it web04 /bin/bash
root@9c8a77065d54:/# cd /usr/share/nginx/html/
root@9c8a77065d54:/usr/share/nginx/html# cat index.html
oldboy
root@9c8a77065d54:/usr/share/nginx/html# echo hhhh > index.html
# 修改页面后,成功拉取到
root@9c8a77065d54:/usr/share/nginx/html# curl localhost
hhhh
root@9c8a77065d54:/usr/share/nginx/html# exit
exit
# 退出容器后,宿主机里面的文件也被修改了
[root@Docker ~]# cat /data/index/index.html
hhhh

docker volume#

Terminal window
[root@Docker ~]# docker volume ls
DRIVER VOLUME NAME
local 0d47xxxxx
local 3d03xxxxx
local 9e9fxxxxx
............
[root@Docker ~]# cd /var/lib/docker/volumes/
"默认的存储位置"
# 把数据放在一个固定的目录
[root@Docker volumes]# ll
drwx-----x 3 root root 19 Apr 19 15:35 0d47xxx
drwx-----x 3 root root 19 Apr 19 14:41 3d03xxx
drwx-----x 3 root root 19 Apr 19 13:41 9e9fxxx
...............
[root@Docker ~]# docker rm -f $(docker ps -aq)
'清除环境'
[root@Docker ~]# docker volume --help
Usage: docker volume COMMAND
Commands:
create Create a volume # 创建数据卷
inspect Display detailed information
ls List volumes # 列出
prune Remove unused local volumes # 删除未使用的
rm Remove one or more volumes # 删除
[root@Docker ~]# docker volume prune -f
Deleted Volumes:
'清理数据卷'
👆匿名卷好用,手动创建的数据卷
---> 再加上-a选项,所有都删除
docker volume prune -fa
1)创建数据卷
[root@Docker ~]# docker volume create --help
Usage: docker volume create [OPTIONS] [VOLUME]
Options:
-d, --driver string 设备驱动(default "local")
[root@Docker ~]# docker volume create
# 后面什么都不跟
674760xxx
'创建了一个匿名的数据卷'
[root@Docker ~]# docker volume ls
DRIVER VOLUME NAME
local 674760xxx
2)设备驱动,不能乱写!
[root@Docker ~]# docker volume create -d xixi
❌️plugin "xixi" not found--->🉐安装插件
"默认是local设备"
3)指定数据卷名字
'对应具名挂载'
[root@Docker ~]# docker volume create -d local kpyun
# -d 默认就是local,可以省略不写
kpyun
[root@Docker ~]# docker volume ls
local kpyun
4)删除数据卷
[root@Docker ~]# docker volume rm kpyun 674760xxx
# rm 指定删除
[root@Docker ~]# docker volume prune -fa
'全部未使用的数据卷'
✅️更推荐这个
-a选项手动创建的数据卷也适用
5)详细信息的查看
[root@Docker ~]# docker volume create kpyun
kpyun
[root@Docker ~]# docker volume inspect kpyun
[
{
"CreatedAt": "2026-04-21T11:01:11+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/kpyun/_data",
✅️上面是挂载点,数据存放的位置
"Name": "kpyun",
"Options": null,
"Scope": "local"
}
]
[root@Docker ~]# cd /var/lib/docker/volumes/
[root@Docker volumes]# tree kpyun/
kpyun/
└── _data
[root@Docker volumes]# echo Hello World > kpyun/_data/index.html
'数据卷里面不是空的,提前写了一个主页'
6)具名挂载
'指定数据卷'
[root@Docker ~]# docker run -d --name web -v kpyun:/usr/share/nginx/html nginx
# 这次是我们提前创建的数据卷kpyun
[root@Docker ~]# docker exec -it web /bin/bash
root@8e1728b6ebe1:/# curl localhost
Hello World
'这里是提前写的主页'
root@8e1728b6ebe1:/# echo aaaa > /usr/share/nginx/html/test.html
# 创建测试文件
root@8e1728b6ebe1:/# exit
exit
[root@Docker ~]# cd /var/lib/docker/volumes/
[root@Docker volumes]# tree kpyun/
kpyun/
└── _data
├── index.html
└── test.html
[root@Docker volumes]# cat kpyun/_data/test.html
aaaa
7)再次挂载
'在挂载的同时创建数据卷'
[root@Docker volumes]# docker volume ls | grep xixi | wc -l
0
# 并没有这个数据卷
[root@Docker volumes]# docker run -d --name web02 -p 82:80 -v xixi:/usr/share/nginx/html nginx
# 指定xixi数据卷
[root@Docker volumes]# docker volume ls | grep xixi | wc -l
1
[root@Docker volumes]# docker volume ls | grep xixi
local xixi
# 自动创建的xixi数据卷
[root@Docker volumes]# tree /var/lib/docker/volumes/xixi
/var/lib/docker/volumes/xixi
└── _data
├── 50x.html
└── index.html
'它把,容器里对应路径下的文件“复制”一份到数据卷里'
# 而不是覆盖为空!
[root@Docker volumes]# curl localhost:82
<title>Welcome to nginx!</title>

Docker 数据卷(Named Volume)有一个“初始化机制”

==核心原则是:==

  • 如果数据卷是空的(刚创建,里面没东西)

  • Docker 会把容器镜像里对应路径下的文件==“复制”==一份到数据卷里

    • ⚠️指定宿主机路径为==覆盖行为==
Terminal window
'上面是提前创建数据卷并给了一个主页'
# 我们这次试试 新创建数据卷--->里面没东西
[root@Docker ~]# docker volume create xin
# 新创建的数据卷
[root@Docker ~]# tree /var/lib/docker/volumes/xin/
/var/lib/docker/volumes/xin/
└── _data
👇0个文件-->里面是空的
2 directories, 0 files
[root@Docker ~]# docker run -d -p 84:80 --name web04 -v xin:/usr/share/nginx/html nginx
# 手动指定我们刚创建的数据卷
[root@Docker ~]# tree /var/lib/docker/volumes/xin/
/var/lib/docker/volumes/xin/
└── _data
├── 50x.html
└── index.html
'现在里面有文件了'
2 directories, 2 files
[root@Docker ~]# curl localhost:84
<title>Welcome to nginx!</title>
'Nginx的默认主页'

为什么会有这个机制?

为了把原本容器里自带的“初始数据”搬运到外部存储中,保证程序能正常启动

Note
  • 卷空 -> 复制容器数据进去(保留文件)
  • 卷有数据 -> 直接挂载(覆盖/隐藏容器文件)

我们可以把数据卷比作**“书包”**

操作结果原因
你没准备书包,直接去上学 docker run -v xixi:/path老师(Docker)看你没带书包,发了一个新书包,并把新课本(容器文件)帮你装进书包里初始化机制:空卷会自动填充容器数据
你提前买了一个空书包 docker volume create (空)老师看你带了空书包,还是会把新课本(容器文件)帮你装进书包里同上,只要书包是空的,就会填充
你提前准备了一个装有旧书的书包 docker volume create (有数据)老师看你书包里有书,就不会发新课本了==挂载覆盖==:已有数据优先,不再初始化
Terminal window
8)匿名挂载
-v /data
# 只写一个路径
✅️它是容器里面的路径
那宿主机呢? 随机生成一个数据卷(长串字符)
[root@Docker ~]# docker rm -f $(docker ps -qa)
# 把容器都删除了
[root@Docker ~]# docker volume ls
DRIVER VOLUME NAME
local kpyun
local xin
local xixi
'这是现在的容器卷!'
[root@Docker ~]# docker run -d --name web -p 81:80 -v /data nginx
# 跑一个容器, -v /data
[root@Docker ~]# docker exec -it web /bin/bash
root@61b72b61452c:/# ls -d /data
/data
'证明: 是在容器里面创建出来的目录!'
root@61b72b61452c:/# echo Hello > /data/test.md
root@61b72b61452c:/# cat /data/test.md
Hello
root@61b72b61452c:/# exit
exit
[root@Docker ~]# docker volume ls
DRIVER VOLUME NAME
local 931bbxxx....
# 你会发现自己的数据卷多出来一个!
如何确定,数据卷和容器的对应关系呢❓️
docker inspect 容器名 -f {{.Mounts}}
[root@Docker ~]# docker inspect web -f {{.Mounts}}
[{volume 931bbfxx....
'可以迅速确定它对应的数据卷'
[root@Docker ~]# docker volume inspect 931bbfxx....
# 查看数据卷的详细信息
[
{
"CreatedAt": "2026-04-21T13:09:51+08:00",
"Driver": "local",
"Labels": {
"com.docker.volume.anonymous": ""
},
"Mountpoint": "/var/lib/docker/volumes/931../_data",
✅️挂载点
"Name": "931bbfb...xxx",
"Options": null,
"Scope": "local"
}
]
[root@Docker ~]# tree /var/lib/docker/volumes/931../
└── _data
└── test.md
# 这里面也有这个文件!
[root@Docker ~]# cat /var/lib/docker/volumes/931./_data/test.md
Hello
'内容一致!'
Terminal window
docker rm -f -v
✅️可以删除匿名挂载的数据卷
❌️手动创建的删除不掉
"清理环境"
[root@Docker ~]# docker rm -f $(docker ps -qa)
[root@Docker ~]# docker volume prune -fa
[root@Docker ~]# docker volume ls
DRIVER VOLUME NAME
# 里面是空的
[root@Docker ~]# docker volume create kpyun
kpyun
[root@Docker ~]# docker run -d --name web -p 81:80 -v kpyun:/oldboy -v /data nginx
🌰第一个指定数据卷-->具名挂载
🌰第二个匿名挂载
[root@Docker ~]# docker volume ls
DRIVER VOLUME NAME
local 6d294xxx...
local kpyun
[root@Docker ~]# docker exec -it web /bin/bash
root@c4cb1b1483e2:/# ls -d /data
/data
root@c4cb1b1483e2:/# ls -d /oldboy
/oldboy
[root@Docker ~]# docker rm -f -v web
web
[root@Docker ~]# docker volume ls
DRIVER VOLUME NAME
local kpyun
# 只剩下一个我们创建的数据卷
[root@Docker ~]# docker ps -a
# 没有容器占用数据卷
[root@Docker ~]# docker volume prune -f
Total reclaimed space: 0B
'只加 -f 还删除不了--->手动创建的数据卷'
✅️ -a all所有的都删除,有它才能全部删除干净
[root@Docker ~]# docker volume prune -fa
Deleted Volumes:
kpyun
[root@Docker ~]# docker volume ls
DRIVER VOLUME NAME
# 现在一个也没有了!

🌐网络#

docker0#

Terminal window
[root@test ~]# ip a show docker0
4: docker0: xxx
link/ether 02:42:3e:89:e1:a9 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
✅️ docker 0的IP地址为 172.17.0.1
[root@test ~]# docker rm -f $(docker ps -aq)
'清理环境'
1)docker带来的网卡都是成对出现
[root@test ~]# docker run -d -it --name v1 alpine:3.20.2
[root@test ~]# docker exec v1 ip a show eth0
'容器内部'
7: eth0@if8: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
🌰前面有个7,过滤宿主机就过滤if7肯定没错!
[root@test ~]# ip a | grep -A 4 'if7'
⚠️还要看vethxxx..@if7
'前面的数字和字母串唯一'
'if8对应着vethxxx..@if7'--->成对出现
8: veth37417ae@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether a2:ba:16:99:dd:f6 brd ff:ff:ff:ff:ff:ff link-netnsid 0
2)互相ping
'再跑一个容器'
[root@test ~]# docker run -d -it --name v2 alpine:3.20.2
[root@test ~]# docker exec v2 ip a show eth0
9: eth0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.3/16 xxx...
[root@test ~]# ip a | grep -A 4 'if9'
10: veth0ec9eb6@if9: xxx...
✅️依旧成对出现!
[root@test ~]# docker exec -it v2 sh
/ # tail -1 /etc/hosts
172.17.0.3 516ef652fd31
/ # ping 172.17.0.2
'v1容器的IP为172.xxx.2'
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.087 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.080 ms

image-20260421205916758
image-20260421205916758

veth-pair技术#

你可以把它通俗地理解为一根虚拟的网线

它的工作原理非常简单,核心特点如下:

  • 成对出现:它总是由两个虚拟接口组成,就像一根网线的两个水晶头
    • 💚容器内部: 7: eth0@if8
    • ❤️宿主机中: 8: veth37417ae@if7
  • 连接桥梁:它的主要作用是连接两个不同的网络环境
    • 最常见的场景就是连接宿主机(Linux)容器

容器通常有自己独立的网络空间,就像在一个封闭的房间里

  • veth-pair 就像是在墙上打了个洞,穿了一根网线进去
    • 一头插在容器里面, 另一头插在宿主机
    • 然后又连接到了 docker0
    • docker0 在这里扮演了一个虚拟交换机的角色
Terminal window
[root@test ~]# yum -y install bridge-utils
[root@test ~]# brctl show docker0
bridge name interfaces
docker0 veth0ec9eb6
veth37417ae
# v1和v2宿主机上的网卡再次接到了docker0上
veth0ec9eb6@if9 && veth37417ae@if7
它是如何连接宿主机(Linux)和容器的呢❓️
✅️宿主机有docker0这张网卡
使用这张网卡的IP地址:172.17.0.1和容器进行通信
[root@test ~]# ping 172.17.0.2
'用宿主机ping 容器v1'
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.066 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.102 ms
'开另一个窗口抓包'
[root@test ~]# tcpdump -nnvvi docker0 host 172.17.0.2
tcpdump: listening on docker0
172.17.0.1 > 172.17.0.2: ICMP echo request, id 3589, seq 1, length 64
172.17.0.2 > 172.17.0.1: ICMP echo reply, id 3589, seq 1, length 64

宿主机 Ping 容器的完整路径

当你在宿主机上执行 ping 172.17.0.2 时,数据包是这样走的:

  1. 起点:Ping 命令在宿主机发起,数据包的目标是容器的 IP 172.17.0.2
  2. 进入交换机:宿主机会发现这个 IP 属于 docker0 网桥所在的网段(172.17.0.1docker0 的 IP),于是数据包被送到了 docker0 虚拟交换机
  3. 查找端口docker0 交换机根据 MAC 地址表,知道去往 172.17.0.2 的数据需要从连接着 veth37417ae 的端口转发出去
  4. 穿过网线:数据包进入 veth37417ae 接口,通过这根“虚拟网线”,瞬间从容器内部的 eth0@if7 接口出来
  5. 抵达终点:数据包最终到达容器 v1,容器处理后,再以同样的路径返回一个 Echo Reply
  • 整个通信流程就是:宿主机 -> docker0 -> veth-pair -> 容器
  • docker0 是连接宿主机和所有容器的核心枢纽

容器如何上网#

Terminal window
[root@test ~]# docker exec -it v1 sh
/ # route -n
Destination Gateway
0.0.0.0 172.17.0.1
'默认网关是docker0'
/ # ping www.baidu.com
'容器ping百度'
PING www.baidu.com (39.156.70.239): 56 data bytes
64 bytes from 39.156.70.239: seq=0 ttl=127 time=10.631 ms
64 bytes from 39.156.70.239: seq=1 ttl=127 time=9.768 ms
[root@test ~]# tcpdump -nnvvi vetha463a34 icmp
tcpdump: listening on vetha463a34
172.17.0.2 > 39.156.70.239: ICMP echo request, id 15, seq 0, length 64
39.156.70.239 > 172.17.0.2: ICMP echo reply, id 15, seq 0, length 64
'👆vetha463a34 和 👇docker0抓包的内容是一样的!'
[root@test ~]# tcpdump -nnvvi docker0 icmp
tcpdump: listening on docker0
172.17.0.2 > 39.156.70.239: ICMP echo request, id 13, seq 21, length 64
39.156.70.239 > 172.17.0.2: ICMP echo reply, id 13, seq 21, length 64
[root@test ~]# tcpdump -nnvvi eth0 icmp
tcpdump: listening on eth0
10.0.0.128 > 39.156.70.239: ICMP echo request, id 14, seq 0, length 64
39.156.70.239 > 10.0.0.128: ICMP echo reply, id 14, seq 0, length 64
[root@test ~]# sysctl -q net.ipv4.ip_forward
net.ipv4.ip_forward = 1
'这里内核转发默认是开启的'
✅️允许数据包在不同网卡(docker0 -> eth0)之间流动
[root@test ~]# sysctl -w net.ipv4.ip_forward=0
net.ipv4.ip_forward = 0
'关闭后'
'容器中再次ping'
/ # ping www.baidu.com
ping: bad address 'www.baidu.com'
'这次就ping不通了'

网络拓扑结构:

  • 宿主机 (Host):
    • 物理网卡 (eth0): 10.0.0.128
    • Docker 网桥 (docker0): 172.17.0.1 (通常默认网关)
    • Veth Pair (宿主机端): vetha463a34 (连接到 docker0)
  • 容器 (Container v1):
    • IP 地址: 172.17.0.2
    • 默认网关: 172.17.0.1 (指向宿主机的 docker0)
  • 目标 (Target):
    • www.baidu.com (39.156.70.239)

数据包流向分析:

  1. 容器发出请求:
    • 容器 (172.17.0.2) 发送 ICMP 请求给百度
    • 数据包到达容器的默认网关,即宿主机的 docker0 网桥
  2. 宿主机接收 (docker0/veth):
    • 抓包证据: tcpdump -i veth...tcpdump -i docker0 显示 172.17.0.2 > 39.156.70.239
    • 数据包成功到达了宿主机的内部网桥接口
  3. 路由与转发 (关键步骤):
    • 宿主机内核检查路由表,发现目标 39.156.70.239 不在本地网段,需要通过 eth0 发往外部网关
    • 内核检查 net.ipv4.ip_forward
      • 此时值为 1 (开启)
      • 内核允许将数据包从 docker0 接口 转发eth0 接口
    • NAT (SNAT): Docker 的 iptables 规则通常会将源 IP 172.17.0.2 伪装成宿主机的 IP 10.0.0.128
      • 于是就成了--->宿主机的 IP 10.0.0.128 访问 baidu.com
  4. 发往外部:
    • 抓包证据: tcpdump -i eth0 显示 10.0.0.128 > 39.156.70.239
    • 数据包成功离开宿主机,到达百度服务器
  5. 回程: 百度回复数据包给 10.0.0.128 -> 宿主机收到 -> DNAT还原目标 IP 为 172.17.0.2 ->转发回 docker0 -> 容器

docker容器端口转发底层原理图解
docker容器端口转发底层原理图解

  • 涉及到 IPtables

端口转发#

Terminal window
[root@test ~]# docker run -d -p 90:80 --name web nginx
[root@test ~]# docker ps
d337385e7c7b nginx "/docker-entrypoint.…"
[root@test ~]# iptables-save | grep 90
:PREROUTING ACCEPT [8867:1493909]
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 90 -j DNAT --to-destination 172.17.0.4:80
# 这条规则是 Docker 自动添加的,用于实现端口映射
==========================================
-A DOCKER # Append(追加)到 DOCKER 链
! -i docker0 # 不是从 docker0 网卡进来的包
-p tcp # 指定协议
-m tcp # 加载 TCP 协议的扩展模块
'访问90端口 --> DNAT --> 172.17.0.4:80'

基本网络类型#

类型\描述描述
bridge为容器创建一对虚拟网卡,默认类型
none不为容器分配任何网卡设备,仅有一块lo本地回环网卡
host不为容器创建虚拟网卡,而是使用宿主机的IP和端口
这种网络类型性能最高,但是要注意容器和宿主机端口冲突问题
container和一个正在运行的容器共享IP、端口范围
Terminal window
'清理环境'
[root@test ~]# docker rm -f $(docker ps -aq)
1)准备测试环境
[root@test ~]# docker run -id --name c1-bridge --network bridge alpine:3.20.2
⬆️默认类型,可以省略不写
--network 可以写成 --net
[root@test ~]# docker run -id --name c2-none --network none alpine:3.20.2
[root@test ~]# docker run -id --name c3-host --network host alpine:3.20.2
[root@test ~]# docker run -id --name c4-container --network container:c1-bridge alpine:3.20.2
⬆️:c1-bridge 冒号:后跟容器名
# 和后面容器的网络保持一致
2)查看网卡
🌰"bridge网桥"
[root@test ~]# docker exec c1-bridge ip a
1: lo: xxx
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
13: eth0@if14:xxx
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
[root@test ~]# ip a | grep -A 5 @if13
14: vethbdbbeab@if13:xxx
link/ether a6:a7:70:a9:5f:e3 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet6 fe80::a4a7:70ff:fea9:5fe3/64 scope link
valid_lft forever preferred_lft forever
🌰"none"
[root@test ~]# docker exec c2-none ip a
👆只有回环网络
1: lo: xxx
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
[root@test ~]# docker exec c2-none ping www.baidu.com -W2 -c2
ping: bad address 'www.baidu.com'
[root@test ~]# docker exec c2-none route -n
Kernel IP routing table
Destination Gateway
'没有网关!没有路由'
🌰"host"
[root@test ~]# docker exec c3-host ip a
👆和宿主机中查看出来的网络信息一模一样✅️
⚠️不要有端口冲突
1: lo: <LOOPBACK,UP,LOWER_UP>
2: eth0: xxx
link/ether 00:0c:29:ec:ba:7b brd ff:ff:ff:ff:ff:ff
inet 10.0.0.128/24
5: docker0:xxx
link/ether 02:42:86:07:07:c6 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16
14: vethbdbbeab@if13:xxx
[root@test ~]# docker exec c3-host netstat -lntup | wc -l
27
'监听的网络信息也一致'
[root@test ~]# netstat -lntup | wc -l
27
[root@test ~]# docker exec c3-host route -n | wc -l
8
'路由信息也一致'
[root@test ~]# route -n | wc -l
8
🌰"container"
[root@test ~]# docker exec c1-bridge ip a | wc -l
10
[root@test ~]# docker exec c4-container ip a | wc -l
10
Terminal window
'清理环境'
[root@test ~]# docker rm -f $(docker ps -aq)
[root@test ~]# docker run -d -it --name v1 alpine:3.20.2
[root@test ~]# docker attach v1
/ # hostname
fc7e5245d29a
'主机名太长了'
/ # cat /etc/hosts | tail -1
172.17.0.2 fc7e5245d29a
/ # cat /etc/resolv.conf | grep nameserver
nameserver 223.6.6.6
⬆️DNS服务器地址
🌰-h 指定主机名 && --dns 指定dns服务器
[root@test ~]# docker run -d -it --name v1 -h kpyun --dns 114.114.114.114 alpine:3.20.2
[root@test ~]# docker attach v1
/ # hostname
kpyun
/ # cat /etc/hosts | tail -1
172.17.0.2 kpyun
/ # cat /etc/resolv.conf | grep nameserver
nameserver 114.114.114.114
/ # ping www.baidu.com -W2 -c2
PING www.baidu.com (110.242.70.57): 56 data bytes
64 bytes from 110.242.70.57: seq=0 ttl=127 time=10.369 ms
64 bytes from 110.242.70.57: seq=1 ttl=127 time=9.509 ms

自定义网络#

  • 可以自定义子网/掩码,网关,驱动等信息

    • 内置DNS解析功能
  • 如果不为网络指定驱动 ==-d==

    • 则默认使用bridge网络类型驱动
Terminal window
'清理环境'
[root@test ~]# docker rm -f $(docker ps -aq)
🌰网络驱动
[root@test ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
14ec8fea0ee8 bridge bridge local
b98e2e9c87db host host local
51394abfec25 none null local
'bridge、host 和 none 就是网络驱动(Driver)的名称'
✅️后续创建网络可以-d指定
🌰创建网络
[root@test ~]# docker network create --help
Create a network
-d, --driver # 网络设备(default "bridge")
--gateway # 指定网关
--subnet # 指定子网/掩码
[root@test ~]# docker network create -d bridge --subnet 172.20.0.0/16 --gateway 172.20.0.1 mynet
[root@test ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
4df8f531278c mynet bridge local
🌰第一个容器
[root@test ~]# docker run --name v1 -d -it --network mynet alpine:3.20.2
✅️指定为自己刚创建的网络
[root@test ~]# docker exec v1 ip a
'容器内部网络地址'
1: lo: xxx
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8
34: eth0@if35: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:14:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.20.0.2/16 brd 172.20.255.255
[root@test ~]# ip a | grep -A 4 @if34
'宿主机对应的网络'
35: vethaee52b3@if34:xxx
link/ether 82:bd:a1:09:ba:d6 brd ff:ff:ff:ff:ff:ff
'下面过滤的是网关'
[root@test ~]# ip a | grep -C 2 172.20.0.1
✅️ br-938e75f76ce7 等价于 docker0✅️
33: br-938e75f76ce7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:48:4c:39:56 brd ff:ff:ff:ff:ff:ff
inet 172.20.0.1/16 brd 172.20.255.255
🌰第二个容器
[root@test ~]# docker run --name v2 -d -it --network mynet alpine:3.20.2
[root@test ~]# docker exec v2 ip a
1: lo:
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8
36: eth0@if37:
link/ether 02:42:ac:14:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.20.0.2/16 brd 172.20.255.255
[root@test ~]# ip a | grep -A 4 @if36
37: veth21ab5d4@if36: xxx
link/ether e2:16:c6:17:32:92 brd ff:ff:ff:ff:ff:ff
==========================================
宿主机对应的网卡:
veth21ab5d4@if36
vethaee52b3@if34
他们都绑定在br-938e75f76ce7
[root@test ~]# brctl show br-938e75f76ce7
bridge name interfaces
br-938e75f76ce7 veth21ab5d4
vethaee52b3
'等价docker0'
🌰通过inspect查看网络
[root@test ~]# docker inspect v1 -f {{.NetworkSettings.Networks.mynet}}
{.xxx. 172.20.0.1 172.20.0.2 16 .xxx.}
"Gateway": "172.20.0.1",
"IPAddress": "172.20.0.2",
"IPPrefixLen": 16,
🌰内置DNS解析功能
[root@test ~]# docker exec -it v1 sh
/ # cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
....
172.20.0.2 47efc57c32c4
/ # cat /etc/resolv.conf | grep nameserver
nameserver 127.0.0.11
/ # ping v2
❤️即使本地hosts文件中没有
v2 ---> 172.20.0.3的映射关系
✅️可以ping通✅️
🦄容器重启后即使IP地址发生变化,可以通过容器名ping通
PING v2 (172.20.0.3): 56 data bytes
64 bytes from 172.20.0.3: seq=0 ttl=64 time=0.089 ms
64 bytes from 172.20.0.3: seq=1 ttl=64 time=0.066 ms
🌰IP地址抢夺
[root@test ~]# docker stop -t 0 v1
'停止他'
[root@test ~]# docker run --name v3 -d -it --network mynet alpine:3.20.2
[root@test ~]# docker exec v3 ip a
38: eth0@if39: ...xxx
link/ether 02:42:ac:14:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.20.0.2/16 brd 172.20.255.255
# 把ip地址抢回来了
[root@test ~]# docker start v1
[root@test ~]# docker exec v1 ip a
40: eth0@if41: ...xxx
link/ether 02:42:ac:14:00:04 brd ff:ff:ff:ff:ff:ff
inet 172.20.0.4/16 brd 172.20.255.255
[root@test ~]# docker exec v2 ip a
36: eth0@if37: ...xxx
link/ether 02:42:ac:14:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.20.0.3/16 brd 172.20.255.255
[root@test ~]# docker exec v2 ping v3
PING v3 (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.063 ms
64 bytes from 172.20.0.2: seq=1 ttl=64 time=0.075 ms
[root@test ~]# docker exec v2 ping v1
PING v1 (172.20.0.4): 56 data bytes
64 bytes from 172.20.0.4: seq=0 ttl=64 time=0.113 ms
64 bytes from 172.20.0.4: seq=1 ttl=64 time=0.067 ms
'依旧可以ping通'
⚠️容器在stop后,再启动,容器的IP可能会发生变化!
✅️也没有太大的关系,我们用容器名,依旧可以ping通
🌰docker0 会发生类似的情况嘛❓️
[root@test ~]# docker run -d -it --name test alpine:3.20.2
# 默认就是docker0网络
[root@test ~]# docker exec test ip a
42: eth0@if43: ...xxx
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16
[root@test ~]# docker run -d -it --name test-02 alpine:3.20.2
[root@test ~]# docker exec test-02 ip a
44: eth0@if45: ...xxx
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.3/16 brd 172.17.255.255
[root@test ~]# docker stop -t 0 test
'关闭第一个创建的容器'
[root@test ~]# docker run -d -it --name test-03 alpine:3.20.2
[root@test ~]# docker exec test-03 ip a
46: eth0@if47: ...xxx
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255
[root@test ~]# docker start test
'再次启动!'
[root@test ~]# docker exec test ip a
48: eth0@if49: ...xxx
link/ether 02:42:ac:11:00:04 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.4/16 brd 172.17.255.255
✅️IP地址发生改变
[root@test ~]# docker exec -it test-02 sh
/ # cat /etc/hosts | tail -1
172.17.0.3 a7a5e96a2b53
/ # cat /etc/resolv.conf | grep nameserver
nameserver 223.6.6.6
/ # ping test
ping: bad address 'test'
/ # ping test-03
ping: bad address 'test-03'
/ # ping 172.17.0.4
PING 172.17.0.4 (172.17.0.4): 56 data bytes
64 bytes from 172.17.0.4: seq=0 ttl=64 time=0.120 ms
64 bytes from 172.17.0.4: seq=1 ttl=64 time=0.073 ms
/ # ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.076 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.074 ms
⚠️docker0 没有内置DNS解析功能
✅️必须手动添加才行!
/ # cat >> /etc/hosts <<EOF
> 172.17.0.2 test-03
> 172.17.0.4 test
> EOF
/ # ping test
PING test (172.17.0.4): 56 data bytes
64 bytes from 172.17.0.4: seq=0 ttl=64 time=0.098 ms
64 bytes from 172.17.0.4: seq=1 ttl=64 time=0.072 ms
/ # ping test-03
PING test-03 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.077 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.078 ms
🌰断开网路连接
[root@test ~]# docker network --help
Commands:
connect # 连接容器网络
create # 创建网络
disconnect # 断开容器网络
inspect # 展示网络详细信息
ls # 列出网络
prune # 移除没有使用的网络
rm # 手动删除指定网络
[root@test ~]# docker network disconnect --help
docker network disconnect [选项] 网络名 容器
# 用法
-f # 强制移除网络
[root@test ~]# docker exec v1 ip a
1: lo: ...xxx
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8
40: eth0@if41: ...xxx
link/ether 02:42:ac:14:00:04 brd ff:ff:ff:ff:ff:ff
inet 172.20.0.4/16 brd 172.20.255.255
'现在还是有网络的'
[root@test ~]# docker network disconnect mynet v1
[root@test ~]# docker exec v1 ip a
1: lo: ...xxx
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8
✅️现在只剩回环地址了
[root@test ~]# docker network connect mynet v1
'重新连接网络'
[root@test ~]# docker exec v1 ip a
1: lo: ...xxx
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
50: eth1@if51: ...xxx
link/ether 02:42:ac:14:00:04 brd ff:ff:ff:ff:ff:ff
inet 172.20.0.4/16 brd 172.20.255.255
'环境清理'
[root@test ~]# docker rm -f $(docker ps -aq)
[root@test ~]# docker network prune -f
Terminal window
🌰不同网段无法ping通!
[root@test ~]# docker network create -d bridge --subnet 172.20.0.0/16 --gateway 172.20.0.1 mynet
[root@test ~]# docker run --name v1 -d -it --network mynet alpine:3.20.2
# 手动指定网络
[root@test ~]# docker run --name v2 -d -it alpine:3.20.2
# 这个是默认的docker0
[root@test ~]# docker exec v1 cat /etc/hosts | tail -1
172.20.0.2 093c532e53af
[root@test ~]# docker exec v2 cat /etc/hosts | tail -1
172.17.0.2 20e09a957076
'一个是我们新建的网络,一个是docker0'
[root@test ~]# docker exec v1 ping 172.17.0.2 -W2 -c2
# v1: 172.20.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
0 packets received, 100% packet loss❌️
❤️ping不通的!
🌰一个容器可以有多个IP
如何才能ping通呢❓️
[root@test ~]# docker network connect bridge v1
'再给v1一个网络,bridge就是docker0网卡'
[root@test ~]# docker exec v1 ip a
1: lo:
inet 127.0.0.1/8
53: eth0@if54:
inet 172.20.0.2/16 brd 172.20.255.255
57: eth1@if58:
inet 172.17.0.3/16 brd 172.17.255.255
'v1有两个不同网段的IP地址!'
[root@test ~]# docker exec v1 ping 172.17.0.2 -W2 -c2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.075 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.083 ms
'这样就能够ping通了'

实战案例#

部署WordPress#

要求:

  • 使用自定义网络
  • MySQL不对外暴露端口
    • 仅将WordPress数据进行暴露
  • 发表测试文字,删除MySQL或者wordpress容器==数据不丢失==
Terminal window
'清理环境'
[root@Docker ~]# docker rm -f $(docker ps -aq)
[root@Docker ~]# docker network prune -f
1)网络的创建
[root@Docker ~]# docker network create -d bridge --subnet 172.30.0.0/16 --gateway 172.30.0.1 mynet
[root@Docker ~]# docker network ls | grep mynet
1c94f7d15cac mynet bridge local
2)数据库创建
[root@Docker ~]# docker run -d \
--network mynet \
--name db01 \
-v boke-db:/var/lib/mysql/ \
--restart unless-stopped \
-e MYSQL_ALLOW_EMPTY_PASSWORD="yes" \
-e MYSQL_DATABASE="wordpress" \
-e MYSQL_USER="jiu" \
-e MYSQL_PASSWORD="oldboy123.com" \
mysql:8.0.36 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_unicode_ci \
--default-authentication-plugin=mysql_native_password
✅️自己创建的网络
✅️"因为不暴露它的端口,这里没有做端口映射"
✅️'为了数据持久化,给了一个数据卷'
[root@Docker ~]# docker ps
3926d1ddc721 mysql:8.0.36 "docker-entrypoint.s…" 15 seconds ago Up 15 seconds 3306/tcp, 33060/tcp db01
🦄并没有暴露端口
[root@Docker ~]# docker volume ls
DRIVER VOLUME NAME
local boke-db
[root@Docker ~]# docker volume inspect boke-db
[
{
"CreatedAt": "2026-04-22T15:03:05+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/boke-db/_data",
"Name": "boke-db",
"Options": null,
"Scope": "local"
}
]
[root@Docker ~]# tree /var/lib/docker/volumes/boke-db/_data/ | wc -l
189
# 里面是有初始换数据的
3)wordpress创建
[root@Docker ~]# docker run -d \
--name my-wordpress \
--network mynet \
--restart unless-stopped \
-v boke-wp:/var/www/html \
-p 8080:80 \
-e WORDPRESS_DB_HOST=db01 \
-e WORDPRESS_DB_USER=jiu \
-e WORDPRESS_DB_PASSWORD=oldboy123.com \
-e WORDPRESS_DB_NAME=wordpress \
-e WORDPRESS_TABLE_PREFIX=wp_ \
wordpress:6.7.1
✅️-v # 挂载wp中的内容
✅️--network # 指定网络
✅️数据库DB_HOST=db01,"直接跟的容器名"
[root@Docker ~]# docker ps
42dc44d2c9f7 wordpress:6.7.1 "docker-entrypoint.s…" 0.0.0.0:8080->80/tcp, [::]:8080->80/tcp my-wordpress
✅️wordpress做了端口映射
[root@Docker ~]# docker volume ls
DRIVER VOLUME NAME
local boke-db
local boke-wp
[root@Docker ~]# tree /var/lib/docker/volumes/boke-wp/_data | wc -l
3570
4)访问博客
http://10.0.0.99:8080/

image-20260422151046100
image-20260422151046100

  • 随手写几篇文章, 上传点图片

  • 然后删除容器, 重复上面的操作

    • 重新创建容器
  • 再次访问测试

    • 观察博客文章是否丢失

image-20260422152125665
image-20260422152125665

Terminal window
[root@Docker ~]# docker rm -f $(docker ps -aq)
42dc44d2c9f7
3926d1ddc721
'删除所有容器'
[root@Docker ~]# docker volume ls
DRIVER VOLUME NAME
local boke-db
local boke-wp
'数据卷是一直存在的!'
✅️后面容器再次挂载时,因为数据卷里面是有东西的
❤️会"覆盖隐藏"容器原来的内容!
🌰重新运行这两个容器
[root@Docker ~]# docker run -d \
--network mynet \
--name db01 \
-v boke-db:/var/lib/mysql/ \
--restart unless-stopped \
-e MYSQL_ALLOW_EMPTY_PASSWORD="yes" \
-e MYSQL_DATABASE="wordpress" \
-e MYSQL_USER="jiu" \
-e MYSQL_PASSWORD="oldboy123.com" \
mysql:8.0.36 \
--character-set-server=utf8mb4 \
--collation-server=utf8mb4_unicode_ci \
--default-authentication-plugin=mysql_native_password
[root@Docker ~]# docker run -d \
--name my-wordpress \
--network mynet \
--restart unless-stopped \
-v boke-wp:/var/www/html \
-p 8080:80 \
-e WORDPRESS_DB_HOST=db01 \
-e WORDPRESS_DB_USER=jiu \
-e WORDPRESS_DB_PASSWORD=oldboy123.com \
-e WORDPRESS_DB_NAME=wordpress \
-e WORDPRESS_TABLE_PREFIX=wp_ \
wordpress:6.7.1
🌰再次测试访问
http://10.0.0.99:8080/
'原来发布的文章和图片都还在'
✅️并且跳过了安装步骤

部署Zabbix 7.0#

  • 产品手册

  • Zabbix 7.0 LTS 支持的数据库版本范围如下:

    • 最低版本: MySQL 8.0.30
    • 支持范围: MySQL 8.0.30 至 9.0.x
Terminal window
❤️主要用到四个容器(数据库、服务端、Web界面、Java网关)
共同构成了 Zabbix 的“监控中心”
# 这里并没有Zabbix Agent
⚠️我们需要手动在被'监控的目标机器'上,安装原生的 Zabbix Agent
1)拉取镜像
[root@Docker ~]# docker pull docker.xuanyuan.run/zabbix/zabbix-java-gateway:alpine-7.2-latest
✅️java网关
[root@Docker ~]# docker pull docker.xuanyuan.run/zabbix/zabbix-server-mysql:alpine-7.2-latest
✅️zabbix服务端
[root@Docker ~]# docker pull docker.xuanyuan.run/zabbix/zabbix-web-nginx-mysql:alpine-7.2-latest
✅️zabbix web页面
'MySQL还用我们的8.0.36版本'
# 我这里手动进行改个名tag
# 要不然太长了!
docker tag docker.xuanyuan.run/zabbix/zabbix-java-gateway:alpine-7.2-latest zabbix-java-gateway:alpine-7.2-latest
docker tag docker.xuanyuan.run/zabbix/zabbix-server-mysql:alpine-7.2-latest zabbix-server-mysql:alpine-7.2-latest
docker tag docker.xuanyuan.run/zabbix/zabbix-web-nginx-mysql:alpine-7.2-latest zabbix-web-nginx-mysql:alpine-7.2-latest
# 再删除之前的冗余的镜像
docker rmi docker.xuanyuan.run/zabbix/zabbix-java-gateway:alpine-7.2-latest
docker rmi docker.xuanyuan.run/zabbix/zabbix-server-mysql:alpine-7.2-latest
docker rmi docker.xuanyuan.run/zabbix/zabbix-web-nginx-mysql:alpine-7.2-latest
[root@Docker ~]# docker images
🎶mysql:8.0.36
🎶zabbix-java-gateway:alpine-7.2-latest
🎶zabbix-server-mysql:alpine-7.2-latest
🎶zabbix-web-nginx-mysql:alpine-7.2-latest
'需要提前准备4个镜像!'
2)清理环境
[root@Docker ~]# docker rm -f $(docker ps -aq)
[root@Docker ~]# docker network prune -f
Deleted Networks:
mynet
[root@Docker ~]# docker volume prune -fa
Deleted Volumes:
boke-wp
boke-db
3)创建专属的网络
[root@Docker ~]# docker network create -d bridge --subnet 172.20.0.0/16 --gateway 172.20.0.1 zabbix-net
[root@Docker ~]# docker network ls | grep zabbix-net
3d252d08d0a2 zabbix-net bridge local
4)运行数据库
[root@Docker ~]# docker run -d \
--network zabbix-net \
--name mysql-server \
-v zabbix-db:/var/lib/mysql/ \
--restart unless-stopped \
-e MYSQL_ROOT_PASSWORD="root_pwd" \
-e MYSQL_DATABASE="zabbix" \
-e MYSQL_USER="zabbix" \
-e MYSQL_PASSWORD="oldboy123.com" \
mysql:8.0.36 \
--character-set-server=utf8 \
--collation-server=utf8_bin \
--default-authentication-plugin=mysql_native_password
✅️自定义网络
✅️数据卷挂载
✅️没有暴露端口
mysql: 3306
✅️数据库和用户为必须为zabbix⚠️
⚠️root密码不能为空⚠️
'否则zabbix-server导入数据失败'
# zabbix的表结构和基本数据
[root@Docker ~]# docker volume ls | grep zabbix-db
local zabbix-db
5)部署java-gateway组件
[root@Docker ~]# docker run -d \
--name zabbix-java-gateway \
--network zabbix-net \
--restart unless-stopped \
zabbix-java-gateway:alpine-7.2-latest
✅️自定义网络
6)部署zabbix server
[root@Docker ~]# docker run -d \
--name zabbix-server-mysql \
--network zabbix-net \
--restart unless-stopped \
-e DB_SERVER_HOST=mysql-server \
-e MYSQL_DATABASE=zabbix \
-e MYSQL_USER=zabbix \
-e MYSQL_PASSWORD=oldboy123.com \
-e MYSQL_ROOT_PASSWORD="root_pwd" \
-e ZBX_JAVAGATEWAY=zabbix-java-gateway \
zabbix-server-mysql:alpine-7.2-latest
✅️自定义网络
✅️没有暴露端口
server: 10051
agent: 10050
⚠️root密码不能为空
7)部署zabbix的web页面
[root@Docker ~]# docker run -d \
--name zabbix-web-nginx-mysql \
--network zabbix-net \
--restart unless-stopped \
-p 80:8080 \
-e ZBX_SERVER_HOST=zabbix-server-mysql \
-e DB_SERVER_HOST=mysql-server \
-e MYSQL_DATABASE=zabbix \
-e MYSQL_USER=zabbix \
-e MYSQL_PASSWORD=oldboy123.com \
-e MYSQL_ROOT_PASSWORD="root_pwd" \
zabbix-web-nginx-mysql:alpine-7.2-latest
✅️自定义网络
✅️映射端口80,用于浏览器访问
✅️指定zabbix-server
⚠️root密码不能为空
8)查看运行结果
[root@Docker ~]# docker ps
🌏zabbix-web-nginx-mysql Up 2 seconds (health: starting) 8443/tcp, 0.0.0.0:80->8080/tcp, [::]:80->8080/tcp
🌏zabbix-server-mysql Up 10 seconds 10051/tcp
🌏zabbix-java-gateway Up 17 seconds 10052/tcp
🌏mysql:8.0.36 Up 22 seconds 3306/tcp, 33060/tcp
'只有web映射了端口!'
9)测试访问
http://10.0.0.99/
用户名: Admin
密码: zabbix

image-20260422181250460
image-20260422181250460

部署JumpServer#

image-20260422231701323
image-20260422231701323

Terminal window
jumpserver/jms_all
# 用最新的就行
1)拉取镜像
[root@Docker ~]# docker pull docker.xuanyuan.run/jumpserver/jms_all
[root@Docker ~]# docker tag docker.xuanyuan.run/jumpserver/jms_all:latest jumpserver/jms_all:latest
[root@Docker ~]# docker rmi docker.xuanyuan.run/jumpserver/jms_all:latest
[root@Docker ~]# docker images
jumpserver/jms_all:latest
2)创建网络
[root@Docker ~]# docker network create -d bridge --subnet 172.20.0.0/16 --gateway 172.20.0.1 jumpserver-net
3)创建容器
[root@Docker ~]# docker run -d \
--name jms_all \
--network jumpserver-net \
-e SECRET_KEY="$SECRET_KEY" \
-e BOOTSTRAP_TOKEN="$BOOTSTRAP_TOKEN" \
-v jsdata:/opt/data \
-v pgdata:/var/lib/postgresql \
-p 2222:2222 \
-p 80:80 \
--restart unless-stopped \
jumpserver/jms_all:latest
参数含义
--networkjumpserver-net连接到自定义网络
-eSECRET_KEY="$SECRET_KEY"加密密钥,用于数据加密和会话安全(需50位随机字符)
-eBOOTSTRAP_TOKEN="$BOOTSTRAP_TOKEN"认证令牌,用于组件间通信认证(需16位随机字符)
-vjsdata:/opt/data数据卷挂载,持久化 JumpServer 媒体文件和附件
-vpgdata:/var/lib/postgresql数据卷挂载,持久化 PostgreSQL 数据库数据
Terminal window
[root@Docker ~]# docker ps
jumpserver/jms_all:latest Up About a minute 0.0.0.0:80->80/tcp, [::]:80->80/tcp, 0.0.0.0:2222->2222/tcp, [::]:2222->2222/tcp jms_all
4)浏览页面
默认账号: admin
默认密码: ChangeMe

image-20260423081836598
image-20260423081836598

部署Nginx负载#

  • 使用自定义网络部署3个容器,容器名称分别为: lb,web01,web02,要求如下:
    • 修改web01和web02的首页内容,内容自定义即可
    • 流量访问入口从lb访问,有lb代理流量到web01和web02,其中的比例为4:1
    • 删除lb,web01,web02,要求数据不丢失
Terminal window
# 先去清理环境
1)创建网络
[root@Docker ~]# docker network create -d bridge --subnet 172.20.0.0/16 --gateway 172.20.0.1 mynet
2)web创建
[root@Docker ~]# docker run -d \
--name web01 \
--network mynet \
-v web01-html:/usr/share/nginx/html/ \
nginx
✅️数据卷挂载
✅️隐藏端口
[root@Docker ~]# docker run -d \
--name web02 \
--network mynet \
-v web02-html:/usr/share/nginx/html/ \
nginx
3)修改默认主页
[root@Docker ~]# docker exec -it web01 /bin/bash
root@46550e3ff026:/# echo web01... > /usr/share/nginx/html/index.html
root@46550e3ff026:/# curl localhost
web01...
[root@Docker ~]# docker exec -it web02 /bin/bash
root@fccfbcb1731d:/# echo web02... > /usr/share/nginx/html/index.html
root@fccfbcb1731d:/# curl localhost
web02...
4)lb负载
[root@Docker ~]# docker run -d \
--name lb01 \
--network mynet \
-p 81:80 \
-v lb01-conf:/etc/nginx/conf.d/ \
nginx
[root@Docker ~]# docker exec -it lb01 /bin/bash
root@e15291045302:/# cd /etc/nginx/conf.d/
root@e15291045302:/etc/nginx/conf.d# cat > default.conf <<EOF
upstream webs {
server web01 weight=4;
server web02;
}
server {
listen 80 default_server;
server_name _;
location / {
proxy_pass http://webs;
}
}
EOF
root@e15291045302:/etc/nginx/conf.d# nginx -t
nginx: the configuration file ...xxx is ok
nginx: configuration file ...xxx is successful
root@e15291045302:/etc/nginx/conf.d# exit
exit
[root@Docker ~]# docker restart lb01
lb01
# 通过重启容器--->重启nginx
[root@Docker ~]# curl localhost:81
web02...
[root@Docker ~]# curl localhost:81
web01...
[root@Docker ~]# curl localhost:81
web01...
[root@Docker ~]# curl localhost:81
web01...
[root@Docker ~]# curl localhost:81
web01...
[root@Docker ~]# curl localhost:81
web02...
'比例 4:1'
5)数据卷验证
[root@Docker ~]# docker volume ls
DRIVER VOLUME NAME
local lb01-conf
local web01-html
local web02-html
[root@Docker ~]# tree /var/lib/docker/volumes/
/var/lib/docker/volumes/
├── lb01-conf
│   └── _data
│   └── default.conf
├── web01-html
│   └── _data
│   ├── 50x.html
│   └── index.html
└── web02-html
└── _data
├── 50x.html
└── index.html
6)删除容器&&重启运行
[root@Docker ~]# docker rm -f $(docker ps -aq)
[root@Docker ~]# docker run -d \
--name web01 \
--network mynet \
-v web01-html:/usr/share/nginx/html/ \
nginx
[root@Docker ~]# docker run -d \
--name web02 \
--network mynet \
-v web02-html:/usr/share/nginx/html/ \
nginx
[root@Docker ~]# docker run -d \
--name lb01 \
--network mynet \
-p 81:80 \
-v lb01-conf:/etc/nginx/conf.d/ \
nginx
[root@Docker ~]# curl localhost:81
web02...
[root@Docker ~]# curl localhost:81
web01...
[root@Docker ~]# curl localhost:81
web01...
[root@Docker ~]# curl localhost:81
web01...
[root@Docker ~]# curl localhost:81
web01...
[root@Docker ~]# curl localhost:81
web02...
'成功负载均衡,比例 4:1'

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

数据卷&&网络
https://www.kpyun.fun/posts/docker/docker03/
作者
久棹
发布于
2026-02-19
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
久棹
只要胆子大,天天寒暑假!
公告
欢迎来到久棹的技术小站!本站专注 Linux 运维学习笔记分享,如有问题欢迎交流探讨 🎉
分类
标签
站点统计
文章
98
分类
11
标签
203
总字数
244,453
运行时长
0
最后活动
0 天前
站点信息
构建平台
Local
博客版本
Firefly v6.13.5
文章许可
CC BY-NC-SA 4.0

文章目录