黒縁眼鏡は海を飛ぶ

IT中心にそこはかとなく

Dockerシングルホストでのコンテナ間通信

Docker Composeを使うとyamlでまとめられるし非常に楽、という話を聞いたので試そうと思ったけど、一度くらいはlink使ってみたほうが良い気がしたので試してみる。

環境は前回と同じ。

2016/04/04追記
本記事ではDockerのデフォルトネットワークを使用してコンテナ間通信を試行していますが、公式曰くデフォルトのbrigeはレガシーとのことなのでもっと便利なユーザー定義ネットワークを使用しましょう。
ユーザー定義ネットワークの試行もすぐやろう。

やること

個人で所謂LAMP環境なサービスを作ったりする時、私の場合は殴ることができるほどの札束を持っていないので、VPSを借りるにしても複数台借りるようなリッチなことができない。
なので、サーバの80番portはnginxにもたせて、サービス用のWebサーバには3000番だったり5000番を割り当て、リバースプロキシさせることでアクセスを振り分けたりする。

サービスなんか運用してるのかって?してたけど需要なさすぎて止めてるんですよ!何かおもしろいこと思いついたら作りますね!!!!思いつかないけど!!!!



ということで、コンテナ間通信の題材はnginxによるリバースプロキシということにする。
各コンテナをホストのポートとマッピングするのが簡単なんだけど、そうするとDBコンテナやAPコンテナを外部に晒すことになりそうなので回避したい。
そういう時に便利なのがlink機能なんだそう。

Dockerのネットワーク周りは色々ありそうなので、ドキュメントはちゃんと読んでおきたい。。。願望。


準備

  • リバースプロキシ用コンテナ
    • コンテナ名
      • proxy
  • バックエンド用コンテナ
    • コンテナ名
      • backend
  • ボリュームコンテナ
    • proxyのconfig用
      • コンテナ名
        • proxy_config
    • proxyのhtml用
      • コンテナ名
        • proxy_html
    • backendのhtml用
      • コンテナ名
        • backend_html

proxybackendもnginxを立ち上げるだけなので、Dockerfileは以下のようにした。

FROM centos:latest
MAINTAINER ryoana

RUN yum -y update
RUN yum -y install http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm
RUN yum -y install nginx

EXPOSE 80

ENTRYPOINT /usr/sbin/nginx -g 'daemon off;'

先にbuildしておく。

# docker build -t ryoana/nginx .

ドメインでアクセスできるように、Dockerホストが乗ってるクライアントの/etc/hostsファイルを編集する。

$ sudo vim /etc/hosts
192.168.0.2 proxy.example.com
192.168.0.2 backend.example.com


backendコンテナをたてる

先にbackendコンテナをたてる。

後でテストできるように、/var/lib/docker/volumes/backend_html/_data/index.htmlIt is backend page.とかなんとか書いておく。

# docker run -d --name backend -v backend_html:/usr/share/nginx/html ryoana/nginx
# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS               NAMES
7a994bad7e68        ryoana/nginx        "/bin/sh -c '/usr/sbi"   3 seconds ago       Up 2 seconds        80/tcp              backend

ホスト側のポートとマッピングしていないので、ブラウザからはまだアクセスできない。


proxyコンテナをたてる(linkなし)

まずはlink機能を使わずにコンテナ間の通信を実現してみる。
backendと違いを明確にするために、/var/lib/docker/volumes/proxy_html/_data/index.htmlIt is proxy page.と書いておく。

# docker run -d --name proxy -v proxy_html:/usr/share/nginx/html -v proxy_config:/etc/nginx -p 80:80 ryoana/nginx
# docker ps 
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                NAMES
e8bada83de7e        ryoana/nginx        "/bin/sh -c '/usr/sbi"   24 seconds ago      Up 24 seconds       0.0.0.0:80->80/tcp   proxy
7a994bad7e68        ryoana/nginx        "/bin/sh -c '/usr/sbi"   7 minutes ago       Up 7 minutes        80/tcp               backend

proxyはホストの80番ポートとマップして、ちゃんと外から通信できるようにする。

ホストはVirtualBoxで動いているので、クライアントのブラウザからDockerホストの80番ポートにアクセスしてみる。

f:id:ryo14_ana:20160403222503p:plain

proxy pageを見ることができた。
ではconfigにリバースプロキシ用の設定を追加して、backend.example.com宛のリクエストをbackendに流れるようにしよう。

まずはbackendIPアドレスを調べる。

# docker inspect backend | grep IPAddress
IPAddress": "172.17.0.2"

IPがわかったのでconfigを編集する。
ここではリクエストを流すことができればそれでいいので、proxy_passだけ設定する。

# vim /var/lib/docker/volumes/proxy_config/_data/proxy_config/_data/conf.d/virtual.conf
server {
  listen 80;
  server_name backend.example.com;

  location / {
    proxy_pass http://172.17.0.2;
  }
}

config編集したのでproxyコンテナを一度停止して、再度起動する。

# docker restart proxy

再起動できたらクライアントのブラウザからbackend.example.comにアクセスしてみる。

f:id:ryo14_ana:20160403222517p:plain

コンテナのIPアドレスによる通信についての問題点

ここまでで一応「コンテナ間の通信」ができることは確認したけど、そもそもDockerコンテナはIPアドレスを固定できない。(私の知る限りでは。。。できるんでしょうか)

色々コンテナを立ち上げたり立ち上げ直したりするたびIPアドレスが変わる→proxyのconfigを書き換えないといけない、というのはとてもいけてない。

そこでlink機能が登場する。


proxyコンテナをたてる(linkあり)

ということで、link機能を使ってproxyコンテナを立ち上げてみる。

# docker run -d --name proxy --link backend:backend -v proxy_html:/usr/share/nginx/html -v proxy_config:/etc/nginx -p 80:80 ryoana/nginx

link機能を使ってproxyコンテナを立ち上げているので、configを以下のように編集してもアクセスすることができる。(この場合backendIPアドレスは変わっていないので、configをいじらなくてもアクセスはできる)

# vim /var/lib/docker/volumes/proxy_config/_data/proxy_config/_data/conf.d/virtual.conf
server {
  listen 80;
  server_name backend.example.com;

  location / {
    proxy_pass http://backend;
  }
}

proxyコンテナを立ち上げるときに指定している--link backend:bacnendは、--link <コンテナ名>:<エイリアス>という書式になっていて、proxyコンテナからは<エイリアス>で指定した名前を使ってbackendコンテナと通信することができる。


ちなみに

link機能を使うだけでどうして通信できるようになるの?と思ったのですが、/etc/hostsに該当するエントリを書き込んでいるみたい。

# docker exec proxy cat /etc/hosts
127.0.0.1       localhost
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.2      backend 7a994bad7e68
172.17.0.3      e2df163580d2

link機能を使えばコンテナを直接外部ポートに紐付ける必要がなくなっていい感じかなと思います。

Dockerのネットワーク周りはパフォーマンスにも大きく影響を与えるようなので、もうちょっとお勉強しようかなと思いました。


謝辞