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

tha*_*smo 373 port lxc docker linux-containers

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

小智 427

我也对这个问题感兴趣.

正如@Thasmo所提到的,只能通过docker run命令指定端口转发.
其他命令docker start没有-p选项,docker port只显示当前转发.

要添加端口转发,我始终按照以下步骤操作:

  1. 停止运行容器

    docker stop test01
    
    Run Code Online (Sandbox Code Playgroud)
  2. 提交容器

    docker commit test01 test02
    
    Run Code Online (Sandbox Code Playgroud)

    注意:上面test02是我从test01容器构建的新图像.

  3. 从提交的图像中重新开始

    docker run -p 8080:8080 -td test02
    
    Run Code Online (Sandbox Code Playgroud)

第一个8080是本地端口,第二个8080是集装箱端口.

  • 这是一个可怕的解决方案,我不知道它如何设法获得250个赞成票.也许那些投票的人不知道这个解决方案会造成什么样的混乱.是的,这很糟糕,它等于启动在不同端口上运行的新容器. (67认同)
  • @Arrrr也许您想留下更好的答案?如果你告诉我们更好的方法,我相信我们都会感激不尽. (17认同)
  • 如果我想保留test01名称该怎么办? (11认同)
  • 任何人都知道Docker是否存在一个开放的问题,允许使用`docker start`进行端口规范(--publish)? (11认同)
  • 在这种情况下,卷会发生什么? (6认同)
  • @Arrrr当您有一个沉重的容器需要很长时间才能进入该状态,然后您意识到需要打开一些端口时,此答案很有用。 (5认同)
  • @ user69715 - 如Luca的回答 - http://stackoverflow.com/a/36189165/33204所述,您可以通过创建容器的图像,删除当前容器,`test01`来保留容器的现有容器,然后重新创建它使用以前保存的图像. (3认同)
  • @AndrewSavinykh卷不会被转移到新容器.但是,您可以手动链接它们:`docker inspect test01`并搜索mounts部分,您将在其中找到已安装的卷.然后,您可以将它们安装在运行命令中:`docker run -p 8080:8080 -v 401959be5b03e750500a543e858dc021a5b98c96d10c7c595e4b100edca513d0:/ data/db -td test02` (3认同)
  • @Arrrr-这的确不是一般的“最佳实践”。作为战术上的工作,对于Windows上具有冲突端口的持久性Linux容器(这就是我正在使用的容器),这几乎是推进我的工作的唯一方法。 (2认同)
  • 这不是解决方案。您将丢失容器中的内容。 (2认同)
  • @user3335999 怎么样? (2认同)

hol*_*vaj 254

您可以通过直接编辑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
Run Code Online (Sandbox Code Playgroud)

因此,您无需使用此方法创建图像.您也可以在此处更改重启标志.

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

  • 当docker停止时,它似乎会覆盖您的更改,因此2.停止docker,3.更改文件,4.启动docker引擎 (13认同)
  • 停止容器,停止docker引擎并更改`hostconfig.json`和`config.v2.json`以使其工作非常重要.使用@rohitmohta提供的链接查看详细信息. (8认同)
  • 完美......没有必要用这种方法创建图像 (4认同)
  • 我已经尝试了上述并且它有效.有关详细信息,请参阅:https://mybrainimage.wordpress.com/2017/02/05/docker-change-port-mapping-for-an-existing-container/ (4认同)
  • 为我工作,如果在Mac上使用docker app只是一件事情,请按照此处的说明进入/ var / lib / docker / containers文件夹:/sf/answers/2885884221/,基本上运行`screen〜/ Library / Containers / com.docker.docker / Data / com.docker.driver.amd64-linux / tty`一旦运行了tty,就可以导航到/ var / lib / docker (4认同)
  • Docker Desktop 不再有这些配置文件。 (4认同)
  • @Vijay,WSL2 下 Windows 上的 docker 文件位置:/sf/ask/4588227591/ (4认同)
  • 我认为答案缺少端口转发的语法,在 hostconfig.json 添加配置如下`"PortBindings": {"3306/tcp": [{"HostIp": "","HostPort": "3306"} ]},` (4认同)
  • 这应该是公认的答案。该死的,所以docker正在缓存配置并通过该缓存覆盖它。 (3认同)
  • 对于Windows,可以让我分享conatiners文件夹的位置吗? (3认同)
  • 重要的是要记住在更改 hostconfig.json 文件后使用 (service docker restart) 重新启动 docker 引擎,否则该文件将恢复。 (2认同)
  • 如果端口未从计算机导出,您还必须将其添加到 `config.v2.json` 文件中,语法类似于 `"ExposedPorts":{"8080/tcp":{}}`,通常在 `附加错误` (2认同)

jpe*_*zzo 30

