こんにちは、Acroquest Technologyの横山です。

少し前の話になりますが、4月下旬に技術書典4がありましたね。そこで@llminatoll さんの「マンガでわかるDocker」が販売されていました。今はダウンロード販売されています。例えなどもわかりやすくおすすめですので、紹介させてもらいました。興味のある方はぜひ読んでみると良いと思います。

はじめに

第四回では、Dockerfileについて説明し、自分でDockerイメージを作成する方法を説明しました。また、これまでの説明では一つのコンテナを動かして説明してきましたが、一つのコンテナでは一つの機能(アプリケーション)を動かす構成にする場合が多いため、コンテナ間の連携が必要になります。

そこで第五回は、複数のコンテナを起動させたときのコンテナ間通信について説明します。

コンテナ間通信

コンテナ間通信をする方法は、以下の二つがあります。

①Dockerネットワークを作成してコンテナ名で接続できるようにする
②「--link」オプションを使用する

第一回でWordPressコンテナを起動した際は、公開されているWordPressのDockerイメージの使用手順に沿って、②の「--link」オプションを使用して、コンテナ間通信を実現していました。しかし、このオプションはレガシー機能であり、将来的に削除される可能性があります。そのため今回の記事では、推奨されている①の方法をメインに説明します。「--link」オプションについても、まだ使用している手順が多々ありますので、こちらについても簡単にですが説明しておきます。

それでは、第一回でも利用したWordPressのDockerイメージを例に、コンテナ間通信について説明します。

Dockerネットワークを作成してコンテナ間通信

まず、Dockerネットワークを作成してコンテナ間通信する方法を説明します。

WordPressのDockerイメージでは、WordPressのコンテナとMySQLのコンテナを別々に起動し、MySQLのコンテナにデータを持たせています。そのため、WordPressコンテナからMySQLコンテナに接続できるようにする必要があります。イメージとしては、以下の図のようになります。図の中の括弧内は、この後の説明にでてくる「コンテナ名」を表しています。

wordpress-mysql-connection

Dockerネットワークを作成する

まず、Dockerネットワーク(bridgeタイプ)を作成します。Dockerネットワークの種類はいくつかありますが、その説明については、本連載では扱わないため、興味がある方は「Docker コンテナ・ネットワークの理解」を参照ください。

以下のコマンドを実行し、「wordpress-network」というDockerネットワークを作成します。

# docker network create wordpress-network

以下のコマンドを実行することで、「wordpress-network」というネットワークが作成されていることが確認できます。

# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
aa8e930020fe        bridge              bridge              local
cd9e589bc655        host                host                local
537eb04a7697        none                null                local
0a67e4a78dd6        wordpress-network   bridge              local

また、Dockerインストール時には、デフォルトで「bridge」という名前のDockerネットワークも作成されていますが、今回新規で作成した理由を説明しておきます。デフォルトで存在するbridgeという名前のネットワークでは、DNS設定がされていないため名前解決ができません。そのため、コンテナ名を使用したコンテナ間通信ができず、--linkオプションを使用する方法か、コンテナ起動時に自動で割り当てられるプライベートIPアドレスを用いる方法でしか通信できません。それに対し、新規でDockerネットワークを作成すると、DNS設定がされるため名前解決ができ、コンテナ名を使用してコンテナ間で通信ができます。より詳細について知りたい方は、「Docker コンテナ・ネットワークの理解」を参照ください。

以下のコマンドでDockerネットワークの詳細を確認することができます。

