実行中の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へのマッピングを追加します。2つのセクションを変更する必要があることに注意してください。一方のセクションでは、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 をご覧ください。