容器通信除了可以使用ip以外,还可以使用容器名称进行通信
dns解析功能在自定义网络中才可以生效
Docker容器之间实现通信
1.启动容器使用–name指定容器的名称
[root@server1 ~]# docker network ls ##查看当前网络
NETWORK ID NAME DRIVER SCOPE
a3b785379510 bridge bridge local
66a8ce5625c5 host host local
0f283adad81f my_net1 bridge local
64ecaf807e64 my_net2 bridge local
ebc2c1a28d75 none null local
[root@server1 ~]# docker run -it --name vm1 --network my_net1 ubuntu ##以自定义网络my_net2创建容器vm1
root@9918b4adf65e:/# ip addr ##查看分配ip为172.18.0.2
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.2/16 brd 172.18.255.255 scope global eth0
valid_lft forever preferred_lft forever
[root@server1 ~]# docker run -it --name vm2 --network my_net1 ubuntu ##以自定义网络my_net2创建容器vm2
root@9d8a238d96cb:/# ip addr ##查看分配ip为172.18.0.3
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
20: eth0@if21: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:12:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.3/16 brd 172.18.255.255 scope global eth0
valid_lft forever preferred_lft forever
root@9d8a238d96cb:/# ping vm1 ##通过dns解析,以容器名称实现通信功能
PING vm1 (172.18.0.2) 56(84) bytes of data.
64 bytes from vm1.my_net1 (172.18.0.2): icmp_seq=1 ttl=64 time=0.060 ms
64 bytes from vm1.my_net1 (172.18.0.2): icmp_seq=2 ttl=64 time=0.058 ms
64 bytes from vm1.my_net1 (172.18.0.2): icmp_seq=3 ttl=64 time=0.049 ms
^C
--- vm1 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 1999ms
rtt min/avg/max/mdev = 0.049/0.055/0.060/0.009 ms
2.容器之间实现网络共享
创建容器时使用–network=container:vm1指定(vm1运行容器的名称)
[root@server1 ~]# docker run -it --name vm1 ubuntu ##创建容器1
root@655ab1b2369e:/# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
22: eth0@if23: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
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@server1 ~]# docker run -it --name vm2 --network container:vm1 ubuntu
root@655ab1b2369e:/# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
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
22: eth0@if23: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
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
两容器ip地址完全相同均为172.17.0.2/16实现网络共享,处于这个模式下的容器会共享一个网络线,这样两个容器之间可以使用localhost实现高效快速的通信
3.容器之间实现链接
创建容器时使用–link,指定源容器的名称和id(作用:更新host文件,将原容器的变量设置到新容器)
[root@server1 ~]# docker run -d nginx ##创建源容器
abbf190aca8c869211d1f2a858761b53b390f824c7216e9b3f6fdcd18137c801
[root@server1 ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
abbf190aca8c nginx "nginx -g 'daemon of…" 9 seconds ago Up 7 seconds 80/tcp blissful_robinson
[root@server1 ~]# docker inspect abbf190aca8c ##获取到的ip为172.17.0.2
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
[root@server1 ~]# docker run -it --name vm1 --link blissful_robinson:web ubuntu ##新容器vm1链接源容器,并给源容器起名为web
root@32b018ee1ea7:/# ping web ##与源容器实现通信
PING web (172.17.0.2) 56(84) bytes of data.
64 bytes from web (172.17.0.2): icmp_seq=1 ttl=64 time=0.105 ms
64 bytes from web (172.17.0.2): icmp_seq=2 ttl=64 time=0.052 ms
^C
--- web ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.052/0.078/0.105/0.027 ms
root@32b018ee1ea7:/# cat /etc/hosts ##实现通信源因更改了解析文件
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 web abbf190aca8c blissful_robinson ##源容器ip,别名,id,原name
172.17.0.3 32b018ee1ea7 ##vm1容器ip及id
root@32b018ee1ea7:/# env ##查看环境可知:将原容器的变量作为参数全部传输至vm1
HOME=/root
WEB_NAME=/vm1/web
WEB_PORT_80_TCP_PROTO=tcp
WEB_PORT_80_TCP_ADDR=172.17.0.2
LESSOPEN=| /usr/bin/lesspipe %s
WEB_PORT=tcp://172.17.0.2:80
LESSCLOSE=/usr/bin/lesspipe %s %s
_=/usr/bin/env
–link自动更改解析文件hosts
[root@server1 ~]# docker stop blissful_robinson ##停止源容器
blissful_robinson
[root@server1 ~]# docker start blissful_robinson ##开启源容器
blissful_robinson
[root@server1 ~]# docker inspect blissful_robinson ##查看源容器信息
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2", ##ip依旧分配为172.17.0.2
[root@server1 ~]# docker stop blissful_robinson ##再次关闭源容器
blissful_robinson
[root@server1 ~]# docker run -d nginx ##重新开启一个新的容器
1c4834e8777a8c34908fb3059c1e4b50725e9e4ab2028c518cd526dcc8f64714
[root@server1 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1c4834e8777a nginx "nginx -g 'daemon of…" 10 seconds ago Up 9 seconds 80/tcp jolly_leakey
32b018ee1ea7 ubuntu "/bin/bash" 12 minutes ago Up 12 minutes vm1
[root@server1 ~]# docker inspect jolly_leakey
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2" ##新容器ip为172.17.0.2占用源容器ip
[root@server1 ~]# docker start blissful_robinson ##开启之前关闭的源容器
blissful_robinson
[root@server1 ~]# docker inspect blissful_robinson
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.4", ##此时源容器获取的ip为172.17.0.4
此时进入容器vm1中再次查看
root@32b018ee1ea7:/# cat /etc/hosts
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.4 web abbf190aca8c blissful_robinson ##web源ip被自动更改为172.17.0.4
172.17.0.3 32b018ee1ea7
容器访问外网
1.与外网实现通信的原理
原理:
容器与docker0以桥接的方式连接,则docker0做为容器的网关,数据到达docker0网关;docker0与宿主机之间通过内核路由功能实现通信,则数据经过内核路由功能并转换为当前宿主机的地址到达宿主机;由宿主机将数据包传达至外网
[root@server1 ~]# iptables -t nat -S ##查看火墙策略
-A POSTROUTING -s 172.22.0.0/24 ! -o br-64ecaf807e64 -j MASQUERADE
-A POSTROUTING -s 172.18.0.0/16 ! -o br-0f283adad81f -j MASQUERADE
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
所有容器地址均需要进行伪装,才可以将数据传出去
[root@server1 ~]# docker ps ##查看当前容器共有3个
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1c4834e8777a nginx "nginx -g 'daemon of…" 23 minutes ago Up 23 minutes 80/tcp jolly_leakey
32b018ee1ea7 ubuntu "/bin/bash" 35 minutes ago Up 35 minutes vm1
abbf190aca8c nginx "nginx -g 'daemon of…" 39 minutes ago Up 21 minutes 80/tcp blissful_robinson
[root@server1 ~]# brctl show ##当前三个容器均桥接到docker0上
bridge name bridge id STP enabled interfaces
br-0f283adad81f 8000.024250685ac8 no
br-64ecaf807e64 8000.02424cef9619 no
docker0 8000.0242c447dc14 no veth5a5ea00
veth7857d82
vetha38d4bb
以容器vm1为例
[root@server1 ~]# docker container attach vm1 ##进入容器vm1
root@32b018ee1ea7:/#
root@32b018ee1ea7:/# ping www.baidu.com ##可以与外网进行通信,即容器ip伪装成功
PING www.a.shifen.com (220.181.38.149) 56(84) bytes of data.
64 bytes from 220.181.38.149: icmp_seq=1 ttl=49 time=25.3 ms
64 bytes from 220.181.38.149: icmp_seq=2 ttl=49 time=22.6 ms
^C
--- www.a.shifen.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
2.端口映射实现外网通信
-p:指定映射端口
[root@server1 ~]# docker run -d --name vm2 -p 80:80 nginx ##创建容器并端口映射为80
c48bfc53f3eae09ae06276b63d855087e559fd45aaa7a2b979b9edacaf87a032
[root@server1 ~]# docker inspect vm2 ##查看新容器的信息,其中分配ip为172.17.0.3
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.3",
[root@server1 ~]# docker ps -a ##查看端口映射是否成功
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c48bfc53f3ea nginx "nginx -g 'daemon of…" About a minute ago Up About a minute 0.0.0.0:80->80/tcp vm2
32b018ee1ea7 ubuntu "/bin/bash" 44 minutes ago Exited (0) About a minute ago vm1
[root@server1 ~]# docker port vm2
80/tcp -> 0.0.0.0:80
[root@server1 ~]# netstat -antlp ##查看80端口是否暴露出去
tcp6 0 0 :::80 :::* LISTEN 14416/docker-proxy ##开启docker-proxy进程
tcp6 0 0 :::22 :::* LISTEN 650/sshd
tcp6 0 0 ::1:25 :::* LISTEN 885/master
[root@server1 ~]# iptables -t nat -nL ##查看nat策略,进行了地址转换
Chain DOCKER (2 references)
target prot opt source destination
RETURN all -- 0.0.0.0/0 0.0.0.0/0
RETURN all -- 0.0.0.0/0 0.0.0.0/0
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:80 to:172.17.0.3:80
[root@server1 ~]# iptables -t nat -S
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.17.0.3:80
当外网访问容器vm2时时,首先容器通过火墙nat规则,将172.17.0.3:80端口暴露出去,并与宿主机80端口连接;则外网访问宿主机80端口时,会连接到容器
测试:
(1)宿主机访问容器
[root@server1 ~]# curl localhost:80
<h1>Welcome to nginx!</h1>
(2)浏览器端访问宿主机80端口
http://172.25.4.111:80
访问成功
[root@server1 ~]# ps ax |grep docker-proxy ##容器每进行一次端口映射,均会开启一个docker-proxy进程
14416 ? Sl 0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 80 -container-ip 172.17.0.3 -container-port 80
14567 pts/1 R+ 0:00 grep --color=auto docker-proxy
当宿主机访问本机容器时,使用iptables DNAT策略
当外网访问容器或容器之间进行访问时,使用docker-proxy策略