# docker network inspect wordpress-network
[
    {
        "Name": "wordpress-network",
        "Id": "0a67e4a78dd60a1e355b35e61feeeb56ff86a99f9fba3a966e01174103f1db0e",
        "Created": "2018-05-27T17:36:45.862146941+09:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": {},
            "Config": [
                {
                    "Subnet": "172.18.0.0/16",
                    "Gateway": "172.18.0.1"
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {},
        "Options": {},
        "Labels": {}
    }
]

ネットワークを指定してコンテナを起動する

次に、上記で作成したDockerネットワークを使用して、MySQLコンテナとWordPressコンテナを起動します。Dockerネットワークは、「–network <ネットワーク名>」で指定することができます。

そして、ここでポイントとなるのが、MySQLコンテナのコンテナ名です。MySQLのコンテナ名は「mysql」としてください。理由は、WordPressのDockerイメージでは、MySQLへの接続先の指定として、「mysql」というホスト名を指定しているためです。

# docker run --name mysql --network wordpress-network -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:5.7
# docker run --name wordpress --network wordpress-network -e WORDPRESS_DB_PASSWORD=my-secret-pw -p 8080:80 -d wordpress

このように起動することで、WordPressコンテナ(wordpress)からMySQLコンテナ(mysql)に向けて通信が可能な状態となります。
(http://<ホストマシンのIPアドレス>:8080/でブラウザからアクセスできます)

ポート指定の注意点

注意点として、WordPressコンテナからアクセスするMySQLのポート番号は、コンテナの内部で使用しているポートを指定してください。

例えば、MySQLのポートに対して、ホスト側からも接続できるようにポートフォワード設定をしてコンテナを起動していたとします。(ホスト側:13306、コンテナ内:3306)

# docker run --name mysql --network wordpress-network -p 13306:3306 -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:5.7

この場合でも、wordpress-networkを経由して「コンテナ間通信」でmysqlにアクセスする場合は、3306ポートを使用することで接続できます。

「--link」オプションを使用したコンテナ間通信

「--link」オプションを使用する場合について説明します。ただし、前述の「コンテナ間通信」でも書きましたが、このオプションはレガシー機能であり、将来的に削除される可能性があります。

「--link」オプションを使用する場合は、以下のように使用します。

# docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:5.7
# docker run --name some-wordpress -e WORDPRESS_DB_PASSWORD=my-secret-pw --link some-mysql:mysql -d -p 8080:80 wordpress

「--link」オプションで、接続先のコンテナ名(some-mysql)と、WordPressコンテナ内で使用しているMySQLのホスト名(mysql)を指定します。これにより、コンテナ間で接続が可能となります。

Nginx、Tomcatコンテナでのコンテナ間通信

上記のWordPressの例では、既存のWordPressのDockerイメージを使用していました。自分で作成したDockerイメージを用いてコンテナ間で通信するためには、定義ファイルなどに接続先としてコンテナ名を指定しておくことが必要です。その例として、第四回で作成したTomcatイメージを利用し、追加でコンテナ間通信確認用のNginxイメージを作成して、コンテナ間通信を行ってみましょう。

Tomcatイメージは、第四回に作成したものをそのまま利用します。Nginxについては、以下のようなファイルを準備し、今回のコンテナ間通信確認用のNginxイメージを作成しましょう。イメージとしては以下の図のようになります。図の中の括弧内は、この後の説明にでてくる「コンテナ名」を表しています。

nginx-tomcat-connection

各種ファイルの準備

まず、以下のようにファイルを準備してください。

${SOME_DIR}
  /nginx
    Dockerfile  ・・・①
    /files
      tomcat.conf  ・・・②
  /tomcat
    Dockerfile  ・・・③

※${SOME_DIR}は任意のディレクトリ

①のDockerfileは以下になります。

FROM nginx:latest

RUN rm -f /etc/nginx/conf.d/default.conf
COPY ./files/tomcat.conf /etc/nginx/conf.d/

Nginxのtomcat.confは以下になります。Tomcatの接続先として「tomcat-1」を使用するため、Tomcatコンテナを起動する際にはコンテナ名を「tomcat-1」とします。

server {
    location /tomcat/ {
        proxy_pass    http://tomcat-1:8080/;
    }
}

③のDockerfileは、第四回の「Dockerfileの作成」部分を参照してください。

Nginxイメージ、Tomcatイメージの作成

NginxのDockerイメージを作成します。(TomcatのDockerイメージについて、第四回で作成済みの場合は実行不要です。)

# cd ${SOME_DIR}/nginx
# docker build -t nginx-tomcat:1 .
# cd ${SOME_DIR}/tomcat
# docker build -t tomcat:1 .

Dockerネットワーク作成、コンテナ起動

Dockerネットワークを作成し、TomcatとNginxコンテナを起動します。

# docker network create tomcat-network
# docker run --name tomcat-1 --network tomcat-network -d tomcat:1
# docker run --name nginx-tomcat-1 --network tomcat-network -p 10080:80 -d nginx-tomcat:1
# docker ps -a
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                   NAMES
657ab3ee8737        nginx-tomcat:1      "nginx -g 'daemon of…"   11 seconds ago      Up 10 seconds       0.0.0.0:10080->80/tcp   nginx-tomcat-1
24f6ae102be7        tomcat:1            "/opt/apache-tomcat-…"   26 seconds ago      Up 25 seconds                               tomcat-1

コンテナの起動ができたら、以下のURLにブラウザでアクセスしてみましょう。Nginx経由でTomcatの画面を見ることができます。
http://<ホストのIPアドレス>:10080/tomcat/

複数ホストでのコンテナ間通信

今回説明したコンテナ間通信は、1ホスト上でコンテナを動かす場合についてです。複数ホストでコンテナを起動して、コンテナ間通信するには、今回説明したことの他にも必要な設定があります。そこで活躍するのが、KubernetesDocker Swarmなどのコンテナオーケストレーションツールになります(今はKubernetesがデファクトスタンダードとなっています)。本連載では扱いませんが、コンテナオーケストレーションツールを使用することで、複数ホストでのコンテナ間通信の設定を自動化してくれます。

まとめ

今回は、コンテナ間通信の方法を説明しました。これにより、Dockerコンテナの利用の幅も広がると思います。ぜひ、いろいろと試していただければと思います。