The result of tag: (1 results)

Docker动态映射运行Container的端口

by LauCyun Dec 15,2016 23:09:53 17,068 views

Docker自带了EXPOSE命令,可以通过编写dockerfile-p参数方便的映射container内部端口,但是对于已经运行的container,如果你想对外开放一个新的端口,只能编辑dockerfile然后重新build,有点不太方便。

其实Docker本身使用了iptables来做端口映射的,所以我们可以通过一些简单的操作来实现动态映射运行中的container端口。

通过运行iptables命令可以看到具体的端口映射:

root@localhost:/home/ubuntu# iptables -nxvL
...
Chain DOCKER (1 references)
    pkts      bytes target     prot opt in     out     source               destination         
...

root@localhost:/home/ubuntu# iptables -t nat -nxvL
...
Chain POSTROUTING (policy ACCEPT 30 packets, 1756 bytes)
    pkts      bytes target     prot opt in     out     source               destination         
     557    33795 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0           

Chain DOCKER (2 references)
    pkts      bytes target     prot opt in     out     source               destination         
       0        0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0           

我们要做的就是根据自己container的情况配置iptables规则。

  • 首先是filter这个表,我们要配置其放通转发,Docker默认已经将所有的FORWARD规则放到了DOCKER这个chain中了,这样方便配置,也方便查看。
  • 然后再配置nat表为其配置DNAT,这个才是端口转发的核心配置。这个表中只需要配置POSTROUTINGDOCKER链即可,这里不讲为什么这么配置,如果想要深入了解iptables请google一下。

下面举个例子:

假如我有一个container名为ngrok-server(通过运行docker ps命令即可查询),现在我在docker内部运行ngrok-server程序,监听了41575端口(转发了本地192.168.100.106的22端口),我希望外网可以通过22222端口访问:

1. 找到docker为ngrok-server分配的IP:

root@localhost:/home/ubuntu# docker inspect -f '{{.NetworkSettings.IPAddress}}' ngrok-server
172.17.0.3

2. 配置iptablesfilter表的FORWARD(DOCKER)链:

root@localhost:/home/ubuntu# iptables -A DOCKER -p tcp -d 172.17.0.3 --dport 41575 -j ACCEPT

3. 配置iptablesnat表的PREROUTING(DOCKER)POSTROUTING链:

root@localhost:/home/ubuntu# iptables -t nat -A POSTROUTING -p tcp -s 172.17.0.3 -d 172.17.0.3 --dport 41575 -j MASQUERADE
root@localhost:/home/ubuntu# iptables -t nat -A DOCKER -p tcp --dport 2222 -j DNAT --to-destination 172.17.0.3:41575

4.  验证一下,如图:

OK,连接成功了!

5. 最后iptables规则:

root@localhost:/home/ubuntu# iptables -nxvL
...
Chain DOCKER (1 references)
    pkts      bytes target     prot opt in     out     source               destination         
       4      240 ACCEPT     tcp  --  *      *       0.0.0.0/0            172.17.0.3           tcp dpt:41575
...

root@localhost:/home/ubuntu# iptables -t nat -nxvL
...
Chain POSTROUTING (policy ACCEPT 30 packets, 1756 bytes)
    pkts      bytes target     prot opt in     out     source               destination         
     557    33795 MASQUERADE  all  --  *      !docker0  172.17.0.0/16        0.0.0.0/0           
       0        0 MASQUERADE  tcp  --  *      *       172.17.0.3           172.17.0.3           tcp dpt:41575

Chain DOCKER (2 references)
    pkts      bytes target     prot opt in     out     source               destination         
       0        0 RETURN     all  --  docker0 *       0.0.0.0/0            0.0.0.0/0           
       4      240 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22222 to:172.17.0.3:41575

当然,使用手动配置也是比较麻烦的,所以我写了一个脚本来自动配置端口映射,使用方法脚本中有说明:

#!/bin/sh

# ./docker_expose.sh -I -hport 22222 -cip 172.17.0.3 -cport 41575
# ./docker_expose.sh -D -hport 22222 -cip 172.17.0.3 -cport 41575

INSERT_FLAG=false
DELETE_FLAG=false
HOST_PORT=''
CONTAINER_IP=''
CONTAINER_PORT=''

while [ $# -gt 0 ]
do
    case "$1" in
    (-I) INSERT_FLAG=true;;
    (-D) DELETE_FLAG=true;;
    (-hport) HOST_PORT="$2"; shift;;
    (-cip) CONTAINER_IP="$2"; shift;;
    (-cport) CONTAINER_PORT="$2"; shift;;
    (--) shift; break;;
    (-*) echo "$0: error - unrecognized option $1" 1>&2; exit 1;;
    (*)  break;;
    esac
    shift
done

echo "$HOST_PORT -> $CONTAINER_IP:$CONTAINER_PORT"

if [ $INSERT_FLAG = true ]; then
    iptables -t nat -A DOCKER -p tcp --dport $HOST_PORT -j DNAT --to-destination $CONTAINER_IP:$CONTAINER_PORT
    iptables -t nat -A POSTROUTING -p tcp -s $CONTAINER_IP -d $CONTAINER_IP --dport $CONTAINER_PORT -j MASQUERADE
    iptables -A DOCKER -p tcp -d $CONTAINER_IP --dport $CONTAINER_PORT -j ACCEPT
fi
if [ $DELETE_FLAG = true ]; then
    iptables -t nat -D DOCKER -p tcp --dport $HOST_PORT -j DNAT --to-destination $CONTAINER_IP:$CONTAINER_PORT
    iptables -t nat -D POSTROUTING -p tcp -s $CONTAINER_IP -d $CONTAINER_IP --dport $CONTAINER_PORT -j MASQUERADE
    iptables -D DOCKER -p tcp -d $CONTAINER_IP --dport $CONTAINER_PORT -j ACCEPT
fi

iptables -t nat -nvxL
iptables -nvxL

网上我看一下更加全面的脚本:http://yaxin-cn.github.io/Docker/expose-port-of-running-docker-container.html

...

Tags Read More