最近GitHub Actionsを触り始めました。
リポジトリで発生したイベントをトリガーに処理したり、JavaScriptでActionを作ってパッケージにして公開できたり、かなり遊べそうな感じなのですが、まずはベーシックな使い方としてCI/CDパイプラインを構築してみたので記録します。
アプリケーション
TypeScript(Node.js)で作ったTwitter botのアプリケーションを対象とします。
構成
name: Node.js CI
on:
push:
branches: [master]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
os: [ubuntu-latest]
node-version: [12.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: yarn install, and test
run: |
yarn
yarn test
env:
CI: true
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: yarn install and build
run: |
yarn
yarn build
- name: upload dist
uses: actions/upload-artifact@main
with:
name: dist
path: dist
deploy:
needs: [test, build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: douwnload dist
uses: actions/download-artifact@main
with:
name: dist
path: dist
- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@master
with:
project_id: ${{ secrets.GCP_PROJECT_ID }}
service_account_key: ${{ secrets.GCP_SA_KEY }}
export_default_credentials: true
- name: Setup Node.js
uses: actions/setup-node@v1
with:
node-version: "12.x"
- name: Load Env Variables
run: node ./ci/load-env-variables.js
env:
APP_TWITTER_COSUMER_KEY: ${{ secrets.APP_TWITTER_COSUMER_KEY}}
APP_TWITTER_COSUMER_SECRET: ${{ secrets.APP_TWITTER_COSUMER_SECRET}}
APP_TWITTER_TOKEN_KEY: ${{ secrets.APP_TWITTER_TOKEN_KEY}}
APP_TWITTER_TOKEN_SECRET: ${{ secrets.APP_TWITTER_TOKEN_SECRET}}
APP_TWITTER_BOT_ACCOUNT_ID: ${{ secrets.APP_TWITTER_BOT_ACCOUNT_ID}}
- name: Deploy App to GAE
run: |
gcloud app deploy
rm -f app.yaml
- masterブランチへのpushをトリガーにワークフローが起動します。
- test, build, deployというJobによって構成されます。
- test, buildは並列で実行されます。deployはtest, buildの完了をもって実行が開始されます。
test
jestを実行します。今回はユニットテストしか行っていませんが、静的解析ツールによるチェックなどを入れてもいいでしょう。
strategy.matrixに、テストを実行する環境の組み合わせ(OS, 言語のバージョン)を指定することで複数の環境でのテストを実行可能です。
今回はUbuntu, Node.12.xで指定しました。
build
yarn build(中身はtscでのコンパイル)で、コンパイル済みの成果物(distディレクトリ)を出力します。
distディレクトリはdeployステップで必要なので、artifactとしてアップロードしておきます。
生成されたdistはJob間で共有することができないためです。
アップロードされたartifactは、ワークフローの詳細画面からダウンロードすることもできるようです。
deploy
needs
に、test, buildを指定しているため、test, buildのJobが完了してから実行されます。
buildでアップロードされたartifact(distディレクトリ)をダウンロードします。
次に、GCPのCloud SDKの初期化を行います。
初期化処理は、それ用のアクションが提供されているので使いましょう。
https://github.com/google-github-actions/setup-gcloudGCP_SA_KEY
には、GCP管理画面から取得できる秘匿情報のjsonをbase64でエンコードした文字列を指定します。
secretsはリポジトリのsettingsから設定可能です。
その後、secretsに設定された環境変数をapp.yaml
に埋め込みます。
最終的にgcloud app deploy
するときに参照されるapp.yaml
にアプリケーションで使用する環境変数を指定する必要があるのですが、APIキーなどはGitの管理下に置くことができません。
そのため、環境変数の値の部分だけを置換用の文字列で設定したapp.template.yaml
を用意しておき、デプロイ直前に置換用の文字列をsecretsで取得した値で置き換えることで、バージョン管理に晒すことなくアプリケーションに環境変数を注入します。
このやり方は以下のブログで紹介されており、参考にさせていただきました。
GitHub Actionsから環境変数をマスクしてGAEにデプロイする
最後は、gcloud app deploy
で完了です。
デプロイが完了すると、GCP管理画面から新しいバージョンが追加されていることが確認できます。
作成したワークフロー
https://github.com/EringiV3/dev-article-reply-twitter-bot/blob/master/.github/workflows/node.js.yml
感想とワークフローがお蔵入りした理由
肝心のアプリケーションが仕様的にGAEとマッチしていなかったため、このワークフローはお蔵入りになってしまったのですが、GitHub Actionsを使ってGAEにデプロイしたくなるときがいつか来そうな気がしたので記事にしました。
Node.jsの実行環境としてのGAEはとてもお手軽で便利だと感じたので、手持ちの弾にしておきたいです。
スタンダード環境だと最初からNode.js(この記事書いた時点では12.x)が入っていて、言語のセットアップをすることなくNode.jsアプリケーションを動かすことができます。
しかもスタンダード環境はある程度までは無料で使える!
静的なサイト作成時やNext.jsを使うときは、それらに特化したプラットフォーム(NetlifyやVercel)を使ったほうが良さそうですが、素のNode.jsでなにかやりたいときはGAEかなり良さそうです。
ただ、GAEはデフォルトの自動スケーリング(https://cloud.google.com/appengine/docs/standard/nodejs/how-instances-are-managed?hl=ja)だと、HTTPリクエストが10分来ないとシャットダウンされてしまいます。
今回デプロイしたアプリケーションは、Twitterのタイムラインをストリーミングして特定の条件を満たすツイートが流れてきたらアクションするものだったので、アプリケーションは常に稼働状態である必要がありました。そのため、GAEの制約がある実行環境ではうまく動作しませんでした(デプロイされたサーバーにHTTPリクエストしてから10分間しか動かない)。
アプリケーションの仕様をよく考えず、実行環境の選定をしてしまった結果踏んでしまった間違いだと言えます。
セットアップの手間が増えますが、GCE(Google Compute Engine)でうまくできないか実験してみます。
それでもダメそうなら、おとなしくラズパイ買ってお家サーバー立てて運用しようと思います。。