Google App Engineへのデプロイをgithub -> werckerで自動化する(手動でもできるようにする)


Google App Engineってサーバレスで大体のものは作れるので、とっても便利な感じです。
ただ、デプロイしようとすると、どこかのマシンなりサーバでdeployコマンドを叩かないといけません。
特定の開発者のマシンに依存すると、デプロイの回数が多くなると負担になりますし、マシンがクラッシュするとデプロイできなくなる……という難点が。
とはいえ、デプロイ用のサーバをわざわざ用意すると今度は24/365で費用がかかるというデメリットが。

という訳で、werckerを使ってみようと思います。
staging環境は指定のブランチにpushされる度に自動デプロイ、本番には任意のタイミングで手動でデプロイできるようにしてみようと思います。

※使用したソース
https://github.com/fumihiko-hidaka/gae-deploy-test

簡単な仕組みの図

デプロイ設定ファイル(wercker.yml)の構成

google/cloud-sdk:alpineのdockerイメージをベースとして、buildとdeployの二段構成になってます。
実際にはcomposerとかもあるんですが、今回はテスト用のプロジェクトなので一旦はhello worldのphpだけで。

box: google/cloud-sdk:alpine
build:
    steps:
        - script:
            name: end build
            code: |-
                echo build 🙆‍

deploy:
    steps:
        - script:
            name: make auth json file
            code: |-
                echo $GAE_DEPLOY_TEST_KEY_FILE > service.json
        - script:
            name: gcloud auth
            code: |-
                gcloud auth activate-service-account "$GAE_DEPLOY_TEST_ACCOUNT" --key-file "$WERCKER_SOURCE_DIR"/service.json --project "$GAE_DEPLOY_TEST_PROJECT"
        - script:
            name: decript .env
            code: |-
                gcloud kms decrypt --location=global --keyring="$GAE_KEYRING_NAME" --key="$GAE_KEY_NAME" --ciphertext-file=cloud/"$ENV_FILE_NAME" --plaintext-file=.env
        - script:
            name: get timestamp for tag
            code: |-
                apk --update add tzdata
                cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
                GAE_TAG=`date +"%Y%m%d-%H%M%S"`
        - script:
            name: deploy gae
            code: |-
                echo Y | gcloud app deploy --version "$GAE_TAG" --project "$GAE_DEPLOY_TEST_PROJECT"
        - script:
            name: delete old version
            code: |-
                sh cloud/remove_old_branch.sh

buildでやっていること

  • ビルドOKの記念のecho

まぁつまり……ほとんど何もしていません。
ここで.envファイルの復号等してしまうと、次のパイプライン処理に引き継がれてしまうので。
staging用の処理を入れてproducionでも動いちゃったーとかにならないようにしています。

deployでやっていること

  • GCPへの認証処理
  • DBへの接続情報など環境ごとに異なる情報をまとめた.envファイルを暗号化したものを復号
  • 日本時刻で日付を処理したかったのでパッケージの追加
  • GAEへのアプリケーションのデプロイ
  • バージョンの保持数に限度があるので、10個以上のバージョンがあれば古いものから削除する処理

gcloudコマンドでgcpへの認証を通した後、gcpのKMSを使用して.envファイルの復号を行っています。
この時の認証用のjsonファイルは、対象の.envファイルなどの認証時に必要なパラメータは
werckerのEnvironmentに登録しておくことで、build実行時に参照できるようにしておいてあります。

詰まったところ

  • GCPに認証用JSONファイルから改行を削除しておかないと、コンテナの処理の中で\nなんていう文字があるからjsonとしてparseできないんだけど?と怒られたところ……改行を削除したけど何か違う気が
  • デプロイを行わせるユーザには「App Engine デプロイ担当者」「App Engine サービス管理者」「クラウド KMS 暗号鍵の復号」「ストレージのオブジェクト管理者」の権限がないとコケます😱
  • gcloud authに読ませる認証用のjsonファイルをそのままwerckerに登録すると、他のユーザで参照し放題になるのでprotectedのチェックを。
  • app.yamlのskip_filesを明示的に設定しないと、「.env」ファイルがアップロードされませんでした……

werckerの設定

GitHubのリポジトリとwerckerのWebHookの登録は略で。
これでpushする度にstaging上のgaeが自動的にdeployされます!

  • 本番とstaging環境のdeploy用に2つのpipelineを用意
  • ただ、build後に実行されるのはstaging-deployだけになるようにする
  • production-deploy、staging-deployともにwercker.ymlの「deploy」の処理を実行する
  • 誰かがpushする度にstagingがその環境に切り替わるのも困りものなので、release/, hotfix/ の命名規則に一致するものだけ、staging-deployのpipelineが動くようにしています

手動で実行する場合

buildが終わったものに対して、画面からポチッと!