StackStormを公式Dockerイメージで動かす際のTips

今年(2017年)の春頃より、StackStorm公式のDockerイメージが公開されています。

- [Official StackStorm Docker Image is Here! (公式ブログ)](https://stackstorm.com/2017/04/21/official-stackstorm-docker-image-here/)
- https://github.com/StackStorm/st2-docker

これを使うと簡単にStackStormのコンテナを起動することが出来ます。[以前は色々と面倒だったよう](https://qiita.com/tkit/items/b78c9ff691e8d7661807)ですが、現在ある公式Dockerイメージはレポジトリにある `docker-compose.yml` を使えば特に難しいこと無く起動出来るようになっています。

README.mdに書いてある通り、

```
git clone https://github.com/StackStorm/st2-docker.git
cd st2-docker
make env
docker-compose up -d
```

これだけでOKです。実際に色々試すには `docker-compose exec stackstorm bash` でコンテナに入って `st2` コマンドを叩くか、もしくはWeb UIをいじくることになると思います。st2のパスワードは `make env` した際に作成される `config/stackstorm.env` に記載されていますので、そちらを確認してください。

さて、この公式Dockerイメージですが、使うにあたって幾つかTipsがありますので、以下に記載していきます。

# Tips

## 複数プロセスが1コンテナ内で起動する (Upstart)

いきなりDockerアンチパターン状態なのですが、とりあえずまずは早急に動くコンテナを公式で用意しよう、という方向性でスタートしたため、Ubuntu 14.04のベースイメージの上に、通常のサーバーにst2をインストールする場合の動作方式と全く同じように、Upstartでst2の各コンポーネントを起動するような形でイメージが作成されています。Ubuntu 16.04ベースにしてsystemdに変えるか？みたいな議論もありましたが、今のところそういった予定は全く無さそうです。

ちなみに公式イメージは1ppc = One Process Per Containerモード、すなわち1コンテナあたり1コンポーネント方式の動作方式も実はサポートしていて、まだ実験段階ですが試すことが出来ます。`runtime/compose-1ppc` にサンプルのdocker-compose.ymlと簡単なREADME.mdがありますので、興味がある方はトライしてみてください。1ppcモードを使うと、各コンポーネント毎にHA・スケールアウトがKubernetes等の環境で簡単に実現出来るようになるでしょう。

## `/opt/stackstorm/packs` をbind mountすると最初に詰む

StackStormはデフォルトで `/opt/stackstorm/packs` 配下にインストールしたpackのファイルを保管します。コンテナを再起動した時にインストールしたpackが消えないようにするためには、ここにDocker volumeをマウントするか、ホストのディレクトリをbind mountを使うことになりますが、後者の場合、もともとバインド先に存在していたファイルやディレクトリは自動的にコピーされません。さて、これの何が問題かというと、まずst2でpackをインストールする際に使う `st2 pack install` コマンドは、実は `packs` という名前のpackに依存しており、これがインストールされていないと使えません。そしてその `packs` packは標準で `/opt/stackstorm/packs/packs` にあります。つまりここをbind mountしてしまうと、永久に他のpackのインストールが出来ないのです。

これを解決するためには、面倒ですがbind mountするディレクトリに `packs` packのフォルダの中身を手動で全部コピーする必要があります。そしてその後 `st2ctl reload --register-all --register-setup-virtualenvs` コマンドでpackを登録してあげます。

ちなみに `packs` packは無いと本当にクリティカルですが、他にもデフォルトで `/opt/stackstorm/packs` の下に配置される core, chatops, st2, default の4つのpackも必須ですので、同じように手動でコピーしてあげましょう。

一時的にコンテナに `sys_admin` の権限を付与出来るのであれば、コンテナ内部で `/` をどっか適当な場所にbind mountしてあげると、元々あったファイルにアクセス出来るようになり簡単に取り出すことが出来ます。

```bash
# stackstormコンテナ内で

mkdir /tmp/tmproot
mount -o bind / /tmp/tmproot
cp -r /tmp/tmproot/opt/stackstorm/packs/* /opt/stackstorm/packs
st2ctl reload --register-all --register-setup-virtualenvs
```

## entrypoint.dとst2.dを活用する

コンテナ内の `/st2-docker/entrypoint.d/*.sh` はst2の各コンポーネントを起動する前に、`/st2-docker/st2.d/*/sh`はst2の起動後に実行されるようになっています。レポジトリにある `docker-compose.yml` を使うと、これらはそれぞれ `runtime/entrypoint.d` と `runtime/st2.d` にbind mountされるようになっています。今のところentrypoint.dの方には特に何もなく、st2.dの方にはデフォルトの5つのpackを登録するスクリプトと、サンプルのパックを登録するスクリプトの2つが配備されています。

この仕組みを使って、例えば以下のようなケースに対応出来ます。

- `/etc/st2/st2.conf` の内容を変更したい
-> entrypoint.dの方に `crudini` を羅列した.shを置いておく

- st2chatopsを起動するようにしたい
-> entrypoint.dの方に `rm /etc/init/st2chatops.override` する.shを置いておく

実際のところ、シェルスクリプトを実行するのでスクリプトで書けることは実質何でも出来ちゃいます。ただ、packで必要なライブラリパッケージのインストール等をするようなケース(例えば、具体的にはansible packをインストールするためには `libkrb5-dev` を追加インストールする必要あり)で、長い時間がかかるのであれば、それはもうDockerイメージ自体に含めるようにしてしまう、つまりカスタムのDockerイメージを作成したほうが良いと思われます。