我们知道,docker
通过命名空间实现了环境隔离。
据docker
官方文档,网络模式主要有几种不同程度的隔离方式,host
、bridge
、overlay
、macvlan
、none
。我们先讲讲这几种网络模式,稍后我们会提出题目所示的疑问,你可以先带着这个疑问往下走。
host
删除容器和Docker主机之间的网络隔离,直接使用主机的网络
bridge
默认网络模式,桥接网络,在网段之间转发流量的链路层设备。桥接网络使用软件桥,该软件桥允许连接到同一桥网络的容器进行通信,同时提供与未连接到该桥网络的容器的隔离。
overlay
覆盖网络将多个Docker守护程序连接在一起,使得Swarm服务彼此通信。
macvlan
MacVlan
网络允许为容器分配MAC
地址,使其显示为网络上的物理设备。
none
禁用容器所有网络,通常与自定义网络驱动程序一起使用。
网络插件
使用Docker安装第三方网络插件。
讨论容器网络方案时,我们可以只考虑bridge
和host
模式,其他网络模式基本不常用。
host
模式,屏蔽了容器与宿主机的网络隔离,可以直连主机,这没有问题。
所以,我们一般所说的网络问题,指的是网桥模式下的网络问题。
因此我们要问:docker
容器之间怎么访问呢?
其实,docker
给容器创建网络时,使用linux
网络虚拟技术,在主机和容器内分别创建一个虚拟接口veth pair
, 主机这端的veth
接口给了docker0
,另一端,则给容器,修改名称为eth0
。随后,从网桥可用地址段中,获取一个空闲地址分配给容器的eth0
, 并把docker0
设置为默认网关。
也就是,同一主机上的docker
容器docker0
作为docker通信间的连接,充当默认网关。不同主机上的容器通信,需要将主机上的docker0
打通即可,这个不是本篇的重点,粗略来说,需要配置docker0
启动时候的bip
,并在本机上添加对端静态路由地址和路由转发规则,并且双向配置。例如,主机6上添加route add -net 10.0.6.0/24 gw 192.168.88.6
以及iptables -t nat -I PREROUTING -s 10.0.5.0/24 -d 10.0.6.0/24 -j DNAT --to 10.0.5.1
。
那我们接下来说说标题上的问题:如何给正在运行的容器暴露服务端口?
前提
假设你的环境跟我一样已经运行了一个名叫nginx-test
的容器,只知道容器内部端口是80, 并没有暴露主机端口映射, 镜像模板是一个nginx
镜像。
我们一起看看有哪些解决方案。
ip直连模式
$ docker inspect nginx-test |jq ".[0].NetworkSettings.IPAddress""172.17.0.4"
已知容器上的端口80,获取到docker
分配的容器ip
,直接访问http://172.17.0.4:80
可以直接访问容器服务。
$ curl 172.17.0.4:80----<p><em>Thank you for using nginx.</em></p>----
在docker
里面很方便获取到容器名称的,在知道容器端口的时候,这种方法简单有效。
Commit
通过commit
我们可以重新构建一个镜像,用新镜像替换旧的镜像,运行一个暴露了端口的容器:
$ echo "some_text" > test.txt$ docker cp test.txt nginx-test:/home$ docker commit nginx-test nginx-test-commit-1$ docker stop nginx-test$ docker run --name nginx-test-commit-1 -p 8001:80 nginx-test-commit-1:latest$ curl localhost:8001----<p><em>Thank you for using nginx.</em></p>----
虽然这种方式也能达到我们的需求,但是破坏性太大,需要重建容器。
nginx 反向代理
我们知道通过反向代理能完成请求转发给上游服务器,同时通过docker link
可以将已有运行容器的网络链接到新的容器,于是我们可以用这种方式达到暴露容器端口的服务。这种方式还是比较适合容器编排的处理方式的。
$ lsdefault.conf run-docker.sh$ cat default.confserver {listen 80;location / {proxy_pass http://upstream:80;}}$ cat run-docker.sh#!/bin/bashlink=$1sed -i "s/upstream/$link/g" $(pwd)/default.confdocker run --name nignx-test -p 8002:80 -v $(pwd):/etc/nginx/conf.d --link=${link} nginx$ bash run-docker.sh nginx-test$ curl localhost:8002----<p><em>Thank you for using nginx.</em></p>----
其他方案
除了上述三种方案,还有诸如通过ssh
转发的,比较复杂,这里就不推荐了,感兴趣的童鞋可以自行探索。另外,值得一提的还有docker-proxy
,这个二进制命令完成了docker
容器ip
、端口到主机ip
、端口的转发,笔者尝试docker-proxy
手动构建转发规则时失败了,貌似这种方法不被docker
允许。借着这个思路,其实我们可以简单做一个iptables
的转发,也能实现我们的需求。
本章就这么多啦。
码字不易,如果本篇对你有所帮助,别忘了点个小星星!更多内容请关注公众号:玩转云原生!