如果"现有"是指"正在运行",那么(目前)不可能添加端口映射.

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

  • 这应该是最佳答案。简洁,它解决了 OP 的问题,而其他人都没有!_有时消极的结果就是结果!_ (7认同)

raj*_*kan 17

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

$ docker run -p <public_port>:<private_port> -d <image>  
Run Code Online (Sandbox Code Playgroud)

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

  • 仅供参考,这个答案并不完全正确.`docker run`创建并启动一个新容器.它等同于`docker create`后跟`docker start`. (14认同)
  • 是的,所以似乎只能在容器创建时设置端口映射等选项. (2认同)

小智 16

在Fujimoto Youichi的例子test01是一个容器,而是test02一个图像.

在此之前,docker run您可以删除原始容器,然后再次为容器指定相同的名称:

$ docker stop container01
$ docker commit container01 image01
$ docker rm container01
$ docker run -d -P --name container01 image01
Run Code Online (Sandbox Code Playgroud)

(-P用于将端口暴露给随机端口而不是手动分配).

  • 请注意.您将丢失所有数据,具体取决于内部的应用程序. (8认同)
  • @Barry - 在什么情况下?这会将容器提交到映像,从而将容器中的所有数据保存到映像中。当然,原始容器使用的任何卷或安装仍然会在那里,因为它们与容器和映像是分开的。所以我不跟。 (2认同)
  • 我试过这个。它成功删除了我的所有数据库:/ (2认同)
  • 数据可以存储在卷上。在删除之前尝试检查容器中的卷“docker检查container01”,保留卷名称并在运行新容器时挂载它 (2认同)

Sea*_* C. 11

编辑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;
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    将配置复制到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;
}
Run Code Online (Sandbox Code Playgroud)

  • 好方法!我认为使用像“socat”这样的 TCP 代理可能会更容易。 (2认同)

小智 10

If you run docker run <NAME> it will spawn a new image, which most likely isn't what you want.

If you want to change a current image do the following:

docker ps -a

Take the id of your target container and go to:

cd /var/lib/docker/containers/<conainerID><and then some:)>
Run Code Online (Sandbox Code Playgroud)

Stop the container:

docker stop <NAME>
Run Code Online (Sandbox Code Playgroud)

Change the files

vi config.v2.json

"Config": {
    ....
    "ExposedPorts": {
        "80/tcp": {},
        "8888/tcp": {}
    },
    ....
},
"NetworkSettings": {
....
"Ports": {
     "80/tcp": [
         {
             "HostIp": "",
             "HostPort": "80"
         }
     ],
Run Code Online (Sandbox Code Playgroud)

And change file

vi hostconfig.json

"PortBindings": {
     "80/tcp": [
         {
             "HostIp": "",
             "HostPort": "80"
         }
     ],
     "8888/tcp": [
         {
             "HostIp": "",
             "HostPort": "8888"
         } 
     ]
 }
Run Code Online (Sandbox Code Playgroud)

Restart your docker and it should work.

  • 这有效!谢了!1.停止容器,2.更改文件,3.重新启动docker,4.重新启动容器 (5认同)
  • 在主机系统@thegeko中重启docker服务 (3认同)
  • 这在Docker 17.09.0-ce版本上对我不起作用。启动后,容器配置文件被覆盖回旧值。 (2认同)

rof*_*rol 10

在 Docker 桌面上更改容器的 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
Run Code Online (Sandbox Code Playgroud)
  • i进入插入模式。
  • 更改"HostPort":"80""HostPort":"8092"
  • 按下Escape并书写:wq。按Enter
  • 现在不要开始/停止docker101tutorial。否则HostPort将恢复对 的更改。
  • 右键单击 Docker 桌面托盘图标,然后单击重新启动。
  • 在 Docker Desktop 的容器列表中,查看您的容器。显示的端口应更改为8092
  • 启动你的容器。现在它将被映射到8092主机上的端口。

基于@holdfenytolvaj 的回答。


Man*_*Ali 9

如果您对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}
Run Code Online (Sandbox Code Playgroud)

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


小智 7

手写法

如果有人使用 portainer,我发现这个解决方案是“Gui 友好且安全的”

  1. 转到 Portainer 中的容器
  2. 停止容器
  3. 选择“复制/编辑”在此输入图像描述
  4. 添加所需的端口并部署。
  5. 当询问是否替换或取消时,选择替换。项目清单
  6. 享受生活


mel*_*chi 6

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

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

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

当需要映射新端口时,

在docker内部运行以下命令

ssh -R8888:localhost:8888 <username>@172.17.0.1
Run Code Online (Sandbox Code Playgroud)

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

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

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

我已经用netcat测试过了。


小智 6

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


归档时间:

查看次数:

344485 次

最近记录:

5 年,10 月 前