1、docker原身网络
[root@server1 harbor]# docker-compose down 为了实验效果,先将所有镜像删除
[root@server1 harbor]# docker network prune 关闭不常用网络
[root@server1 harbor]# docker network ls 剩下的就是docker默认网络
NETWORK ID NAME DRIVER SCOPE
e014ad524f8c bridge bridge local docker原身网络
595de9c635c6 host host local docker原身网络
8f69944486a3 none null local docker原身网络
docker网络模式默认是桥接模式:
[root@server1 harbor]# ip addr 容器地址是单调递增的,所以容器的ip地址是会变的是动态的
[root@server1 harbor]# yum install bridge-utils -y 安装桥接指令
[root@server1 ~]# docker run -d --name nginx nginx 运行容器
[root@server1 ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02429831a7e5 no vethcd9db6c 可以发现nginx容器已经桥接到docker0上了
[root@server1 ~]# docker run -d --name nginx2 nginx 再次开启一个容器
[root@server1 ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.02429831a7e5 no vethcd9db6c 可以发现也桥接到docker0上了
vethf80cb76
[root@server1 ~]# curl 172.17.0.2 访问第一个容器ip 地址 ,容器ip地址是单调递增的
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
[root@server1 ~]# curl 172.17.0.3 访问第二个容器ip 地址,容器ip地址是单调递增的
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
桥接模式的缺点: 如果可以让外网访问容器需要通过主机的NAT规则才可以访问外网
host网络模式:
[root@server1 ~]# docker rm -f nginx2
nginx2
[root@server1 ~]# docker run -d --name demo --network host nginx 运行容器,并指定网络模式为主机模式
8e4292d9fc16394dc271ad01675c5fc37d3aa44f1abf1ad7ecde6c44d662c11e
注意:host网络模式,宿主机ip地址和容器ip地址是共享的
[root@server1 ~]# curl 172.25.50.1 访问宿主机ip地址,就可以访问到容器nginx,ip地址是共享的
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
[root@server1 ~]# docker run -d --name demo2 --network host nginx 再次运行一个host模式容器
[root@server1 ~]# docker ps 查看容器是否运行,容器demo2没有运行
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8e4292d9fc16 nginx "/docker-entrypoint.…" 13 minutes ago Up 13 minutes demo
85e88ed124bc nginx "/docker-entrypoint.…" 33 minutes ago Up 33 minutes 80/tcp nginx
[root@server1 ~]# docker logs demo2 查看demo2日志,发现80端口已经被占用
造成上述原因是因为host网络模型是用同一个网络栈,会造成容器之间的网络争抢,所以80端口只能让一个容器使用
none模式:
[root@server1 ~]# docker rm demo2 删除demo2
demo2
[root@server1 ~]# docker run -it --rm --network none busybox 以none网络模式运行容器
/ # ip addr 可以运行
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 但是ip地址
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
/ #
2、doker自定义网络
创建自定义网桥
[root@server1 ~]# docker network create my_net1
64c6a33f42c0a22628c2b22456c495fd3c316a3571af1594091a45258b17127b
[root@server1 ~]# docker network ls
[root@server1 ~]# docker rm -f nginx 删除之前容器
nginx
[root@server1 ~]# docker rm -f demo 删除之前容器
demo
[root@server1 ~]# docker run -d --name web1 nginx 运行容器,用默认桥接方式
d03446624523b95d630a90f240b772d16b3b089b825db08bd3e64fb9c258bbfb
[root@server1 ~]# brctl show
bridge name bridge id STP enabled interfaces
br-64c6a33f42c0 8000.0242457e59ec no
docker0 8000.02429831a7e5 no vethefd382f 默认桥接方式
[root@server1 ~]# docker run -d --name web2 --network my_net1 nginx 运行容器,选者自定义桥接方式
d860d5bbac1cd40469d0f353c3d0cc33fc3a8db3784a82b7b2776e54e1475145
[root@server1 ~]# brctl show 查看
bridge name bridge id STP enabled interfaces
br-64c6a33f42c0 8000.0242457e59ec no vethd8b409d 自定义桥接方式
docker0 8000.02429831a7e5 no vethefd382f
[root@server1 ~]# docker run -it --rm busybox 运行交互式容器
/ # ping web1 可以发现默认桥接方式不可以ping 通主及名web1
ping: bad address 'web1'
/ # ping 172.25.50.2 只能ping通ip地址
PING 172.25.50.2 (172.25.50.2): 56 data bytes
64 bytes from 172.25.50.2: seq=0 ttl=63 time=0.950 ms
64 bytes from 172.25.50.2: seq=1 ttl=63 time=0.391 ms
[root@server1 ~]# docker run -it --rm --network my_net1 busybox 运行容器,用自定义桥接模式
/ # ping web2 自定义桥接模式提供解析,可以ping通web2容器名
PING web2 (172.18.0.2): 56 data bytes
64 bytes from 172.18.0.2: seq=0 ttl=64 time=0.127 ms 此时获取的web2地址为172.18.0.2
64 bytes from 172.18.0.2: seq=1 ttl=64 time=0.066 ms
[root@server1 ~]# docker stop web2 停止web2
web2
[root@server1 ~]# docker run -d --name web3 --network my_net1 nginx 再次运行,同样以network模式
root@server1 ~]# docker start web2 再次启动web2
web2
[root@server1 ~]# docker run -it --rm --network my_net1 busybox 运行
/ # ping web2
PING web2 (172.18.0.3): 56 data bytes
64 bytes from 172.18.0.3: seq=0 ttl=64 time=0.109 ms 此时可以发现web2地址从172.18.0.2变成172.18.0.3了
64 bytes from 172.18.0.3: seq=1 ttl=64 time=0.065 ms
自定义桥接也可以固定ip创建
[root@server1 ~]# docker network create --subnet 172.20.0.0/24 --gateway 172.20.0.1 my_net2 --subnet 表示子网段 -gateway网关
3e8cdb823759f6e0e5f7fe4519001eaa9b25444f3e3da25c0378c9d9a48904bd
[root@server1 ~]# docker run -d --name web4 --network my_net2 --ip 172.20.0.100 nginx 运行并创建容器 ,可以指定容器ip,注意--ip只适合有--subnet,-gateway的条件
ed506c0edc25dc83471457b498d639a7ecd2477d87dc8d0cebb8f7b98905bbbc
[root@server1 ~]# docker inspect web4 查看容器详细信息
[root@server1 ~]# docker stop web4 停止web4
web4
[root@server1 ~]# docker start web4 启动web4
web4
[root@server1 ~]# docker inspect web4 查看容器详细信息,可以发现容器ip地址没有变化
如何让不同网桥的容器通信?
如何让web3和web4网络互通了?
[root@server1 ~]# docker network connect my_net1 web4 相当于给web4添加了一快网卡
相当于一个容器有两块网卡,一个网卡连接一个不通vlan他们之间是可以互通的
joined网络模式
[root@server1 ~]# docker pull radial/busyboxplus 拉取busyboxplus
[root@server1 ~]# docker tag radial/busyboxplus:latest busyboxplus:latest 改名字
[root@server1 ~]# docker rmi radial/busyboxplus:latest 删除原始的
[root@server1 ~]# docker run -it --rm --network container:web3 busyboxplus container:web3 表示此容器和指定的web3容器共享一个网络栈
/ # ip addr 可以发现共享了容器web3的ip地址
/ # curl localhost 可以使用localhost高速快速通信
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
link网络模式 可以用来链接两个容器
[root@server1 ~]# docker run -it --rm --link web1:nginx (此处nginx是起的容器别名)busyboxplus link模式不支持指定义网络,用于默认网络
/ # env link模式自动添加了变量
HOSTNAME=aba29e480314
SHLVL=1
HOME=/
NGINX_ENV_PKG_RELEASE=1~bullseye
NGINX_PORT_80_TCP=tcp://172.17.0.2:80
NGINX_ENV_NGINX_VERSION=1.21.5
NGINX_ENV_NJS_VERSION=0.7.1
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
NGINX_PORT=tcp://172.17.0.2:80
NGINX_NAME=/bold_aryabhata/nginx
PWD=/
NGINX_PORT_80_TCP_ADDR=172.17.0.2
NGINX_PORT_80_TCP_PORT=80
NGINX_PORT_80_TCP_PROTO=tcp
/ # ping nginx link模式可以用别名来访问
PING nginx (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.148 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.073 ms
/ # ping web1 也可以用容器名来访问
PING web1 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.128 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.101 ms
/ # cat /etc/hosts 因为link模式自动给web1、nginx加了解析了
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2 nginx d03446624523 web1
172.17.0.3 aba29e480314
[root@server1 ~]# docker stop web1 关闭web1容器
web1
[root@server1 ~]# docker run -d nginx 创建运行一个容器
[root@server1 ~]# docker start web1 再次打开web1容器
web1
[root@server1 ~]# docker inspect web1 查看web1容器详细信息,发现容器ip地址由原来的172.17.0.2变成172.17.0.3了
[root@server1 ~]# docker run -it --rm --link web1:nginx busyboxplus
/ # ping web1
PING web1 (172.17.0.3): 56 data bytes ip地址变成了172.17.0.3
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.125 ms
/ # cat /etc/hosts
3、容器通信原理
容器网关连接docker0,docker0和eth0在同一个宿主机,但是彼此之间网段不一样,需要通过linux内核进行地址转发,然后直接从eth0出去
[root@server1 ~]# docker ps -aq 查看所有容器
3d45355536bd
ed506c0edc25
3667fb786338
1c4ad45c1553
d03446624523
9a3f7a47740b
[root@server1 ~]# docker rm -f ' docker ps -aq ' 删除所有容器
[root@server1 ~]# docker run -d --name demao -p80:80 nginx 运行容器,建立端口映射
dace0215b173b3650f4e41e88a2bd9d4659bceecd8f35f4337b30e11c44911f6
[root@server1 ~]# iptables -t nat -nL
当外部访问本机的80,会定向到容器的80,这样外部就可以访问容器
测试:
[root@server1 ~]# curl 172.25.50.1 直接访问本机,就会定向到容器
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
但是即使把端口映射删除了,外部也可以访问容器,因为查看进程可以发现有个docker-proxy代理进行,此代理可以负责地址转发
[root@server1 ~]# netstat -antlp
端口映射和docker-proxy是docker的冗余机制,存在一种即可
测试:
两个容器之间的通讯 ,因为两个容器都在一个vlan,都在本机
[root@server1 ~]# docker run -it --rm busyboxplus
/ # ip addr
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
8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
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 scope global eth0 此容器的ip为172.17.0.3
valid_lft forever preferred_lft forever
/ # ping 172.17.0.2 访问之前建立的nginx容器,可以ping通
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.156 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.069 ms
外部主机访问容器:
[root@server1 ~]# iptables -t nat -F 把nat策略全部刷掉,DNAT端口映射也没有了
[root@server1 ~]# iptables -t nat -nL
Chain PREROUTING (policy ACCEPT)
target prot opt source destination 没有策略了
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
[root@server1 ~]# docker run -it --rm busyboxplus
/ # ping 172.17.0.2 容器之间还是可以ping通的
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.112 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.108 ms
[root@server1 ~]# ps ax
[root@server1 ~]# kill 3989 杀掉docker-proxy进程,此时DNAT策略和docker-proxy代理都没有了
[root@server1 ~]# docker run -it --rm busyboxplus
/ # ip addr
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
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 scope global eth0 容器ip变成172.17.0.4
valid_lft forever preferred_lft forever
/ # 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.128 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.078 ms
[root@foundation50 network-scripts]# curl 172.25.50.1 外部访问,就不通了,80端口过不去,因为docker-proxy进程被杀掉了
curl: (7) Failed to connect to 172.25.50.1 port 80: Connection refused
恢复iptables策略
[root@server1 ~]# systemctl restart docker 重启doaker引擎
[root@server1 ~]# iptables -t nat -nL 查看防火墙策略已经生效
Chain PREROUTING (policy ACCEPT)
target prot opt source destination
DOCKER all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
Chain INPUT (policy ACCEPT)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
DOCKER all -- 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
[root@foundation50 network-scripts]# curl 172.25.50.1 此时外部访问就可以
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
[root@server1 ~]# ps ax | grep proxy 此时proxy代理也出来了
4750 ? Sl 0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 80 -container-ip 172.17.0.2 -container-port 80
4824 pts/0 S+ 0:00 grep --color=auto proxy
现在把防火墙刷掉,只留proxy
[root@server1 ~]# iptables -t nat -F 刷掉所有防火墙策略,保留docker-proxy策勒
[root@foundation50 network-scripts]# curl 172.25.50.1 外部访问容器,还可以访问,所以docker-proxy负责外部访问容器
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
现在把proxy杀掉,保留防火强
[root@server1 ~]# systemctl restart docker 再次重启docker,恢iptables策略
[root@server1 ~]# docker start demao 启动容器
demao
[root@server1 ~]# kill 5101 杀掉proxy
[root@foundation50 network-scripts]# curl 172.25.50.1 外部访问容器,也可以访问; DNAT策略也可以实现外部访问容器
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
宗上所述,上述两种机制存在一种就可以保证外部主机可以访问容器
4、跨主机容器网络
实验之前清理环境:
[root@server1 ~]# docker rm -f demao 删除容器
demao
[root@server1 ~]# docker network prune 删除不用的网络
WARNING! This will remove all custom networks not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Networks:
my_net1
my_net2
[root@server1 ~]# docker volume prune 删除不用的卷
[root@server1 ~]# docker image prune 删除不用的卷
[root@server1 ~]# docker container prune 删除所有停止的容器
[root@server1 ~]# docker network ls 网络模式
NETWORK ID NAME DRIVER SCOPE
aac988c7d96a bridge bridge local
595de9c635c6 host host local
8f69944486a3 none null local
在server1、server2上各添加一块网卡
[root@server1 ~]# ip link set eth1 promisc on 在server1上打开eth1的混杂模式
[root@server1 ~]# ip addr promisc混杂模式已经添加
[root@server1 ~]# ip link set up eth1 激活网卡
[root@server2 ~]# ip link set eth1 promisc on 在server2上打开 eth1混杂模式
[root@server2 ~]# ip link set up eth1 激活网卡
[root@server1 ~]# docker network create -d macvlan --subnet 10.0.0.0/24 --gateway 10.0.0.1 -o parent=eth1 mynet1 自定义创建以macvlan虚拟化技术的mynet1网络模式,
-d表示指定驱动 -o表示指定父级网卡 parent父级的意思
523ef6d5d33681b9caacf5118512eee3f8132c9cc03cf6f94ebffa4a16200a66
[root@server1 ~]# docker network ls
[root@server1 ~]# docker run -it --rm --network mynet1 --ip 10.0.0.10 busyboxplus 运行容器,以mynet1 模式运行
/ # ip addr
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
17: eth0@if16: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:0a:00:00:0a brd ff:ff:ff:ff:ff:ff
inet 10.0.0.10/24 brd 10.0.0.255 scope global eth0
valid_lft forever preferred_lft forever
在server2上同样操作:
[root@server2 ~]# docker network create -d macvlan --subnet 10.0.0.0/24 --gateway 10.0.0.1 -o parent=eth1 mynet1
3879e795cdb7462547fdd7308d2f0e9aded47a23e47cef67b9bf52753199ca8b
[root@server2 ~]# docker network ls
[root@server2 ~]# docker run -it --rm --network mynet1 --ip 10.0.0.11 busybox 以mynet1网络方式
/ # ip addr
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
5: eth0@if4: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:0a:00:00:0b brd ff:ff:ff:ff:ff:ff
inet 10.0.0.11/24 brd 10.0.0.255 scope global eth0 ip地址为10.0.0.11
valid_lft forever preferred_lft forever
/ # ping 10.0.0.10 ping server1上容器,可以ping通
PING 10.0.0.10 (10.0.0.10): 56 data bytes
64 bytes from 10.0.0.10: seq=0 ttl=64 time=0.583 ms
64 bytes from 10.0.0.10: seq=1 ttl=64 time=0.313 ms
/ # ping 10.0.0.11 ping本机上的容器也可以ping通
PING 10.0.0.11 (10.0.0.11): 56 data bytes
64 bytes from 10.0.0.11: seq=0 ttl=64 time=0.107 ms
64 bytes from 10.0.0.11: seq=1 ttl=64 time=0.058 ms
macvlan模式容器接口直接与主机网卡连接,无需NAT端口映射和docker-proxy
测试:
[root@server2 ~]# docker run -d --name demo --network mynet1 --ip 10.0.0.11 nginx 在server2上运行nginx容器,mynet1网络模式
0561b0c677af762608227dea093c3e36cbdb16cc328920cd01484c79aa6357bc
[root@server1 ~]# docker run -it --rm --network mynet1 --ip 10.0.0.10 busyboxplus 在server1上运行容器,以mynet1网络模式
[root@server1 ~]# docker ps 查看运行的容器
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
202b2b00b24b busyboxplus "/bin/sh" 26 seconds ago Up 24 seconds practical_hawking
[root@server1 ~]# docker attach 202b2b00b24b 当容器退出了,也可以附加此容器进入交互模式
/ # curl 10.0.0.11 访问server2上的容器 可以访问,他们之间是直通的
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
[root@server2 ~]# netstat -antlp 在server2上查看端口,发现没有80端口,没有docker-proxy
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 3214/sshd
tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 3328/master
tcp 0 0 172.25.50.2:22 172.25.50.250:54976 ESTABLISHED 3724/sshd: root@pts
tcp6 0 0 :::22 :::* LISTEN 3214/sshd
tcp6 0 0 ::1:25 :::* LISTEN 3328/master
[root@server2 ~]# iptables -t nat -nL 查看火墙策略,发现没有DNAT
macvlan模式缺点:会独占主机网卡
[root@server1 ~]# docker network create -d macvlan --subnet 20.0.0.0/24 --gateway 20.0.0.1 -o parent=eth1.1 mynet2
c6bae3603c46dff911977d58ce54c388237756abcb8a5b292172192a8329df56
[root@server2 ~]# docker network create -d macvlan --subnet 20.0.0.0/24 --gateway 20.0.0.1 -o parent=eth1.1 mynet2
[root@server1 ~]# docker run -d --network mynet2 nginx 运行容器,以mynet2网络模式
[root@server1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
6c9de2935997 nginx "/docker-entrypoint.…" About a minute ago Up About a minute magical_chaum 容器已经运行
202b2b00b24b busyboxplus "/bin/sh" 26 minutes ago Up 26 minutes practical_hawking
[root@server1 ~]# docker inspect 6c9de2935997 查看容器详细信息,分到的ip地址为20.0.0.2
[root@server1 ~]# docker network create -d macvlan --subnet 30.0.0.0/24 --gateway 30.0.0.1 -o parent=eth1.2 mynet3 然后按此方法以此类推建立多macvlan网络
dda0c0cd1bcf8fb2fa478cac292621e9476e5cf6fa843bf72ba048b1e54c8afa
[root@server1 ~]# docker network ls 查看docker网络
|