2025年05月24日
第20回
GitHubアクションで
CIシステムを構築

今回は GitHubアクションを利用して CIシステムを構築する方法を確認します。
CI(Continuous Integration)システムは、ソフトウエア開発プロセスでビルド、テスト、イメージのアップロードまでの自動化をサポートする重要なツールです。CIシステムは開発者がアプリケーションコードを統合してエラーを素早く発見し、アプリケーションの品質を維持し、改善することに使用されます。
開発者が新しいコードをバージョン管理システム(GitHub)にPushすると、CIシステムがコードを検知して自動でビルドから、テスト、イメージのアップロードまでを実行します。求める条件を満たした時に自動で実行し、イメージのビルド時間を削減します。
主に使用するCIツールにはJenkins、GitLab CI/CD、Travis CI、CircleCI等がありますが、最近はGitHubアクションを使用するユーザーが増えています。その理由は、ほとんどの開発者がGitHubアカウントを持っているので、参入ハードルが低く、便利だからです。DebOpsの立場ではCIは単純作業のため、CI用に追加ツールを使用して管理工数を増やすより、Gitの保存と統合されたCIシステムが求められています。
例えば、JenkinsはGitHubアクションに比べて最も多く使用されるツールの一つですが、追加プラグイン管理などが複雑で初期設定が難しいため、参入ハードルが高いです。大半のスタートアップ、中小企業は GitHub チームプラン(使用料が6US$/月)を使用していると推測されます。このプランは GitHubアクションを 3,000分まで無料で使用できるため、そのコストは大きくありません。また、GitHubアクションを EC2またはVMのセルフホストで使用すると、追加費用の負担がなく使用できるため、無料の3,000分以上を使用する組織でもコスト削減に繋がります。
次は実習で詳細を説明します。
今回の実習リストを整理します。
実習の内容:
① AWS IAM ロールとIdentity Providerの生成
② AWS ECRの生成
③ Dockerfileとサンプル用 APPコードの生成
④ CIテスト用の GitHubレポジトリの生成(環境変数の登録)
⑤ GitHubアクションワークフローファイルの生成
⑥ イメージ build & push GitHubアクション作業の検証
⑦ 生成 ECRイメージ基盤 Podの生成 (イメージの検証)
他のCI設定と類似したプロセスですが、少し異なるところはイメージタグ情報を GitHubソースタグ情報として使用することや、ECR認証情報を永久資格証明のユーザー基盤ではない、トークン基盤の臨時資格証明を使用することです。
次はステップ別に実習で確認します。
1. AWS IAM ロールとIdentity Providerの生成
認証用のセキュリティー強化のため、ユーザーではなくAWS IAMロールを使用します。 ロールの Trust Relations(信頼関係)では GitHubを使用しますが、GitHub公式ドキュメントで詳細な設定を確認できます。

GitHubアクションワークフローが使用する認証をクラウドプロバイダーの AWSがOIDCトラストを提供し、AWSの ロールとそのロールが使用するリソースを定義したポリシーを事前に定義します。その設定を利用して、GitHubアクションワークフローで認証をリクエストすると、AWSが臨時トークンを発給し、認証ステップを完了して、要求事項を満たすようにAWSの関連設定を進めます。
先ず、AWSコンソールでIdentity Providerを生成します。

上記のスクリーンショットのようにIAM – Identity Providerメニューで新しいIdentity Providerの追加を選択し、OpenID Connect を選択してProvider URLと Audienceに‘https://token.actions.githubusercontent.com’と ‘sts.amazonaws.com’ をそれぞれ入力します。
ここで指定した Providerを利用して IAM ロール認証を実行します。
次にIAM ロールを生成します。コンソールメニューでRoles – Create Roleを選択し、下記のスクリーンショットのように Select trusted entityのTrusted entity typeに Webで資格証明の Web identityを選択し、以前作成したGitHubアクション設定を選択します。

組織設定のGitHub organizationで個人アカウントの場合、個人のアカウント ID(例:junghoon2)を登録します。
次に、権限設定でECR関連ポリシー(policy)を選択します。 ECRイメージを照会してPushできる権限を次のように選択します。

