為正在執行的 Docker 容器動態新增連接埠對應

為正在執行的 Docker 容器動態新增連接埠對應

連接埠對應是開發和部署容器化應用程式的重要環節。通常,我們在建立容器時,會建立容器內部連接埠與主機機器上的一個連接埠之間的連線。然而,有些情況我們可能需要為已執行的容器動態新增新的連接埠對應。這在開發、除錯或臨時開放新服務端點時特別有用。本文將詳細說明如何在不停止容器的情況下,動態為容器新增連接埠對應。

1. 背景知識

容器連接埠對應的基本原理

在 Docker 中,容器內部連接埠與主機機器連接埠的連線是透過連接埠對應實現的。通常我們在啟動容器時使用 -p--publish 參數指定連接埠對應,如下所示:

docker run -d -p 8080:80 nginx

上述指令將主機機器的 8080 連接埠對應到容器內的 80 連接埠。這樣外部使用者就可以透過主機的 8080 連接埠存取容器中執行的 Web 服務。

動態新增連接埠對應的挑戰

容器啟動後,Docker 通常不支援動態新增新的連接埠對應。也就是說,初始的連接埠對應在容器的整個生命週期中保持不變。如果需要新增更多連接埠對應,傳統方法是停止並重啟容器,這會中斷服務,在生產環境中是不可接受的。

2. 實作方案

有多種方法可以為正在執行的容器動態新增連接埠對應:

2.1 使用 docker network 建立代理容器

可以在與原始容器相同的網路中建立一個新的代理容器,並將新的連接埠對應新增到代理容器上。具體步驟如下:首先,在與原始容器相同的網路上建立一個代理容器:

docker run -d --name proxy-container --net container:your-container nginx

然後,將所需的連接埠對應新增到代理容器:

docker run -d -p 8081:81 --net container:your-container nginx

這種方法無需修改原始容器即可新增新的連接埠對應,但會引入額外的容器實例,且可能不適用於所有場景。

2.2 使用 iptables 手動新增連接埠轉發規則

透過修改 iptables,可以將主機機器特定連接埠的請求轉發到正在執行的 Docker 容器的內部連接埠。例如,要將主機的 8081 連接埠對應到容器中的 81 連接埠,可使用以下指令:

iptables -t nat -A DOCKER -p tcp --dport 8081 -j DNAT --to-destination <container_ip>:81

其中 <container_ip> 是容器的內部 IP 位址,可以使用 docker inspect 指令取得。此方法在新增連接埠對應方面非常靈活,但需要對 iptables 有充分了解,且由於其複雜性,不建議在生產環境中頻繁使用。

2.3 使用 socat 建立連接埠轉發

socat 是一個多功能網路工具,可以在主機和容器之間建立連接埠轉發。您可以執行以下指令,將主機上的特定連接埠轉發到容器中的指定連接埠:

socat TCP-LISTEN:8081,fork TCP:<container_ip>:81

此方法的優點是不需要停止容器。但由於 socat 是額外的進程,需要注意其效能和穩定性。其他連接埠轉發工具也能達到類似效果。

2.4 使用 Docker Compose 動態更新服務

如果您的應用程式使用 Docker Compose 管理容器,可以透過更新 docker-compose.yml 檔案,然後執行 docker-compose up 來新增新的連接埠對應。這個方法方便且統一管理,但每次更新都需要重新套用 Compose 檔案,可能會導致暫時性的服務中斷。

2.5 強制修改容器設定檔

首先,直接修改 /var/lib/docker/containers/<container_id>/config.v2.json 檔案,新增將 HostPort 8081 對應到容器 81 連接埠的設定。請注意需要修改兩個區塊。在一個區塊中,只需新增 HostPort 8081

    "ExposedPorts": {
      "8080/tcp": {}
      "8081/tcp": {}
    },

在另一個區塊中,需要新增完整的對應關係:

   "Ports": {
      "80/tcp": [
        {
          "HostIp": "0.0.0.0",
          "HostPort": "8080"
        },
      ],
      "81/tcp": [
        {
          "HostIp": "0.0.0.0",
          "HostPort": "8081"
        },
      ]
    },

此外,還需要修改 /var/lib/docker/containers/<container_id>/hostconfig.json,新增新的對應:

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

最後,需要重新啟動 dockerd:

sudo systemctl restart docker

這個方法可以永久性地為容器新增連接埠對應,但重新啟動 dockerd 會導致主機上的所有容器停止。如果容器沒有設定自動啟動,即使 dockerd 重新啟動,它們也不會自動啟動。雖然這個方法有效,但對執行中的容器影響較大,不建議在生產環境中使用。

3. 結論

雖然動態為容器新增連接埠對應並非 Docker 的原生功能,但上述方法可以在一定程度上幫助實現。每種方法都有其優缺點,開發者可以根據具體需求選擇最適合的方案。在生產環境中,建議使用代理容器或 Docker Compose,因為它們相對簡單且風險較低。對於需要頻繁變更連接埠對應的應用程式,建議在設計階段考慮靈活的網路架構,以避免在容器執行期間頻繁修改連接埠對應,從而減少服務中斷。

您可以造訪 Novita AI 了解更多!