この記事はRancher Advent Calendar 2017の12/17の記事です。
さて、先週先々週とconfd、giddyupというRancherのStackを構成する上で重要なソフトを取り上げてきました。今週はそれを踏まえた上で一つ既存のカタログを改良してみたいと思います。
今回のターゲットはRabbitMQです。
RabbitMQって?
今更語るまでもない超有名なメッセージキューイング(MQ)のOSSですね。Erlangという他の言語とはまるで異なる文法で書かれています。
もっと詳しく知りたいかは公式ページや他の方が書かれたわかりやすいページを是非ご覧ください(丸投げ
コミュニティカタログのRabbitMQについて
既にRancherのコミュニティカタログにはRabbitMQが存在します。
んじゃこれでいいじゃん、となるところですが使ってみると
- 1node構成
- ユーザ/パスワード/vhostなどの本来rabbitmqコンテナイメージが持っている起動時の設定が出来ない
- 他にもpermissoinやpolicyの設定もできない
などあり、特に1node構成などは せっかくcluster構成が取りやすいソフトウェアなのに勿体ない! となります。
(前もってゴメンナサイm(. .)m)
今回は基本的にバージョン0.2.0を対象にしています。改良を始めた頃はまだ0.2.1はなかったんや 。・゚・(ノД`)・゚・。
やった!出来たぜ!ってなった時に改めてみたら0.2.1が...
コミュニティカタログのRabbitMQを試してみる
コミュニティカタログでRabbitMQを作成した場合、以下のような構成になります。コミュニティカタログでは割とオーソドックスな形です。
sidekickでvolumeコンテナを立ち上げて、conf用コンテナが設定ファイルを生成、volumeに設置、そしてメインコンテナがサービスを提供する、という形です。
あれ?何か変ですね。上の図だとメインがsidekickにいます。何故でしょう?
これは恐らくですがrabbitmq-confイメージ内に含まれているconfdに理由がありそうです。以前書いた記事をみるとわかるのですが、confdはRancherのmetadata-serviceと連携しているのですが、confdがsidekick側にいると上手くコンテナ名とかが取得できずに設定ファイルが生成出来ないのでは?と考えています。細かく検証していないのであくまで推論ですが...(なおsidekickにしたら失敗したっところまではやりました)
それとsidekick側にメインサービスがいて、ちゃんとそのコンテナにパケットが飛ぶのか?という疑問もあります。その秘密はnetworkにあります。
rabbitmq-base:
(中略)
net: "container:rabbitmq"
dockerのドキュメントをみると conteiner:<name/id>
は指定したコンテナのnetworkを間借りするみたいです。つまりここでは rabbitmq
つまり rabbitmq-conf
イメージのコンテナとnetworkを共有していることになります。ちゃんとサービスが提供できるわけです。
rabbitmq-confの中身をみてみる
ではrabbitmq-confの中身をみていきましょう。ここにDockerfileなどがあります
https://github.com/ddmng/catalog-dockerfiles/tree/master/rabbitmq/0.2.0
ディレクトリ構成はこんな感じ
|--Dockerfile <- 言わずもがなDockerfile
|--README.md
|--conf.d
| |--rabbitmq.toml <- confdが出力するファイルの設定
|--dockerentry.sh <- このコンテナのentrypoint
|--run.sh <- rabbitmq本体が起動するためのシェル、
|--templates
| |--rabbitmq.tmpl <- confdがファイルを作成するためのテンプレート
confd用のファイルが確認出来ますね。rabbitmq.tmplを覗いてみましょう。
{cluster_nodes,
{[
{{range $idx, $cnt := gets "/self/service/containers/*"}}{{ if (ne $idx 0) }},{{end}} 'rabbit@{{.Value}}'{{end}}
], disc} },
おや?なんかscale数に応じてnodeが増えそうに見える??
試しにscaleを3つに増やしてみましょう。
適当にproxyつけてGUIでみてみます。15672portがGUIです。
http://[自分のIP]:15672 にアクセスしてみます。
......
これはもしかして何もしなくていいのでは??
そんなことはない。コミュニティカタログ版の問題点
じゃあ、なんでコミュニティカタログは最初からscaleが3じゃないのでしょう?scaleを最初から3にして起動してみましょう。
あれ?1nodeだけ?
リロードしてみましょう
???も一回リロード
これはどういうことでしょう?つまり全てが 俺が!Primaryだっ!! って主張してバラバラに動いてるんですね。これは困りました。
1台をPrimaryとして上手く立ち振舞えないでしょうか?
Giddyupがあるじゃない!!
ここで前回取り上げたGiddyupです。
リーダーかどうかをチェックする機能があります。それにコンテナが規定数に達するまで待つこともできます。
# Waiting for leader service up
if [ "$( ${GIDDYUP} leader check ; echo $? )" -ne "0" ] ; then
echo "waiting..."
${GIDDYUP} service wait scale --timeout 120
# add wait
sleep 30
fi
sleep 30
を入れているのは実は giddyup service wait scale
を入れてるのは、本体はsidekick側にいるので 正確にリーダーのサービス起動のタイミングが確認出来ない という問題があり、しょうがなくsleepでごまかしてる感じです。わざわざcurl入れたくないし、いい手段があったらどなたか教えてくださいm(. .)m
(自分でgoあたりで簡単にチェックするアプリ作るのが一番なんでしょうけどね)
他の問題にも対応する
さて、最初に他にも問題があることを言いました。
- ユーザ/パスワード/vhostなどの本来rabbitmqコンテナイメージが持っている起動時の設定が出来ない
- 他にもpermissoinやpolicyの設定もできない
本来ならカタログからポチーっで全て設定したいのに、作った後にちまちま設定するのは非常に億劫です。
本来Rabbitmqイメージだとだと RABBITMQ_DEFAULT_USER
RABBITMQ_DEFAULT_PASS
RABBITMQ_DEFAULT_VHOST
で設定できるのですが、これをコミュニティカタログに追加したバージョンを作っても反映されません。どうやらconfdでrabbitmq.confが作成されたせいで、後からの変更を受け付けないことが原因です。
はてさて、どうしたものかと調べていると以下の記事が引っかかりました。
なるほど。既存の設定をjsonファイルに書き出してそれを設定して読み出すことが可能なようです。
ということで別に手動で設定したRabbitmqの設定情報をjsonファイルに出力してコネコネいじってconfd用のテンプレートを作成してみました。
というわけでrabbitmq-confの改良版をまとめるとこんな感じになります。
|--Dockerfile
|--README.md
|--conf.d
| |--rabbitmq_config.toml <- rabbitmq.tomlから変更
| |--rabbitmq_definitions.toml <- 追加
|--dockerentry.sh
|--run.sh
|--templates
| |--rabbitmq_config.tmpl <- rabbitmq.tmplから変更
| |--rabbitmq_definitions.tmpl <- 追加
そこから作成したイメージファイルはこちらです。
https://hub.docker.com/r/mdaichang/rabbitmq-conf/
集大成
さて、rabbitmq-confの改良が出来上がったところで、カタログに反映してみましょう。
https://github.com/m-daichang/rancher-catalog/tree/master/templates/rabbitmq-3/1
ユーザ/パスワード/vhostなどを設定できるようにしてみました。
stackを作ってみましょう。んで、proxyの設定を行い外から接続できるようにします。
やった!ちゃんと最初から3node見えてますね。他の設定は?
ちゃんと作成時に設定した情報が反映されているようです!
まとめ
さて、今回は先週先々週の集大成としてRabbitMQカタログの改修を行いました。
RabbitMQは元々clusterを作成することを考慮されて作られているため(というよりErlangがもともとそういう作りになってる?)、HA構成が取りにくいdockerでも比較的簡単に?clueter構成を取ることが出来ました。
今回はちょっと長めで、それでもあちこち端折ったので、内容的にはわかりづらかったかもしれませんm(. .)m
ただ、なんとなくやりたいことはわかっていただけたかと。このページを元に各ソースを眺めていただき、それでもわからない際はコメントいただけると助かります。