方言を話すおしゃべり猫型ロボット『ミーア』をリリースしました(こちらをクリック)

【Docker】コンテナ間通信を理解する。external設定とアクセス方法

この記事は約8分で読めます。

はじめに

異なる二つのサービス(例えば、サービスAとサービスB)でそれぞれdocker-compose.ymlファイルがあり、それぞれのサービスでappdbがあるシナリオについて説明する。

ここでの目標は、サービスAのappがサービスBのdbにアクセスできるようにすること。この例では、両方のサービスがmy-custom-networkという共通のネットワークを使用することを想定している。

既存のDockerネットワークの作成

まず、手動で既存のDockerネットワークを作成する必要がある。以下のコマンドをターミナルで使用して、my-custom-networkという名前のネットワークを作成する。

ShellScript
docker network create my-custom-network

このネットワークは、異なるdocker-compose.ymlファイル間で共有されることを意図している。

docker-compose.ymlファイルを使用してサービスを立ち上げる前に、ターミナルで個別に実行する必要がある。これにより、異なるdocker-compose.ymlファイルから起動されるコンテナが同じネットワーク内で互いに通信できるようになる。

docker-compose.ymlでのexternal: true設定の利用

次に、external: true設定を含むdocker-compose.ymlファイルを作成する。

この設定は、サービスが既に作成されたmy-custom-networkに接続するために使用される。

分かりやすさのために、今回サービスAはデータベースとしてmysql(デフォルトポート3306):サービスBはデータベースとしてPostgreSQL(デフォルトポート5432)を使用するものとする。

サービスAのdocker-compose.yml

YAML
version: '3'
services:
  app-a:
    container_name: app_a_container
    image: app-a:latest
    ports:
      - "8000:8000"
  db-a:
    container_name: db_a_container
    image: mysql:8.0
    environment:
			MYSQL_DATABASE: db_a_database
      MYSQL_ROOT_PASSWORD: password
    ports:
      - "33060:3306"

networks:
  my-custom-net:
    external: true
    name: my-custom-network

サービスBのdocker-compose.yml

YAML
version: '3'
services:
  app-b:
    container_name: app_b_container
    image: app-b:latest
    ports:
      - "8100:8100"
  db-b:
    container_name: db_b_container
    image: postgres:latest
    environment:
      POSTGRES_DB: db_b_database
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
    ports:
      - "54320:5432"

networks:
  my-custom-net:
    external: true
    name: my-custom-network

docker psの出力状態の例

ShellScript
CONTAINER ID   IMAGE            COMMAND                  CREATED         STATUS         PORTS                               NAMES
<id>           app-a:latest     "docker-entrypoint..."   12 seconds ago  Up 11 seconds  0.0.0.0:8000->8000/tcp              app_a_container
<id>           mysql:8.0        "docker-entrypoint..."   13 seconds ago  Up 12 seconds  0.0.0.0:33060->3306/tcp             db_a_container
<id>           app-b:latest     "docker-entrypoint..."   10 seconds ago  Up 9 seconds   0.0.0.0:8100->8100/tcp              app_b_container
<id>           postgres:latest  "docker-entrypoint..."   11 seconds ago  Up 10 seconds  0.0.0.0:54320->5432/tcp             db_b_container

アプリケーションにアクセスするURL

  • サービスAのアプリケーション: http://localhost:8000
  • サービスBのアプリケーション: http://localhost:8100

これらのURLは、docker-compose.ymlファイルで指定されたポートマッピングに基づいている。ホストマシンのポート(左側)がコンテナ内のポート(右側)にフォワードされている。

Dockerポートマッピングに関しては、以前こちらの記事で記載。

サービスAからサービスBのデータベースへアクセスするには?

サービスAのアプリケーションからサービスBのpostgreSQLデータベースに接続するには、以下の接続情報を使用する

  • ホスト名: db_b_container (サービスBのデータベースコンテナ名)
  • ポート番号: 5432 (サービスBがリッスンしている内部ポート:postgreSQLのデフォルトポート)
  • データベース名: db_b_database
  • ユーザー名: user (または環境変数で設定されたpostgreSQLのユーザー名)
  • パスワード: password (環境変数で設定されたパスワード)

コンテナ間での通信には、外部ネットワークmy-custom-networkを介しているため、db_b_containerの名前を直接ホスト名として使用できる。そして、コンテナ間通信ではホストのポートマッピングは関係なく、内部ポートを直接使用する。

データベースの接続情報は次のようになる

ShellScript
DATABASE_URL = "postgresql://user:password@db_b_container:5432/db_b_database"

Dockerコンテナ内でのlocalhostの挙動

ちなみにここで、DATABASE_URL=postgresql://root:password@localhost:5432/db_b_databaseと設定してもサービスBのデータベースには接続できない。

Dockerコンテナを使用してアプリケーション(サービスA)とデータベース(サービスB)が実行されている状況では、localhostはその特定のコンテナ内部のループバックアドレス(つまり、そのコンテナ自体)を指す。

サービスAのアプリケーションがDockerコンテナ内で実行されているときにlocalhostを使って何かに接続しようとすると、それはサービスAのアプリケーションが動作しているその同じコンテナ内部に接続しようとするので、サービスBはもちろんのこと、サービスAのデータベースにも接続できない。

サービスBからサービスAのデータベースへの接続

サービスBのアプリケーションからサービスAのMySQLデータベースに接続する場合も、同様にサービスAのデータベースコンテナ名(db_a_container)をホスト名として、そしてデータベースがリッスンしている内部ポート(3306)を使用する。

サービスAのデータベース接続情報は次のようになる:

ShellScript
DATABASE_URL=mysql://root:password@db_a_container:3306/db_a_database

おわりに

Dockerコンテナ間での通信には、コンテナ名ホスト名として使用し、適切な内部ポート番号を指定する。これは、Dockerの内部DNSが自動的にコンテナ名をそのコンテナのIPアドレスに解決するため。

docker-compose.ymlで定義されたポートマッピング(例えば、54320:3306)は、コンテナの外部(ホストマシンなど)からアクセスするために使用される。コンテナ間通信では、この外部ポート(54320)ではなく、サービスの内部ポートを直接使用する。

【Docker備忘録】DockerFile・docker-compose.yml・Dockerコマンドに関しては、こちら。

コメント

タイトルとURLをコピーしました