【问题标题】:How do I assign a port mapping to an existing Docker container?如何将端口映射分配给现有的 Docker 容器?
【发布时间】:2013-10-20 13:19:32
【问题描述】:

我不确定我是否在这里误解了某些内容,但似乎只能通过从图像创建新容器来设置端口映射。有没有办法将端口映射分配给现有的 Docker 容器?

【问题讨论】:

  • 使用 iptables 可能会像这个答案一样工作 Exposing a Port on a Live Docker Container
  • 我怀疑这是设计使然。 Docker 试图强迫你是“可重复的”,而容器是一种“记录系统”。您作为不影响容器的步骤所做的任何事情都将是一个容易丢失的手动步骤。换一种说法:您希望您的容器代表操作所需的所有配置。所以如果你想打开一个新的端口,那么你需要创建一个新的容器。
  • 老问题,我不回答了,但我想说,也许你和提出这个问题和答案的人可能完全误解了 docker 的概念。 Docker 用于无状态应用程序,可以多次扩展或缩减。对于无法重新创建的生产环境,您永远不应该在容器内保留某些内容,如果您需要保留,请映射目录。 Docker 不是一个“轻量级虚拟机”之类的东西,也许你正在寻找的是 linuxcontainers.org,lxd 是基于 docker 概念但考虑到了一个“轻量级虚拟机”。
  • 以防万一这可能会有所帮助,可以使用“Kitematic”工具将端口映射添加到已经运行的容器。这应该意味着必须有 docker 命令来做完全相同的事情,但需要一点谷歌搜索:) 祝你好运

标签: docker port lxc linux-containers


【解决方案1】:

在 Docker Desktop 上更改容器的 HostPort(在 Windows 10 / MacOS 上)

# list all containers
$ docker ps -a
$ docker stop docker101tutorial 
# Use grep to get id of container
$ docker inspect docker101tutorial | grep -i id
        "Id": "sha256:fff0a4b22d6f3d2eb8d2748b8a8bbc9967ea87199988acee8e86ac70bce9c3eb",
# run plain ubuntu docker image with shell and change it's namespace to docker host
# https://stackoverflow.com/questions/60408574/how-to-access-var-lib-docker-in-windows-10-docker-desktop/60411313#60411313
# https://forums.docker.com/t/the-location-of-images-in-docker-for-windows/19647/4
$ docker run -it --privileged --pid=host ubuntu nsenter -t 1 -m -u -i sh
# We want to find out the directory of docker101tutorial container. We are looking for:
# `"Image":"sha256:fff0a4b22d6f3d2eb8d2748b8a8bbc9967ea87199988acee8e86ac70bce9c3eb"`
# in /var/lib/docker/containers/*/config.v2.json
$ find /var/lib/docker/containers/ -name config.v2.json -exec grep -H fff0a4b22d {} \;
/var/lib/docker/containers/c1eda20b30f058bce9f8ece3b47a21641df5b399770e12ab57416a954d3c8bbf/config.v2.json
# edit it
$ vi /var/lib/docker/containers/c1eda20b30f058bce9f8ece3b47a21641df5b399770e12ab57416a954d3c8bbf/hostconfig.json
  • i 进入插入模式。
  • "HostPort":"80" 更改为"HostPort":"8092"
  • Escape 并写:wq。按Enter
  • 现在不要启动/停止docker101tutorial。否则对 HostPort 的更改将被还原。
  • 右键单击 Docker 桌面托盘图标,然后单击重新启动。
  • 在 Docker Desktop 的容器列表中,查看您的容器。显示的端口应更改为8092
  • 启动您的容器。现在它将映射到主机上的端口8092

基于@holdfenytolvaj 的回答。

