概要
以前別の記事で、少し触ってみたという記載しました。
私自身、Github Actionsに対する知識はまだまだ少ないですが、
この機会で nektos/act に触れながら、Github Actionsに対する理解も深められればと思って始めました。
どういうもの?
Github Actionsのworkflowをローカルで動作させるために使用するライブラリです。
Github Actionsの挙動確認のために、都度git add → commit → push→workflow確認、という操作を何度も実行するのは手間、だと思います。
ターミナル上でworkflowの挙動が確認出来ると便利ではないでしょうか!
ただ新しいライブラリ、という訳ではありません!(初回リリース4年前)
知ったきっかけ
以下のスライドで紹介されてました。
どうやって動く?(公式より)
When you run act it reads in your GitHub Actions from .github/workflows/ and determines the set of actions that need to be run. It uses the Docker API to either pull or build the necessary images, as defined in your workflow files and finally determines the execution path based on the dependencies that were defined. Once it has the execution path, it then uses the Docker API to run containers for each action based on the images prepared earlier.
.github/workflows/
フォルダに配置したyamlファイルを読み込むところから始まります。
Docker APIを使用して、workflowに定義したイメージのpullとbuild実施し、定義された依存関係に基づいて実行パスを決定します。
各アクションのコンテナを実行して、workflowの処理を行っていきます。
セットアップ
さっそくですが、作業を進めます。
インストール
brewコマンドを使います。他はREADME.mdをご確認ください。
brew install act
コマンド初回実行時
Dockerイメージのサイズを聞かれます。Large
が特に大きいです。こちらの記事も見て、Medium
で進めることにしました。
$ act
? Please choose the default image you want to use with act:
- Large size image: +20GB Docker image, includes almost all tools used on GitHub Actions (IMPORTANT: currently only ubuntu-18.04 platform is available)
- Medium size image: ~500MB, includes only necessary tools to bootstrap actions and aims to be compatible with all actions
- Micro size image: <200MB, contains only NodeJS required to bootstrap actions, doesn't work with all actions
Default image and other options can be changed manually in ~/.actrc (please refer to https://github.com/nektos/act#configuration for additional information about file structure) [Use arrows to move, type to filter, ? for more help]
Large
> Medium
Micro
具体的な作業に入っていきます。
今回はpushイベント時のworkflowとします。また以下の2つに関するworkflowを作成しました。
- アプリケーションに対するテスト実行
- AWSサービスとの連携(ECR・Lambda)
アプリケーションのテスト
最初は軽めのものとして、FastAPIアプリケーションの簡単なテストを実施してみました。
python3.12のインストール(デフォルトでは3.10)、必要なライブラリインストール、テスト実行の順に実施します。
- name: Install Python
uses: actions/setup-python@v4
with:
python-version: "3.12"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run app tests
run: |
pytest ./tests/unit/test.py
アプリケーションとテストのコード
from fastapi import FastAPI, status
from mangum import Mangum
from pydantic import BaseModel
from typing import Any
EventAny = Any
env = os.getenv("ENV")
if env is None:
app = FastAPI()
else:
app = FastAPI(
root_path="/dev",
)
class HealthCheck(BaseModel):
"""Response model to validate and return when performing a health check."""
status: str = "OK"
@app.get(
"/health",
status_code=status.HTTP_200_OK,
response_model=HealthCheck,
)
def get_health() -> HealthCheck:
"""Calculate speed as distance divided by time."""
return HealthCheck(status="OK")
def handler(event: EventAny, context: EventAny):
asgi_handler = Mangum(app)
return asgi_handler(event, context)
/health
というエンドポイントにアクセスし、戻り値とHTTPステータスコードが期待値通りか確認するテストです。
from fastapi.testclient import TestClient
from fastapi import status
from src.main import app
client = TestClient(app)
def test_health():
response = client.get("/health")
assert response.status_code == status.HTTP_200_OK
assert response.json() == {"status": "OK"}
コマンドを実行して、actでのテストが成功しました。(pushイベントの場合は、特に引数不要)
act
AWSを用いたworkflowで挙動確認
少し規模を大きくします。以下workflowが、actで動作するか確かめてみました。
- 認証情報設定
- ECRへのログイン
- DockerイメージのBuildとECRへのPush
- Dockerイメージを使用したLambda関数の更新
デフォルトの挙動
コマンド実行時にオプションを付けないと、実際にAWSリソースは更新されますので、ご注意ください。
更新したくない場合は、公式のREADME.mdにも記載の通り、n
オプションを設定してください。
Run in dry-run mode:
act -n
認証情報の設定
- name: Set up AWS
run: |
aws configure set aws_access_key_id $AWS_ACCESS_KEY_ID
aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY
aws configure set region $REGION
actで実行すると、以下のように怒られます。
command not found, please refer to https://github.com/nektos/act/issues/107 for more information
actには、AWS CLIがインストールされていないようです。
Github Actions(Ubuntu22.04)は、AWS CLIがインストール済なので、問題なく動きます。
actのためにawsコマンドを使える状態にするのも変なので、
以下を使って、awsコマンドを明記せずに認証情報を設定できる方法を採用します。
- name: Set AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
actで実行すると、上記の実装で成功しました。
ただ私の場合、実行前の段階で、ターミナル上でaws configure
認証情報を設定したので成功していた、と後で気付きました。
awsの認証情報は設定していない体で、もう少し詳しく確認してみました。
actのドキュメントの通り、Github Actions上で設定したsecrets値を、読み込むために新たにファイルを用意します。
export AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXXXXX
export AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
作成したシークレット値用のファイルを読み込むオプションを追加して実行すると成功しました。
act --secret-file .secrets
何度か実行する中でわかりましたが、
aws configure
コマンドで設定した値 → .env
ファイル → .secrets
ファイル、この順に認証情報があるか確認しているようです。
いずれにも正しい認証情報がない場合、以下のエラーが表示されて、Jobが失敗しました。
ECRへのログイン
awsコマンドは、actでは使えないと、認証情報設定の段階で判明したので、ECRログイン時によく使われるであろう以下のコマンドは使わず進めてみます。
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin
以下のリポジトリを使用して、ログインします。
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
以下を実行して、成功しました。
act --secret-file .secrets -s GITHUB_TOKEN="$(gh auth token)"
DockerイメージのBuildとECRへのPush
以下2つのリポジトリの機能を使って、Pushまで行います。
- name: Set Docker Images and Tags
id: metadata
uses: docker/metadata-action@v5
with:
images: ${{ steps.login-ecr.outputs.registry }}/${{ vars.FASTAPI_LAMBDA_REPOSITORY_NAME }}
flavor: latest=true
- name: Docker build and push to ECR
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ secrets.AWS_REGISTRY_URL }}:latest
-
${{ steps.login-ecr.outputs.registry }}
:XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.comが設定されます。 - login-ecr部分は、
amazon-ecr-login@v2
で設定したid名です。
actで実行すると、失敗しました。
v4に下げても同じエラーが表示されたので、バージョンは関係なさそうです。
こちらの記事に、以下の記載がありました。
act -s GITHUB_TOKEN="$(gh auth token)"
This value is provided to GitHub Actions workflows by the GitHub Actions Runner automatically on the cloud
クラウドでは自動的に与えられている値のようです。ローカルで発行するために、gh
コマンドを使います。
gh auth token
を実行してトークンを確認します。
作成済でなければ、no oauth token
となるはずです。
gh auth login
を実行して、いくつか質問に回答して、トークンを発行します。
ワンタイムパスワードが表示され、Enterキーを押すとブラウザが起動します。
ワンタイムパスワードを入力すると、ターミナル側でLogged in as XXXXXXX
と表示されます。
完了したら、再度gh auth token
を実行します。gho_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
が表示されたので、これでトークンを用意できました。
再度実行します。
act --secret-file .secrets -s GITHUB_TOKEN="$(gh auth token)"
metadata-action@v5
の処理は成功しましたが、docker/build-push-action@v5
の処理でエラーがありました。イメージタグに設定したシークレット値が読み込めていませんでした。
ERROR: invalid tag ":latest": invalid reference format
認証情報設定の段階で記載した通り、シークレットの値をファイルに設定します。AWS_REGISTRY_URL
を追記しました。
export AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXXXXX
export AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
export AWS_REGISTRY_URL=XXXXXXXXXXXX.dkr.ecr.ap-northeast-1.amazonaws.com/repo-name
Dockerイメージを使用したLambda関数の更新
AWS for GitHub ActionsやDockerによって提供された機能ではなく、とある方(Hidetake Iwataさん)が開発された機能のようです。今回はこちらを使わせていただきます。
- name: Update Docker image using Lambda
uses: int128/deploy-lambda-action@v1
with:
function-name: ${{ vars.FASTAPI_LAMBDA_FUNCTION_NAME }}
image-uri: ${{ secrets.AWS_REGISTRY_URL }}:latest
公式ドキュメントの通りですが、Github Actions上で設定したvariable値を、actでも読み込むために新たにファイルを用意します。
export FASTAPI_LAMBDA_FUNCTION_NAME=fastapi-sample-container-lambda
以下を実行して、成功しました。
act --var-file .variables --secret-file .secrets -s GITHUB_TOKEN="$(gh auth token)"
最終的なworkflowはGithub Actions側も成功です!
成果物と感想
決して量は多くないですが、
最後まで成功するフローがあることは確認できました。
job同士の依存関係を見返すなど、workflowも一部整理しましたが、
キャッシュを利用してないので、実行時間短縮ができていません。
そのあたりは、このAdvent Calenderの20日目で、別途公開予定です!
本記事の最終的なyamlファイル
lint
は実際Linterを用いたチェックがありますが、今回は適当に出力する処理だけ設定しました。
name: FastAPI App CI/CD Pipeline
run-name: ${{ github.actor }} is testing out GitHub Actions 🚀
on:
push:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- run: echo "🎉 The job was automatically triggered by a ${{ github.event_name }} event."
check-app:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Python
uses: actions/setup-python@v4
with:
python-version: "3.12"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run app tests
run: |
pytest ./tests/unit/test.py
release:
runs-on: ubuntu-latest
needs: [lint, check-app]
steps:
- uses: actions/checkout@v4
- name: Set AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Set Docker Images and Tags
id: metadata
uses: docker/metadata-action@v5
with:
images: ${{ steps.login-ecr.outputs.registry }}/${{ vars.FASTAPI_LAMBDA_REPOSITORY_NAME }}
flavor: latest=true
- name: Docker build and push to ECR
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ secrets.AWS_REGISTRY_URL }}:latest
- name: Update Docker image using Lambda
uses: int128/deploy-lambda-action@v1
with:
function-name: ${{ vars.FASTAPI_LAMBDA_FUNCTION_NAME }}
image-uri: ${{ secrets.AWS_REGISTRY_URL }}:latest
- run: echo "🍏 This job's status is ${{ job.status }}."
実務の場合、より多くの処理がGithub Actionsのworkflowで実装されており、それもactで代用できるの??開発進めやすいの??と私自身も疑問に思っています。
やってみないと分からないので、皆さんもぜひ導入してみてください!とは、まだまだ言えません。。
今回実施した範囲では、通常の流れ(add→commit→push→ブラウザで確認する流れ)よりは、開発しやすいと感じましたが、もう少し複雑なフローとなった場合はどうなるのか、気になりますね。
nektos/actについて、気になる方はぜひ触ってみてください!