これまでLinuxの開発サーバー上のシェルコマンドでDockerのビルドやイメージのプッシュ、GKEへのデプロイをしていたけど、先日のGitHub Actionsの発表など世の中CI/CDが当たり前になっているので、DockerとGCPでできる範囲でやってみる。
Cloud Buildについて
Gitレポジトリへのプッシュなどに反応して、Dockerfileのビルド、もしくはcloudbuild.yamlに書いたコマンドを実行してくれる。
今回は元々Dockerでやってたので、Dockerfileでやる。
ビルドしたあと、Container Registryにイメージをプッシュしてくれるところまで。
GKEへのデプロイはまだどうやるかわからない。
ソースコードのレポジトリを用意
対象のソースコードは下記。今回はGitHubに公開していたので連携して使う。
github.com
node.jsで動いてHTMLをPDFにするだけのシンプルなアプリケーションなので自動テストもしやすくて。ちょうどいいため。
GCPをすでに使っていて、GitHubか公開する気がないのであればCloud Source Repositoriesでいいと思う。
Cloud Source Repositories - コードを保存、管理するためのプライベート Git リポジトリ | Source Repositories | Google Cloud
* テストを準備
今回はmocha, chaiでユニットテスト、superagentを使ってリクエストのテストを書いた。
網羅性は気にせず、本番で使っている動かないとまずいリクエストや、手動でテストが難しく不安なところだけ書いた。
テストが書けたら稼働中のコンテナ内でmochaコマンドを実行して、大丈夫だったらDockerfileに下記を追加してdocker build時に実行する。
Dockerfile
// 省略 COPY test /hcep/test RUN mocha // 省略
expressが終了しない問題
テストが終わってもexpressのコネクションが残っているようで、express.close()しても終わらず、ちょっとハマった。
下記のような丁寧な解決策もあるようだけど、今回はテストと割り切りprocess.exit()することに。
node.js - How Do I Shut Down My Express Server Gracefully When Its Process Is Killed? - Stack Overflow
describeのafter内でprocess.exit()してしまうとChrome側でまだ生きているというエラーが出たので最後に5秒sleepするようにしたら大丈夫だった。
test/requests.js
// 省略 const sleep = (waitSeconds, someFunction) => { return new Promise(resolve => { setTimeout(() => { resolve(someFunction()) }, waitSeconds) }) } describe('requests routes', (done) => { let app before(beforeDone =>{ (async() => { const browserPage = await hcPage() app = await expressApp(browserPage) beforeDone() })() }) after(afterDone => { (async ()=> { await app.close() sleep(5000, () => { console.log('process.exit!') process.exit() }) afterDone() })() }) const req = request(SERVER_URL) it('Health Check GET /hc', async () => { await req.get('/hc') .expect(200, 'ok', done) }) //以下略
before、afterの中でasync無名関数を実行しているのはbefore、afterがPromise返しに対応していないのか、だめだったため内部で同期処理するようにした。
もっとスマートな方法がありそう。
テストがこけるとビルドも止まりエラーで終了する。
ビルド結果のslack通知もほしいけど、Cloud Pub/SubとCloud Functions連携が必要になるのだろうか。めんどい。
Cloud Buildを設定
トリガーの設定は先程のGihHubのレポジトリを指定して、アカウント連携する。
イメージ名のタグに$COMMIT_SHAを入れた以外、特に設定は変えずそのまま。
これでビルドが成功したらコミットハッシュ付きのイメージがContainer Registryにプッシュされていくようになった。
動作確認
Cloud Buildの履歴で標準出力されたログを確認することができる
無事テストも実行されて通っている。
実行時間もcorei5 4コア、メモリ32GBのローカルサーバーに比べると、コミットごとと思えば遅いけどまあ問題ないレベル。
前回のビルド中にまたpushしてもビルドは再実行されない模様。その場合は手動で実行すればよさげ。
これから
他のCIツールと比べるとできることは少なそうだけど、GitとDockerfileを使っていて、Container Registryにアップするまでならシンプルですぐ使えると思った。
もっといろいろしようとすると独自のcloudbuild.yamlで書く必要があるのでちょっと面倒。
あとはステージング、本番環境への自動デプロイができればCDまでいけそう。
個人的にはすべての開発をクラウド上でやりたくてローカルマシンは端末、エディタとしてだけ使うような開発環境が理想。
- 作者: 山田明憲
- 出版社/メーカー: 技術評論社
- 発売日: 2018/08/25
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (1件) を見る