如何为现有Docker容器分配端口映射?


436

我不确定在这里是否误解了一些东西,但是似乎只能通过从映像创建新容器来设置端口映射。是否可以将端口映射分配给现有Docker容器?


3
使用iptables可能会像这样回答:在Live Docker Container上暴露端口
Choldrim,2016年

2
我怀疑这是设计使然。Docker试图强迫您成为“可重复的”,而容器是一种“记录系统”。您做的任何不影响容器的操作都是很容易丢失的手动步骤。换句话说:您希望容器代表操作所必需的所有配置。因此,如果要打开新端口,则需要创建一个新容器。
Lance Kind

2
老问题,我没有回答,但我想说的是,也许您和其他人在质疑这个问题和答案时可能完全误解了docker的概念。Docker适用于无状态应用程序,可以扩展或缩减多次。对于永远无法重新创建的生产环境,您永远不应在容器内保留某些内容,如果需要保留,请映射目录。Docker不像“轻型虚拟机”,也许您正在寻找的是linuxcontainers.org,lxd基于docker概念,但牢记“轻型虚拟机”。
埃德加·卡瓦略

以防万一这可能会有所帮助,可以使用“ Kitematic”工具将端口映射添加到已经运行的容器中。这应该意味着必须有docker命令来执行完全相同的操作,但要进行少许搜索:)祝您好运
Yaffah

Answers:


298

您可以通过直接编辑 hostconfig.json文件 /var/lib/docker/containers/[hash_of_the_container]/hostconfig.json

您可以通过docker inspect <container_name>命令确定[hash_of_the_container] ,“ Id”字段的值为哈希。

1) stop the container 
2) stop docker service (per Tacsiazuma's comment)
3) change the file
4) restart your docker engine (to flush/clear config caches)
5) start the container

因此,您无需使用这种方法来创建图像。您也可以在此处更改重新启动标志。

PS:您可以访问https://docs.docker.com/engine/admin/,以了解如何根据主机正确重启Docker引擎。我曾经sudo systemctl restart docker重启过在Ubuntu 16.04上运行的Docker引擎


17
当docker停止时,它似乎会覆盖您的更改,因此2.停止docker,3.更改文件,4.启动
docker

5
我已经尝试了上面,它的工作原理。有关更多详细信息,请参见:mybrainimage.wordpress.com/2017/02/05/…–
rohitmohta

11
重要的是停止容器,停止docker引擎,并同时更改它们hostconfig.jsonconfig.v2.json使其工作。使用@rohitmohta提供的链接查看详细信息。
Kalpak Gadre '17

5
为我工作,如果在Mac上使用docker app只是一件事情,请按照此处的说明进入/ var / lib / docker / containers文件夹:stackoverflow.com/a/41226917/2048266,基本上运行screen ~/Library/Containers/com.docker.docker/Data/com.docker.driver.amd64-linux/tty一旦让tty运行,就可以导航到/ var / lib /
docker

14
对于Windows,是否可以与我分享conatiners文件夹的位置?
维杰

463

我对这个问题也很感兴趣。

@Thasmo所述,只能使用docker run(和docker create)命令指定端口转发。
其他命令docker start没有-p选项,docker port仅显示当前转发。

要添加端口转发,我总是遵循以下步骤,

  1. 停止运行容器

    docker stop test01
    
  2. 提交容器

    docker commit test01 test02
    

    注意:上面test02是我正在从test01容器中构造的新图像。

  3. 从提交的映像重新运行

    docker run -p 8080:8080 -td test02
    

其中第一个8080是本地端口,第二个8080是容器端口。


14
如果我想保留test01名称怎么办?
user69715

12
有人知道Docker是否存在开放的问题以允许使用端口规范(--publish)docker start
Elijah Lynn

8
在这种情况下,卷会发生什么?
安德鲁·萨维尼赫

78
这是一个糟糕的解决方案,我不知道它如何获得250票赞成票。也许那些被高估的人不知道该解决方案会造成什么样的混乱。是的,这太可怕了,它等同于启动一个在不同端口上运行的新容器。
Arrrr

25
@Arrrr也许您想留下一个更好的答案?我敢肯定,如果您告诉我们这样做的更好方法,我们将不胜感激。
crockeea '18 -10-9

40

