何かと話題のDockerを最近よく聞くので使ってみたくなり,どうせなら面白いことがしたいなという理由だけでなんとなくMinecratのサーバーを立ててみることにしました.
ただそのまま普通に建てるだけでは何も面白くないので,ログをSlackに飛ばして監視しようかなと.
本番いきなりやるのは厳しいので仮想環境のUbuntuGnome 16.04で実験しています.
dockerのインストール
$ sudo apt-get update $ sudo apt-get install apt-transport-https ca-certificates $ sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D $ vim /etc/apt/sources.list.d/docker.list deb https://apt.dockerproject.org/repo ubuntu-xenial main
xenial以外の場合はhttp://docs.docker.jp/engine/installation/linux/ubuntulinux.htmlを参照してください.
$ sudo apt-get update $ sudo apt-get install linux-image-extra-$(uname -r) $ sudo apt-get install docker-engine $ sudo usermod -aG docker [ユーザ名]
これで準備完了です.一度再起動してhello-worldします.
$ docker run hello-world Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker Hub account: https://hub.docker.com For more examples and ideas, visit: https://docs.docker.com/engine/userguide/
成功です.一度よく分からないエラーが出たときには,最初から入れ直したら動きました.
構成
今回は
の3つで構成したいと思います.
Dockerのlog driverとしてfluentdを指定できるので比較的簡単にできました.
また,全てdocker-composeでまとめてしまいます.これめっちゃ便利です.
$ sudo apt-get install docker-compose
それに伴い,今回は以下のようなディレクトリ構造としました.
~/minecraft_server ├── docker-compose.yml ├── fluentd │ ├── Dockerfile │ ├── fluent.conf │ └── plugins └── minecraft └── Dockerfile
Minecraftコンテナ
今回は既存のコンテナを流用します.バニラ環境だけでなく,Spigotやforgeも使える用なのでMod環境を多く構築している人にも良いのでは?
$ mkdir minecraft_server $ cd minecraft_server $ mkdir minecraft $ mkdir fluentd $ vim docker-compose.yml minecraft: image: iztg/minecraft container_name: mc_server ports: - "25565:25565" volumes_from: - data-minecraft environment: EULA: "TRUE" VERSION: "1.10" data-minecraft: image: busybox container_name: data-minecraft volumes: - /data
このminecraftイメージでは,与える環境変数(environment)に応じたバージョンのMinecraftをダウンロードし,自動で動かしてくれます.
設定可能な項目はgithubのREADMEに書いてあります.
このまま
$ docker-compose up
して正常に立ち上がったら成功です.
上で書いたディレクトリ構成にはminecraftディレクトリとDockerfileが記載されていますが別に要りません(単体でテストしたときの名残でおいてあるだけです
Fluentdコンテナ
Fluentdはログを良い感じにしてくれる(ざっくり)ツールで,今回はSlackに投げますが他にも普通に標準出力したり,他のFluentdコンテナにパイプしたり,ファイルに出力したりといろいろなことができるすごいやつです.Elasticsearchとかとよく組み合わされているのをネットで見ます.
具体的な飛ばし方は上記のページに書いています.
では作っていきます.Slackのwebhook urlは用意できたものとして進めます.
$ mkdir fluentd $ cd fluentd $ vim Dockerfile FROM fluent/fluentd:latest-onbuild USER fluent WORKDIR /home/fluent RUN gem install fluent-plugin-secure-forward RUN gem install fluent-plugin-slack RUN gem install fluent-plugin-rewrite-tag-filter RUN gem install fluent-plugin-rewrite EXPOSE 24224 CMD fluentd -c /fluentd/etc/fluent.conf -p /fluentd/plugins -vv
gem install
でいくつかプラグインをインストールしています.このうちfluent-plugin-slack
によってSlackへ投稿します.
Minecraftコンテナからfluentdコンテナへログを流す設定をします.ルートディレクトリ直下のdocker-compose.ymlに追記します.
$ vim docker-compose.yml minecraft: # ...省略... links: - fluentd log_driver: fluentd log_opt: fluentd-address: localhost:24224 fluentd-tag: minecraft.raw fluentd: container_name: fluentd build: fluentd/ ports: - "24224:24224" volumes: - ./fluentd/:/fluentd/etc/ - ./fluentd/plugins:/fluentd/plugins environment: FLUENTD_CONF: fluent.conf
公式のイメージではfluentdディレクトリの直下にpluginsディレクトリとfluent.confを配置する必要があります.
fluent.confという設定ファイルで出力するログの設定を色々できるのですが,正直あまりまだわかっていないので効率的でない設定を書いていると思います.もっと良い方法がありましたら教えていただきたいです.
$ cd fluentd $ vim fluent.conf <source> type forward port 24224 </source> <match minecraft.raw> type stdout </match>
この状態でルートディレクトリ直下に移動し,docker-compose up
するとfluentdコンテナの標準出力からログが出力されているのが分かると思います.
$ docker-compose up # ...省略... mc_server| [11:15:35] [Server thread/INFO]: Starting GS4 status listener fluentd | 2016-09-07 11:15:35 +0000 minecraft.raw: { "container_id":"4243fdf6b63b393d4e4a2de749f359743d6a5920b9f26e22e7b36cbe03103412", "container_name":"/mc_server", "source":"stdout", "log":"[11:15:35] [Server thread/INFO]: Starting GS4 status listener" }
json形式のログストリームが流れてくるので,これを色々してSlackに投げます.
Slackに投げる
fluent-plugin-slack
Slackはあらかじめ用意しておいてください.まずはとりあえず適当に#console
チャンネルにログを流してみます.
$ cd fluentd $ vim fluent.conf <source> type forward port 24224 </source> <match minecraft.raw> type slack webhook_url https://hooks.slack.com/services/xxxx/xxxxxxx channel console username Minecraft Server message_keys log flush_interval 1s </match>
message_keys
がSlackに投稿されるテキストデータになります.また,flush_interval
は反映するまでのインターバルです.1s以内に出たログメッセージはまとめて投稿されます.
これでdocker-compose up
すれば以下のようになると思います.
fluent-plugin-rewrite-tag-filter
このままではINFOログに他のものが飲み込まれてしまって,必要な情報が埋もれてしまうのでpluginを活用して良い感じにしていきます.
まず,WARNING以上のエラーはwarningチャンネルに流し込んでいきます.
<source> type forward port 24224 </source> <match minecraft.raw> type rewrite_tag_filter rewriterule1 log WARN|ERROR minecraft.raw.error rewriterule2 log INFO minecraft.raw.info </match> <match minecraft.raw.info> type slack webhook_url https://hooks.slack.com/services/xxxx/xxxxxxx channel console username Minecraft Server message_keys log flush_interval 1s </match> <match minecraft.raw.error> type slack webhook_url https://hooks.slack.com/services/yyyy/yyyyyyy channel warning username Minecraft Server message_keys log color danger flush_interval 1s </match>
warningチャンネルを新しく作り,またwebhook_urlを取得する必要があります.
fluent-plugin-rewrite-tag-filter
は,ログのメッセージを正規表現で検索し,マッチした場合tagを書き換えることができるプラグインです.
意図的にエラーを起こす方法が特に思いつかないので,次はチャットの情報を抽出したいと思います.#chat
チャンネルを作り,webhook_urlを取得しておきます.
<source> type forward port 24224 </source> <match minecraft.raw> type rewrite_tag_filter rewriterule1 log \[INFO\]\:\s\<\S+\>\s minecraft.raw.chat rewriterule2 log WARN|ERROR minecraft.raw.error rewriterule3 log INFO minecraft.raw.info </match> <match minecraft.raw.chat> type slack webhook_url https://hooks.slack.com/services/zzzz/zzzzzzzz channel chat username Chat Log message_keys log flush_interval 1s </match> # ...省略...
rewriteruleの先頭にチャットを抽出するルールを追加します.チャットは[00:00:00] [Server thread/INFO] <ユーザ名> チャットテキスト
で表示されるため,以上のような(適当な)正規表現で抜き出しています.
ここでチャットログを抽出すると,以下のrewriterule2,3にはログデータがわたりません.つまり今回の場合,rewriterule3を先頭に(rewriterule1に)すると,チャットの抽出がされません.
ここでdocker-compose up
し,適当にMinecraftサーバにログインしてチャットを入力すると以下のようになります.
fluent-plugin-rewrite
[00:00:00] [Server thread/INFO]
って邪魔だなぁ…って思いません?ただのチャットだしいらない表示は消したいですよね.
ここでfluent-plugin-rewrite
を使います.
# ...省略... <match minecraft.raw> type rewrite_tag_filter rewriterule1 log \[INFO\]\:\s\<\S+\>\s minecraft.raw.chat rewriterule2 log WARN|ERROR minecraft.raw.error rewriterule3 log INFO minecraft.raw.info </match> <match minecraft.raw.chat> type rewrite add_prefix filtered <rule> key log pattern \[.+\]\:\s replace </rule> </match> <match filtered.minecraft.raw.chat> # ...省略... </match> # ...省略...
type rewrite
以下に<rule>
を追加し,
<rule>
はいくつでも追加することができ,ログに対して正規表現での整形が可能です.
上記のようなルールを設定すると以下のようにスッキリとしたチャットが表示されます.
また,ログイン時に色々とINFOログが出ますが欲しいのはjoinedというログだけなので,その他を消すためにruleを追加します.
# ...省略... <match <match minecraft.raw> type rewrite_tag_filter rewriterule1 log \[INFO\]\:\s\<\S+\>\s minecraft.raw.chat rewriterule2 log WARN|ERROR minecraft.raw.error rewriterule3 log INFO minecraft.raw.info </match> # ...省略... <match minecraft.raw.info> type rewrite add_prefix filtered <rule> key log pattern \[.+\.?\]\slogged\sin|TextComponent|UUID\sof ignore true </rule> </match> <match filtered.minecraft.raw.chat> # ...省略... </match> <match filtered.minecraft.raw.info> # ...省略... </match>
ものすごく適当な正規表現でごめんなさい…
これで以下のような感じになるはずです.
データのバックアップとリストア
せっかくデータコンテナを分離したので,手軽にバックアップが取れないかなぁと.
このminecraftイメージでは/data
以下にworldデータが存在するので,それをtarで固めてしまいます.
$ docker run --rm --volumes-from data-minecraft -v $(pwd):/backup ubuntu tar cvf /backup/back.tar /data
これでカレントディレクトリにback.tar
ができるはずです.解凍すればMinecraftのデータが入っていることが分かります.
リストアしてみましょう.
$ docker run --rm --volumes-from data-minecraft -v $(pwd):/backup ubuntu bash -c "cd /data && tar xvf /backup/back.tar"
おそらくこれで問題なくリストアできます.
僕は既に稼働中の他のサーバのデータを引っ張ってこようとしたら色々エラーを吐かれて泣いています.誰か方法教えてください(泣)
総評
強い人が既に作製した強いイメージを簡単に使えるのがdockerの良いところな気もします.ものすごく簡単にここまで持ってくることができました.
あとはバックアップとリストアの仕組みがちゃんとできれば…
良いアイデア募集しています.