docker(七)容器与外部通信

    技术2025-06-15  13

    文章目录

    docker(7)容器与外部通信容器访问外部世界外部世界访问容器

    docker(7)容器与外部通信

    容器如何与外部世界通信,这里涉及两个方向 1.容器访问外部世界 2.外部世界访问容器

    容器访问外部世界

    在我们当前的实验环境下 docker host是可以访问外网的 [root@server7 ~]# ping www.baidu.com PING www.baidu.com (61.135.169.121) 56(84) bytes of data. 64 bytes from 61.135.169.121 (61.135.169.121): icmp_seq=1 ttl=52 time=97.4 ms 64 bytes from 61.135.169.121 (61.135.169.121): icmp_seq=2 ttl=52 time=77.2 ms 我们看一下容器是否也能访问外网呢? [root@server7 ~]# docker run -it busybox / # ping www.baidu.com PING www.baidu.com (61.135.169.125): 56 data bytes 64 bytes from 61.135.169.125: seq=0 ttl=51 time=173.166 ms 64 bytes from 61.135.169.125: seq=1 ttl=51 time=104.223 ms # 可以看到的是,容器默认就能访问外网 # 外网:指的是容器网络以外的网络环境,并非特指Internet [root@server7 ~]# iptables -t nat -S -P PREROUTING ACCEPT -P INPUT ACCEPT -P OUTPUT ACCEPT -P POSTROUTING ACCEPT -N DOCKER -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER -A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE -A POSTROUTING -s 172.22.16.0/24 ! -o br-c8e9feff6d4a -j MASQUERADE -A POSTROUTING -s 172.18.0.0/16 ! -o br-2c251699942a -j MASQUERADE -A DOCKER -i docker0 -j RETURN -A DOCKER -i br-c8e9feff6d4a -j RETURN -A DOCKER -i br-2c251699942a -j RETURN # busybox位于docker0这个私有bridge网络中(172.17.0.0/16) # busybox从容器向外ping时,数据包是怎样到达baidu.com的呢 # 这里的关键就是NAT 我们查看以下docker host 上的iptables规则 """ -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE 其含义是:如果网桥docker0收到来自172.17.0.0/16网段的外出包, 把它交给MASQUERADE处理,而MASQUERADE的处理方式是将包的源地址 替换成host的地址发送出去,即做了一次网络地址转换(NAT) """ 下面我们通过tcpdump查看地址是如何转换的 先查看docker host路由表 [root@server7 ~]# ip r default via 172.25.0.250 dev eth0 # 默认路由通过eth0发出去的,所以我们要同时监控eth0 和docker0上的icpm(ping)数据包 # 当busybox ping baidu.com 时 [root@server7 ~]# docker run -it busybox / # ping www.baidu.com PING www.baidu.com (61.135.169.125): 56 data bytes 64 bytes from 61.135.169.125: seq=0 ttl=51 time=63.100 ms 64 bytes from 61.135.169.125: seq=1 ttl=51 time=66.232 ms 64 bytes from 61.135.169.125: seq=2 ttl=51 time=69.345 ms 64 bytes from 61.135.169.125: seq=3 ttl=51 time=65.300 ms # tcpdump输出如下 [root@server7 ~]# tcpdump -i docker0 -n icmp tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on docker0, link-type EN10MB (Ethernet), capture size 65535 bytes 22:33:58.411204 IP 172.17.0.2 > 61.135.169.125: ICMP echo request, id 1280, seq 46, length 64 22:33:58.623189 IP 61.135.169.125 > 172.17.0.2: ICMP echo reply, id 1280, seq 46, length 64 22:33:59.411449 IP 172.17.0.2 > 61.135.169.125: ICMP echo request, id 1280, seq 47, length 64 [root@server7 ~]# tcpdump -i eth0 -n icmp tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes 22:37:28.382796 IP 172.25.0.7 > 61.135.169.121: ICMP echo request, id 1536, seq 11, length 64 22:37:28.457137 IP 61.135.169.121 > 172.25.0.7: ICMP echo reply, id 1536, seq 11, length 64 22:37:29.383057 IP 172.25.0.7 > 61.135.169.121: ICMP echo request, id 1536, seq 12, length 64 """ docker0收到busybox的ping包 源地址为容器IP 172.17.0.2 交给MASQUERADE 处理 在eth0上面我们看到了变化 ping包的源地址变成了eth0的IP 172.25.0.7 这就是iptable NAT规则的处理结果 从而保证数据包能够到达外网 即: 1.busybox发送ping包:172.17.0.2 >www.baidu.com 2.docker0收到包,发现是发送到外网站的,交给NAT处理 3.NAT将源地址转换成eth0的IP地址:172.25.0.7 >www.baidu.com 4.ping包从eth0发送出去,到达www.baidu.com 通过NAT,docker实现了容器对外网的访问

    外部世界访问容器

    外网如何访问到容器? 端口映射

    docker可将容器对外提供服务的端口映射到host的某个端口,外网通过该端口访问容器,容器启动时通过-p参数映射端口 [root@server7 ~]# docker run -d -p 80 httpd 59605d55848ce748f56abf3079ae3901525000602cdeaf146a778f3d558e3c4f [root@server7 ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 59605d55848c httpd "httpd-foreground" 4 seconds ago Up 4 seconds 0.0.0.0:32768->80/tcp jolly_galileo [root@server7 ~]# docker port 59605d55848c 80/tcp -> 0.0.0.0:32768 # 容器启动后,可通过docker ps或者docker port查看到host映射的端口, #在上面的例子中,httpd容器80端口被映射到host32773上, #这样就可以通过<host ip>:<32773>访问容器的WEB服务了 [root@server7 ~]# curl 172.25.0.7:32768 <html><body><h1>It works!</h1></body></html> 除了映射动态端口,也可以在-p中指定映射到host某个特定端口,例如可以将80端口映射到host的8080端口 [root@server7 ~]# docker run -d -p 8080:80 httpd b59175d1bc6f7f2aa81cd854f87aef4c786a0fa801599125caed4721deb15f62 [root@server7 ~]# curl 172.25.0.7:8080 <html><body><h1>It works!</h1></body></html> # 每一个映射的端口,host都会启动一个docker-proxy进程来处理访问容器的流量 [root@server7 ~]# ps -ef|grep docker-proxy root 2529 2122 0 23:05 ? 00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 32768 -container-ip 172.17.0.2 -container-port 80 root 2672 2122 0 23:11 ? 00:00:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 8080 -container-ip 172.17.0.3 -container-port 80 root 2792 2099 0 23:11 pts/0 00:00:00 grep --color=auto docker-proxy """ 以0.0.0.0:32773->80/tcp 为例分析整个过程 1.docker-proxy 监听host的32773端口 2.当curl访问 172.25.0.7:32773时,docker-proxy转发给容器ip:80 3.httpd容器响应请求并返回结果 """
    Processed: 0.011, SQL: 9