当我们在Docker的宿主机里面启动Docker的时候,他们之间是可以互相通信的,那么外界是如何访问容器的呢?
看看下面这张简图
宿主机上的真正网卡是eth0,他的IP是 10.0.0.11, 当我们配置了docker之后,他会自动生成一个虚拟的网卡 docker0, IP是 172.17.0.1,这个子网是docker容器之间通讯的子网,所有的docker容器会自动生成一个vethxxx的虚拟网卡,IP地址都是172.17.0.0/24这个范围,他们之间通过一个 docker0的网桥虚拟机进行联系。那么外界如何来访问172.17.0.0/24这个内网系统呢? 我们通过DNAT 端口映射来实现。他会把eth0的宿主机的IP和端口和 对应的容器的IP和端口进行映射。 这个映射是通过Linux的防火墙iptables来实现的,不过我们不需要手动配置,而是在启动run命令 的时候用-p选项指定即可
ifconfig查看网卡
[root@ip-172-16-1-150 ec2-user]# docker run -d -p 8000:80 nginx
6bf871a60c8110f3389db0a02a5ff45f8713c157f9cb5fa946e40638acf494a3
[root@ip-172-16-1-150 ec2-user]# ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:4cff:feff:2845 prefixlen 64 scopeid 0x20<link>
ether 02:42:4c:ff:28:45 txqueuelen 0 (Ethernet)
RX packets 1277 bytes 1107179 (1.0 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 1573 bytes 9220451 (8.7 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 9001
inet 172.16.1.150 netmask 255.255.255.0 broadcast 172.16.1.255
inet6 fe80::8a6:48ff:fe3f:cff2 prefixlen 64 scopeid 0x20<link>
ether 0a:a6:48:3f:cf:f2 txqueuelen 1000 (Ethernet)
RX packets 122949 bytes 42060109 (40.1 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 95494 bytes 10487762 (10.0 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
veth63254cc: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::94ca:c5ff:fe3a:cb4c prefixlen 64 scopeid 0x20<link>
ether 96:ca:c5:3a:cb:4c txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8 bytes 696 (696.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
iptable自动配置端口转发的规则
[root@ip-172-16-1-150 ec2-user]# iptables -t nat -L -n
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 POSTROUTING (policy ACCEPT)
target prot opt source destination
MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0
MASQUERADE tcp -- 172.17.0.2 172.17.0.2 tcp dpt:80
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 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:8000 to:172.17.0.2:80
下面看个简单的实例
我的宿主机是一个AWS 的EC2 实例,作为测试,我分配了两个private IP地址给这个服务器,分别是172.16.1.150和 172.16.1.120
然后我给eth0 网卡分配一个新的IP地址
ifconfig eth0:0 add 172.16.1.120/24 up
这样我可以通过两个IP来访问不同的容器。
[root@ip-172-16-1-150 ec2-user]# docker run -d -p 172.16.1.120:80:80 nginx
3c2fe5b1f1e78abc522417bc05668317d18f7e18ba3779e06777238438c1210c
[root@ip-172-16-1-150 ec2-user]# docker run -d -p 172.16.1.150:80:80 ghost:alpine
97782eed76f0b50de459dd3789e58155bd600138dc3d1c433567bcceea310c87
[root@ip-172-16-1-150 ec2-user]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
97782eed76f0 ghost:alpine "docker-entrypoint.s…" 7 seconds ago Up 6 seconds 172.16.1.150:80->80/tcp, 2368/tcp festive_hermann
3c2fe5b1f1e7 nginx "/docker-entrypoint.…" 20 seconds ago Up 19 seconds 172.16.1.120:80->80/tcp laughing_kalam
[root@ip-172-16-1-150 ec2-user]#
测试一下, 成功