Torres-tao  

Docker网络

1、Docker网络实现原理

Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),docker启动一个容器时会根据docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。

因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能通过容器的Container-IP直接通信。

Docker网桥是宿主机虚拟出来的,并不是真实存在的网络设备,外部网络是无法寻址到的,这也意味着外部网络无法直接通过Container-IP访问到容器。

如果容器希望能被外部访问,可通过映射容器端口到宿主机(端口映射),即docker run创建容器的时候通过-p或-P参数来启用,访问容器的时候就通过[宿主机IP]:[容器端口]访问容器。

1.1、随机映射端口

[root@aliyun ~]# docker run -d -P --name nginx01 nginx
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
a2abf6c4d29d: Pull complete 
a9edb18cadd1: Pull complete 
589b7251471a: Pull complete 
186b1aaa4aa6: Pull complete 
b4df32aa5a72: Pull complete 
a0bcbecc962e: Pull complete 
Digest: sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
Status: Downloaded newer image for nginx:latest
2ddb5c52db610939452531a3635e5eda6561e639a945f4ca749c3bc46f95de0d
[root@aliyun ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS                   NAMES
2ddb5c52db61   nginx     "/docker-entrypoint.…"   7 seconds ago   Up 7 seconds   0.0.0.0:49157->80/tcp   nginx01

1.2、指定映射端口

[root@aliyun ~]# docker run -d -p 8088:80 --name nginx02 nginx
823ae713d67ba3771351161d0201528fe072c6c733c9b4acf90abc7324656dfa
[root@aliyun ~]# docker ps
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS          PORTS                   NAMES
823ae713d67b   nginx     "/docker-entrypoint.…"   7 seconds ago    Up 6 seconds    0.0.0.0:8088->80/tcp    nginx02
2ddb5c52db61   nginx     "/docker-entrypoint.…"   39 seconds ago   Up 38 seconds   0.0.0.0:49157->80/tcp   nginx01

1.3、访问测试

#8088端口
[root@aliyun ~]# curl localhost:8088
<!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; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

#49157端口
[root@aliyun ~]# curl localhost:49157
<!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; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

查看iptables规则

[root@aliyun ~]# iptables -nL -t nat
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

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         
MASQUERADE  all  --  172.18.0.0/16        0.0.0.0/0           
MASQUERADE  tcp  --  172.18.0.2           172.18.0.2           tcp dpt:80
MASQUERADE  tcp  --  172.18.0.3           172.18.0.3           tcp dpt:80

Chain DOCKER (2 references)
target     prot opt source               destination         
RETURN     all  --  0.0.0.0/0            0.0.0.0/0           
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:49157 to:172.18.0.2:80
DNAT       tcp  --  0.0.0.0/0            0.0.0.0/0            tcp dpt:8088 to:172.18.0.3:80

2、Docker网络模式

  1. Host:容器不会虚拟出自己的网卡,配置主机的IP等,而是使用宿主机的IP和端口
  2. Container:创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围
  3. None:该模式关闭了容器的网络功能
  4. Bridge:默认为该模式,此模式会为每一个容器分配、设置IP等,并将容器连接到一个docker0的虚拟网桥,通过docker0网桥以及iptables nat表配置与宿主机通信
  5. 自定义网络

2.1、默认网络

当安装docker时,它会自动创建三个网络bridge(创建容器默认连接到此网络)、none、host。可使用docker network ls查询

[root@aliyun ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
8df3cdb08d2a   bridge    bridge    local
c3009610274a   host      host      local
e6d7cbd64aa7   none      null      local

2.2、容器网络模式指定

使用docker run创建docker容器时,可以用--net或--network选项指定容器的网络模式:

  • host模式:使用--net=host指定
  • none模式:使用--net=none指定
  • container模式:使用--net=container:NAME__or_ID指定
  • bridge模式:使用--net=bridge指定,默认配置,可省略

3、Docker网络模式详解

3.1、host模式

host模式相当于VMware中的桥接模式,与宿主机在同一个网络中,但是没有独立IP地址

Docker使用了Linux的Namespace技术来进行资源隔离,如PID Namespace(隔离进程)、Mount Namespace(隔离文件系统)、Network Namespace(隔离网路)等。一个Network Namespace提供了一份独立的网路环境,包括网卡、路由、iptables规则等,均与其他Network Namespace隔离。一个docker容器一般会分配一个独立的Network Namespace。

但是如果启动容器时使用host模式,那么此容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡,配置自己的IP等,而是使用宿主机的IP和端口范围。此时容器不再拥有隔离的、独立的网络栈,不拥有端口资源。

3.2、container模式

这个模式指定新创建的容器和已经存在的一个容器共享一个Network Namespace,而不是和宿主机共享。

新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信。

[root@aliyun ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED       STATUS       PORTS                   NAMES
823ae713d67b   nginx     "/docker-entrypoint.…"   4 hours ago   Up 4 hours   0.0.0.0:8088->80/tcp    nginx02
2ddb5c52db61   nginx     "/docker-entrypoint.…"   4 hours ago   Up 4 hours   0.0.0.0:49157->80/tcp   nginx01
#查看容器进程PID
[root@aliyun ~]# docker inspect -f '{{.State.Pid}}' 2ddb5c52db61
19528
#查看容器的进程、网络、文件系统等命名空间编号
[root@aliyun ~]# ls -l /proc/19528/ns
总用量 0
lrwxrwxrwx 1 root root 0 4月  20 14:07 ipc -> ipc:[4026532160]
lrwxrwxrwx 1 root root 0 4月  20 14:07 mnt -> mnt:[4026532157]
lrwxrwxrwx 1 root root 0 4月  20 10:34 net -> net:[4026532163]
lrwxrwxrwx 1 root root 0 4月  20 10:35 pid -> pid:[4026532161]
lrwxrwxrwx 1 root root 0 4月  20 14:07 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 4月  20 14:07 uts -> uts:[4026532
#新建一个容器,使用container模式
[root@aliyun ~]# docker run -itd --name nginx03 --net=container:2ddb5c52db61 nginx /bin/bash
69ef00e830ecf1da5eb1862b65edf1def73de6f399548d41339d650ec68cc07c
[root@aliyun ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED         STATUS         PORTS                   NAMES
69ef00e830ec   nginx     "/docker-entrypoint.…"   5 seconds ago   Up 4 seconds                           nginx03
823ae713d67b   nginx     "/docker-entrypoint.…"   4 hours ago     Up 4 hours     0.0.0.0:8088->80/tcp    nginx02
2ddb5c52db61   nginx     "/docker-entrypoint.…"   4 hours ago     Up 4 hours     0.0.0.0:49157->80/tcp   nginx01
#查看nginx03的进程PID
[root@aliyun ~]# docker inspect -f '{{.State.Pid}}' 69ef00e830ec
27950
[root@aliyun ~]# ls -l /proc/27950/ns
总用量 0
lrwxrwxrwx 1 root root 0 4月  20 14:12 ipc -> ipc:[4026532284]
lrwxrwxrwx 1 root root 0 4月  20 14:12 mnt -> mnt:[4026532282]
lrwxrwxrwx 1 root root 0 4月  20 14:11 net -> net:[4026532163]
lrwxrwxrwx 1 root root 0 4月  20 14:12 pid -> pid:[4026532285]
lrwxrwxrwx 1 root root 0 4月  20 14:12 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 4月  20 14:12 uts -> uts:[4026532283]

3.3、none模式

使用none模式,Docker容器拥有自己的Network Namespace,但是,并不为docker容器进行任何网络配置

也就是说,这个docker容器没有网卡、IP、路由等信息。这个网络模式下容器只有lo回环网络,没有其他网卡。这种类型的网络没有办法联网,封闭的网络能很好的保证容器的安全性。

3.4、bridge模式

bridge模式是docker的默认网络模式

相当于VMware中的nat模式,容器使用独立Network Namespace,并连接到docker0虚拟网卡。通过docker0网桥以及iptables NAT表配置与宿主机通信,此模式会为每一个容器分配Network Namespace、设置IP等,并将一个主机上的Docker容器连接到一个虚拟网桥上。

  1. 当docker进程启动时,会在主机上创建一个docker0的虚拟网桥,此主机上启动的docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。
  2. 从docker0子网中分配一个IP给容器使用,并设置docker0的IP地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备。veth设备总是成对出现的,它们组成了一个数据的通道,数据从一个设备进入,就会从另一个设备出来。因此,veth设备常用来连接两个网络设备。
  3. Docker将veth pair设备的一段放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以veth*这样类似的名字命名,并将这个网络设备加入到docker0网桥中。可以通过brctl show命令查看。
  4. 使用docker run -p时,docker实际是在iptables做了DNAT规则,实现端口转发功能。可使用iptables -t nat -nL查看。
posted on 2022-04-20 14:34  雷子锅  阅读(154)  评论(0编辑  收藏  举报