すると、ロールの設定が完了し、そのロールがGitHubアクションワークフローで認証用に使用されます。
2. AWS ECRの生成
GitHubアクションでビルドしたイメージをアップロードするAWS ECRを生成します。イメージレポジトリタイプにHarbor、Docker Hub、GitHub等も使用できます。AWS EKS環境であれば、追加の認証なく使用できます。ECRの使用は速度とコストに競争力があり、良い選択です。
ECRは AWSコンソールで生成できますが、できればTerraformなどのIaCツールを使用することをお勧めします。下記は ECR生成の Terraformコードです。
1. resource "aws_ecr_repository" "github_actions_ecr" {
2. name = "python-flask" # ECRレポジトリ名
3. image_tag_mutability = "MUTABLE"
4. }
Terraformコードは非常に単純で、簡単にECRを Terraformコードで生成できますが、以下は各ラインの説明です。
• resource “aws_ecr_repository”
ECRを生成するために Terraformリソースに aws_ecr_repositoryを使用します。 Terraformリソース名は任意の名前で github_actions_ecrを指定します。
• name
ECRレポジトリ名です。他のレポジトリと区別できるように指定します。
• image_tag_mutability
タグの変更可否の設定でMUTABLE(変更可能)とIMMUTABLE(変更不可)のオプションがあります。個別の要求事項に合うように適切に選択してください。筆者は変更可能な MUTABLEオプションを選択しました。
Terraformコードが完成し、Terraformを利用してリソースを生成します。
1. tf init
2. tf plan -out planfile
3. tf apply
適用が完了すると、AWS ECRコンソールで下記のように python-flask名のレポジトリを確認できます。

3. Dockerfileとサンプル用 APPコードの生成
Dockerfileとサンプル用の簡単な APPコードを生成します。全体のコードは GitHubアドレスを参考にしてください。下記は Dockerfileの例です。
1. # ベースイメージにPython 3.8を使用します。
2. FROM python:3.8
3.
4. # 作業ディレクトリ設定
5. WORKDIR /app
6.
7. # Python依存性ファイルをコンテナにコピー
8. COPY requirements.txt requirements.txt
9.
10. # 依存性インストール
11. RUN pip install -r requirements.txt
12.
13. # その他ファイルを作業ディレクトリにコピー
14. COPY . .
15.
16. # Flaskアプリケーション実行
17. CMD [ "python", "./app.py" ]
上記の例は、Python基本イメージを基に依存性ファイル(flask)をインストールし、実行コマンドに app.pyで指定した簡単な Dockerファイルです。その他app.py、requirement.txtファイルは共有したGitHubファイルを参照します。

4. CIテスト用GitHubレポジトリの生成 (環境変数の登録)
次は、GitHubアクションファイルを実行するGitHubレポジトリを生成します。

レポジトリ名は任意の名前で指定できます。生成が完了すると、アクションファイルで使用する環境変数を登録します。 Settingsの Actions secrets and variablesに下記のようにAWS_ECR_REPOと AWS_REGION情報を環境に合わせて登録します。

AWS_ECR_REPOにはECRレポジトリ名を指定します。GitHubアクションワークフローファイルで環境変数を使用し、その名前で ECRレポジトリが生成されます。
5. GitHubアクションワークフローファイルの生成
以上で事前準備が完了したので、GitHubアクションファイルを作成します。アクションファイルは下記のように .github/workflows/ ディレクトリに.yml(又はyaml) 形式で保存します。

イメージの build & pushを実行するアクションファイルの例です。(GitHubリンク)
1. name: Docker Build and Push
2.
3. on:
4. push:
5. tags:
6. - '*' # 全てのタグに対してこのワークフローをトリガーします。
7.
8. jobs:
9. build-and-push:
10. runs-on: ubuntu-latest
11.
12. permissions:
13. id-token: write
14. contents: read
15.
16. steps:
17. - name: Checkout Repository
18. uses: actions/checkout@v4
19.
20. - name: Configure AWS credentials
21. uses: aws-actions/configure-aws-credentials@v4
22. with:
23. aws-region: ${{ vars.AWS_REGION }}
24. role-to-assume: arn:aws:iam::516696002612:role/github-actions-ci
25.
26. - name: Login to Amazon ECR
27. id: login-ecr
28. uses: aws-actions/amazon-ecr-login@v2
29.
30. - name: Extract tag name
31. id: extract_tag
32. shell: bash
33. run: echo "IMAGE_TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
34.
35. - name: echo image tag
36. run: echo $IMAGE_TAG
37.
38. - name: Build and Push Docker Image
39. uses: docker/build-push-action@v5
40. with:
41. push: true
42. tags: ${{ steps.login-ecr.outputs.registry }}/${{ vars.AWS_ECR_REPO }}:${{ env.IMAGE_TAG }}
• on.push.tags. ‘*’
ワークフローは GitHubレポジトリにタグがPushされる度にトリガーされます。ここで ‘*‘ は全てのタグでこのワークフローを実行することを意味します。コードを変更してタグをPushすると、ワークフローファイルが実行します。明示的にタグをコネクションした場合のみワークフローを実行するように指定すると、mainにマージする場合は、ワークフローは実行されません。
• jobs.build-and-push.runs-on: ubuntu-latest
この作業は ubuntu-latest環境で実行されます。Dockerイメージをbuildして、Amazon ECRでPushするステップを含みます。
• permissions.id-token, contents
id-token: writeと contents: read権限を設定して、GitHub Actionsが必要な権限でIDトークンを作成し、レポジトリコンテンツを読めるようにします。
• steps
個別アクションを定義します。
• name: Checkout Repository
actions/checkout@v4アクションでレポジトリのソースコードをチェックアウト(切替え)します。 GitHubアクションに使用できる多様なアクションリストは、下記 github.com/actionsで確認できます。

