为正在运行中docker容器动态添加端口映射

为正在运行中docker容器动态添加端口映射

通常在docker run 时可能会忘记添加必要的端口映射,但是在运行成功后,想要添加新的端口映射。网上给出的方案基本都是要先stop容器再重新commit,这种方式非常麻烦,对于没有volume挂载的容器,容器内部运行时的数据可能会丢失。

查看docker容器的ip

[root@VM-4-7-centos ~]# docker ps
CONTAINER ID   IMAGE          COMMAND                  CREATED        STATUS        PORTS                                         NAMES
84a65294e130   mariadb:10.2   "docker-entrypoint.s…"   9 months ago   Up 3 months   0.0.0.0:28971->3306/tcp, :::28971->3306/tcp   trojan-mariadb
[root@VM-4-7-centos ~]# 
[root@VM-4-7-centos ~]# docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' trojan-mariadb
172.17.0.2
[root@VM-4-7-centos ~]# 

这里以一个只添加了3306数据库端口映射的容器为例,如果我们想添加别的端口映射,但是又不想stop容器,可以通过iptables的规则进行转发。

添加iptables nat转发规则

[root@VM-4-7-centos ~]# iptables -t nat -nvL DOCKER
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           
  392 22932 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:28971 to:172.17.0.2:3306

可以看到DOCKER链上有一条规则,是docker ps 命令可以看到的映射端口。

[root@VM-4-7-centos ~]# iptables -t nat -A DOCKER -p tcp --dport 9090 -j DNAT --to-destination 172.17.0.2:9090
[root@VM-4-7-centos ~]# iptables -t nat -nvL DOCKER
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           
  392 22932 DNAT       tcp  --  !docker0 *       0.0.0.0/0            0.0.0.0/0            tcp dpt:28971 to:172.17.0.2:3306
    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:9090 to:172.17.0.2:9090
[root@VM-4-7-centos ~]# 
[root@VM-4-7-centos ~]# netstat -antup | grep 9090
[root@VM-4-7-centos ~]#

注意:使用iptables添加的转发规则,用netstat是看不到监听端口。这就是为什么有些情况下,没有服务监听端口,但是请求端口又可以正常访问。

监听端口测试

注意这里如果请求127.0.0.1是收不到请求的,而是请求的当前网卡的地址,如果希望本地请求可以收到,还需再添加iptables规则,但是对于外部访问已经足够了。

# 处理本地127.0.0.1的访问(这是curl 127.0.0.1:9090失败的关键)
iptables -t nat -A OUTPUT -p tcp -d 127.0.0.1 --dport 9090 -j DNAT --to-destination 172.17.0.2:9090

# 3. 确保允许转发的流量
iptables -A FORWARD -p tcp -d 172.17.0.2 --dport 9090 -j ACCEPT

socat转发端口

这个是最简单的方案。iptables很多可能不理解命令的含义,但是socat的命令简单直接,还能看到监听的端口。

socat TCP-LISTEN:9090,fork,reuseaddr TCP:172.17.0.2:9090 &

赞赏

微信赞赏支付宝赞赏

Zgao

愿有一日,安全圈的师傅们都能用上Zgao写的工具。

发表评论