【讨论】:

  • 这行得通,我试图在 WIndows 10 上创建一个 postgres 服务,我使用 -p port publish 创建了容器,但由于某种奇怪的原因,它没有发布端口 5432。这行得通。知道为什么会这样吗?仅供参考 - 在主机文件中,我将其添加到工作 "PortBindings":{"5432/tcp":[{"HostIp":"","HostPort":"5432"}]
  • 由于某种原因,最新 Ubuntu 上的 grep 无法识别 --include 选项,但可以使用 find 命令执行相同操作:find /var/lib/docker/containers/ -name config.v2.json -exec grep -H f7828c0aa {} \;
【解决方案2】:

如何将端口映射分配给现有的 Docker 容器?

这很简单。有两件事,一是您机器上的本地服务器端口,例如 800,8080 等,第二件事是您要映射的容器端口。 Docker Port mapping

 docker run -p 8080:8080 <Image ID> 

要获取图像 ID,您可以使用

docker ps

【讨论】:

    【解决方案3】:

    "docker run -p 8761:8761 --name ."

    【讨论】:

    • 他的意思是“现有的 Docker 容器”
    • 虽然此代码可以解决问题,including an explanation 说明如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的答案添加解释并说明适用的限制和假设。
    【解决方案4】:

    我正在开发一个 dockerizer go 包,用于在 docker 容器中部署批处理应用程序。我的包包含一个 MessageBroker 组件,该组件具有 3 个要发布的端口:jobAgentPort、backendPort、frontendPort。

    长话短说,我建议最好设计一个嵌入到服务器/代理/代理中的 endpointProvider 组件。

    也就是说,容器部署至少需要两步。

    1. endpointProvider组件由jobId或类似key创建并缓存在相关包中。
    2. 服务器/代理/代理内置在二进制文件中,您的代码在其中接受由 endpointProvider 输出的 endpointConfig 组件。

    例如 server/proxy/broker 构造函数有一个签名: NewMessageBroker(epc *EndpointConfig) *MessageBroker。然后,使用 docker-client api 创建容器映像,最后启动容器(docker run)并使用暴露端口值的 endpointConfig 发布端口。

    【讨论】:

    • 请了解如何正确格式化帖子。请检查如何在 SO 中使用 markdown 以获得正确的格式。
    • 如果你的意思是答案必须有代码解决方案,那我不同意。在这种情况下,正确的答案是正确的设计模式
    • 我有没有在任何地方说“使用代码”或“代码解决方案”?如果你仔细阅读,我建议你使用 Markdown 来Properly Format你的帖子。这是帮助您了解如何在 SO stackoverflow.com/editing-help 中使用降价的链接
    【解决方案5】:

    您可以通过直接编辑hostconfig.json 文件来更改端口映射: /var/lib/docker/containers/[hash_of_the_container]/hostconfig.json/var/snap/docker/common/var-lib-docker/containers/[hash_of_the_container]/hostconfig.json,我相信,如果你安装了 Docker 的话。

    您可以通过docker inspect &lt;container_name&gt; 命令确定[hash_of_the_container],“Id”字段的值就是哈希值。

    1. 停止容器 (docker stop &lt;container_name&gt;)。
    2. 停止 docker 服务(根据 Tacsiazuma 的评论)
    3. 更改文件。
    4. 重新启动 docker 引擎(以刷新/清除配置缓存)。
    5. 启动容器 (docker start &lt;container_name&gt;)。

    因此您不需要使用这种方法创建图像。您也可以在此处更改重启标志。

    附注您可以访问https://docs.docker.com/engine/admin/ 了解如何根据您的主机正确重启您的 docker 引擎。我使用sudo systemctl restart docker 重新启动在 Ubuntu 16.04 上运行的 docker 引擎

    【讨论】:

    • 当docker停止时,它似乎会覆盖你的更改,所以2.停止docker,3.更改文件,4.启动docker引擎
    • 我已经尝试了上述方法并且它有效。更多详情见:mybrainimage.wordpress.com/2017/02/05/…
    • 停止容器、停止 docker 引擎并更改 hostconfig.jsonconfig.v2.json 以使其正常工作很重要。使用@rohitmohta 提供的链接查看详细信息。
    • 对我有用,如果在 mac 上使用 docker 应用程序只有一件事,请按照此处的说明进入 /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
    • 对于windows,谁能分享一下conatiners文件夹的位置?
    【解决方案6】:

    如果您对 Docker 深度配置不满意,iptables 将是您的朋友。

    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_PORT映射到MACHINE_PORT,应该更改哪些部分?
    • 注意 docker 不会知道这个手动添加。当您稍后使用 docker 正确公开端口重新启动服务时,不会删除 SO 条目。所以当有任何变化时,一定要非常仔细地检查 iptables。尤其是寻找重复的条目!
    • 很好的答案。不要忘记对从本地网络访问 docker 的计算机的主机文件进行更改以获取所需的应用程序。
    【解决方案7】:

    我也对这个问题感兴趣。

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

    要添加端口转发,我总是遵循这些步骤,

    1. stop运行容器

      docker stop test01
      
    2. commit容器

      docker commit test01 test02
      

      注意:以上,test02 是我从 test01 容器构建的新图像。

    3. 从提交的图像中重新run

      docker run -p 8080:8080 -td test02
      

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

    【讨论】:

    • 如果我想保留 test01 名称怎么办?
    • 任何人都知道 Docker 是否存在允许使用docker start 进行端口规范(--publish)的未解决问题?
    • 在这种情况下卷会发生什么?
    • 这是一个糟糕的解决方案,我不知道它是如何获得 250 票的。也许那些被赞成的人不知道这个解决方案会造成什么样的混乱。是的,太可怕了,等于启动了一个新的容器在不同的端口上运行。
    • @Arrrr 也许您想留下更好的答案?如果您告诉我们更好的方法,我相信我们都会感激不尽。
    【解决方案8】:

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

    1. 下载风筝

    2. 进入容器的设置页面,在端口选项卡上,可以直接修改那里发布的端口。

    3. 再次启动容器

    【讨论】:

    • 我试过这种方法。运动学确实应用了端口映射。但是要应用它们,它会从原始图像重新创建我的容器。因此,如果您害怕丢失容器本身所做的更改,请不要使用此方法。
    • 我更喜欢这个,我知道它没有回答问题,它会创建一个新容器。但至少它有效,并且在我的搜索过程中出现了这个 SO 结果。 +1
    【解决方案9】:
    1. 停止 docker 引擎和该容器。
    2. 进入/var/lib/docker/containers/${container_id}目录并编辑hostconfig.json
    3. 编辑 PortBindings.HostPort 您想要更改。
    4. 启动 docker 引擎和容器。

    【讨论】:

      【解决方案10】:

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

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

      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"
               } 
           ]
       }
      

      重启你的docker,它应该可以工作了。

      【讨论】:

      • 这在 Docker 版本 17.09.0-ce 上对我不起作用。启动后,容器配置文件被覆盖回旧值。
      • 在主机系统@thegeko重启docker服务
      • 这行得通!谢谢! 1.stop container, 2.change files, 3.restart docker, 4.start back container
      • 非常适合我。感谢您直接查看文件示例。没有你我做不到。
      • WSL2 下 Windows 上的 Docker 文件位置:stackoverflow.com/questions/65546108/…
      【解决方案11】:

      我们使用 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 测试过了。

      【讨论】:

        【解决方案12】:

        编辑 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;
        }
        

        【讨论】:

        • 这很神奇,也很实用,但是对于企业系统来说,这种方法似乎很容易混淆。让单个系统控制工作流程会更好。
        • @Afshin 对于企业系统或项目,我认为这个解决方案比重新创建(导致停机时间)或破解 hostconfig.json 文件(至少没有正式引入)要好。额外的容器只是暴露业务容器的内部端口,而不是对其进行任何更改。
        • 很棒的方法。我需要以不同的方式配置 nginx 以使我的容器在代理后面工作,但似乎是正确的做事方式。也适用于蓝绿部署。
        • 不错的方法!我认为使用像socat 这样的 TCP 代理可能会更容易。
        【解决方案13】:

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

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

        将开始运行容器。 This tutorial 解释端口重定向。

        【讨论】:

        • 是的,所以似乎只能在容器创建时设置端口映射等选项。
        • 仅供参考,这个答案并不完全正确。 docker run 创建并启动一个新容器。相当于在docker create 后面跟着docker start
        【解决方案14】:

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

        在做docker run之前你可以删除原来的容器,然后再给容器赋予相同的名字:

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

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

        【讨论】:

        • 请注意。您将丢失所有数据,具体取决于内部的应用程序。
        • @Barry - 在什么情况下?这会将容器提交到图像,这会将容器中的所有数据保存到图像中。原始容器使用的任何卷或挂载当然仍然存在,因为它们与容器和图像是分开的。所以我不关注。
        • 我试过这个。它成功删除了我的所有数据库:/
        • 数据可以存储在一个卷上。在删除之前尝试检查容器中的卷docker inspect container01,保留卷名并在运行新容器时挂载它
        【解决方案15】:

        如果“现有”是指“正在运行”,那么(当前)不可能添加端口映射。

        但是,您可以动态添加新的网络接口,例如Pipework,如果您需要在运行的容器中公开服务而不停止/重新启动它。

        【讨论】:

        • 这应该是最佳答案。简洁,它解决了 OP 的问题,其他人都没有! 有时否定结果就是结果!
        猜你喜欢
        • 2019-11-17
        • 1970-01-01
        • 2014-09-01
        • 2014-09-22
        • 2020-07-23
        • 2019-08-28
        • 2020-02-29
        • 2016-10-12
        相关资源
        最近更新 更多