• name: Configure AWS credentials
aws-actions/configure-aws-credentials@v4アクションで、AWS資格証明を作成します。ここでAWSリージョンと GitHub Actionsが使用するIAM Roleの ARNを指定します(vars.AWS_REGIONと role-to-assumeの値を使用)。 前で生成したIAM Roleの情報を使用します。
• name: Login to Amazon ECR
aws-actions/amazon-ecr-login@v2アクションで、Amazon ECRにログインします。このステップは Dockerイメージを Amazon ECRにPushする時に必要な認証情報を取得します。
• id: login-ecr
login-ecrはこのステップのユニーク識別子(ID)です。このIDを使用して、ステップの出力(output)を他のステップで参照できます。例えば、イメージを pushするsteps.login-ecr.outputs.some-outputと同じ方式で使用します。
• name: Extract tag name
自動的に生成されるハッシュ値を基に、Dockerイメージタグとして使用する他のアクションファイルと異なる部分です。 GitHubのタグ情報を環境変数に保存して、これをイメージタグ情報に使用する設定です。 Bashスクリプトを使用してタグ名を抽出し、これを環境変数 IMAGE_TAGに保存します。この変数は Dockerイメージのタグとして使用されます。
• name: echo image tag
デバッグ用にイメージタグ情報を出力する設定です。
• name: Build and Push Docker Image
docker/build-push-action@v5アクションで、Dockerイメージをbuildして、Pushします。 push: trueはイメージをレジストリで実際にPushすることを意味します。Tagsはイメージに使用するタグを指定します。ここでAmazon ECRのレジストリアドレス、ECRレポジトリ名と前に抽出したイメージタグを使用します。
以前にGitHubに設定した環境変数を ECRレポジトリ名で指定します。
以上でGitHubアクションファイルの設定が完了しました。次は、タグを Pushして実際 GitHubアクションワークフローを実行します。
6. イメージ build & push GitHubアクション作業の検証
では、ローカルで新しいタグを生成し、GitHubにそのタグを Pushしてアクションワークフローファイルを実行します。
新しいタグを作成します。
1. (jerry-dev:sns)github-actions-python$ git tag -a v0.1.3
タグをリモートの originに pushします。
1. (jerry-dev:sns)github-actions-python$ git push --tags
2. Enumerating objects: 1, done.
3. Counting objects: 100% (1/1), done.
4. Writing objects: 100% (1/1), 153 bytes | 153.00 KiB/s, done.
5. Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
6. To https://github.com/junghoon2/github-actions-python.git
7. * [new tag] v0.1.3 -> v0.1.3
次は、リモートの GitHubの Actions メニューを確認すると、下記のように自動的にJobsを実行するようになっています。

メニューをクリックすると、詳細作業ログが確認できます。

エラーがなく作業が終了すると、下記のようなチェック表示を確認できます。

次は、作業が終了したので、作業結果をAWS ECRコンソールで確認すると、アクションファイルの設定通りにGitHubタグ名でイメージタグが指定され、イメージが Pushされていることを確認できます。

7. 生成したECRイメージ基盤 Podの生成 (イメージの検証)
最後のステップで生成されたイメージアドレスを Podのマニフェストに表示して、正常にイメージが生成されたかを検証します。基本 deploymentマニフェストを使用して、イメージ部分だけ先程生成したECRイメージアドレスとタグに変更します。
1. apiVersion: apps/v1
2. kind: Deployment
3. metadata:
4. name: python-flask
5. namespace: default
6. spec:
7. selector:
8. matchLabels:
9. app: python-flask
10. template:
11. metadata:
12. labels:
13. app: python-flask
14. spec:
15. containers:
16. - name: python-flask
17. image: 516696002612.dkr.ecr.ap-northeast-2.amazonaws.com/python-flask:v0.1.3
image
各自生成したイメージアドレスに変更します。イメージアドレスは GitHubアクションファイル又は下記のように ECRコンソールで参照できます。

YAMLファイルを適用(apply)し、ポートフォワーディングを利用して接続します。
1. $ k apply -f deployment/deploy-ecr-python-flask.yaml
2. deployment.apps/python-flask created
3.
4. $ k port-forward pod/python-flask-6f75c79c8-pdpnh 8080:8080
5. Forwarding from 127.0.0.1:8080 -> 8080
6. Forwarding from [::1]:8080 -> 8080
正常にPodが実行されて、ブラウザでイメージ内容の変更も確認できます。

次は設定したGitHubアクションファイルを利用してGitHubにタグがPushされると、自動的にイメージをビルドしてリモートの ECRにPushまで行う CIシステムの構成を完了しました。 CIシステムは1回設定すると、その後は変更がほとんどない作業です。
以上で GitHubアクションを利用して Dockerイメージの BuildとPushまでを行い、 CIシステムを構成しました。