ztf.net.cn
七牛云
您当前的位置: 首页 >  个人博客

docker容器添加对外映射端口的四种方式

在docker容器创建之后,想要增加端口映射,一般来说都是将原有的容器导出为镜像,然后删除原有容器,在重新创建的时候增加端口映射,但是这样操作起来太过于麻烦了。还有一种方式就是修改容器的配置文件,而不希望重新开启一个新的docker,这里小编为大家收集了四种方式, 小编推荐第二种方式,失败后可尝试其他方案。


一般在运行容器时,我们都会通过参数 -p(使用大写的-P参数则会随机选择宿主机的一个端口进行映射)来指定宿主机和容器端口的映射,例如

docker run -it -d --name [container-name] -p 8088:80 [image-name]

这里是将容器内的80端口映射到宿主机的8088端口

参数说明

-d 表示后台运行容器

-t 为docker分配一个伪终端并绑定到容器的标准输入上

-i 是让容器的标准输入保持打开状态

-p 指定映射端口

在运行容器时指定映射端口运行后,如果想要添加新的端口映射,可以使用以下方式:

1、将现有的容器打包成镜像

然后在使用新的镜像运行容器时重新指定要映射的端口

先停止现有容器

docker stop container-name

将容器commit成为一个镜像

docker commit container-name new-image-name

用新镜像运行容器

docker run -it -d --name container-name -p p1:p1 -p p2:p2 new-image-name

2、修改容器的配置文件,动态添加端口映射

查看容器信息

docker ps -a

查看容器的端口映射情况,在容器外执行:

docker port 容器ID 或者 docker port 容器名称

查找要修改容器的容器Id

docker inspect f244 |grep Id

进到/var/lib/docker/containers 目录下找到与 Id 相同的目录,修改 hostconfig.json 和 config.v2.json文件

若该容器还在运行,先停掉

docker stop 容器ID

停掉docker服务

systemctl stop docker

修改hostconfig.json如下,添加端口绑定"9003/tcp": [{"HostIp": "","HostPort": "9003"}],表示绑定端口9003

修改config.v2.json在ExposedPorts中加上要暴露的端口,即9003

改完之后保存,重启docker之后可以再次查看添加的端口是否已映射绑定上

systemctl start docker

Mac修改配置文件


参考地址1 参考地址2

1、查看container id

不管是使用docker psdocker ps -adocker inspect containerName哪种方式先获得容器的id
这里我使用inspect

docker inspect mnginx | grep Id

返回的信息如下:

"Id": "27b898aa3e89054dfa5b8c898b01f48b5bb9d59316b8dcb315b63708a702dc9a",

2、进入配置文件

Mac下Docker容器的配置文件在~/Library/Containers/com.docker.docker目录

cd ~/Library/Containers/com.docker.docker

需要修改的文件在Data/vms/0下

cd Data/vms/0

3、进入screen

在~/Library/Containers/com.docker.docker/Data/vms/0目录下有一个tty文件,在终端键入screen tty进行登录,此时会进入一个screen空白窗口,回车即可

docker-desktop:~#

注:如果出现screen is terminating这个提示,请使用第4个方法【nsenter方法

4、在screen窗口中进入容器对应文件夹

进入/var/lib/docker/containers目录下对应容器目录, 进入后看下文件夹下的内容

cd /var/lib/docker/containers/{cantainer_id: 上面找到容器ID}

27b898aa3e89054dfa5b8c898b01f48b5bb9d59316b8dcb315b63708a702dc9a-json.log
checkpoints
config.v2.json
hostconfig.json
hostname
hosts
mounts
resolv.conf
resolv.conf.hash

5、 修改文件内容

接着修改config.v2.json和hostconfig.json文件对应的端口映射部分

⑴ 修改config.v2.json

通过vi找到要修改的关键字ExposedPorts
原先的内容如下:

"ExposedPorts":{"80/tcp":{}}

那我们要增加暴露的7890端口,那么就是配置如下:

"ExposedPorts":{"80/tcp":{},"7890/tcp":{}}

修改完之后保存该文件

⑵ 修改hostconfig.json

通过vi找到要修改的关键字PortBindings
原先的内容为

"PortBindings":{"80/tcp":[{"HostIp":"","HostPort":"8080"}]}

那我们要增加7890端口映射到主机的7890端口,那么配置如下:

"PortBindings":{"80/tcp":[{"HostIp":"","HostPort":"8080"}],"7890/tcp":[{"HostIp":"","HostPort":"7890"}]}

