CI/CDサービス「GitHub Actions」で「コンテナビルド」を自動化してみよう

はじめに
現代の開発現場では、コンテナを活用して開発を効率化する動きが活発です。アプリの動作環境をコンテナにパッケージ化し、それを開発者全体で使用すれば環境の差異に悩まされることがなくなります。
しかし、コンテナは「1度作ればそれで終わり」というものではありません。コンテナ内で使用しているライブラリやミドルウェアのアップデートなど、誰かがメンテナンスを行う必要が出てきます。この作業を手動で行う場合は人的ミスの温床となることでしょう。また、チーム開発では「誰がビルドするか」「どのタイミングでリリースするか」といった調整コストも発生します。
こうした課題を解決するのが、「CI/CD」(継続的インテグレーション/継続的デリバリー)による自動化です。コードの変更を自動で検知し、ビルド・テスト・デプロイまでを自動化することで、開発者はコード品質の向上に集中できるようになります。
本記事では、GitHubが提供するCI/CDサービス「GitHub Actions」を使ってコンテナビルドを自動化し、GitHub Container Registry(ghcr)へのプッシュまでを実践します。GitHub Actionsを活用すれば、外部のCI/CDサービスを導入することなく、GitHub上で完結したワークフローを構築できます。
コードをプッシュするだけで自動的にコンテナイメージが作成・配布される環境を構築できるようになることを目指します。
GitHub Actionsとは
GitHub Actionsは、GitHubが提供するワークフロー自動化プラットフォームです。リポジトリ内で発生するイベント(プッシュ、プルリクエストなど)や決められた時刻をトリガーに、あらかじめ定義したジョブを実行できます。
基本的な構成要素と名称
GitHub Actionsを理解するには、以下の基本概念を押さえておく必要があります。
ワークフロー(Workflow).github/workflows/
ディレクトリ内のYAMLファイルで定義される自動化処理全体のことです。「どのイベントで」「どんな処理を実行するか」を記述したレシピのような存在です。
ワークフローをトリガーするイベントについては、公式ドキュメントに詳しく記載されています。
ジョブ(Job)
1つのワークフロー内に複数のジョブを定義でき、デフォルトでは並列実行されます。依存関係を設定すれば順次実行も可能です。
ステップ(Step)
ジョブ内で実行される個々のタスクです。シェルコマンドの実行や、Actionsの呼び出し(後述)などが該当します。
アクション(Actions)
再利用可能な処理のパッケージです。GitHub Marketplaceで公開されているものや、自作のActionを利用できます。例えば「チェックアウト」「Docker ビルド」「通知送信」といったよくある処理はActionとして提供されているため、自分で再実装することなく手軽に機能を利用できます。
主な特徴
1. GitHubとの統合
リポジトリと緊密に連携し、コードの変更に応じて自動実行されます。外部のCI/CDサービスを導入する必要がなく、GitHub上で完結できます。また、GitHubのサービス(ghcrやIssue、PRなど)を簡単に使用できるのも特徴です。
2. 豊富なActionsエコシステム
GitHub Marketplaceには数千ものActionが公開されており、Docker、AWS、Kubernetesなど様々な技術との連携が簡単に行えます。
3. 柔軟な実行環境
Ubuntu、Windows、macOSの実行環境を選択でき、コンテナ上での実行も可能です。
GitHub Actionsのはじめ方
GitHub Actionsを有効にする
GitHub Actionsは、GitHubリポジトリで自動的に利用可能となっていますが、組織やリポジトリの設定によっては手動で有効化が必要な場合があります。
1. リポジトリでの有効化
- GitHubリポジトリのページで「Settings」タブをクリック
- 左側のメニューから「Actions」→「General」を選択
- 「Actions permissions」で以下のいずれかを選択:
- Allow all actions and reusable workflows(すべてのActionを許可)
- Allow OWNER, and select non-OWNER, actions and reusable workflows(リポジトリ所有者のActionを許可し、非所有者のActionは選択的に許可)
GitHub Actionsの設定方法については、公式ドキュメントで詳しく説明されています。
2. 組織レベルでの設定
組織のオーナーの場合、組織全体でのActions設定も確認できます:
- 組織のSettingsページで「Actions」→「General」を選択
- リポジトリごとの権限設定を確認・変更
3. 初回実行の確認
新しいリポジトリでは、初回のワークフロー実行時に確認画面が表示される場合があります。「I understand my workflows, go ahead and enable them」ボタンをクリックして有効化します。
ワークフローファイルの配置
GitHub Actionsを使うには、リポジトリの.github/workflows/
ディレクトリにYAMLファイルを配置します。ファイル名は任意ですが、.yml
または.yaml
拡張子が必要です。
複数のワークフローを用意して、条件によって使い分けることもできます。また、あるワークフローから別のワークフローを呼び出すこともできるため、同じような処理は1つのワークフローにまとめておくのも良いでしょう。
基本的なワークフロー例
まずは、シンプルなワークフローから始めてみましょう。
.github/workflows/hello.yamlname: Hello World on: push: branches: - main jobs: hello: runs-on: ubuntu-latest steps: - name: Say hello run: echo "Hello, GitHub Actions!"
この例では、main
ブランチへのpushをトリガーに「Hello, GitHub Actions!」を出力するだけのシンプルなジョブが実行されます。
実行結果は、GitHub上のActionsタブから確認できます。
トリガーの種類
GitHub Actionsでは、様々なイベントをトリガーにできます。
push
: 指定ブランチへのプッシュpull_request
: プルリクエストの作成・更新schedule
: 定期実行(cron形式)workflow_dispatch
: 手動実行workflow_call
: 別のワークフローから呼び出す
コンテナをビルドしてみよう
それでは実際にコンテナをビルドして、GitHub Container Registry(ghcr)にプッシュするワークフローを作成してみましょう。
サンプルアプリケーションの準備
まず、簡単なWebアプリケーションを用意します。
app.pyfrom flask import Flask app = Flask(__name__) @app.route("/") def hello(): return "Hello from GitHub Actions!" if __name__ == "__main__": app.run(host="0.0.0.0", port=8000)requirements.txt
flaskDockerfile
FROM python:3.12-slim AS build WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt -t . COPY . . FROM python:3.12-slim WORKDIR /app COPY --from=build /app /app RUN useradd -m appuser USER appuser CMD ["python", "app.py"]
GitHub Actionsワークフローの作成
次に、コンテナビルドとghcrへのプッシュを行うワークフローを作成します。
.github/workflows/build.ymlname: Build and Push Container on: push: branches: - main pull_request: branches: - main env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} jobs: build: runs-on: ubuntu-latest permissions: contents: read # リポジトリのコードを読み取るため packages: write # GitHub Container Registryへプッシュするため steps: - name: Checkout repository uses: actions/checkout@v4 - name: Log in to Container Registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | type=ref,event=branch type=ref,event=pr type=sha,prefix={{branch}}- - name: Build and push Docker image uses: docker/build-push-action@v5 with: context: . push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }}
ワークフローの解説
1. トリガー設定
main
ブランチへのプッシュとプルリクエストで実行されます。
2. 権限設定
packages: write
権限により、ghcrへのプッシュが可能になります。
3. 認証
GITHUB_TOKEN
を使ってghcrにログインします。これは自動的に提供される認証トークンです。
4. メタデータ抽出
ブランチ名やコミットハッシュを基に、適切なタグを自動生成します。
5. ビルド・プッシュ
Dockerイメージをビルドし、生成されたタグでghcrにプッシュします。
ポイント1: アクションの活用
各ステップでuses: <owner>/<repo>@<version>
を定義しています。これはアクションと呼ばれ、ある処理をパッケージ化したものです。ghcrへのログインやコンテナのビルド処理は1から全てを手書きすると大変ですが、アクションを使うことで簡潔にステップを記述できます。
ポイント2: ステップ間でのデータ受け渡し
ステップ3(33行目)のExtract metadata
でid: meta
を指定しています。これは、別のステップからこのステップの実行結果を参照するためのステップ識別子です。ステップ4のBuild and push Docker image
から${{ steps.meta.outputs.tags }}
や${{ steps.meta.outputs.labels }}
を使って参照しています。
実行結果の確認
ワークフローを実行すると、Actions画面でビルドログを確認できます。
成功すると、リポジトリのPackagesタブにコンテナイメージが表示されます。
イメージは、以下のような形式でpullできます:
docker pull ghcr.io/username/repository:main
セキュリティスキャンの追加
コンテナイメージのセキュリティを向上させるため、脆弱性スキャンをワークフローに組み込むことができます。以下は、Trivyを使用したスキャンの例です。
.github/workflows/build-with-scan.ymlname: Build, Scan and Push Container on: push: branches: - main pull_request: branches: - main env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} jobs: build-and-scan: runs-on: ubuntu-latest permissions: contents: read # リポジトリのコードを読み取るため packages: write # GitHub Container Registryへプッシュするため security-events: write # セキュリティスキャン結果をアップロードするため steps: - name: Checkout repository uses: actions/checkout@v4 - name: Log in to Container Registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Extract metadata id: meta uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | type=ref,event=branch type=ref,event=pr type=sha,prefix={{branch}}- - name: Build Docker image uses: docker/build-push-action@v5 id: build with: context: . load: true # イメージをローカルに保存(スキャン用) tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@v0.32 with: image-ref: ${{ steps.build.outputs.imageid }} format: 'sarif' output: 'trivy-results.sarif' - name: Upload Trivy scan results to GitHub Security tab uses: github/codeql-action/upload-sarif@v3 if: always() with: sarif_file: 'trivy-results.sarif' - name: Push Docker image if: github.event_name != 'pull_request' uses: docker/build-push-action@v5 with: context: . push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }}
ワークフローが成功すると、Securityタブにコンテナのセキュリティ情報がアップロードされます。
「View alerts」にこのコンテナが抱える脆弱性の一覧が記載されるので、問題を確認して修正可能な部分から順次修正するのが良いでしょう。
スキャンワークフローの特徴
1. 段階的ビルド
イメージを1度ローカルにビルドしてスキャンを実行します。
2. セキュリティタブ連携
スキャン結果はGitHubのSecurityタブに表示され、脆弱性の詳細を確認できます。
3. プルリクエスト対応
プルリクエストではスキャンのみ実行し、プッシュはスキップします。
おわりに
GitHub Actionsを使うことで、コードの変更と同時にコンテナイメージの自動ビルド・配布が実現できました。これにより、手作業でのビルドやデプロイ作業が不要となり、開発効率の大幅な向上が期待できます。
今回紹介した内容は基本的なものですが、実際のプロジェクトではテストの実行、セキュリティスキャン、複数環境への自動デプロイなど、より高度なワークフローを構築することも可能です。
次回は、いよいよAWSの操作に進んでいきます。AWS ECRを構築し、コンテナイメージをプッシュするところまでを解説していきます。
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- CI/CDを実現するツール「GitHub Actions」を使ってみよう
- クロスコンパイルできるC言語のビルド&実行環境をGitHubActionsとQEMUで作る
- Oracle Cloud Hangout Cafe Season4 #3「CI/CD 最新事情」(2021年6月9日開催)
- テストコードを書いて「GitHub Actions」でCIを実行してみよう
- Rancherのカスタムカタログの作成
- 「GitHub」にブランチ保護、Dependabot、Secret Scanningを設定してみよう
- CI/CDを使ってみよう
- GitHubがCI/CDソリューションを発表。GitHub Actionsによる実装
- GitLabを用いた継続的インテグレーション
- DevOpsのサイクルをコードで管理し、プロセスを自動化する「CI/CDパイプライン」