経緯
クローズドな環境で動いている非常にシンプルなCMSを、一部Docker環境へ移行しました。
このアプリケーションは簡単に3つのサービスで構成されており、それぞれ以下の様な感じです。
・CMS(htmlのみ)
・API(SpringBoot)
・Backend+Batch(SpringBoot)
本格的にDockerに置き換えるのは初めてだったのと、クローズドな環境で身内しか使っていないシステムだったので、今回Docker化するにあたり無停止アップデートは考慮しませんでした。
また、データベースのDocker化とBackendのDocker化は行いませんでした。内部の専用のサーバーで動いておりローカルディスク内にBackendが処理したファイルを配置する必要があったためです。
BackendのDocker化も将来的には行う予定ですがRDBMSのPostgreSQLは今のところDocker化は・・・迷い中。
各サービスの簡単な説明
・CMS
BackboneとMarionetteで作られたCMS。
ビルドはGruntで実行し成果物をDockerへADDで追加。
・API
SpringBootにて稼働。
CMSからのAPIリクエストに対してJSONで返す。一部Postを受け付けてDBを更新している。
Mavenでjarを生成して、生成したjarファイルをDockerへADDで追加。
・Backend
SpringBootにて稼働。
内部のSchedulerが定期的に外部のAPIにアクセスし取得したデータをDBに更新したり、バイナリファイルをダウンロードして保存したりしている。
バージョンアップ
Jenkinsでジョブを作成して流しています。
以下は、APIの場合です。
(1)テスト&ビルド
起動時に、パラメータとしてgitでチェックアウトするタグと、アプリのバージョンを指定しています。この時指定されたバージョンはイメージのビルド時、コンテナの起動時に指定します。
テスト&ビルドして成果物を保存。具体的にはjarとDocker起動用のpythonスクリプトとDockerfile。
(2)Dockerコンテナの作成
[bash]
docker build -t app-api:$APP_VERSION .
[/bash]
と実行。
(3)Dockerコンテナの起動
どうやろうか迷ったのですが無停止アップデートは想定しなかったので起動中のアプリコンテナを終了→(2)でビルドしたアプリコンテナを起動してます。
jenkinsにシェルファイルを実行でも実現できたのですが、コンテナの起動オプションも大事なのでレポジトリで管理してビルド時にビルドディレクトリにコピーしてます。
[bash]
python target/wdocker.py $APP_VERSION
[/bash]
Dockerコンテナからホストで起動しているPostgreSQLへ接続
--add-hostでホストのIPを指定してます。
[bash]
docker run --name app-api-0.0.3 -i -d --add-host=db:ホストのIP -p 8080:8080 -v /etc/localtime:/etc/localtime:ro -e LANG=ja_JP.UTF-8 app-api:0.0.3
[/bash]
はまったこと
無停止アップデートを想定していないので必然的にあんまりはまりどころはありませんでした。
コンテナ内のタイムゾーン設定がUTCになっていて、Javaのアプリケーションで現在時刻を指定しているところが軒並みうまく動かなくなったので、docker run時のオプションにタイムゾーンの設定を行って対応しました。アプリケーションでうまく動かなかったのはこの部分だけ。
あとはすんなり。
まとめ
SpringBootは元々jarファイルのみで固めてjavaコマンドで実行できるので元々ポータビリティは高いと思いますが、今回Dockerコンテナ内に配置したことで更にポータビリティが高まりました。
今までAnsibleを使ってデプロイをしていたのですが、Dockerで動作環境まで準備できるのは本当に楽。今思ったら、Ansibleは色々できるから無理に複雑にしすぎてたのかもしれない・・・。
あとは、バックエンドとPostgreSQLもDocker化してもう少し様子を見てみる予定。