LoginSignup
42
52

More than 3 years have passed since last update.

【Docker】複数のコンテナ(サービス)を1サーバーで起動させてサブドメインで80ポートにアクセスする

Last updated at Posted at 2019-06-23

Background

1サーバーに複数のコンテナ(サービス)を綺麗に乗せられるDockerってすごい便利です。こんなことがしたい。
Untitled Diagram.png
四角で囲まれている部分が1サーバー、例えばlocalhostだったりAWSやGCPの1インスタンスだったりということです。
service-a.hoge.comにアクセスするとcontainer Aのサービスを利用できて、service-b.hoge.comにアクセスするとcontainer Bのサービスが利用できるという世界。

nginx-proxy

GitHub - jwilder/nginx-proxy: Automated nginx proxy for Docker containers using docker-gen
こちらのDocker imageを使わせてもらいます。
上の図でいうところのcontainer A、container BにそれぞれVIRTUAL_HOSTを設定することでサブドメインに応じてアクセスできるようになります。

使い方はこんな感じ。

docker-compose.yml
services:
  nginx-proxy:
    image: jwilder/nginx-proxy
    ports:
      - "80:80"
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro

  service-a:
    image: xxxxxxxxxx
    environment:
      - VIRTUAL_HOST=service-a.hoge.com

  service-b:
    image: xxxxxxxxxx
    environment:
      - VIRTUAL_HOST=service-b.hoge.com

基本の型はこんな感じです。

実際はサービスごとにdocker-compose.ymlつくりますよね。

例えば、「Rocket.Chat」と「Wekan」をlocalhostで展開することを考えます。それぞれのサービスのdocker-compose.yml自体が複雑になったりもするので、それらを一つのyamlファイルとして管理するのは抵抗がありました。上のyamlファイルの例では1つのyamlファイルにnginx-proxyservice-aservice-bを記載していますが、別々のyamlファイルに宣言することも可能です。ただし、nginx-proxyservice-aservice-bが同じネットワークに存在していないと互いに通信ができないのでその設定をしてあげることが注意点です。

ちょうど、「Rocket.Chat」と「Wekan」を例に出したので、これをサンプルにhttp://rocketchat.localhostに接続したら「Rocket.Chat」、http://wekan.localhostに接続したら「Wekan」にアクセスできるようにしてみます。

Directory structure

/
├ nginx-proxy
|  └ docker-compose.yml
├ rocketchat
|  └ docker-compose.yml
└ wekan
   └ docker-compose.yml

nginx-proxy/docker-compose.yml

nginx-proxy/docker-compose.yml
version: "3.5"

services:
  nginx-proxy:
    container_name: nginx-proxy
    image: jwilder/nginx-proxy
    ports:
      - 80:80
    volumes:
      - /var/run/docker.sock:/tmp/docker.sock:ro
    networks:
      - proxy-network

networks:
  proxy-network:
    name: proxy_network

最初の例と大きく違うところはnetworksを指定したところです。ちょっと上の方で注意点としてあげましたが、この後に宣言する「Rocket.Chat」と「Wekan」のアプリケーションのコンテナとこの「nginx-proxy」のコンテナは同じネットワークに存在しなければなりません。同じネットワークに存在させるためにproxy_networkという名前のネットワークに所属することを宣言しています。
ちなみにnetworksの方で宣言しているnameというプロパティですが、versionが3.xと宣言されていないと使えないらしいので、今回の例ではversionを3.5としています。

rocketchat/docker-compose.yml

rocketchat/docker-compose.yml
version: "3.5"

services:
  app:
    container_name: rocketchat_app
    image: rocketchat/rocket.chat:latest
    command: bash -c 'for i in `seq 1 30`; do node main.js && s=$$? && break || s=$$?; echo "Tried $$i times. Waiting 5 sec..."; sleep 5; done; (exit $$s)'
    restart: unless-stopped
    volumes:
      - ./uploads:/app/uploads
    environment:
      - PORT=3000
      - ROOT_URL=http://rocketchat.localhost
      - MONGO_URL=mongodb://mongo:27017/rocketchat
      - MONGO_OPLOG_URL=mongodb://mongo:27017/local
      - VIRTUAL_HOST=rocketchat.localhost
    depends_on:
      - mongo
    networks:
      - proxy-network
      - rocketchat-network

  mongo:
    container_name: rocketchat_db
    image: mongo:4.0
    restart: unless-stopped
    volumes:
      - ./data/db:/data/db
      - ./data/dump:/dump
    command: mongod --smallfiles --oplogSize 128 --replSet rs0 --storageEngine=mmapv1
    networks:
      - rocketchat-network

  mongo-init-replica:
    image: mongo:4.0
    command: 'bash -c "for i in `seq 1 30`; do mongo mongo/rocketchat --eval \"rs.initiate({ _id: ''rs0'', members: [ { _id: 0, host: ''localhost:27017'' } ]})\" && s=$$? && break || s=$$?; echo \"Tried $$i times. Waiting 5 secs...\"; sleep 5; done; (exit $$s)"'
    depends_on:
      - mongo
    networks:
      - rocketchat-network

networks:
  proxy-network:
    name: proxy_network
  rocketchat-network:
    name: rocketchat_network

Rocket.Chatを起動させるための基本的なdocker-compose.ymlについては説明を省略します。(「大人の事情でSlackが使えないのでRocket.ChatをBasic認証ありでdocker-composeで起動した - Qiita」で書いてますのでよろしければ参考に〜)

ここで肝になる部分をいくつかご紹介。

services.app.environmentVIRTUAL_HOST

ここがRocket.Chat用のURLを宣言する箇所です。今回はhttp://rocketchat.localhostを指定します。

services.app.networks

appコンテナはnginx-proxyと同一ネットワークに存在する必要があるので、proxy-networkを指定しています。proxy-networknetworks.proxy-network.namenginx-proxyで作成したproxy_networkと同じであると定義しています。
また、appコンテナはrocketchat-networkにも所属するようにしています。これは後ろの方で宣言しているmongoコンテナと接続するためのネットワークです。mongoコンテナはnginx-proxyと直接接続する必要がないので敢えてネットワークを切り離しています。Untitled Diagram-Page-2.png

wekan/docker-compose.yml

wekan/docker-compose.yml
version: "3.5"

services:
  app:
    container_name: wekan_app
    image: wekanteam/wekan:latest
    links:
      - mongo
    environment:
      - MONGO_URL=mongodb://wekandb/wekan
      - ROOT_URL=http://wekan.localhost
      - VIRTUAL_HOST=wekan.localhost
    depends_on:
      - mongo
    networks:
      - proxy-network
      - wekan-network

  mongo:
    container_name: wekan_db
    image: mongo:3.2.14
    volumes:
      - ./data:/data/db
    networks:
      - wekan-network

networks:
  proxy-network:
    name: proxy_network
  wekan-network:
    name: wekan_network

注目ポイントはRocket.Chatの宣言と同じなので省略。

Check

全てのdocker-compose.ymlを起動してみて、サブドメインでアクセスするアプリケーションが制御されているか確認してみましょう!
nginx-proxy/rocketchat/wekan/のそれぞれのディレクトリで$ docker-compose up -dコマンドを実行し、各コンテナが完全に立ち上がったらhttp://rocketchat.localhosthttp://wekan.localhostにアクセスしてみましょう!

あとがき

実際にドメインを取得してマネージドクラウドなんかにアプリをたてる場合も、VIRTUAL_HOSTの設定をそのサブドメインに宣言するだけでいける!!

References

42
52
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
42
52