修改完之后保存该文件

⑥ 退出screen,重启Docker

建议在此步骤之前再检查一遍步骤 ⑤ 中的两文件配置
输入ctrl+a+c(先按ctrl,再按a,然后按c即可)

3、Iptables 添加端口映射

原文地址:https://www.jb51.net/article/142462.htm

创建两个容器并进行了端口映射,结果如图所示:

假如,我start一个容器,其内部IP为172.17.0.5,并在容器内部启动了80端口。

FORWARD规则链我们不用管它,docker已经帮我们写好了,我们只需要关心NAT中的几条链即可。

查看NAT表中的PREROUTING链

从上面可以看出,iptables将满足条件的数据都转发到了DOCKER链上去了。

查看NAT表中的DOCKER链

仿照上图,我们添加一条自己的映射规则,将宿主的8082端口映射到172.17.0.5的80端口上去,规则如下:

iptables -t nat -A DOCKER ! -i docker0 -p tcp -m tcp --dport 8082 -j DNAT --to-destination 172.17.0.5:80

查看NAT表中的POSTROUTING链

仿照上图中的规则,书写的规则如下:

iptables -t nat -A POSTROUTING -s 172.17.0.5/32 -d 172.17.0.5/32 -p tcp -m tcp --dport 80 -j MASQUERADE

查看FILTER表中的DOCKER链

仿照上图书写规则如下:

iptables -t filter -A DOCKER -d 172.17.0.5/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 80 -j ACCEPT

结果

虽然IP为172.17.0.5的容器没有开启端口映射,如下图所示:

但我们依然能够通过访问宿主机(192.168.78.238)的8082端口来访问172.17.0.5的80端口,效果如下:

使用此方法有一个缺点,不能访问localhost:8082,也就是说如果想对localhost也进行转发,需要进行额外的配置。

4、使用nsenter容器


a、运行容器,指定容器运行在pid=host命名空间下,然后该容器运行nsenter命令

docker run -it --rm --privileged --pid=host alpine:edge nsenter -t 1 -m -u -n -i sh

如果说觉得5.56MB的Alpine Linux镜像太大了,那么可以选择下载这个镜像walkerlee/nsenter镜像有583KB。

docker run --rm -it --privileged --pid=host walkerlee/nsenter -t 1 -m -u -i -n sh

justincormack/nsenter1镜像更小,只有101KB。

docker run -it --rm --privileged --pid=host justincormack/nsenter1

b、执行如下命令可以看到对应的容器ID

cd /var/lib/docker/containers

c、接下来修改配置文件就好,可以参考方法二【修改容器的配置文件,动态添加端口映射】


扩展知识


详细解释一下这条命令为什么就会登录进macOS中作为宿主机的VM里面。

docker run -it --rm --privileged --pid=host alpine:edge nsenter -t 1 -m -u -n -i sh


  • –rm表示在退出的时候就自动删除该容器;
  • –privileged表示允许该容器访问宿主机(也就是我们想要登录的VM)中的各种设备;
  • –pid=host表示允许容器共享宿主机的进程命名空间(namespace),或者通俗点儿解释就是允许容器看到宿主机中的各种进程;


这些是docker在启动容器时候的参数设置,但是仅仅依靠这些参数还无法让我们直接登录到宿主机VM中,接下来解释最主要的nsenter命令。

nsenter允许我们进入一个指定的namespace然后运行指定的命令,ns=namespace,enter=进入。

namespace是容器技术的根基,基本上可以认为namespace就是一组隔离的资源,不同的进程可以看到不同的系统资源这里这里有比较详细的关于namespace的介绍。

最后解释一下nsenter命令的选项。回顾一下命令是:nsenter -t 1 -m -u -n -i sh
-t 1: 表示要进入哪个pid,1表示整个操作系统的主进程id
-m: 进入mount namespace,挂载点
-u: 进入UTS namespace,也就是上面我们演示的那个namespace
-n: 进入network namespace,网络
-i: 进入IPC namespace,进程间通信
sh: 表示运行/bin/sh




相关链接

动态添加端口:https://www.jianshu.com/p/6aefed2be1c7

HOW TO LOGIN THE VM OF DOCKER DESKTOP FOR MAC

https://www.dbform.com/2019/07/08/how-to-login-the-vm-of-docker-desktop-for-mac/


ZTF

ZTF|时间:2022-10-09

如果缘分安排我们相遇,请不要让她擦肩而过。扫一扫二维码,加我为好友吧!
标签云