Upgrade to Pro — share decks privately, control downloads, hide ads and more …

もしCIAの男子エンジニアがドッカーの「マネジメント」を考えたら@Adtech Develop...

もしCIAの男子エンジニアがドッカーの「マネジメント」を考えたら@Adtech Developer Conference 2017 / adc2017 docker

もしCIAの男子エンジニアがドッカーの「マネジメント」を考えたら
Adtech Developer Conference 2017

Masaya Aoyama (@amsy810)

July 07, 2017
Tweet

More Decks by Masaya Aoyama (@amsy810)

Other Decks in Technology

Transcript

  1. コンテナって?(今回は Docker) カーネルの機能を用いてプロセスを分離し、OS の一部のみを仮想化したもの  = ただプロセスを走らせてるだけに近い ハードウェア ハードウェア OS (カーネル)

    OS (カーネル) KVM (仮想化ミドルウェア) Docker OS (カーネル) OS (カーネル) bin / libs bin / libs app app app app bin / libs bin / libs app app app app bin / libs bin / libs 仮想マシン (VM) コンテナ 3
  2. Docker のざっくりした使い方 1.Dockerfile をつくります。 2.Docker Image を build します。 3.コンテナを実行します。

    FROM docker.io/centos:7 MAINTAINER aoyama_masaya EXPOSE 80 RUN yum -y install epel-release RUN yum -y install nginx ENTRYPOINT ["nginx", "-g", "daemon off;"] Docker Image # docker build # docker run ./Dockerfile 4
  3. Docker のざっくりした使い方 1.Dockerfile をつくります。 2.Docker Image を build します。 3.コンテナを実行します。

    FROM docker.io/centos:7 MAINTAINER aoyama_masaya EXPOSE 80 RUN yum -y install nginx RUN yum -y install epel-release CMD ["nginx", "-g", "daemon off;"] Docker Image # docker build # docker run ./Dockerfile どこかで似たようなこと聞いたことありませんか? 5
  4. Docker のざっくりした使い方 1.Dockerfile をつくります。 2.Docker Image を build します。 3.コンテナを実行します。

    FROM docker.io/centos:7 MAINTAINER aoyama_masaya EXPOSE 80 RUN yum -y install nginx RUN yum -y install epel-release CMD ["nginx", "-g", "daemon off;"] Docker Image # docker build # docker run ./Dockerfile そうですみなさん大好き Java (JVM) です。 なので、皆さんと相性が悪くないはず。 6
  5. Docker のざっくりした使い方 1.Dockerfile をつくります。 2.Docker Image を build します。 3.コンテナを実行します。

    FROM docker.io/centos:7 MAINTAINER aoyama_masaya EXPOSE 80 RUN yum -y install epel-release RUN yum -y install nginx ENTRYPOINT ["nginx", "-g", "daemon off;"] Docker Image # docker build # docker run ./Dockerfile 7
  6. Dockerfile FROM: ベースとなる Docker Image MAINTAINER: メンテナー情報 EXPOSE: アクセスを許可するポート RUN:

    コマンドの実行 FROM docker.io/centos:7 MAINTAINER aoyama_masaya EXPOSE 80 RUN yum -y install epel-release RUN yum -y install nginx COPY nginx.conf /etc/nginx/ ADD doc.tar.gz /usr/share/nginx/html/ USER nginx WORKDIR /usr/sbin ENTRYPOINT ["nginx", "-g", "daemon off;"] 8
  7. Dockerfile COPY: ベースとなる Docker Image ADD: COPYの上位版。圧縮ファイルの展開、 URL 先のファイル配置などに対応 USER:

    実行ユーザ WORKDIR: 実行ディレクトリ ENTRYPOINT: コンテナ起動時の実行コマンド FROM docker.io/centos:7 MAINTAINER aoyama_masaya EXPOSE 80 RUN yum -y install epel-release RUN yum -y install nginx COPY nginx.conf /etc/nginx/ ADD doc.tar.gz /usr/share/nginx/html/ USER nginx WORKDIR /usr/sbin ENTRYPOINT ["nginx", "-g", "daemon off;"] 9
  8. Docker のざっくりした使い方 1.Dockerfile をつくります。 2.Docker Image を build します。 3.コンテナを実行します。

    FROM docker.io/centos:7 MAINTAINER aoyama_masaya EXPOSE 80 RUN yum -y install epel-release RUN yum -y install nginx ENTRYPOINT ["nginx", "-g", "daemon off;"] Docker Image # docker build # docker run ./Dockerfile 10
  9. では build してみましょう。 Dockerfile が 1 行毎に実行され、 Git と同じように更新毎にハッシュ値が付与 #

    docker history aoyama-image IMAGE CREATED BY SIZE 44324d6e2de3 #(nop) ENTRYPOINT ["nginx" "-g" 0 B ... 45c562b138a9 yum -y install epel-release 102.1 MB ... 1c5f31460904 #(nop) MAINTAINER aoyama_masaya 0 B 3bee3060bfc8 #(nop) CMD ["/bin/bash"] 0 B <missing> #(nop) LABEL name=CentOS Base I 0 B <missing> #(nop) ADD file:d22a9c627d1d1f32 192.5 MB 11 # docker build -f Dockerfile -t aoyama-image Sending build context to Docker daemon 670.3 MB Step 1 : FROM docker.io/centos:7 ---> 3bee3060bfc8 Step 2 : MAINTAINER aoyama_masaya ---> Running in 19e9355a7478 ---> 1c5f31460904 Removing intermediate container 19e9355a7478 ... Step 4 : RUN yum -y install epel-release ---> Running in 90f51b35430a ---> 45c562b138a9 Removing intermediate container 90f51b35430a ... Step 10 : ENTRYPOINT nginx -g daemon off; ---> Running in 7311256a5dc2 ---> 44324d6e2de3 Removing intermediate container 7311256a5dc2 Successfully built 44324d6e2de3
  10. 2回目以降の build # docker build -f Dockerfile -t aoyama-image Step

    1 : FROM docker.io/centos:7 ---> 3bee3060bfc8 Step 2 : MAINTAINER aoyama_masaya ---> Using cache ---> 1c5f31460904 Step 4 : RUN yum -y install epel-release ---> Using cache ---> 45c562b138a9 Step 10 : ENTRYPOINT nginx -g daemon off; ---> Using cache ---> 44324d6e2de3 Step 11 : RUN echo “” > test.txt ... 2 回目の実行は変更がない部分は キャッシュとなるイメージを利用します 変更とみなされるケース ・Dockerfile の命令の書き換え ・ADD, COPY などで  ファイルのチェックサムが異なる ちなみに RUN コマンドは字面で判断 (yum とか curl は注意、必要なら --no-cache) 12
  11. 差分(レイヤー)って?「Docker イメージの構造」 レイヤーは更新された生ファイルの塊(Git のように純粋な差分ではありません) # docker save aoyama-image -o output.tar

    # cat output.tar 197563acb8ef55a6f15d7ad08b35a8a0cf20aa1d70cfce7819d3141c2b73d368/ 4b029cd17078142030f714cc073f5c76c0e6eb7a57e962665ea5bef50f1376b3/ 6816b808e31938ed8a0a2a862180c5d5945b627bc123a989cfc05027e3f50a0f/ ed24c53d89b244652da4069b61087029dca466fce2febdc478dc56e4c35e666d/ 3845b781e1be1f89ac76bbf3b3303a4d76bff5004015e31529e5d8253925da77/ 5c51ffad28e39af58c4d382a86f9f67934fffcf7cbe9b2edd2a9cd1ca3ebe8c4.json manifest.json repositories Docker Image usr/share/nginx/html/ aoyama.html ... ① ② ③ ④ ⑤ ①はベースイメージ ⑤は “ADD doc.tar.gz /usr/share/nginx/html/” で更新された生ファイル ②③④ も同様に更新された生ファイル  ※その他の Dockerfile 命令は 5c51ffad*.json を更新しています。 13
  12. 差分(レイヤー)って?「Docker イメージの構造」 レイヤーは更新された生ファイルの塊(Git のように純粋な差分ではありません) Docker Image usr/share/nginx/html/ aoyama.html ... ①

    ② ③ ④ ⑤ ②③ には同じファイルが沢山含まれている “RUN yum -y install nginx” で更新された生ファイル “RUN yum -y install epel-release” で更新された生ファイル ... RUN yum -y install epel-release \     && yum -y install nginx ... ... RUN yum -y install epel-release RUN yum -y install nginx ... STEP 数の削減 14
  13. Docker のざっくりした使い方 1.Dockerfile をつくります。 2.Docker Image を build します。 3.コンテナを実行します。

    FROM docker.io/centos:7 MAINTAINER aoyama_masaya EXPOSE 80 RUN yum -y install epel-release RUN yum -y install nginx ENTRYPOINT ["nginx", "-g", "daemon off;"] Docker Image # docker build # docker run ./Dockerfile 15
  14. Docker 実行時の挙動 新たに書き込み可能なレイヤーを構築して起動されます(# docker run -d aoyama-image) ① ② ③

    ④ ⑤ 読み込み専用な Docker Image 書き込み可能なレイヤー ① ② ③ ④ ⑤ ① ② ③ ④ ⑤ ① ② ③ ④ ⑤ # docker ps CONTAINER ID IMAGE 2bad520684dc aoyama-image:latest 1cdd782599c5 aoyama-image:latest 57c5f717d2ba aoyama-image:latest 2bad52 0684dc 1cdd78 2599c5 57c5f7 17d2ba 複数起動した場合  共通の Read Only Docker Image  + 複数の Writable レイヤーで構成 16
  15. Docker のざっくりした使い方 1.vi ./Dockerfile 2.docker build -f ./Dockerfile -t sample

    3.docker run -d sample FROM docker.io/centos:7 MAINTAINER aoyama_masaya EXPOSE 80 RUN yum -y install epel-release RUN yum -y install nginx ENTRYPOINT ["nginx", "-g", "daemon off;"] Docker Image # docker build # docker run ./Dockerfile 18
  16. Docker のざっくりした使い方 1.Dockerfile をつくります。 2.Docker Image を build します。 3.コンテナを実行します。

    FROM docker.io/centos:7 MAINTAINER aoyama_masaya EXPOSE 80 RUN yum -y install nginx RUN yum -y install epel-release CMD ["nginx", "-g", "daemon off;"] Docker Image # docker build # docker run ./Dockerfile みなさん Docker が好きになってきましたか? 19
  17. ログの管理 基本的には docker logs CONTAINER_ID で出力されます Docker でログを管理する場合には標準出力にログを出力する必要があります ボリュームを使ってそこに書き出して、td-agent で転送して…とかは…

    ABC コンテナ内の標準出力を Docker daemon が収集 json file に出力 {"log":"200 /index.html", "stream":"stdout", "time":"2017-07-05T04:54:04.093527102Z"} {"log":"403 /test.html", "stream":"stdout", "time":"2017-07-05T04:54:06.622045641Z"} ... /var/lib/docker/containers/ABC/ABC-json.log 21
  18. ログの管理 実は後段の部分が plugableで 様々な driver が用意されている ※ json-file 形式でないと docker

    logs は使えない ABC コンテナ内の標準出力を Docker daemon が収集 json-file {"log":"200 /index.html", "stream":"stdout", "time":"2017-07-05T04:54:04.093527102Z"} {"log":"403 /test.html", "stream":"stdout", "time":"2017-07-05T04:54:06.622045641Z"} ... /var/lib/docker/containers/ABC/ABC-json.log syslog journald gelf splunk none fluentd cloud logging awslogs gcplogs 22
  19. リソースの制限 CPU  利用 CPU、CPU の割当比率、CPU の割当コア数などを設定可能 Memory  メモリ容量、SWAP 容量、OOM 関連などを設定可能

    Block Device  iops, Bandwidth を設定可能 Network Device  現時点では帯域制限はかけられない模様                        (細かい内容は末尾の付録へ) 24
  20. イメージの置き場 dockerhub  Github 的な存在でオープンソースなイメージが置いてある  有料だが Private Repository も提供 artifactory  adtech

    studioでおなじみの環境 docker registry(Private Repository)  Izanami 環境に swift(S3 クローン) バックエンドで構築中 イメージは centos:6 のようにイメージ名:バージョンタグ で保存 個人的には latest 運用はやめたほうが良いと思っています。 26
  21. Docker Volume volume 機能を使えばコンテナに永続データ領域を追加できます  ・Docker ホストのディレクトリをマウント  ・LVM で切り出す  ・外部ストレージ(EBSなど)をアタッチ  ・etc…

    しかし、データベースは基本的には VM が良いと思います。 全てをコンテナ化する必要はありません。 /srv EBS LVM /usr/local/somedir 28
  22. バックアップ? その運用だめじゃない? 本来 immutable infrastructure (不変なインフラ)です。 本来 ephemeral(短命)です。 個人的には Jenkins とか一部は使っても良いんじゃないかと思っています。

     docker run -d jenkins(インストール)  docker export CONTAINER_ID -o backup.tar(バックアップ)  cat backup.tar | docker import - restored_jenkins(障害時にリストア)                        (細かい内容は末尾の付録へ) 30
  23. コンテナ内で利用する認証情報の取り扱い VM のときはパスワードの渡し方はどちらか  ・環境変数で渡す  ・ファイルにパスワードが書かれている コンテナでは全て環境変数で渡します  docker run --env DB_PASS=pass

    -d aoyama-image  docker run --env-file ./envfile -d aoyama-image ファイルにパスワードが書かれていないとダメな場合は…?  ・パスワード書いたファイルをイメージに入れちゃう?  ・しかもまだ build し直し? 32
  24. コンテナ内通信では IP Address は不要 38 DB App # docker run

    -d centos:7 --name db-server # docker run --link db-server:db -d centos:7 cat /etc/hosts … xxx.xxx.xxx.xxx db-server db 15b0a2b93ff5 DB のアドレスなんだろう… ping db-server ping db
  25. コンテナオーケストレーションエンジン Amazon ECS GKE Docker Swarm Kubernetes Apache Mesos DC/OS

    今日は詳しくは話しません。 ・オートスケール ・負荷分散 ・複数ホストでのリソース配分 ・etc… 要望があれば是非共有会とかしたいので コメントなど頂けると...! 43
  26. その他◯◯ってなに? Docker Compose:複数コンテナで連携した build, run を行うツール Docker machine:Docker 環境を整えるツール(プロビジョニング +

    インストール)          AWS, GCP, OpenStack などの Driver がある Helm:Kubernetes のパッケージマネージャ     クラスタや複数コンテナを連携した環境を1コマンドで構築するツール     (例: redis cluster, Wordpress) 46
  27. docker イメージの保存関連 Docker Image の保存と読み込み  docker save IMAGE -o image.tar 

     docker load < image.tar コンテナ生ファイル全体の保存(レイヤー情報などは保存しません)  docker export CONTAINER_ID -o container.tar  cat container.tar > docker import - imagename:latest   この工程を踏むとレイヤーが1つのイメージとなります。 48
  28. イメージの確認がしたい! そんなときはイメージのシェルを実行します  docker run -it IMAGE_NAME /bin/sh (ENTRYPOINT 未使用時)  docker run

    --entrypoint=/bin/sh -it IMAGE_NAME (ENTRYPOINT 使用時) ※ shell のパス (/bin/sh) が異なることもあります。 49
  29. run, exec, start などの違い docker run IMAGE  docker コンテナをイメージから起動する docker

    exec CONTAINER_ID  既存の docker コンテナで別のコマンドを実行する docker start CONTAINER_ID  処理が終了して停止している docker コンテナを再度起動する 50
  30. CPU のリソース制御 --cpuset-cpus:コンテナに割り当てる CPU の ID を設定 --cpu-shares:CPU 割当の重み (defualt:

    1024)  各コンテナが設定した値から相対的にスケジューリングされる  100, 100, 200 で割当てられていた場合、 1:1:2 の割合で CPU 時間がスケジューリングされる --cpus:割当 CPU (CPU 時間)  1.5 を指定した場合 1.5 コア相当の CPU 時間を利用 --cpu-period:CPU スケジューラのスケジューリング期間(1.13 で --cpus に代替)  cpus の指定を cpu-quota/cpu-period でしていた --cpu-quota:cpu-period 中割り当てる期間 (1.13 で --cpus に代替)  cpus の指定を cpu-quota/cpu-period でしていた 52
  31. Docker build 時の詳細 Sending build context to Docker daemon 670.3

    MB Step 1 : FROM docker.io/centos:7 ---> 3bee3060bfc8 Step 2 : MAINTAINER aoyama_masaya ---> Running in 19e9355a7478 ---> 1c5f31460904 Removing intermediate container 19e9355a7478 Step 3 : EXPOSE 80 ---> Running in 82dcdaa6c130 ---> 9edd36aaa131 Removing intermediate container 82dcdaa6c130 Step 4 : RUN yum -y install epel-release ---> Running in 90f51b35430a ---> 45c562b138a9 Removing intermediate container 90f51b35430a Step 5 : RUN yum -y install nginx ---> Running in 8dd7a5dfe5e0 ---> 142f6513d74a Removing intermediate container 8dd7a5dfe5e0 Step 6 : COPY nginx.conf /etc/nginx/ ---> d9ad771169e3 Removing intermediate container f1fe08180c9e Step 7 : ADD doc.tar.gz /usr/share/nginx/html ---> 7ec7c9895e87 Removing intermediate container f2c493556a91 Step 8 : USER nginx ---> Running in dbe346c5bf95 ---> 4ddbda493ef1 Removing intermediate container dbe346c5bf95 Step 9 : WORKDIR /usr/sbin ---> Running in 465403979c02 ---> 495d1aaa5b28 Removing intermediate container 465403979c02 Step 10 : ENTRYPOINT nginx -g daemon off; ---> Running in 7311256a5dc2 ---> 44324d6e2de3 Removing intermediate container 7311256a5dc2 Successfully built 44324d6e2de3 docker history で確認できる ID 一時的に走っているコンテナのID docker ps で確認可能 (docker run と同じ要領で writable レイヤーを一時的に生成して  コマンドを実行し、イメージを作成している) COPY, ADD などはイメージに埋め込むだけなので docker run はされない 53
  32. Kubernetes のリソース Pod:  1つまたは複数でセットのDocker コンテナを提供する Replication Controller / ReplicaSet:  特定の数の

    Pod を起動した状態に維持する Service:Pod へのエンドポイントを提供する  ClusterIP:仮想 NW 上に作られる VIP  ExternalIP:コンテナホストの IP を利用  NodePort:全コンテナホストの IP を利用  LoadBalancer:クラウド基盤用と連携 C C C C C Pod Replication Controller / ReplicaSets Endpoint Service
  33. Kubernetes 仮想ネットワーク External network Container-B Container-A Kubernetes のコンテナクラスタへのアクセス方法は主に2パターン  (ReplicationController で作成される

    Pod への Service は主に 2 パターン) Container-B Container-B Container-A Container-A Kubernetes cluster flannel internal network VXLAN overlay Service Service
  34. Kubernetes 仮想ネットワーク flannel internal network VXLAN overlay NIC NIC flannel.1

    flannel.1 External network docker0 docker0 minion minion Container-B Container-B Container-A Container-A 192.168.1.1 192.168.1.2 Kubernetes のコンテナクラスタへのアクセス方法は主に2パターン  (ReplicationController で作成される Pod への Service は主に 2 パターン)
  35. コンテナクラスタへのアクセス(1) flannel internal network VXLAN overlay NIC NIC flannel.1 flannel.1

    External network docker0 docker0 minion minion Container-B Container-B Container-A Container-A 192.168.1.1 192.168.1.2 flannel Internal network の VIP を利用(ClusterIP)  ただし疎通する範囲は Kubenetes のクラスタ内からのみ  = 外部公開はできない 10.254.0.y:80 > Container-A:80 への LB 10.254.0.z:80 > Container-B:80 への LB
  36. コンテナクラスタへのアクセス(2) flannel internal network VXLAN overlay NIC NIC flannel.1 flannel.1

    External network docker0 docker0 minion minion Container-B Container-B Container-A Container-A 192.168.1.1 192.168.1.2 External network を利用(ExternalIP, NodePort)  ポートフォワーディングする形  = 同じポート番号を使用できない 192.168.1.1:80 192.168.1.2:80 > Container-A:80 への LB 192.168.1.1:8080 192.168.1.2:8080 > Container-B:80 への LB
  37. Simple Docker and Problems # docker run IMAGENAME -p SRC_PORT:DST_PORT

    自ホストで Docker Container を起動するだけ 負荷分散や冗長構成で複数ホストでイメージを展開したい場合には...? ポートが空いているかの管理は...? リソースの管理は...? ヘルスチェックは...?  etc... Container Container Container # docker run... # docker run... # docker run...
  38. Overview of Built in Swarm LVS によるロードバランシング iptablesによるポートフォワーディング VXLANによるOverlay Network

    Ingress (IPVS + iptables + VXLAN) :8080 :8080 :8080 :80 192.168.0.1/24 192.168.0.2/24 192.168.0.3/24 192.168.0.1/24 192.168.0.2/24 192.168.0.3/24 Container Container Container Container Container Container Container
  39. Built in Swarm Ingress VXLAN overlay(Virtual Network over Physical Network)

    Container Container Container eth0 eth0 eth0 ingress(Container) ingress(Container) ingress(Container) 10.255.0.10/24 10.255.0.9/32 (VIP) 10.255.0.11/24 10.255.0.9/32 (VIP) 10.255.0.12/24 10.255.0.9/32 (VIP) 10.255.0.13/24 10.255.0.9/32 (VIP) 10.255.0.14/24 10.255.0.9/32 (VIP) 10.255.0.15/24 10.255.0.9/32 (VIP) 10.255.0.3/24 10.255.0.5/24 10.255.0.7/24 Container Container Container
  40. Built in Swarm :8080 Ingress VXLAN overlay(Virtual Network over Physical

    Network) Container Container Container eth0 eth0 eth0 10.255.0.10/24 10.255.0.9/32 (VIP) 10.255.0.11/24 10.255.0.9/32 (VIP) 10.255.0.12/24 10.255.0.9/32 (VIP) 10.255.0.13/24 10.255.0.9/32 (VIP) 10.255.0.14/24 10.255.0.9/32 (VIP) 10.255.0.15/24 10.255.0.9/32 (VIP) ingress(Container) ingress(Container) ingress(Container) iptables POSTROUTING ACCEPT dstPort 80 > setMark(外部から) dstIP 10.255.0.7 > setMark(内部から) 10.255.0.3/24 10.255.0.5/24 10.255.0.7/24 Container Container Container
  41. Built in Swarm Ingress VXLAN overlay(Virtual Network over Physical Network)

    Container Container Container eth0 eth0 eth0 10.255.0.10/24 10.255.0.9/32 (VIP) 10.255.0.11/24 10.255.0.9/32 (VIP) 10.255.0.12/24 10.255.0.9/32 (VIP) 10.255.0.13/24 10.255.0.9/32 (VIP) 10.255.0.14/24 10.255.0.9/32 (VIP) 10.255.0.15/24 10.255.0.9/32 (VIP) ingress(Container) ingress(Container) ingress(Container) 10.255.0.3/24 10.255.0.5/24 10.255.0.7/24 IPVS fwm > 10.255.0.10 > 10.255.0.11 > 10.255.0.12 > 10.255.0.13 > 10.255.0.14 > 10.255.0.15 Container Container Container
  42. Built in Swarm Ingress VXLAN overlay(Virtual Network over Physical Network)

    Container Container Container eth0 eth0 eth0 10.255.0.10/24 10.255.0.9/32 (VIP) 10.255.0.11/24 10.255.0.9/32 (VIP) 10.255.0.12/24 10.255.0.9/32 (VIP) 10.255.0.13/24 10.255.0.9/32 (VIP) 10.255.0.14/24 10.255.0.9/32 (VIP) 10.255.0.15/24 10.255.0.9/32 (VIP) ingress(Container) ingress(Container) ingress(Container) 10.255.0.3/24 10.255.0.5/24 10.255.0.7/24 iptables DOCKER POSTROUTING dstPort 80 > redirect 8080 ipvs > source 10.255.0.{3|5|7} Container Container Container
  43. Simply Orchestrate [1台目で実行] docker swarm init --listen-addr 0.0.0.0:2377 [2台目以降で実行] docker

    swarm join 192.168.100.44:2377 --token SWMTKN-* [コンテナの起動] docker service create --replicas 3 --name NAME --publish 80:8080 IMAGENAME たったのこれだけ。 クラスタの構築
  44. {,Dis}Advantages of Built in Swarm Advantages  簡潔な Orchestration (≈ docker

    run) Disadvantages  マルチテナント機能の欠如  replication 数に関わらず全ノードでPortをbind  外部疎通性のある VIP の払い出しが不可   大規模環境やContainerのIaaSには向かない?(個人的感想)  マルチテナント機能の欠如=セキュリティ的にいまいち  VIPが払い出せない=ポートの奪い合い
  45. Usecase of Docker Swarm (1.12) インフラ部門での基本サービス用クラスタとしては良さそう  DNS, DHCP, SMTP, NTP,

    ZooKeeper, Web, and multi-master services  ・マルチテナント性が不要  ・数台で構成するため全ポートでbindされても問題ない  ・ポートがそもそも被らない Github で config を管理   → 更新を元に Docker Image を生成      → Swarm の rolling update を適用