Docker容器内部端口映射到外部宿主机端口

[Docker容器内部端口映射到外部宿主机端口 - 运维笔记]

Docker允许通过外部访问容器或者容器之间互联的方式来提供网络服务。
容器启动之后,容器中可以运行一些网络应用,通过-p或-P参数来指定端口映射。

注意:
宿主机的一个端口只能映射到容器内部的某一个端口上,比如:8080->80之后,就不能8080->81
容器内部的某个端口可以被宿主机的多个端口映射,比如:8080->80,8090->80,8099->80

1)启动容器时,选择一个端口映射到容器内部开放端口上
**-p ** 小写p表示docker会选择一个具体的宿主机端口映射到容器内部开放的网络端口上。
**-P ** 大写P表示docker会随机选择一个宿主机端口映射到容器内部开放的网络端口上。
比如:

[root@docker-test ~]# docker run -ti -d --name my-nginx -p 8088:80 docker.io/nginx
2218c7d88ccc917fd0aa0ec24e6d81667eb588f491d3730deb09289dcf6b8125
[root@docker-test ~]# docker run -ti -d --name my-nginx2 -P docker.io/nginx
589237ceec9d5d1de045a5395c0d4b519acf54e8c09afb07af49de1b06d71059
[root@docker-test ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED              STATUS              PORTS                   NAMES
589237ceec9d        docker.io/nginx     "nginx -g 'daemon ..."   6 seconds ago        Up 5 seconds        0.0.0.0:32770->80/tcp   my-nginx2
2218c7d88ccc        docker.io/nginx     "nginx -g 'daemon ..."   About a minute ago   Up About a minute   0.0.0.0:8088->80/tcp    my-nginx

由上面可知:
容器my-nginx启动时使用了-p,选择宿主机具体的8088端口映射到容器内部的80端口上了,访问http://localhost/8088即可
容器my-nginx2启动时使用了-P,选择宿主机的一个随机端口映射到容器内部的80端口上了,这里随机端口是32770,访问http://localhost/32770即可

2)启动创建时,绑定外部的ip和端口(宿主机ip是192.168.10.214)

[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.10.214: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.10.214: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.10.214:8888就会拒绝!
容器my-nginx4绑定的宿主机外部ip是192.168.10.214,端口是9999,则访问http://192.168.10.214: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.10.214:8077: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.10.214:8077->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

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
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.6",
                    "IPAddress": "172.17.0.6",

5)容器启动绑定多IP和端口(跟多个-p)

[root@docker-test ~]# docker run -ti -d --name my-nginx8 -p 192.168.10.214:7777:80 -p 127.0.0.1:7788:80 docker.io/nginx
0e86be91026d1601b77b52c346c44a31512138cedc7f21451e996dd2e75d014d
[root@docker-test ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                                 NAMES
0e86be91026d        docker.io/nginx     "nginx -g 'daemon ..."   17 seconds ago      Up 15 seconds       127.0.0.1:7788->80/tcp, 192.168.10.214:7777->80/tcp   my-nginx8

6)容器除了在启动时添加端口映射关系,还可以通过宿主机的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端口了!!!
一次性删除所有容器,包括正在运行的容器

[root@docker-test ~]# docker rm -f `docker ps -a -q`
990752e39d75
0e86be91026d
ff2bc46a8ee4
c08eb29e3c0a
ba72a93196f7
debca5ec7dbb
589237ceec9d
2218c7d88ccc
[root@docker-test ~]# docker ps -a
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

如果启动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后,该容器就能正常启动和使用了!

===========问题: Docker 端口映射到宿主机后, 外部无法访问对应宿主机端口==============
创建docker容器的时候,做了端口映射到宿主机, 防火墙已关闭, 但是外部始终无法访问宿主机端口?
这种情况基本就是因为宿主机没有开启ip转发功能,从而导致外部网络访问宿主机对应端口是没能转发到 Docker Container 所对应的端口上。

解决办法:
Linux 发行版默认情况下是不开启 ip 转发功能的。这是一个好的做法,因为大多数人是用不到 ip 转发的,但是如果架设一个 Linux 路由或者VPN服务我们就需要开启该服务了。

在 Linux 中开启 ip 转发的内核参数为:net.ipv4.ip_forward,查看是否开启 ip转发:

# cat /proc/sys/net/ipv4/ip_forward           // 0:未开启,1:已开启

==============================
打开ip转发功能, 下面两种方法都是临时打开ip转发功能!

# echo 1 > /proc/sys/net/ipv4/ip_forward
# sysctl -w net.ipv4.ip_forward=1

==============================
永久生效的ip转发

# vim /etc/sysctl.conf
net.ipv4.ip_forward = 1
 
# sysctl -p /etc/sysctl.conf      // 立即生效

Linux 系统中也可以通过重启网卡来立即生效 (修改sysctl.conf文件后的生效)

# service network restart                  //CentOS 6
# systemctl restart network              //CentOS 7
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,561评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,218评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,162评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,470评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,550评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,806评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,951评论 3 407
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,712评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,166评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,510评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,643评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,306评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,930评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,745评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,983评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,351评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,509评论 2 348

推荐阅读更多精彩内容