如果通过“现有”来表示“正在运行”,那么(当前)无法添加端口映射。

但是,如果需要在不停止/重新启动服务的情况下将服务公开到正在运行的容器中,则可以使用Pipework动态添加新的网络接口。


4
这应该是最佳答案。简洁,它解决了OP的问题,其他任何人都没有! 有时结果是负面的!
局部多云,

19

不确定是否可以应用端口映射正在运行的容器。您可以在运行与创建新容器不同的容器时应用端口转发。

$ docker run -p <public_port>:<private_port> -d <image>  

将开始运行容器。本教程介绍了端口重定向。


2
是的,因此似乎只能在创建容器时设置端口映射之类的选项。
thasmo

20
仅供参考,这个答案并不完全正确。docker run创建并启动一个新的容器。等同于docker create接着执行docker start
Trevor Sullivan

19

现在编辑hostconfig.json似乎无法正常工作。它仅以暴露该端口而不发布给主机为结尾。对我来说,提交和重新创建容器不是最佳方法。没有人提到docker network吗?

最好的解决方案是在同一网络中使用反向代理

  1. 如果您以前的容器不在任何命名容器中,请创建一个新的网络。

    docker network create my_network

  2. 将现有容器加入创建的网络

    docker network connect my_network my_existing_container

  3. 启动反向代理服务(例如nginx),发布所需的端口,加入同一网络

    docker run -d --name nginx --network my_network -p 9000:9000 nginx

    (可选)在Nginx中删除default.conf

    docker exec nginx rm /etc/nginx/conf.d/default.conf

  4. 创建一个新的Nginx配置

    server
    {
        listen 9000;
    
        location / {
            proxy_pass http://my_existing_container:9000;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection 'upgrade';
            proxy_set_header Host $host;
            proxy_cache_bypass $http_upgrade;
        }
    }
    

    将配置复制到nginx容器。

    docker cp ./my_conf.conf nginx:/etc/nginx/conf.d/my_conf.conf

  5. 重新启动nginx

    docker restart nginx

优点:要发布新端口,您可以安全地停止/更新/重新创建nginx容器,而无需触摸业务容器。如果您需要nginx的停机时间为零,则可以添加更多反向代理服务加入同一网络。此外,一个容器可以加入多个网络。

编辑:

要反向代理非HTTP服务,配置文件会有所不同。这是一个简单的示例:

upstream my_service {
    server my_existing_container:9000;
}

server {
    listen 9000;
    proxy_pass my_service;
}

1
这是惊人的且实用的,但是对于企业系统而言,这种方法似乎令人困惑。让单个系统控制工作流程会更好。
阿夫申

1
@Afshin对于企业系统或项目而言,我认为此解决方案比重新创建(导致停机)或入侵hostconfig.json文件(至少未正式引入)要好。额外的容器只是公开您的业务容器的内部端口,而不是对其进行任何更改。
肖恩·

1
很棒的方法。我需要为容器配置不同的nginx才能在代理后面工作,但似乎是做事的正确方法。也适用于蓝绿色部署。
Brooks DuBois

17

在Fujimoto Youichi的示例中test01是一个容器,而test02一个图像。

在执行此操作之前,docker run您可以删除原始容器,然后再次为该容器分配相同的名称:

$ docker stop container01
$ docker commit container01 image01
$ docker rm container01
$ docker run -d -P --name container01 image01

-P用于将端口公开给随机端口,而不是手动分配)。


12
请注意。您将丢失所有数据,具体取决于内部应用程序。
巴里

14

如果运行docker run <NAME>,它将生成一个新图像,这很可能不是您想要的。

如果要更改当前图像,请执行以下操作:

docker ps -a

获取目标容器的ID,然后转到:

cd /var/lib/docker/containers/<conainerID><and then some:)>

停止容器:

docker stop <NAME>

变更档案

vi config.v2.json

