社のCI/CDをJenkinsからGitHub Actionsに移行しました。公式ドキュメント読み倒してたくさんのymlを書いたので、tipsでも残して置きます。
環境
移行の背景
2019年までに作ったアプリケーションのデプロイ・リリース作業はJenkinsで行なっていました。2020年に入ってコンテナ化が進み、AWS CodeBuild・AWS CodeDeployを使ってデプロイするようになったり、一部ではGitHub Actionsを使ってデプロイするようになったりとデプロイ・リリース方法が多様化していきました。 JenkinsはEC2インスタンス立てて、そこにインストールしていましたが長年メンテナンスされてなかったし、ジョブの作り上デプロイ完了待ちが発生していました。
移行理由をまとめると、次の通りです。
- デプロイ・リリース方法が多様化されている上にちゃんとドキュメントがなく、全環境の手順把握してる人もいないため、使うツールや手順を統一したい
- 数年Jenkinsのメンテナンスされてこなかったし、これからもメンテナンスしたくない
- ジョブの作り上、ビルド・デプロイに時間がかかるため改善したい
既存で使われていたのが、AWS CodeBuild・AWS CodeDeployとGitHub Actionsだったのでこの2択でした。前者だと、設定ファイル結構用意しないといけないしデプロイ作業が手間そうだったので、後者に決めました。
移行作業
主に作ったワークフローは次の通りです。
- ビルド用ワークフロー(PR作成・更新をトリガ)
- テスト環境にデプロイするワークフロー(手動実行)
- 本番環境にデプロイするワークフロー(手動実行)
- テスト環境に日次デプロイするワークフロー(スケジューリングトリガ)
公式ドキュメントを読めばできることしかやってないので、実際のワークフローの中身については省略します。
利用した公式アクション
- actions/cache
- actions/checkout
- actions/setup-java
- actions/setup-python
- aws-actions/amazon-ecr-login
- aws-actions/amazon-ecs-deploy-task-definition
- aws-actions/amazon-ecs-render-task-definition
- aws-actions/configure-aws-credentials
- codecov/codecov-action
工夫点
実行ログの永続化
デプロイログを一定期間残したかったので、独自でバッチを作りました。今はプライベートレポジトリの実行ログ保存期間は最大400日になっていますが、当時は最大90日だった(気がする)のでログを永続化する方法を考えました。
GitHub Actions側の後処理も含めて全ジョブ終了後にログが保存されるため、ワークフローの中にログを保存するジョブを入れることができませんでした。 そこで、1. GitHub APIを叩いてログファイルを取得 、2. 1で取得したZIPファイルをS3にアップロード を行うバッチを作って、GitHub Actionsのscheduleトリガを使って日次で動かすようにしました。
複数レポジトリにワークフローを置くのは管理コストが高くなるので、それ用にレポジトリを立てるようにしました。これは、ログアップロードバッチのレポジトリのログアップロード用ワークフローです。
name: Upload CI Log on: schedule: - cron: '0 1 * * *' jobs: upload: name: CI Log uplaad runs-on: ubuntu-latest strategy: matrix: repository: - repo-a - repo-b - repo-c steps: - uses: actions/checkout@v2 - name: Set up JDK 11 uses: actions/setup-java@v1 with: java-version: 11 - name: Cache modules uses: actions/cache@v2 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} restore-keys: | ${{ runner.os }}-gradle- - name: Upload env: AWS_REGION: ap-northeast-1 AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # GitHub APIを叩くための個人アクセストークン DOWNLOAD_LOGS_ACCESS_TOKEN: ${{ secrets.DOWNLOAD_LOGS_ACCESS_TOKEN }} run: | ./gradlew -x test build # 引数はOrganization名/Repository名 java -jar ./build/libs/upload-ci-logs.jar Hoge/${{ matrix.repository }}
EB CLIのインストール
AWS CLIはデフォルトで、 インストールされている のですが、EB CLIはインストールが必要です。 このように書けば、20秒ほどでインストールできます。
steps: - name: Set up Python uses: actions/setup-python@v2 with: python-version: '3.9' - name: Install awsebcli run: pip install -U awsebcli
action用プライベートレポジトリ
GitHub Actionsでは、 独自アクション を作成することができます。複雑な処理をしたいときに使うのがよいかと思います。 独自アクションの使い方は次の通りで、action用のプライベートレポジトリを作るには工夫が必要でした。
- 公開アクションは
uses: Organization名/Repository名
で指定 - 非公開アクションは実行するレポジトリ内に独自アクションを置き、
uses: ./アクション配置パス
で指定
全レポジトリでSlackにデプロイ通知する必要がありました。複雑な処理だったので「独自アクションにしたい!」となったのですが各レポジトリに置きたくはなかったので、独自アクション×別レポジトリのチェックアウトでaction用プライベートレポジトリっぽいことを実現しました。
- action用プライベートレポジトリの用意
- アクションを作る(複数作ることを考えて、独自アクションごとにディレクトリ分けるのがおすすめ)
- アクションを実行したいレポジトリで、1で作成したレポジトリをチェックアウト
- 3でチェックアウトした独自アクションを実行
これは、アクションを利用するレポジトリのワークフローです。
steps: - name: Checkout actions uses: actions/checkout@v2 with: # Hoge/actionsレポジトリにnotify-slackという名前のディレクトリを切って独自アクションを準備 repository: Hoge/actions # 外部のプライベートレポジトリをチェックアウトするときは個人トークンが必要 token: ${{ secrets.TOKEN }} # 配置するパス path: actions - name: Notification uses: ./actions/notify-slack with: message: "Test notificatin"
入力値チェック
手動実行時の入力値は、プルダウンが使えないためワークフロー内で入力値チェックを行うようにした。
これは、パラメータ environment
の入力値がtest1でもtest2でもない時に失敗させる例です。
steps: - name: Check if: ${{ github.event.inputs.environment != 'test1' && github.event.inputs.environment != 'test2'}} run: | echo "::error ${{ github.event.inputs.environment }} is invalid. environment must be 'test1' or 'test2'." exit 1
依存関係やビルドによる成果物をキャッシュする
公式の actions/cache を使えば簡単に実現できます。
jobやstep単位でタイムアウト時間を設定する
jobのタイムアウト時間はデフォルトで360分なので設定しないと長時間実行し続けて無料枠をすぐ消費してしまいます。timeout-minutes: 時間(分)
で指定します。 公式ドキュメント