【追記】docker-composeを使って環境ごとにprofileの異なるSpringBootプロジェクトのサーバ立ち上げを少しでも安心できるようにする
こないだこういうことをやりました。
mao-instantlife.hatenablog.com
結論として、環境変数SPRING_PROFILES_ACTIVEをセットすれば良いんじゃないかという所までは行きましたが、まだまだ事故りそうで怖いですね。サーバへの環境変数設定を忘れたり、間違えたり。現在の所は、私が扱っているプロダクトは、アクセス数も限定されているものが多いので大きな問題にはなっていませんが、デプロイやスケールアウトが容易な(自動化しやすい)状況を作っておくにこしたことはありません。
この辺り、dockerを使って楽にならないかと考えていて、ちょっと試してみたのでまとめておきます。
必要なツールのインストール
- docker-machine
- docker-compose
VirtualBox5をインストールしている人は、docker-machineのインストールで注意が必要です。公式のインストール用のコマンドは0.3.0のURLになっているので実行時に0.3.1に変更して上げてください。
参考: mao-instantlife.hatenablog.com
その他はあまりインストールで迷うことはないと思います。
docker-composeでサーバをスケールするまで
docker-composeで各環境用のサーバを作り、それをスケールさせるところまでやってみようと思います。
ホストを作る
まず、dokcer-machineを使ってdockerコンテナを動かすためのdockerホストを作ります。これがないと何も始まりません。
docker-machine create -d virtualbox dev
ホストを作ったら、dockerコマンドがホストを捜すための環境変数をセットする必要があります。macかlinuxであれば、以下のコマンドを実行すれば環境変数にセットされます。
eval “$(docker-machine env dev)"
これでdockerにコンテナを作成する準備ができました。
Dockerfile
を書く
dockerホストを作ったので、そのホストでアプリケーションが動くコンテナ毎の設定を作成します。先日のSpringBootCampの資料を参考に作りました。プロジェクト直下にDockerfile
という名称で以下のようなファイルを作成します。
FROM java:8 ADD build/libs/app-1.0.jar /opt/spring/app.jar EXPOSE 8080 WORKDIR /opt/spring ENTRYPOINT [“java”, “-Djava.security.edg=file:/dev/./urandom”, “-jar”, “app.jar”]
とりあえずこのコンテナが動くかどうか確認してみましょう。まずはこのDockerfileに従ってイメージをビルドします。
docker built -t apptag ./
Dockerfileにシンタックスエラーがあったりするとここでエラーになるはずです。-t
オプションは、イメージにタグ付けして、そのタグ名を後で使えるようにするためのものです。
次に作ったイメージでコンテナを実行します。
docker run -ti --rm -p 8080:8080 apptag
apptagイメージを使ってホストの8080ポートにアクセスすると、コンテナの8080ポートと連携するように実行しています。-rm
オプションは終了時にコンテナを破棄してくれるオプション、-p
オプションはポート連携のプションです。書式は[HOST_PORT]:[CONTAINER_PORT]
となっています。ホストの8081に連携するコンテナを実行したい場合は以下のようにコマンドを叩いてください。
docker run -ti --rm -p 8081:8080 apptag
環境変数付きで実行したい場合は以下のようなコマンドになります。
docker run -ti --rm -e “SPRING_PROFILES_ACTIVE=product” -p 8080:8080 apptag
docker-compose.yml
を書く
前項でやったイメージのビルドやコンテナの実行などを各環境ごとで毎回手動で実行しても良い(良くないけど)のですが、面倒ですよね。これらの構成管理と実行をして、ラベリングした状態で実行できるようにするツールがdocker-composeです。
プロジェクト直下にdocker-compose.yml
という名前で以下のファイルを作成します。このファイルがdocker-compose実行のための構成ファイルになります。
webapp: build: . development: image: project_webapp ports: - “8080" environment: SPRING_PROFILES_ACTIVE: dev product: image: project_webapp ports: - “8080" environment: SPRING_PROFILES_ACTIVE: product
再度になりますが、イメージをビルドしましょう。buildサブコマンドは、構成ファイル内のbuildプロパティが指定されているものをすべてビルドします。
docker-compose build
次に、development環境のコンテナを実行しましょう。
docker-compose up development
upサブコマンドは構成ファイルに基づいて、必要なイメージのビルドをした上で実行してくれます。なお、環境名を省略すると、構成ファイルに記載のすべての環境が実行されます。
ちなみに、構成ファイル上ではホスト上のポートについては指定してないので、実行しているコンテナがホストのどのポートに関連づけられているかはdocker ps
コマンドで確認します。
development環境をスケールさせてみます。
docker-compose scale development=3
これで、コンテナが3個になるまでdevelopment環境のコンテナを実行します。実行後にdocker ps
で確認してみると3個のコンテナが立ち上がってそれぞれに別のホスト上のポートが割あたっているはずです。scaleサブコマンドで指定する数値は、ホスト上で稼働する既に起動している数を含めた総コンテナ数なので、今回の流れでやった場合、新しく作られるコンテナの数は2個になります。
dockerコマンド単体で使っているときよりもだいぶすっきり実行できます。
【追記】ロードバランシングしてみる
ロードバランサについては、槙さんから以下のような指摘をいただき、試したらさくっとできました。
@mao_instantlife nginxのは http://t.co/dSczFj0XgR で言ってたのとは異なります?
— Toshiaki Maki (@making) 2015, 8月 7
docker-compose.yml
に以下のように追記します。
lb: image: jwilder/nginx-proxy ports: - "80:80" volumes: - "/var/run/docker.sock:/tmp/docker.sock" webapp: build: . development: image: project_webapp ports: - “8080" environment: SPRING_PROFILES_ACTIVE: dev VIRTUAL_HOST: dev.webapp.com product: image: project_webapp ports: - “8080" environment: SPRING_PROFILES_ACTIVE: product VIRTUAL_HOST: product.webapp.com
追記後、資料の通りに/etc/hosts
ファイルを修正し、ロードバランサを立ち上げます(試したときは、いったん全てのコンテナをクローズしています)。
docker-compose up lb
ローバランサを立ち上げた後、開発環境を幾つか立ち上げてみます。
docker-compose scale development=3
これで、hostsファイルに指定したドメイン名で80ポートにアクセスすると、アプリケーションにアクセスできるので、ロードバランサは上手く機能しているようです。ポートをごにょごにょする必要はなかった、という。。。
これ、各環境用のdockerホストは変わる訳だし、各環境用のVIRTUAL_HOST
の設定を異なる値にして80ポート以外をアクセスできない様にすれば、間違えて別環境用のコンテナを実行してしまってもアクセスできなくなって安全かな、と思いました。間違って実行してしまうことは(手作業してしまえば)不可避なので、間違っても事故らない様にできれば良いかと。これについてはまだ未検証なので、週明けに追加で検証したいと思います。
詳細
公式のドキュメントがまとまっているので、それぞれのツールの詳しいことはこちらを参照してください。
https://docs.docker.com/machine/
https://docs.docker.com/compose/
【修正】これから
とりあえず、環境を指定してのコンテナ作成とスケーリング、ロードバランサによる負荷分散までができました。まだ、環境ごとの相違点が環境変数一つしかないため *1 、恩恵というほどの恩恵は受けていませんが、サーバ構成の相違点が増えるに従って恩恵が得られるようになりそうです。動く環境がほとんどリポジトリの中に表現できることになって非常に見通しが良いですね。
やったことは、名前を付けてコマンドでシンプルに扱えるようにした、ということなんですが、それだけでも見通しがかなり良くなります。シンプルなコマンドになれば、それだけ自動化にも取り組みやすくなるということなので、今回試したのは割と実りが大きかったと感じました。ほとんど触りだけでこの便利さなので、使い倒せばもっと恩恵が受けれるのではないかと期待してしまいました。
ちなみに、やってしまってから気づいたことが一つ。今回憲章のために実験台にしているアプリ、社内用のツールなのですが、扱うデータの関係上インターネットにつなげないサーバなんですよね。。。構築済dockerホストかビルド済イメージをどうにかしてサーバに渡さないとそもそもdocker使えないという。。。次調べることはこれになりました。
*1:アプリケーションの環境ごとの相違点はapplication.ymlで吸収しているのでなおさら