Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
15
Help us understand the problem. What is going on with this article?

More than 5 years have passed since last update.

@zERobYTezERo

ELB+Swarm+Compose+Consul+Registratorで夢は叶うのか(2)

前回の続きです

前の記事 : ELB+Swarm+Compose+Consul+Registratorで夢は叶うのか(1)

スプリットブレイン状態なConsulを立てる

Swarmは全ノードとコンテナを知っているがConsulは自ノードの設定しか責任を持たないようにしたかった。

Dockermanの/root/docker-host/にnodesを掘ってそこに新しいdocker-compose.ymlを書こう

# cd /root/docker-host
# mkdir nodes
# cd nodes
# nano docker-compose.yml
docker-compose.yml
consul:
  command: -server -bootstrap -ui-dir /ui
  image: progrium/consul:latest
  ports:
  - "8300"
  - "8400"
  - "8500"
  - "8600/udp"
  environment:
  - "affinity:container!=nodes_consul_*"
  net: "host"

registrator:
  command: consul://127.0.0.1:8500
  image: progrium/registrator:latest
  volumes:
  - "/var/run/docker.sock:/tmp/docker.sock"
  environment:
  - "affinity:container!=nodes_registrator_*"
  net: "host"

この構成では

  • 各ノードでConsulが8500で待ち受けし
  • Registratorが自分が所属しているノードのdockerコンテナを把握して自分と同じノードのConsulに通知

となっていてサービス定義のenvironmentにあるaffinity:container!=ほにゃららは同じノードでの多重起動を防止するために設定されているもの

ここまでは悩むところも無いのでさくっと起動してしまおう
DOCKER_HOSTを2380ポート(swarm manage)に向けてからdocker-composeをすればSwarm API経由でコンテナの制御が出来るようになる

# export DOCKER_HOST=tcp://localhost:2380
# pwd
/root/docker-host/nodes
# docker-compose up -d consul
Creating nodes_consul_1...
# docker-compose scale consul=3
Creating nodes_consul_2...
Creating nodes_consul_3...
Starting nodes_consul_2...
Starting nodes_consul_3...
# docker-compose up -d registrator
Creating nodes_registrator_1...
# docker-compose scale registrator=3
Creating nodes_registrator_2...
Creating nodes_registrator_3...
Starting nodes_registrator_2...
Starting nodes_registrator_3...
# docker-compose ps
       Name                      Command               State   Ports
--------------------------------------------------------------------
nodes_consul_1        /bin/start -server -bootst ...   Up
nodes_consul_2        /bin/start -server -bootst ...   Up
nodes_consul_3        /bin/start -server -bootst ...   Up
nodes_registrator_1   /bin/registrator consul:// ...   Up
nodes_registrator_2   /bin/registrator consul:// ...   Up
nodes_registrator_3   /bin/registrator consul:// ...   Up

ああ、なんて楽ちんなんでしょう。

docker-loadbalancerをビルドする

このdocker-loadbalancerはConsulと通信しサービスの状態変化に合わせてConsul-templete起動、設定ファイルを展開して、Nginxを制御してくれる。

ノードのどれでもいいので、展開して設定を修正しよう

# pwd
/root/docker-host
# git clone https://github.com/bellycard/docker-loadbalancer.git loadbalancer
Cloning into 'loadbalancer'...
remote: Counting objects: 40, done.
remote: Total 40 (delta 0), reused 0 (delta 0), pack-reused 40
Unpacking objects: 100% (40/40), done.
Checking connectivity... done.
# cd loadbalancer
# ls -al
-rwxr-xr-x 1 root root  151 Mar  7 10:21 consul-template.service
-rw-r--r-- 1 root root  619 Mar  7 10:21 Dockerfile
-rw-r--r-- 1 root root  164 Mar  7 10:21 .envrc
-rw-r--r-- 1 root root  532 Mar  7 10:21 fig.yml
drwxr-xr-x 8 root root 4096 Mar  7 10:21 .git
-rw-r--r-- 1 root root  420 Mar  7 10:21 nginx.conf
-rwxr-xr-x 1 root root  123 Mar  7 10:21 nginx.service
-rw-r--r-- 1 root root 1064 Mar  7 10:21 README.md

