実環境でDockerを使い始めてみよう、と思うけど考えないといけないことが色々ありそう。どんなことを考える必要があるか、それぞれどうしていくのが良いか、考えてみる。
導入の目的
以下を目的にする。
- アプリケーションのポータビリティ
- 開発・テスト環境と同じイメージを本番でも利用することで、環境差異に起因するトラブルを減らす
- サーバが増えた際に、簡単に同じアプリケーション環境をセットアップできるようにする
- リソースの分離
- 同じサーバに複数のアプリケーションが乗った際に、それぞれの環境やOSリソースを分離し、お互いに影響しないようにする
導入の対象は、まずはデータをストアしないjavaアプリケーションサーバとする.
考える事
いざ、使ってみようと思うと以下のような点が悩ましくなってきた。
- イメージを作る単位
- 既存の構成管理ツール(Ansible)との連携
- ネットワークをどうする?外部からどう接続するか
- 起動先の環境に依存する部分をどう吸収するか
考えてみる
さて、どうしようか
イメージを作る単位
イメージの差分管理ができる、とは言え何か変わる度に一直線に更新をしていくのもなんか違う気がする.
以下のようにレイヤを分けて作るのが管理しやすいのでは、と考えた.
- baseイメージ
- OSの基本パッケージと、構成管理ツールをインストールしたイメージ.
- ミドルウェアイメージ
- baseイメージを元にビルドする. アプリケーションデプロイの手前までの環境を提供する
- 割と複雑になりそうなので、Dockerfile内からAnsible playbookを呼び出すことで実行する
- アプリケーションイメージ
- ミドルウェアイメージに対して、アプリケーションをデプロイして使える状態にしたイメージ
新しいアプリケーションをデプロイする際は、最新のミドルウェアイメージを利用して新しいアプリケーションイメージを作成する. もしミドルウェアの設定変更などが発生した場合は、ミドルウェアイメージを再作成し、それを元に再度アプリケーションイメージを作成する.
それぞれのレイヤごとに更新の頻度も違うし、更新を入れる担当も違うのでこのように分けて、それぞれのレイヤでバージョンを管理していくのが良さそう.
既存の構成管理ツールとの連携
Ansible playbookの資産があるので、再利用したい. また、Dockerfileは基本コマンドを羅列するだけなので、ある程度複雑になってくると辛い. Dockerfileだけで環境を作ることもできるが、メンテナンス性や再利用性を考えると構成管理ツールは必要だと思う.
そこで、DockerfileからAnsible playbookを実行して環境を構築することにする.
通常ansible-playbookはSSH経由で実行するが、そのためにコンテナの中でsshdを上げるのも。。。と思ってたら、SSHを使わなくても実行できるらしい. Local Playbooks
playbookをDockerfile内でADDするか、VOLUMEに置くかしてコンテナから見えるようにすれば、コンテナに対するplaybookの適用はできそう.
ネットワークをどうする?
普通にコンテナを起動すると、Dockerホスト内のプライベートネットワーク空間に入るので、外部からどう接続するかを考える必要がある.
ドキュメントによると、ネットワークのオプションもいくつかある.
--net=bridge
(デフォルト)- Dockerホストが提供する仮想ブリッジに接続される. 外部にポートを公開するにはexposeする必要がある
--net=container
- 起動済みコンテナのネットワークスタックを再利用する. ネットワークスタックを共用しているコンテナ同士は、localhostで通信できる. 外部から繋ぐには、やはりexposeが必要
--net=host
- ホストのネットワークスタックをそのまま利用する. 普通にホストの中にプロセスが起動しているのと同じ状態になる.
IBMの検証結果や、こちらによると、--net=bridge
だとNATのオーバーヘッドにより--net=host
に対して20%程度性能が落ちる場合があるらしい.
ただ、--net=host
だと同一ホストで複数コンテナ起動する場合にはポートがバッティングしないように何かしら工夫する必要がある. --net=bridge
だとdocker run
するときにオプションでマッピングを変えればいいので、そっちの方が扱いやすいか. これは、とりあえず両方試してみて後で決める.
外部からの接続方法については、Kubernetesとか、serf+HAProxy/nginxとか、カッコイイ方法はありそうだけど、とりあえずは手で接続元やHAProxy等の設定を変更することにする. 自動化は後.
起動先の環境に依存する部分をどう吸収するか
実行環境がコンテナ内に固められている、とは言えやはり環境に依存する部分はあり得る. アプリケーションサーバから接続する先のDBとか、ホストのメモリに応じてコンテナ内のjavaアプリケーションサーバのヒープサイズを変えたいとか、自ホストのIPアドレスが設定ファイルに書かれている場合とか.
調べてみると、docker run
に-e
オプションを付けて環境変数を渡すことはできそう. すると、環境変数を元に関連する部分を書き換えた上でアプリケーションサーバを起動するようなラッパースクリプトを作り、DockerfileのCMD
でコンテナ起動時に実行するようにする必要がある.
以下が参考になりそう
他には?
ログをどうするとか、モニタリングとか、他にも色々考えることはありそうだけど、とりあえずここまで.