Docker容器内部端口映射到外部宿主机端口的方法总结
好记性不如烂笔头,将docker容器端口映射到宿主机的方法做一个总结,方便后边忘记了能快速的查询。
首先需要注意:
宿主机的一个端口只能映射到容器内部的某一个端口上,比如:8080->80之后,就不能8080->81
容器内部的某个端口可以被宿主机的多个端口映射,比如:8080->80,8090->80,8099->80
1)启动容器时, 选择一个端口映射到容器内部开放端口上
-p 小写p表示docker会选择一个具体的宿主机端口映射到容器内部开放的网络端口上。
-P 大写P表示docker会随机选择一个宿主机端口映射到容器内部开放的网络端口上。很少用P,都是指定的宿主机端口
2)启动创建时,绑定外部的ip和端口(宿主机ip是192.168.0.134)
可以根据不同网卡的IP来绑定宿主机的IP地址
[root@docker-test ~]# docker run -ti -d --name my-nginx3 -p 127.0.0.1:8888:80 docker.io/nginx debca5ec7dbb770ca307b06309b0e24b81b6bf689cb11474ec1ba187f4d7802c [root@docker-test ~]# docker run -ti -d --name my-nginx4 -p 192.168.0.134:9999:80 docker.io/nginx ba72a93196f7e55020105b90a51d2203f9cc4d09882e7848ff72f9c43d81852a [root@docker-test ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ba72a93196f7 docker.io/nginx "nginx -g 'daemon ..." 2 seconds ago Up 1 second 192.168.0.134:9999->80/tcp my-nginx4 debca5ec7dbb docker.io/nginx "nginx -g 'daemon ..." 3 minutes ago Up 3 minutes 127.0.0.1:8888->80/tcp my-nginx3 由上面可知: 容器my-nginx3绑定的宿主机外部ip是127.0.0.1,端口是8888,则访问http://127.0.0.1:8888或http://localhost:8888都可以,访问http://192.168.0.134:8888就会拒绝! 容器my-nginx4绑定的宿主机外部ip是192.168.10.214,端口是9999,则访问http://192.168.0.134:9999就可以,访问http://127.0.0.1:9999或http://localhost:9999就会拒绝!
3)容器启动时可以指定通信协议,比如tcp、udp
[root@docker-test ~]# docker run -ti -d --name my-nginx5 -p 8099:80/tcp docker.io/nginx c08eb29e3c0a46386319b475cc95245ccfbf106ed80b1f75d104f8f05d0d0b3e [root@docker-test ~]# docker run -ti -d --name my-nginx6 -p 192.168.0.134:8088:80/udp docker.io/nginx 992a48cbd3ef0e568b45c164c22a00389622c2b49e77f936bc0f980718590d5b [root@docker-test ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 992a48cbd3ef docker.io/nginx "nginx -g 'daemon ..." 3 seconds ago Up 2 seconds 80/tcp, 192.168.0.134:8088->80/udp my-nginx6 c08eb29e3c0a docker.io/nginx "nginx -g 'daemon ..." 53 seconds ago Up 51 seconds 0.0.0.0:8099->80/tcp my-nginx5
容器my-nginx6无法访问,因为映射的是udp的80端口
4)查看容器绑定和映射的端口及Ip地址
[root@docker-test ~]# docker port my-nginx5 //查看容器映射的端口 80/tcp -> 0.0.0.0:8099 [root@docker-test ~]# docker inspect my-nginx5|grep IPAddress //查看容器的IP地址 "SecondaryIPAddresses": null, "IPAddress": "172.17.0.6", "IPAddress": "172.17.0.6",
5)容器除了在启动时添加端口映射关系,还可以通过宿主机的iptables进行nat转发,将宿主机的端口映射到容器的内部端口上,这种方式适用于容器启动时没有指定端口映射的情况!
[root@docker-test ~]# docker run -ti -d --name my-nginx9 docker.io/nginx 990752e39d75b977cbff5a944247366662211ce43d16843a452a5697ddded12f [root@docker-test ~]# docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 990752e39d75 docker.io/nginx "nginx -g 'daemon ..." 2 seconds ago Up 1 second 80/tcp my-nginx9 这个时候,由于容器my-nginx9在启动时没有指定其内部的80端口映射到宿主机的端口上,所以默认是没法访问的! 现在通过宿主机的iptables进行net转发 首先获得容器的ip地址 [root@docker-test ~]# docker inspect my-nginx9|grep IPAddress "SecondaryIPAddresses": null, "IPAddress": "172.17.0.9", "IPAddress": "172.17.0.9", [root@docker-test ~]# ping 172.17.0.9 PING 172.17.0.9 (172.17.0.9) 56(84) bytes of data. 64 bytes from 172.17.0.9: icmp_seq=1 ttl=64 time=0.105 ms 64 bytes from 172.17.0.9: icmp_seq=2 ttl=64 time=0.061 ms ..... [root@docker-test ~]# telnet 172.17.0.9 80 Trying 172.17.0.9... Connected to 172.17.0.9. Escape character is '^]' centos7下部署iptables环境纪录(关闭默认的firewalle) 参考:http://www.cnblogs.com/kevingrace/p/5799210.html 将容器的80端口映射到dockers宿主机的9998端口 [root@docker-test ~]# iptables -t nat -A PREROUTING -p tcp -m tcp --dport 9998 -j DNAT --to-destination 172.17.0.9:80 [root@docker-test ~]# iptables -t nat -A POSTROUTING -d 172.17.0.9/32 -p tcp -m tcp --sport 80 -j SNAT --to-source 192.16.10.214 [root@docker-test ~]# iptables -t filter -A INPUT -p tcp -m state --state NEW -m tcp --dport 9998 -j ACCEPT 保存以上iptables规则 [root@docker-test ~]# iptables-save > /etc/sysconfig/iptables 查看/etc/sysconfig/iptables文件,注意下面两行有关icmp-host-prohibited的设置一定要注释掉!否则nat转发会失败! [root@docker-test ~]# cat /etc/sysconfig/iptables # Generated by iptables-save v1.4.21 on Fri Aug 10 11:13:57 2018 *nat :PREROUTING ACCEPT [32:1280] :INPUT ACCEPT [0:0] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] -A PREROUTING -p tcp -m tcp --dport 9998 -j DNAT --to-destination 172.17.0.9:80 -A POSTROUTING -d 172.17.0.9/32 -p tcp -m tcp --sport 80 -j SNAT --to-source 192.16.10.214 COMMIT # Completed on Fri Aug 10 11:13:57 2018 # Generated by iptables-save v1.4.21 on Fri Aug 10 11:13:57 2018 *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [50:5056] -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -p icmp -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT -A INPUT -p tcp -m state --state NEW -m tcp --dport 9998 -j ACCEPT #-A INPUT -j REJECT --reject-with icmp-host-prohibited #-A FORWARD -j REJECT --reject-with icmp-host-prohibited COMMIT # Completed on Fri Aug 10 11:13:57 2018 最后重启iptbales服务 [root@docker-test ~]# systemctl restart iptables 查看iptables规则 [root@docker-test ~]# iptables -L Chain INPUT (policy ACCEPT) target prot opt source destination ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED ACCEPT icmp -- anywhere anywhere ACCEPT all -- anywhere anywhere ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:ssh ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:distinct32 Chain FORWARD (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination [root@docker-test ~]# iptables -L -t nat Chain PREROUTING (policy ACCEPT) target prot opt source destination DNAT tcp -- anywhere anywhere tcp dpt:distinct32 to:172.17.0.9:80 Chain INPUT (policy ACCEPT) target prot opt source destination Chain OUTPUT (policy ACCEPT) target prot opt source destination Chain POSTROUTING (policy ACCEPT) target prot opt source destination SNAT tcp -- anywhere 172.17.0.9 tcp spt:http to:192.16.10.214 然后访问http://192.168.10.214:9998/,就能转发访问到my-nginx9容器的80端口了!!!
如果启动docker 容器时,有如下报错: /usr/bin/docker-current: Error response from daemon: driver failed programming external connectivity on endpoint my-nginx (db5a0edac68d1ea7ccaa3a1e0db31ebdf278076ef4851ee4250221af6167f9ac): (iptables failed: iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --dport 8088 -j DNAT --to-destination 172.17.0.2:80 ! -i docker0: iptables: No chain/target/match by that name。
解决办法
1)不需要关闭防火墙 2)重启docker服务:systemctl restart docker 3)docker服务重启后,所有容器都会关闭,应立即批量启动全部容器:docker start `docker ps -a -q` 启动的容器也会包括上面报错的容器,重启docker后,该容器就能正常启动和使用了!