ここで編集が必要なのは nginx.conf と consul-template.service だ

nginx.conf
upstream nohost {
  least_conn;
  server 127.0.0.1:65535;
}

upstream testweb {
  least_conn;
  {{range service "production.testweb"}}server {{.Address}}:{{.Port}} max_fails=3 fail_timeout=60 weight=1;
  {{else}}server 127.0.0.1:65535; # force a 502{{end}}
}

server {
  listen 80 default_server;

  location / {
    proxy_pass http://nohost;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }
}

server {
  listen 80;
  server_name docker.example.com;

  location / {
    proxy_pass http://testweb;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }
}

こうすることで

サービス名(SERVICE_NAME) testweb
タグ名(SERVICE_TAGS) production

という環境変数がついたコンテナが増減した時、上記設定ファイルをConsul-templeteが{{.Address}}:{{.Port}}部分を実際のIPとポート番号に展開してくれる

consul-template.service
#!/bin/sh

exec consul-template \
     -consul=127.0.0.1:8500 \
     -template "/etc/consul-templates/nginx.conf:/etc/nginx/conf.d/app.conf:sv hup nginx"

Consul-templateの起動オプションにConsulの接続先が書いてあるのでここを書き換えている。
(127.0.0.1だとこのコンテナ内なんじゃないの?と思われたあなたは鋭い.ホストネットワーク機能のおかげです)

書き換えが完了したならばビルドしてプライベートレジストリにpushしてしまおう

# docker build .
Sending build context to Docker daemon 113.2 kB
Sending build context to Docker daemon
Step 0 : FROM nginx:1.7
 ---> 2485b0f89951
Step 1 : MAINTAINER Shane Sveller <shane@bellycard.com>
 ---> Using cache
 ---> 8b00a2293a97
...
...
...
Step 5 : ADD nginx.service /etc/service/nginx/run
 ---> b1b0b05a408b
Removing intermediate container ee6e15440531
Step 6 : ADD consul-template.service /etc/service/consul-template/run
 ---> 1daacc85e833
Removing intermediate container bb545c650ac1
...
...
...
Removing intermediate container 33bab34d8d86
Successfully built d0b8fa1bb2df
# docker tag d0b8fa1bb2df 10.10.0.110:5000/zerobytezero/docker-loadbalancer:latest
# docker push 10.10.0.110:5000/zerobytezero/docker-loadbalancer:latest
The push refers to a repository [10.10.0.110:5000/zerobytezero/docker-loadbalancer] (len: 1)
Sending image list
Pushing repository 10.10.0.110:5000/zerobytezero/docker-loadbalancer (1 tags)
...
...
...
1daacc85e833: Image successfully pushed
c878bca3ec0c: Image successfully pushed
9201627715ed: Image successfully pushed
d0b8fa1bb2df: Image successfully pushed
Pushing tag for rev [d0b8fa1bb2df] on {http://10.10.0.110:5000/v1/repositories/zerobytezero/docker-loadbalancer/tags/latest}

pushが終わったなら、各ノードで予めpullしておけばOK.

Dockermanに戻ってdocker-compose.ymlに以下定義を追加する

docker-compose.yml
loadbalancer:
  image: 10.10.0.110:5000/zerobytezero/docker-loadbalancer:latest
  ports:
  - "80"
  expose:
  - "80"
  environment:
  - "affinity:container!=nodes_loadbalancer_*"
  net: "host"

docker-loadbalancerも各ノードに1つだけになるよう制限が必要だ
よーしloadbalancerも立ち上がっておしまい!

# docker-compose up -d loadbalancer
Creating nodes_loadbalancer_1...
# docker-compose scale loadbalancer=3
Creating nodes_loadbalancer_2...
Creating nodes_loadbalancer_3...
Starting nodes_loadbalancer_2...
Starting nodes_loadbalancer_3...

残るは中身だけだっ

Webコンテナを準備する

なにか表示するものが無いと寂しいので...

# mkdir -p /docker-volumes/testweb
# nano /docker-volumes/testweb/index.php
index.php
<?php ini_set('date.timezone', 'Asia/Tokyo'); ?>
<html>
<head>
  <title>docker-container</title>
</head>
<body>
  <h1>
    docker00:<?php echo $_SERVER['SERVER_ADDR']; ?>
  </h1>
  <ul>
  <?php
    foreach (getallheaders() as $name => $value) {
      echo "<li>$name: $value</li>";
    }
  ?>
  </ul>
</body>
</html>

各ノードにそれぞれ、こんなPHPファイルを配置した。
"docker00"の部分を各ノード名に書き換えておけばどのノードがコンテンツを返しているのかわかりやすいと思う。

Dockermanのdocker-compose.ymlにさらに以下を追加する

docker-compose.yml
webapps:
  image: php:5.6-apache
  volumes:
   - "/docker-volumes/testweb:/var/www/html"
  ports:
   - "80"
  environment:
   - "affinity:container!=nodes_webapps_*"
   - SERVICE_80_NAME=http
   - SERVICE_NAME=testweb
   - SERVICE_TAGS=production

scalewebapps:
  image: php:5.6-apache
  volumes:
   - "/docker-volumes/testweb:/var/www/html"
  ports:
   - "80"
  environment:
   - SERVICE_80_NAME=http
   - SERVICE_NAME=testweb
   - SERVICE_TAGS=production

なんで2つにしちゃったの?

Nginxが生きてるのに1台もWebコンテナが無いと502が返ってしまうので、最低限ノード数と同じだけのWebサーバを用意しておく必要があって、これがwebappsサービス。

scalewebappsはルールに無用でramdomにノードに散らばっていく設定として、パワー不足はこいつをスケールすることで対応していく。

レッツ起動

# docker-compose up -d webapps
Creating nodes_webapps_1...
# docker-compose scale webapps=3
Creating nodes_webapps_2...
Creating nodes_webapps_3...
Starting nodes_webapps_2...
Starting nodes_webapps_3...
registrator_2 | 2015/03/07 23:21:37 registrator: added: 540cc048a95b ip-10-10-0-50:nodes_webapps_1:80
consul_2      |     2015/03/07 23:21:37 [INFO] agent: Synced service 'ip-10-10-0-50:nodes_webapps_1:80'
registrator_3 | 2015/03/07 23:21:39 registrator: added: 665e35e82457 ip-10-10-0-51:nodes_webapps_2:80
consul_1      |     2015/03/07 23:21:39 [INFO] agent: Synced service 'ip-10-10-0-51:nodes_webapps_2:80'
registrator_1 | 2015/03/07 23:21:39 registrator: added: e9aaf6a0c092 ip-10-10-0-49:nodes_webapps_3:80
consul_3      |     2015/03/07 23:21:39 [INFO] agent: Synced service 'ip-10-10-0-49:nodes_webapps_3:80'

ちゃんと、RegistratorがConsulに登録してくれてるぽい!

Macbookに/etc/hostsを書いてアクセスして各ノードがちゃんと動いているようなら、ELB配下にノードを置いてしまおう。

スクリーンショット 2015-03-08 8.48.49.png

リロードする度にちゃんとノードがグリグリしてれば大成功!

いやー、久々に

インフラ屋の魂が◯◯する!! by ゴールデンカムイ

長くなっちゃったので次の記事で「秘技ノード落とし」とか「必殺300コンテナ起動」とか書くとしますかね。

パトラッシュ、僕はもう疲れたよ。。。

次の記事 : ELB+Swarm+Compose+Consul+Registratorで夢は叶うのか(3)

15
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
15
Help us understand the problem. What is going on with this article?