更新:2016/09/23 23:30
当初「EFKスタックで始めるDocker Compose on CoreOS」というタイトルにしていましたが、EFKに全然触れていないことに気付いたのでタイトル変更。
Dockerをどのようにサービスとして扱っていくか、という全体的なライフサイクル、運用的な部分を知りたくて、EFKスタックをDocker化して動かしていくにはどうするかということを学んでみました。要するにやりたいのは、 複数コンテナから成り立つサービスを、いかに永続化して動かすか。
前提
- ホストOSはCoreOSとする(元々さくらクラウドで借りていたので)。従ってローリングアップデートによるOS再起動への対応が必要。
- ただしCoreOS1台のみの構成のため、フェイルオーバーは考慮しない。
- 勉強のために各Dockerイメージは公式の配布イメージ等を使わず、自分でDockerfileを書く。
- DockerイメージのベースOSはAlpine linuxを使う。
複数コンテナの協働
いわゆるウェブサーバーとDBサーバーを別でコンテナ立てて一緒に動かすような需要。今回の場合はElasticsearch、Kibana、fluentdを別コンテナで立てることにした。前知識だと、この分野はDocker Composeを使えばいいのかな?と思っていたのだけど、CoreOSの場合はfleetがあることを知る。
fleet
CoreOSは複数のホストOSでクラスターを組み、その上でコンテナを動かすが、どのコンテナを動かすのかというスケジューリングを担うのがfleet。Systemdライクなつくりになっていて、Unitファイルを使って定義を記述し、それに沿ってCoreOSが必要なコンテナを上げる。
複数コンテナが必要な場合はそのようにUnitファイルを書いてしまえばいいので、fleetでもDocker Compose的なことはできる気がした。むしろCoreOSだとDocker Composeがデフォルトで導入されていないので、スケジューリングにはfleetを使うのが前提になっているのかもしれない? また複数コンテナのネットワーキングも、flannelというのを使うとできるらしい。
Docker Compose
一方のDocker Composeはyamlファイルを使って、どのコンテナが必要か、各コンテナにポートやボリュームなどのオプションはどのように与えるかという部分を定義していく。
version: '2'
services:
elasticsearch:
build: ./elasticsearch
volumes:
- /opt/esdata:/run/elasticsearch-2.3/data
ports:
- "9200:9200"
- "9300:9300"
kibana:
build: ./kibana
ports:
- "5601:5601"
fluentd:
build: ./fluentd
ports:
- "24224:24224"
個人的にはこのやり方がしっくりきたいので、Docker Composeを今回は使っている。というのも、UnitファイルはどちらかといえばOS側の定義という印象が強いし、fleetはDockerとは明確に別サービスになる。一方composeのyamlファイルであれば、そのDockerサービスのレポジトリの中に含めてしまえるので、Dockerサービスをパッケージングしているという意識が強くなる気がした。従って今回のファイル構成は以下のようになっている。
.
├── docker-compose.yaml
├── compose-efk.env
├── elasticsearch
│ ├── Dockerfile
│ └── elasticsearch.yml
├── fluentd
│ ├── Dockerfile
│ └── fluent.conf
├── kibana
│ └── Dockerfile
└── README.md
ディレクトリのトップにdocker-compose.yml
を配置し、各コンテナの定義はフォルダを分けて、必要なDockerfileや設定定義ファイルを入れておく。サービス全体の構成はdocker-compose.yml
を見ればわかり、コンテナの設定はフォルダでまとめることができるので見通しがよくなる。
chroju/docker_elasticsearch: elasticsearch with alpine linux
Docker Composeはdocker-compose
コマンドにより操作する。だいたいはdocker
コマンドと似た感覚で扱うことができる。まとめられた複数コンテナによるサービスは「プロジェクト」とされ、docker-compose.ymlの所在するフォルダ名がプロジェクト名(変更したい場合は-p
で指定が可能)となり、up
やstop
といったプロジェクトに対する操作は、基本的にカレントディレクトリ上のdocker-compose.ymlで記載されたプロジェクトへの操作になる。別のファイルを操作する場合は-f
でファイルを指定する。docker-compose
コマンドはまた別でまとめたい。
# コンテナを作成して起動
$ docker-compose up
# 起動中のプロジェクトを確認
$ docker-compose ps
# プロジェクトを停止
$ docker-compose stop
Docker Composeの永続化
CoreOSはローリングアップデートで自動再起動がかかるので、サービスを永続化するために何かしらの仕掛けが必要になる。Docker Composeはあくまで、複数コンテナを協働させるためのサービスなので、スケジューリングには対応していない。
fleet
これについてもfleetがCoreOSだとデフォルトで使われる。Unitファイルを定義してサービス化したDockerコンテナをfleetに登録しておくと、CoreOSが落ちた場合はクラスタ内の別のCoreOS上でコンテナを継続稼動させてくれる。なのでUnitファイルにDocker Composeのコマンドを書いて、fleetにサービスとして登録する。
[Unit]
Description=efk
After=docker.service
[Service]
ExecStart=docker-compose -f /opt/efk/docker-compose.yml -p efk -d up
ExecStop=docker-compose -p efk down
ただ、fleetにはsystemctl enable
に相当するコマンドはないため、単体ホストにおける自動起動については、cloud-config.yml
上で定義する必要がある。
coreos:
units:
- name: "fleet.service"
command: "start"
- name: "efk.service"
command: "start"
Docker Swarm
自分は使ったことがないのでなんともだが、Docker側が用意しているスケジューリングツールとしてはDocker Swarmが存在する。これもCompose同様にCoreOSには初期導入されていない。というのも、CoreOSは独自でetcdによるクラスタリングを行っているからだ。Swarmとetcdを並行導入して扱うというのが果たして行儀が良いのか、なんとも判断しかねるので今回はやめておいた。
DockerとCoreOSのエコシステムの相違
DockerにおけるSwarm、Composeと、CoreOSにおけるetcd、fleetがそれぞれ対応関係にあって、どちらを選んで実装するかが悩ましいように思えた。そもそもCoreOSは独自のコンテナ実装であるrktを開発しているので、Dockerのエコシステムとは別のものを進めたいのかとも思えるが、一方で両社はコンテナ仕様の統一も進めていて、よくわからない。
参考:Docker対抗のコンテナ型仮想化、CoreOSの「rkt 1.0」正式リリース。Dockerイメージも実行可能 - Publickey
現状コンテナを扱う上ではDockerがデファクト・スタンダードだとは思うが、エコシステムのベストプラクティスはどこから学べばいいのかというのが、まだ腑に落ちていない。