"Config": {
    ....
    "ExposedPorts": {
        "80/tcp": {},
        "8888/tcp": {}
    },
    ....
},
"NetworkSettings": {
....
"Ports": {
     "80/tcp": [
         {
             "HostIp": "",
             "HostPort": "80"
         }
     ],

并更改文件

vi hostconfig.json

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

重新启动您的泊坞窗,它应该可以工作。


2
这在Docker 17.09.0-ce版本上对我不起作用。启动后,容器配置文件被覆盖回旧值。
thegeko '18

3
在主机系统@thegeko中重启docker服务
yurenchen 18-10-17

1
这可行!!1.停止容器,2。更改文件,3。重新启动docker,4。重新启动容器
daddinhquoc

12

如果您对Docker深度配置IPtable不满意,可以采取另一种解决方法。

iptables -t nat -A DOCKER -p tcp --dport ${YOURPORT} -j DNAT --to-destination ${CONTAINERIP}:${YOURPORT}

iptables -t nat -A POSTROUTING -j MASQUERADE -p tcp --source ${CONTAINERIP} --destination ${CONTAINERIP} --dport ${YOURPORT}

iptables -A DOCKER -j ACCEPT -p tcp --destination ${CONTAINERIP} --dport ${YOURPORT}

这只是一个技巧,不建议与我的方案配合使用,因为我无法停止容器,希望对您有所帮助。


这是一个很好的答案!谢谢!如果要映射DOCKER_PORTMACHINE_PORT,应该更改哪些部分?
CiprianTomoiagă

注意码头工人将不知道此手动添加。当您稍后在docker正确暴露端口的情况下重新启动服务时,不会删除SO条目。因此,当发生任何更改时,请务必非常仔细地检查iptables。特别是寻找重复的条目!
安东尼

8

我们使用诸如ssh之类的方便工具轻松完成此操作。

我正在使用ubuntu主机和基于ubuntu的docker映像。

  1. 在docker内部,已安装openssh-client。
  2. 外部docker(主机)安装了openssh-server服务器。

当需要映射新端口时,

在docker内部运行以下命令

ssh -R8888:localhost:8888 <username>@172.17.0.1

172.17.0.1是docker接口的ip(您可以通过ifconfig docker0 | grep "inet addr" | cut -f2 -d":" | cut -f1 -d" "在主机上运行来获取此地址 )。

在这里,我将本地8888端口映射回了主机8888。您可以根据需要更改端口。

如果还需要一个端口,则可以终止ssh并使用新端口向其添加-R一行。

我已经用netcat测试过了。


2
  1. 停止docker引擎和该容器。
  2. 转到/var/lib/docker/containers/${container_id}目录并编辑hostconfig.json
  3. 编辑PortBindings.HostPort您想要的更改。
  4. 启动Docker引擎和容器。

-1

对于Windows和Mac用户,还有另一种非常简单友好的方式来更改映射端口:

  1. 下载风筝

  2. 转到容器的设置页面,在“端口”选项卡上,可以直接在此处修改已发布的端口。

  3. 再次启动容器


2
我尝试过这种方法。实际上,Kinematic应用了端口映射。但是要应用它们,它从原始图像重新创建了我的容器。因此,如果您担心失去对容器本身所做的更改,请不要使用此方法。
VeganHunter

1
我更喜欢这样做,因为它没有回答问题,而是创建了一个新容器。但是,至少它可以正常工作,并且在搜索过程中会显示出这样的结果。+1
2b77bee6-5445-4c77-b1eb-4df3e5

-7

简短的答案:您不能将端口映射分配给现有的Docker容器

您需要一个新的容器...进行处理。


4
不需要态度。同样,这个答案完全没有细节。
lovefaithswing

1
无需细节。语调对于传达节省时间的答案和容器的短暂性质至关重要。
stephen

-11

如果只想更改正在运行的容器的端口,则可以执行以下操作:

  1. 停止现有容器

    sudo docker停止NAME

  2. 现在使用新的端口映射重新启动

    sudo docker run -d -p 81:80名称

如:

“ -d”到后台/守护docker

“ -p”启用端口映射

用于通过浏览器访问的“ 81”个外部(公开)端口

“ 80”内部Docker容器侦听端口


4
这是错误的。在docker run命令中,NAME是要从其运行容器的映像的名称,而在中docker stopNAME是指要停止的容器的名称。
jonatan '16

1
“ docker run”将创建一个新的容器。它不能使用与已停止的容器相同的容器名称,因为您只能使用一个具有该名称的容器。因此,您需要做的是:“ docker stop NAME”,docker容器rm NAME,然后编写时“ docker run -d -p 81:80 NAME”。
Lance Kind
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.