0x00 前言

这章还是挺有意思的,解决了前期学习的几个大问题,我创建了容器后,容器如何被主机访问,容器之间是否可以正常访问,不过这章内容讲的比较浅,后面的章节还有具体内容的学习,先来初体验。


0x01 端口映射

端口映射在之前的章节实现中也使用过,属于run指令中的选项-P或者-p,也就是前面所说的暴露端口。

如果在启动容器时不进行暴露端口,在容器外部是无法通过网络来访问容器内的网络应用和服务的,在使用-P参数时会随机指定49000-49900中的端口进行映射,拿httpd来举例

[root@localhost ~]# docker container run -d -P --name http httpd
62714120aebf976310ae684913a7e9e7d0c6501e7b4a7442155ca50d40779693
[root@localhost ~]# docker container port http
80/tcp -> 0.0.0.0:49157

#访问测试,正常访问
[root@localhost ~]# curl localhost:49157
<html><body><h1>It works!</h1></body></html>

也可以使用-p来进行特定端口的映射

[root@localhost ~]# docker container run -d -p 5080:80 --name http2 httpd 
91f7cb39a02eec7f609639907689fda586afc22974b8a9389a4b0aff13464c16
[root@localhost ~]# docker container port http2                          
80/tcp -> 0.0.0.0:5080
[root@localhost ~]# curl localhost:5080
<html><body><h1>It works!</h1></body></html>

如果有多少个端口需要暴露也可以指定多个,甚至绑定特定IP也可以。

[root@localhost ~]# docker container run -d -p 5081:80 -p 127.0.0.1:81:81 --name http3 httpd
6990991ca1c9c195cf8b53678b8f41b7178206682dc78c07cef2a4e8fecd4913
[root@localhost ~]# docker container port http3
80/tcp -> 0.0.0.0:5081
81/tcp -> 127.0.0.1:81

0x02 互联机制实现便捷互访

容器的互联link是一种让多个容器中的应用进行快速交互的方式。它会在源和接收容器之间创建连接关系,接收容器可以通过容器名直接访问源容器,而不需要使用特定IP地址。

#创建两个centos
[root@localhost ~]# docker container run -it -d --name centos1 centos:7 /bin/bash
45e631cbec7d0261d08ab7c7f14f8f6b81eaaaa057455768154d7a472fb7236a
[root@localhost ~]# docker container run -it -d --name centos2 centos:7 /bin/bash 
463e58702993998d01665b512ad3b2085e773c91fa12b93605651cc75309bf7d

#没有选择网络,则查看默认网络的IP分配情况,具体原理会在后面章节有讲。
[root@localhost ~]# docker network inspect bridge 
[
    {
        "Name": "bridge",
        "Id": "8d7a0a2939bcec65c705c12b9ac5aead3aa7ea65e3c5bd64a39ccf8c1bffde45",
        "Created": "2021-02-07T12:51:22.673514815+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",
                    "Gateway": "172.17.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "45e631cbec7d0261d08ab7c7f14f8f6b81eaaaa057455768154d7a472fb7236a": {
                "Name": "centos1",
                "EndpointID": "b61bfd3c5f10c2e9f0638ea5e47cd0fe87ab71cd9def68699ef7cddd53c47347",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "463e58702993998d01665b512ad3b2085e773c91fa12b93605651cc75309bf7d": {
                "Name": "centos2",
                "EndpointID": "b601feeb630d09c92e475f96969552a8286ec3a118fac6c3a556345d9bf49caa",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]
#从上可以看到centos1的ip为172.17.0.2,centos2的ip为172.17.0.3。

#测试访问ip
[root@localhost ~]# docker container exec -t centos1 ping -c 1 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.063 ms

--- 172.17.0.3 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.063/0.063/0.063/0.000 ms

#测试访问容器名
[root@localhost ~]# docker container exec -t centos1 ping -c 1 centos2
ping: centos2: Name or service not known

结果也非常明显,只能通过IP地址互联,假设容器重启后,获取的IP地址变化,则有可能导致环境出现故障,如果是使用容器名进行连接,则可解决这种情况带来的问题,继续测试

#创建新的容器centos3,使用--link互联到centos1上,
[root@localhost ~]# docker container run -it -d --link centos1 --name centos3 centos:7 /bin/bash

#centos3的IP地址为172.17.0.4
[root@localhost ~]# docker network inspect bridge 
			...
            "94670a0bb6826ea05fce2ff9d7d90d336f5c766e9ff312f1bab7f079e86db2f3": {
                "Name": "centos3",
                "EndpointID": "1af5265372a588afee953275ddc9fd36f76a77ed749ecaab07c93a8e5e0d1e66",
                "MacAddress": "02:42:ac:11:00:04",
                "IPv4Address": "172.17.0.4/16",
                "IPv6Address": ""
            }

#测试互联,centos1分别使用ip和容器名访问centos3,结果ip能通,容器名不能通。
[root@localhost ~]# docker container exec -t centos1 ping -c 1 172.17.0.4
PING 172.17.0.4 (172.17.0.4) 56(84) bytes of data.
64 bytes from 172.17.0.4: icmp_seq=1 ttl=64 time=0.085 ms

--- 172.17.0.4 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.085/0.085/0.085/0.000 ms
[root@localhost ~]# docker container exec -t centos1 ping -c 1 centos3 
ping: centos3: Name or service not known

#测试互联,centos3分别使用ip和容器名访问centos1,结果ip和容器名都能通
[root@localhost ~]# docker container exec -t centos3 ping -c 1 172.17.0.2
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.064 ms
[root@localhost ~]# docker container exec -t centos3 ping -c 1 centos1  
PING centos1 (172.17.0.2) 56(84) bytes of data.
64 bytes from centos1 (172.17.0.2): icmp_seq=1 ttl=64 time=0.060 ms

--- centos1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.060/0.060/0.060/0.000 ms

明显看到--link是单向的参数,由于只在centos3做了link,所以centos1并不能像centos3一样,使用容器名进行互访,另外--link的原理也非常简单,利用着host文件来进行实现。

#centos3的hosts文件
[root@localhost ~]#   docker container exec -t centos3 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      centos1 45e631cbec7d
172.17.0.4      94670a0bb682

#centos1的hosts文件
[root@localhost ~]#   docker container exec -t centos1 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      45e631cbec7d

明显可以看到centos3中对于172.16.0.2的域名是添加上了容器名centos1的。

不过这个功能实际上看似好用,但是实际上当我们学过docker高级网络后,发现其实是不需要用到--link参数的,可以自动完成!