1.初めに
N番煎じネタですが、やはり使っていて便利だとしみじみ思うGitHub Actionsをご紹介したいと思います。
(こういった記事を書くのは初めてですので若干緊張しています。。。)
この記事の目標はGitHub Actionsがどういうものかを知っていただくことと、実際にサンプルを作れるようになっていただくこととしています。
2.GitHub Actionsって何?
GitHub Actions は簡単に言うと GitHub が用意した CI/CD サービスのことです。
yaml形式の定義ファイルを指定のディレクトリに入れておくだけで、勝手に処理を行なってくれます。
ちなみに CI/CD サービスと書いていますが、CI/CD 以外にも利用できます。
あんまり長々書いてもよろしくないので、もっと詳細が知りたい方は公式ドキュメントを見て下さい。
3.使い方
GitHub に用意したリポジトリに「.github/workflows」ディレクトリを用意してその中にyaml形式の定義ファイルを入れるだけです。
yamlファイルは以下のように記載します。
name: GitHub Actions Demo
on:
push:
branches:
- 'main'
jobs:
Sample:
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: run command
run: echo "Hello GitHub Actions!"
これだけでもGitHub Actionsは動かせます。
このサンプルでやっていることを簡単に説明すると、
- mainブランチにコードがプッシュされたら処理を開始する。
- ubuntuの最新バージョンの仮想環境を用意する。
- リポジトリのソースコードをチェックアウトする。
- "Hello GitHub Actions!"と出力する。
こんな感じです。
この steps のところに処理を追加し、組み合わせることでお好みのワークフローを構築することができるのです。
ではこのサンプルの中身を詳細に見ていきましょう。
3.1.on:
「on:」ではワークフローの発火条件を定義しています。
このサンプルでは発火条件を以下としています。
on:
push:
branches:
- 'main'
これは main ブランチに push したら開始するよ、という条件です。
このほかにも
on:
schedule:
- cron: 0 15 * * *
で日本時間深夜00:00に開始する、という条件にしたり、
on:
workflow_dispatch:
でブラウザ上から手動起動する、という条件にしたりすることができます。
公式ドキュメントからお好みの発火条件を探してみて下さい。
3.2.jobs:
「jobs:」では実際のワークフローの内容を定義しています。
このサンプルでは一つのみですが、複数の job を用意して並列処理を行わせることもできます。
jobs:
Sample:
「Sample」が job の名前です。
複数の job を用意する場合はこの名前を使って処理の順番などを決めることができます。
job の名前が決まったら、まずワークフローの実行環境を定義します。
runs-on: ubuntu-latest
この「runs-on」でワークフローの実行環境を定義しています。
このサンプルでは最新バージョンの ubuntu 上で処理を行わせています。
GitHub Actionsでは ubuntu の他に
runs-on: windows-latest
で Windows の実行環境にしたり、
runs-on: macos-latest
で MacOS の実行環境にすることもできます。
また、「セルフホストランナー」と呼ばれる機能を使うことで自分の好きな環境を用意し、実行環境に利用することもできます。
実行環境を定義したら、次はいよいよ処理を定義していきます。
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: run command
run: echo "Hello GitHub Actions!"
「steps」にワークフローで行わせる処理を記載していきます。
このサンプルでは、まずリポジトリに存在するソースコードをチェックアウトし、次に"Hello GitHub Actions!"と出力させています。
処理を「uses」と「run」で書いていますが、「uses」はGitHubのMarketplaceで公開されているワークフローを実行するよ、と言う宣言です。
本来であれば、Gitコマンドを使ってソースコードをチェックアウトする処理を書く必要があるのですが、その一連の処理を自分で書かずに済む便利なものです。
いろいろなワークフローが公開されていますので、それを利用すれば、想像以上に簡潔な定義ファイルになるかもしれません。
「run」では通常のCLIコマンドを実行しています。
ライブラリを追加する処理を入れれば様々なコマンドを実行することも可能です。
4.実際に CI/CD ツールとして使ってみた。
GitHub Actions は CI/CD 用に用意されたサービスですので実際に CI/CD 環境を用意してみました。
それがこちらになります。
# ECS on Fargate Deployment Action
name: deploy to ECS on Fargate - Develop Environment
# setting trigger
on:
push:
# developブランチ、かつnode-express/app配下に変更があった場合のみ実行
branches:
- 'develop'
paths:
- 'node-express/app/**'
# setting enviroment
env:
DEPLOY_ENV: develop
TARGET_DIRECTORY: node-express
AWS_REGION: ap-northeast-1
CLUSTER_NAME: ecs-demo
ECR_REPOSITORY_NAME: ecs-demo/node-express
IMAGE_TAG: ${{ github.sha }}
ECS_SERVICE_NAME: ecs-demo-container-service
AWS_WEB_IDENTITY_TOKEN_FILE: /tmp/awscreds
jobs:
build-and-deploy:
name: build docker image and deploy ecs
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ${{ env.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: Build, tag, and push image to Amazon ECR
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
run: |
cd ./${{ env.TARGET_DIRECTORY }}/app
docker build -t ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY_NAME }}:${{ env.IMAGE_TAG }} .
docker push ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY_NAME }}:${{ env.IMAGE_TAG }}
echo "::set-output name=image::${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY_NAME }}:${{ env.IMAGE_TAG }}"
- name: Fill in the new image ID in the Amazon ECS task definition
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: node-express/task-definition.json
container-name: ecs-demo-container
image: ${{ steps.build-image.outputs.image }}
- name: Deploy Amazon ECS task definition
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: ${{ steps.task-def.outputs.task-definition }}
service: ${{ env.ECS_SERVICE_NAME }}
cluster: ${{ env.CLUSTER_NAME }}
wait-for-service-stability: true
今回は Docker コンテナイメージをビルドして、 Amazon ECR (以下ECRとします。)にプッシュ後、 AWS の Amazon ECS (以下ECSとします。)にプッシュしたコンテナイメージを反映させるところまでを GitHub Actions にやらせています。
(ECS や ECR についての説明は公式サイトをご参照ください。)
では簡単にやっている事を説明していきます。
まずは GitHub Actions の発火条件ですね。
on:
push:
# developブランチ、かつnode-express/app配下に変更があった場合のみ実行
branches:
- 'develop'
paths:
- 'node-express/app/**'
コメントに書いている通りですが、developブランチのnode-express/appディレクトリ内に変更があった場合に実行されるようにしています。
何でもかんでも変更があったら動くようにするのは困るので制限をつけています。
env:
DEPLOY_ENV: develop
TARGET_DIRECTORY: node-express
AWS_REGION: ap-northeast-1
CLUSTER_NAME: ecs-demo
ECR_REPOSITORY_NAME: ecs-demo/node-express
IMAGE_TAG: ${{ github.sha }}
ECS_SERVICE_NAME: ecs-demo-container-service
AWS_WEB_IDENTITY_TOKEN_FILE: /tmp/awscreds
こちらではワークフロー内で使用する環境変数を定義しています。
このサンプルを流用したときに変更の必要がある場所を変数化したつもりです。
ジョブは長いので分割して説明して行きます。
jobs:
build-and-deploy:
name: build docker image and deploy ecs
runs-on: ubuntu-latest
今回はジョブは一つのみで行なっています。
このジョブで何をやっているかの説明と ubuntu の最新バージョンの環境で実行するとしています。
permissions:
id-token: write
contents: read
こちらは後述する AWS の認証処理で必要な権限を付与させています。
この権限を付与しておかないと AWS 連携がうまく行きませんのでご注意ください。
- name: Checkout
uses: actions/checkout@v3
こちらではリポジトリからソースコードをチェックアウトしています。
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ${{ env.AWS_REGION }}
こちらでは AWS 認証処理を行なっています。
通常はアクセスキーを使用して認証を行うことが多いですが、漏洩などのリスクがありますのでこちらの記事を参考に IAM ロールを使用した認証処理で行なっています。
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
Docker コンテナイメージのアップロード先となる ECR にログインしています。
- name: Build, tag, and push image to Amazon ECR
id: build-image
env:
ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
run: |
cd ./${{ env.TARGET_DIRECTORY }}/app
docker build -t ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY_NAME }}:${{ env.IMAGE_TAG }} .
docker push ${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY_NAME }}:${{ env.IMAGE_TAG }}
echo "::set-output name=image::${{ env.ECR_REGISTRY }}/${{ env.ECR_REPOSITORY_NAME }}:${{ env.IMAGE_TAG }}"
こちらで Docker コンテナイメージをビルドし、ECR にプッシュしています。
次の処理に使うので、プッシュしたコンテナイメージの ECR 情報を環境変数に設定しています。
- name: Fill in the new image ID in the Amazon ECS task definition
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: node-express/task-definition.json
container-name: ecs-demo-container
image: ${{ steps.build-image.outputs.image }}
こちらで先ほどビルドして ECR にプッシュしたコンテナイメージを使用するように ECS のタスク定義ファイルを更新しています。
- name: Deploy Amazon ECS task definition
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: ${{ steps.task-def.outputs.task-definition }}
service: ${{ env.ECS_SERVICE_NAME }}
cluster: ${{ env.CLUSTER_NAME }}
wait-for-service-stability: true
最後に更新したタスク定義ファイルを ECS にデプロイしています。
以上が今回用意した CI/CD 環境となります。
100行にも満たない定義ファイルを用意するだけで以降はビルドからデプロイまでを勝手に実行してくれるので非常に便利ですね。
5.最後に
今回は単純なサンプルや CI/CD 環境の構築サンプルを用意して説明させていただきましたが、他にも様々な使い道があると思います。
例えばソースコードをリポジトリにプッシュするたびに、ビルドして、単体テストや静的解析を実行させたり、定期スクリプトを実行させたり用途は様々です。
特にAWSについてはMarketplace上に公開されているワークフローが充実しているので、簡単に連携ができます。
CI/CD 環境を用意したい、とある作業を自動化させたいなど、効率化するためのツールを探している方は GitHub Actions を検討してみては如何でしょうか?