- Authors

- Name
- Youngju Kim
- @fjvbn20031
- Part 1: GitHub Actionsアーキテクチャ
- Part 2: GoプロジェクトCI/CD
- Part 3: ブランチ戦略
- Part 4: フルパイプライン -- Goマイクロサービス
- Part 5: パフォーマンスとコスト最適化
- クイズ
- 参考文献(さんこうぶんけん)
Part 1: GitHub Actionsアーキテクチャ
1.1 コアコンセプト
GitHub Actionsは、GitHubに深(ふか)く統合(とうごう)されたCI/CDプラットフォームです。外部(がいぶ)CIツールとは異(こと)なり、Pull Request、Issue、Release、そしてGitHubエコシステム全体(ぜんたい)へのネイティブアクセスを持(も)ちます。
アーキテクチャは5つの基本(きほん)プリミティブで構成(こうせい)されています。
- Workflow(ワークフロー) --
.github/workflows/配下(はいか)のYAMLファイルで、自動化(じどうか)プロセスを定義(ていぎ)する - Event(イベント) -- ワークフローを起動(きどう)するトリガー(push、pull_request、schedule、workflow_dispatchなど)
- Job(ジョブ) -- 同(おな)じランナー上(じょう)で実行(じっこう)されるステップの集合(しゅうごう)、デフォルトで並列(へいれつ)実行
- Step(ステップ) -- ジョブ内(ない)の個々(ここ)のタスク、シェルコマンドまたはアクション
- Runner(ランナー) -- ジョブが実行される仮想(かそう)または物理(ぶつり)マシン
# .github/workflows/ci.yml
name: CI Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
concurrency:
group: ci-BRANCH_REF
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- name: Run tests
run: echo "Running tests..."
1.2 イベントタイプとトリガー
GitHub Actionsは35以上(いじょう)のイベントタイプをサポートしています。最(もっと)もよく使(つか)われるものは以下の通りです。
| イベント | 説明 | ユースケース |
|---|---|---|
| push | ブランチへのコードプッシュ | main/developでのCIビルド |
| pull_request | PRのオープン/更新/クローズ | コードレビュー自動化 |
| schedule | Cronベースのトリガー | ナイトリービルド、クリーンアップ |
| workflow_dispatch | 手動トリガー | オンデマンドデプロイ |
| release | リリース公開 | 本番デプロイメント |
| repository_dispatch | 外部Webhook | クロスリポジトリトリガー |
| workflow_call | 別ワークフローからの呼び出し | 再利用可能ワークフロー |
パスとブランチによるイベントフィルタリング:
on:
push:
branches:
- main
- 'release/**'
paths:
- 'src/**'
- 'go.mod'
- 'go.sum'
paths-ignore:
- '**.md'
- 'docs/**'
Cron式(しき)によるスケジュール:
on:
schedule:
# 平日のUTC 2:00に実行
- cron: '0 2 * * 1-5'
1.3 並行制御(へいこうせいぎょ)
Concurrencyグループは重複(ちょうふく)するワークフロー実行を防止(ぼうし)し、コンピューティングリソースを節約(せつやく)します。
concurrency:
group: deploy-production
cancel-in-progress: false # 進行中のデプロイはキャンセルしない
# PRビルドの場合、同じPRの前回の実行をキャンセル
concurrency:
group: pr-build-PR_NUMBER
cancel-in-progress: true
1.4 ランナータイプ
| ランナー | vCPU | RAM | ストレージ | コスト(分) |
|---|---|---|---|---|
| ubuntu-latest | 4 | 16 GB | 14 GB SSD | $0.008 |
| ubuntu-latest-xl (4x) | 16 | 64 GB | 150 GB SSD | $0.032 |
| macos-latest | 3 (M1) | 7 GB | 14 GB SSD | $0.08 |
| windows-latest | 2 | 7 GB | 14 GB SSD | $0.016 |
| self-hosted | カスタム | カスタム | カスタム | 無料(自前インフラ) |
1.5 必須(ひっす)アクション Top 20
最も有用(ゆうよう)なコミュニティおよび公式(こうしき)アクション:
# 1. コードのチェックアウト
- uses: actions/checkout@v4
# 2. Goのセットアップ
- uses: actions/setup-go@v5
with:
go-version: '1.22'
cache: true
# 3. 依存関係のキャッシュ
- uses: actions/cache@v4
with:
path: ~/go/pkg/mod
key: go-mod-HASH_OF_GO_SUM
# 4. アーティファクトのアップロード
- uses: actions/upload-artifact@v4
with:
name: binary
path: ./bin/
# 5. アーティファクトのダウンロード
- uses: actions/download-artifact@v4
# 6. Dockerビルドとプッシュ
- uses: docker/build-push-action@v6
with:
push: true
tags: myapp:latest
# 7. コンテナレジストリへのログイン
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: GITHUB_ACTOR
password: GITHUB_TOKEN_SECRET
# 8. Docker Buildxのセットアップ
- uses: docker/setup-buildx-action@v3
# 9. GitHubリリース
- uses: softprops/action-gh-release@v2
# 10. Slack通知
- uses: slackapi/slack-github-action@v2
# 11. Node.jsのセットアップ
- uses: actions/setup-node@v4
# 12. Pythonのセットアップ
- uses: actions/setup-python@v5
# 13. golangci-lint
- uses: golangci/golangci-lint-action@v6
# 14. CodeQL分析
- uses: github/codeql-action/analyze@v3
# 15. K8sへのデプロイ
- uses: azure/k8s-deploy@v5
# 16. AWS認証情報
- uses: aws-actions/configure-aws-credentials@v4
# 17. GCP認証
- uses: google-github-actions/auth@v2
# 18. Terraform
- uses: hashicorp/setup-terraform@v3
# 19. PRコメント作成
- uses: peter-evans/create-or-update-comment@v4
# 20. PRラベル
- uses: actions/labeler@v5
1.6 シークレット管理(かんり)とOIDC
リポジトリシークレットと環境(かんきょう)シークレット:
シークレットは暗号化(あんごうか)され、ワークフローにのみ公開(こうかい)されます。ログでは自動的(じどうてき)にマスクされます。
jobs:
deploy:
environment: production
steps:
- name: Deploy
env:
API_KEY: SECRETS_API_KEY_REF
DB_PASSWORD: SECRETS_DB_PASSWORD_REF
run: ./deploy.sh
注:上記(じょうき)のYAMLでは、SECRETS_API_KEY_REFとSECRETS_DB_PASSWORD_REFはリポジトリ設定(せってい)で構成されたGitHubシークレットへの参照(さんしょう)を表します。
クラウドプロバイダー認証(にんしょう)のためのOIDC(静的認証情報不要):
jobs:
deploy-aws:
permissions:
id-token: write
contents: read
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions
aws-region: us-east-1
OIDCはGitHubとクラウドプロバイダー間(かん)の信頼(しんらい)関係を確立(かくりつ)することで、長期間有効(ゆうこう)な認証情報を排除(はいじょ)します。ワークフローは自動的にスコープされ、ローテーションされる短期トークンを要求(ようきゅう)します。
1.7 環境とデプロイメント保護(ほご)
環境を使用すると、デプロイメントの保護ルールを定義できます。
jobs:
deploy-staging:
environment: staging
runs-on: ubuntu-latest
steps:
- run: ./deploy.sh staging
deploy-production:
needs: deploy-staging
environment:
name: production
url: https://myapp.example.com
runs-on: ubuntu-latest
steps:
- run: ./deploy.sh production
環境保護ルールには以下が含(ふく)まれます:
- 必須レビュアー(最大6名)
- 待機(たいき)タイマー(デプロイ前の遅延)
- ブランチ制限(mainのみproductionにデプロイ可能)
- カスタムデプロイメントブランチポリシー
Part 2: GoプロジェクトCI/CD
2.1 Goビルドの基礎(きそ)
Goはランタイム依存関係(いぞんかんけい)のない静的(せいてき)バイナリにコンパイルされるため、コンテナ化されたデプロイメントに最適(さいてき)です。本番(ほんばん)ビルドの主要(しゅよう)フラグ:
# すべての最適化を有効にした本番ビルド
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build \
-ldflags="-s -w -X main.version=1.2.3 -X main.commit=abc123 -X main.buildTime=2026-03-23T10:00:00Z" \
-trimpath \
-o ./bin/myapp \
./cmd/server/
ビルドフラグの説明(せつめい):
| フラグ | 目的 |
|---|---|
| CGO_ENABLED=0 | 完全な静的バイナリのためcgoを無効化 |
| -ldflags="-s -w" | デバッグ情報を削除、バイナリサイズ約30%削減 |
| -ldflags="-X main.version=..." | ビルド時にバージョン情報を注入 |
| -trimpath | バイナリからローカルファイルシステムパスを除去 |
| -race | レースディテクタ有効化(テスト専用、本番には使用しない) |
| -cover | カバレッジ計測付きビルド |
2.2 クロスコンパイルマトリックス
Goはクロスコンパイルに優(すぐ)れています。単一(たんいつ)のCIジョブで複数(ふくすう)プラットフォーム向けにビルドできます。
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
goos: [linux, darwin, windows]
goarch: [amd64, arm64]
exclude:
- goos: windows
goarch: arm64
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.22'
- name: Build
env:
GOOS: matrix-goos-value
GOARCH: matrix-goarch-value
run: |
BINARY_NAME="myapp-matrix-goos-value-matrix-goarch-value"
if [ "matrix-goos-value" = "windows" ]; then
BINARY_NAME="myapp-matrix-goos-value-matrix-goarch-value.exe"
fi
go build -ldflags="-s -w" -trimpath -o "./dist/BINARY_NAME_VAR" ./cmd/server/
- uses: actions/upload-artifact@v4
with:
name: binary-matrix-goos-value-matrix-goarch-value
path: ./dist/
注:上記のマトリックスビルドでは、matrix-goos-valueとmatrix-goarch-valueはstrategy matrix設定から動的(どうてき)に解決(かいけつ)される値を表しています。
2.3 テスト戦略(せんりゃく)
包括的(ほうかつてき)なGoテストパイプラインにはユニットテスト、統合テスト、ベンチマークが含まれます。
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: testdb
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.22'
- name: カバレッジ付きユニットテスト
run: |
go test -v -race -coverprofile=coverage.out -covermode=atomic ./...
go tool cover -func=coverage.out
- name: 統合テスト
env:
DATABASE_URL: postgres://test:test@localhost:5432/testdb?sslmode=disable
run: |
go test -v -tags=integration -count=1 ./tests/integration/...
- name: ベンチマークテスト
run: |
go test -bench=. -benchmem -run=^$ ./... | tee benchmark.txt
- name: カバレッジアップロード
uses: codecov/codecov-action@v4
with:
files: ./coverage.out
token: CODECOV_TOKEN_REF
2.4 リンティングと静的解析(かいせき)
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '1.22'
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
version: v1.57
args: --timeout=5m
- name: go vet
run: go vet ./...
- name: staticcheck
uses: dominikh/staticcheck-action@v1
with:
version: '2024.1'
- name: govulncheck
run: |
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...
golangci-lint設定(.golangci.yml):
run:
timeout: 5m
go: '1.22'
linters:
enable:
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- unused
- bodyclose
- gocritic
- gofumpt
- gosec
- misspell
- prealloc
- revive
- unconvert
linters-settings:
gocritic:
enabled-checks:
- nestingReduce
- truncateCmp
- unnamedResult
gosec:
excludes:
- G104 # 未処理エラー
revive:
rules:
- name: unexported-return
disabled: true
issues:
exclude-rules:
- path: _test\.go
linters:
- gosec
- errcheck
2.5 Goのキャッシュ戦略
効果的(こうかてき)なキャッシュにより、Goビルド時間を60-80%短縮(たんしゅく)できます。
steps:
- uses: actions/setup-go@v5
with:
go-version: '1.22'
cache: true # 組み込みモジュールキャッシュ
# 高速コンパイルのための追加ビルドキャッシュ
- uses: actions/cache@v4
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: go-build-OS-HASH_OF_ALL_GO_FILES
restore-keys: |
go-build-OS-
キャッシュサイズ比較(ひかく):
| キャッシュタイプ | 一般的なサイズ | 節約時間 |
|---|---|---|
| Goモジュールキャッシュ | 100-500 MB | 30-60秒 |
| Goビルドキャッシュ | 200-800 MB | 45-120秒 |
| Dockerレイヤーキャッシュ | 500 MB-2 GB | 60-300秒 |
| golangci-lintキャッシュ | 50-200 MB | 20-40秒 |
2.6 マルチステージDockerビルド
# ステージ1: ビルド
FROM golang:1.22-alpine AS builder
RUN apk add --no-cache git ca-certificates tzdata
WORKDIR /app
# 依存関係のキャッシュ
COPY go.mod go.sum ./
RUN go mod download && go mod verify
# ビルド
COPY . .
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go build \
-ldflags="-s -w -X main.version=VERSION_ARG -X main.commit=COMMIT_ARG" \
-trimpath \
-o /app/server \
./cmd/server/
# ステージ2: ランタイム
FROM scratch
COPY /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY /usr/share/zoneinfo /usr/share/zoneinfo
COPY /app/server /server
EXPOSE 8080
ENTRYPOINT ["/server"]
注:上記のDockerfileでは、VERSION_ARGとCOMMIT_ARGはCIパイプラインで実際のバージョンとコミットハッシュに置換(ちかん)されるプレースホルダーです。
Dockerビルドワークフロー:
jobs:
docker:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: GITHUB_ACTOR_REF
password: GITHUB_TOKEN_REF
- uses: docker/metadata-action@v5
id: meta
with:
images: ghcr.io/OWNER/myapp
tags: |
type=sha
type=ref,event=branch
type=semver,pattern=v{{version}}
type=semver,pattern=v{{major}}.{{minor}}
- uses: docker/build-push-action@v6
with:
context: .
push: true
tags: steps-meta-outputs-tags
labels: steps-meta-outputs-labels
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
VERSION=v1.2.3
COMMIT=GITHUB_SHA_REF
2.7 GoReleaser統合(とうごう)
GoReleaserはリリースプロセス全体(ビルド、パッケージング、公開)を自動化します。
# .goreleaser.yml
version: 2
before:
hooks:
- go mod tidy
- go generate ./...
builds:
- id: server
main: ./cmd/server/
binary: myapp
env:
- CGO_ENABLED=0
goos:
- linux
- darwin
- windows
goarch:
- amd64
- arm64
ldflags:
- -s -w
- -X main.version={{.Version}}
- -X main.commit={{.Commit}}
- -X main.date={{.Date}}
archives:
- format: tar.gz
name_template: 'myapp_{{.Version}}_{{.Os}}_{{.Arch}}'
format_overrides:
- goos: windows
format: zip
dockers:
- image_templates:
- 'ghcr.io/OWNER/myapp:{{.Version}}'
- 'ghcr.io/OWNER/myapp:latest'
dockerfile: Dockerfile.goreleaser
build_flag_templates:
- '--label=org.opencontainers.image.version={{.Version}}'
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
- '^ci:'
release:
github:
owner: myorg
name: myapp
GoReleaserのワークフロー:
name: Release
on:
push:
tags:
- 'v*'
permissions:
contents: write
packages: write
jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version: '1.22'
- uses: goreleaser/goreleaser-action@v6
with:
version: '~> v2'
args: release --clean
env:
GITHUB_TOKEN: GITHUB_TOKEN_SECRET_REF
Part 3: ブランチ戦略
3.1 Git Flow
Git Flowは、スケジュールされたリリースを持つプロジェクトに適(てき)した包括的なブランチモデルです。
ブランチ構成:
main-- 本番対応(たいおう)コード、バージョン番号(ばんごう)でタグ付けdevelop-- フィーチャーの統合ブランチfeature/xxx-- 新機能(きのう)のための短期(たんき)ブランチrelease/x.y.z-- リリース準備(じゅんび)と安定化(あんていか)hotfix/xxx-- 本番の緊急(きんきゅう)修正(しゅうせい)
フロー:
- developからフィーチャーブランチを作成
- フィーチャーを開発・テスト
- PRを通じてフィーチャーをdevelopにマージ
- developからリリースブランチを作成
- 安定化、バージョンバンプ、mainとdevelopにマージ
- mainブランチにバージョンタグを付与(ふよ)
- ホットフィックス:mainからブランチ作成、修正、mainとdevelopにマージ
メリット: 明確(めいかく)な構造、並列開発、リリース管理 デメリット: 複雑、ブランチが多い、高速プロジェクトには遅い
3.2 GitHub Flow
GitHub Flowは継続的(けいぞくてき)デリバリーに焦点(しょうてん)を当てたシンプルなモデルです。
ブランチ構成:
main-- 常(つね)にデプロイ可能feature/xxx-- すべての作業はフィーチャーブランチで行う
フロー:
- mainからブランチ作成
- コミットを追加(ついか)
- Pull Requestをオープン
- コードレビューとディスカッション
- デプロイとテスト(オプションでステージングへ)
- mainにマージ
メリット: シンプル、高速、小さなPRを促進(そくしん) デメリット: リリース管理なし、すべてがmainに入る
3.3 Trunk-Based Development
Trunk-Based Developmentはブランチの存続(そんぞく)期間(きかん)を最小化(さいしょうか)し、継続的インテグレーションを重視(じゅうし)します。
ブランチ構成:
main(トランク) -- 全員がここにコミット、常にリリース可能- 短期フィーチャーブランチ(1-2日以内)
- オプションのリリースブランチ(修正のチェリーピック用)
フロー:
- mainから最新を取得(しゅとく)
- 小さな増分(ぞうぶん)的変更を加える
- ローカルですべてのテストを実行
- mainに直接プッシュ(または非常に短期のPR)
- CIが即座(そくざ)に検証(けんしょう)
- フィーチャーフラグを通じて継続的にデプロイ
メリット: 最速のフィードバック、マージコンフリクト最小、最もシンプルなモデル デメリット: 強力なCIが必要、フィーチャーフラグが必須、規律(きりつ)あるチームが必要
3.4 戦略比較
| 観点(かんてん) | Git Flow | GitHub Flow | Trunk-Based |
|---|---|---|---|
| 複雑さ | 高い | 低い | 非常に低い |
| ブランチ寿命 | 数日〜数週間 | 数時間〜数日 | 数時間 |
| リリース頻度 | スケジュール制 | 継続的 | 継続的 |
| チームサイズ | 大規模 | 小〜中規模 | 任意のサイズ |
| CI/CD成熟度要件 | 低 | 中 | 高 |
| フィーチャーフラグ | 不要 | オプション | 必須 |
| マージコンフリクト | 頻繁 | 時々 | 稀 |
| 最適な用途 | エンタープライズ、バージョン管理 | SaaS、Webアプリ | 高パフォーマンス |
| デプロイ頻度 | 週次/月次 | 日次 | 1日複数回 |
3.5 ブランチ保護ルール
# GitHub API/設定によるブランチ保護
# mainブランチの保護
branches:
main:
protection:
required_status_checks:
strict: true
contexts:
- 'ci/lint'
- 'ci/test'
- 'ci/build'
required_pull_request_reviews:
required_approving_review_count: 2
dismiss_stale_reviews: true
require_code_owner_reviews: true
restrictions:
users: []
teams: ['core-maintainers']
enforce_admins: true
required_linear_history: true
allow_force_pushes: false
allow_deletions: false
3.6 CODEOWNERS
CODEOWNERSファイルは、レビューが自動的にリクエストされる担当者(たんとうしゃ)を定義します。
# .github/CODEOWNERS
# すべてのデフォルトオーナー
* @myorg/backend-team
# Goソースコード
/cmd/ @myorg/go-team
/internal/ @myorg/go-team
/pkg/ @myorg/go-team
# インフラストラクチャ
/.github/ @myorg/devops-team
/deploy/ @myorg/devops-team
/terraform/ @myorg/devops-team
Dockerfile @myorg/devops-team
# ドキュメント
/docs/ @myorg/docs-team
*.md @myorg/docs-team
# API定義
/api/ @myorg/api-team @myorg/backend-team
3.7 リポジトリルールセット
ルールセット(2023年導入(どうにゅう))は従来(じゅうらい)のブランチ保護ルールよりも柔軟(じゅうなん)な保護を提供します。
- パターンマッチングによる複数ブランチ/タグへの適用
- 階層化(かいそうか)されたルール(組織レベル + リポジトリレベル)
- 特定(とくてい)のロールに対するバイパス権限(けんげん)
- タグ保護
- 署名(しょめい)付きプッシュ制限
- メタデータ制限(コミットメッセージ形式、作者メール)
ルールセット設定例:
名前: production-protection
対象: "main" および "release/**" に一致するブランチ
ルール:
- マージ前にPull Requestを要求(2件の承認)
- ステータスチェック必須: lint, test, build
- 署名付きコミットを要求
- 強制プッシュをブロック
- リニア履歴を要求
バイパス: 緊急時のリポジトリ管理者
Part 4: フルパイプライン -- Goマイクロサービス
4.1 プロジェクト構造(こうぞう)
myapp/
cmd/
server/
main.go
internal/
handler/
service/
repository/
pkg/
middleware/
api/
openapi.yaml
deploy/
k8s/
deployment.yaml
service.yaml
ingress.yaml
docker/
Dockerfile
.github/
workflows/
ci.yml
deploy.yml
release.yml
CODEOWNERS
.golangci.yml
.goreleaser.yml
go.mod
go.sum
Makefile
4.2 完全なCIワークフロー
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
paths-ignore:
- '**.md'
- 'docs/**'
pull_request:
branches: [main]
concurrency:
group: ci-REF_NAME
cancel-in-progress: true
env:
GO_VERSION: '1.22'
GOLANGCI_LINT_VERSION: v1.57
REGISTRY: ghcr.io
IMAGE_NAME: myorg/myapp
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: GO_VERSION_ENV
- uses: golangci/golangci-lint-action@v6
with:
version: GOLANGCI_LINT_VERSION_ENV
- name: フォーマットチェック
run: |
if [ -n "$(gofmt -l .)" ]; then
echo "フォーマットされていないファイル:"
gofmt -l .
exit 1
fi
- name: 依存関係の検証
run: |
go mod verify
go mod tidy
git diff --exit-code go.mod go.sum
test:
name: Test
runs-on: ubuntu-latest
needs: lint
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_USER: test
POSTGRES_PASSWORD: test
POSTGRES_DB: testdb
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: GO_VERSION_ENV
- name: ユニットテスト
run: |
go test -v -race -count=1 \
-coverprofile=coverage.out \
-covermode=atomic \
./...
- name: 統合テスト
env:
DATABASE_URL: postgres://test:test@localhost:5432/testdb?sslmode=disable
REDIS_URL: redis://localhost:6379
run: |
go test -v -tags=integration -count=1 ./tests/integration/...
- name: カバレッジレポート
run: |
COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}')
echo "合計カバレッジ: COVERAGE_VAR"
- uses: codecov/codecov-action@v4
with:
files: ./coverage.out
security:
name: Security Scan
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: GO_VERSION_ENV
- name: 脆弱性チェック
run: |
go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...
- name: ライセンスチェック
run: |
go install github.com/google/go-licenses@latest
go-licenses check ./...
build:
name: Build
runs-on: ubuntu-latest
needs: [test, security]
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: GITHUB_ACTOR_REF
password: GITHUB_TOKEN_REF
- uses: docker/metadata-action@v5
id: meta
with:
images: REGISTRY_ENV/IMAGE_NAME_ENV
tags: |
type=sha,prefix=
type=ref,event=branch
type=ref,event=pr
- uses: docker/build-push-action@v6
with:
context: .
file: ./deploy/docker/Dockerfile
push: PUSH_CONDITION
tags: steps-meta-outputs-tags
labels: steps-meta-outputs-labels
cache-from: type=gha
cache-to: type=gha,mode=max
4.3 デプロイメントワークフロー
# .github/workflows/deploy.yml
name: Deploy
on:
workflow_run:
workflows: ['CI']
branches: [main]
types: [completed]
concurrency:
group: deploy-ENVIRONMENT
cancel-in-progress: false
jobs:
deploy-staging:
if: github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
environment:
name: staging
url: https://staging.myapp.example.com
steps:
- uses: actions/checkout@v4
- name: kubectlの設定
uses: azure/setup-kubectl@v4
- name: K8sコンテキストの設定
uses: azure/k8s-set-context@v4
with:
method: kubeconfig
kubeconfig: SECRETS_KUBECONFIG_STAGING_REF
- name: ステージングへのデプロイ
run: |
kubectl set image deployment/myapp \
myapp=ghcr.io/myorg/myapp:COMMIT_SHA \
-n staging
kubectl rollout status deployment/myapp -n staging --timeout=300s
- name: スモークテスト実行
run: |
sleep 10
curl -sf https://staging.myapp.example.com/healthz || exit 1
deploy-production:
needs: deploy-staging
runs-on: ubuntu-latest
environment:
name: production
url: https://myapp.example.com
steps:
- uses: actions/checkout@v4
- name: kubectlの設定
uses: azure/setup-kubectl@v4
- name: K8sコンテキストの設定
uses: azure/k8s-set-context@v4
with:
method: kubeconfig
kubeconfig: SECRETS_KUBECONFIG_PRODUCTION_REF
- name: 本番へのデプロイ
run: |
kubectl set image deployment/myapp \
myapp=ghcr.io/myorg/myapp:COMMIT_SHA \
-n production
kubectl rollout status deployment/myapp -n production --timeout=300s
- name: デプロイメントの検証
run: |
curl -sf https://myapp.example.com/healthz || exit 1
- name: 失敗時の通知
if: failure()
uses: slackapi/slack-github-action@v2
with:
webhook: SECRETS_SLACK_WEBHOOK_REF
webhook-type: incoming-webhook
payload: |
{
"text": "本番デプロイメントが失敗しました: COMMIT_SHA_SHORT"
}
4.4 Kubernetesマニフェスト
# deploy/k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
labels:
app: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: ghcr.io/myorg/myapp:latest
ports:
- containerPort: 8080
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /readyz
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
env:
- name: LOG_LEVEL
value: 'info'
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: myapp-secrets
key: database-url
# deploy/k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
name: myapp
spec:
type: ClusterIP
selector:
app: myapp
ports:
- port: 80
targetPort: 8080
protocol: TCP
4.5 再利用可能(さいりようかのう)ワークフロー
リポジトリ間でCI/CDロジックを共有(きょうゆう)するための再利用可能ワークフローを作成します。
# .github/workflows/reusable-go-ci.yml
name: Reusable Go CI
on:
workflow_call:
inputs:
go-version:
description: '使用するGoバージョン'
required: false
type: string
default: '1.22'
coverage-threshold:
description: '最小カバレッジ率'
required: false
type: number
default: 70
secrets:
CODECOV_TOKEN:
required: false
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: inputs-go-version
- run: go test -race -coverprofile=coverage.out ./...
- run: go vet ./...
再利用可能ワークフローの呼(よ)び出(だ)し:
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
go-ci:
uses: myorg/.github/.github/workflows/reusable-go-ci.yml@main
with:
go-version: '1.22'
coverage-threshold: 80
secrets:
CODECOV_TOKEN: SECRETS_CODECOV_TOKEN_REF
4.6 パスベースのトリガー
モノレポでは、関連(かんれん)ファイルが変更された場合(ばあい)にのみワークフローをトリガーします。
on:
push:
paths:
- 'services/api/**'
- 'shared/pkg/**'
- 'go.mod'
- 'go.sum'
paths-ignore:
- '**.md'
- 'docs/**'
モノレポでの変更検出(けんしゅつ):
jobs:
changes:
runs-on: ubuntu-latest
outputs:
api: steps-filter-outputs-api
web: steps-filter-outputs-web
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v3
id: filter
with:
filters: |
api:
- 'services/api/**'
- 'shared/**'
web:
- 'services/web/**'
- 'shared/**'
build-api:
needs: changes
if: needs.changes.outputs.api == 'true'
runs-on: ubuntu-latest
steps:
- run: echo "APIサービスをビルド中"
build-web:
needs: changes
if: needs.changes.outputs.web == 'true'
runs-on: ubuntu-latest
steps:
- run: echo "Webサービスをビルド中"
4.7 ロールバック戦略
# .github/workflows/rollback.yml
name: Rollback
on:
workflow_dispatch:
inputs:
environment:
description: '対象環境'
required: true
type: choice
options:
- staging
- production
revision:
description: 'ロールバック先のリビジョン(空欄で前回に戻る)'
required: false
type: string
jobs:
rollback:
runs-on: ubuntu-latest
environment: inputs-environment
steps:
- name: kubectlの設定
uses: azure/setup-kubectl@v4
- name: デプロイメントのロールバック
run: |
if [ -z "REVISION_INPUT" ]; then
kubectl rollout undo deployment/myapp -n TARGET_ENV
else
kubectl rollout undo deployment/myapp \
--to-revision=REVISION_INPUT -n TARGET_ENV
fi
kubectl rollout status deployment/myapp -n TARGET_ENV --timeout=300s
- name: ロールバックの検証
run: |
curl -sf https://TARGET_ENV.myapp.example.com/healthz || exit 1
- name: 通知
uses: slackapi/slack-github-action@v2
with:
webhook: SECRETS_SLACK_WEBHOOK_REF
webhook-type: incoming-webhook
payload: |
{
"text": "TARGET_ENV環境のロールバックが完了しました"
}
Part 5: パフォーマンスとコスト最適化
5.1 キャッシュ戦略の深掘(ふかぼ)り
レイヤー1: Goモジュールキャッシュ(actions/setup-go組み込み)
setup-goアクションはGoモジュールディレクトリを自動的にキャッシュします。追加設定は不要です。
レイヤー2: Goビルドキャッシュ
- uses: actions/cache@v4
with:
path: ~/.cache/go-build
key: go-build-OS-HASH_OF_ALL_GO_FILES
restore-keys: |
go-build-OS-
レイヤー3: GitHub Actionsキャッシュバックエンドを使ったDockerレイヤーキャッシュ
- uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
レイヤー4: golangci-lintキャッシュ
golangci-lint-actionは独自(どくじ)のキャッシュを自動的に処理(しょり)します。キャッシュキーはGoバージョンとgolangci-lint設定に基(もと)づきます。
キャッシュ効率(こうりつ)の監視(かんし):
ワークフローログでキャッシュヒット率を追跡(ついせき)しましょう。健全(けんぜん)なパイプラインでは、モジュールとビルドキャッシュのヒット率が80%以上であるべきです。
5.2 ジョブの並列実行
最大の並列性(へいれつせい)を得るためにワークフローDAGを構造化します。
lint ------+
|
test ------+--> build --> deploy-staging --> deploy-production
|
security --+
jobs:
lint:
runs-on: ubuntu-latest
# 依存なし、即座に実行
test:
runs-on: ubuntu-latest
# 依存なし、lintと並列実行
security:
runs-on: ubuntu-latest
# 依存なし、lintとtestと並列実行
build:
needs: [lint, test, security]
# 3つすべての完了を待機
deploy-staging:
needs: build
deploy-production:
needs: deploy-staging
5.3 セルフホストランナー
コストの高い、または特殊(とくしゅ)なワークロードには、セルフホストランナーが分単位(ぶんたんい)の課金(かきん)を排除します。
jobs:
build:
runs-on: [self-hosted, linux, x64, gpu]
steps:
- uses: actions/checkout@v4
- run: nvidia-smi # セルフホストでのGPUアクセス
セルフホストランナーを使うべき場合:
| シナリオ | 推奨(すいしょう) |
|---|---|
| ビルド時間10分未満 | GitHub-hosted |
| ビルド時間10-30分 | セルフホスト検討 |
| ビルド時間30分超 | セルフホスト強く推奨 |
| GPU/専用ハードウェア | セルフホスト(必須) |
| コンプライアンス(データローカリティ) | セルフホスト(必須) |
| 内部リソースへのネットワークアクセス | セルフホスト(必須) |
Dockerによるセルフホストランナーのセットアップ:
# セルフホストランナー用docker-compose.yml
version: '3.8'
services:
runner:
image: myoung34/github-runner:latest
environment:
REPO_URL: https://github.com/myorg/myrepo
RUNNER_TOKEN: your-registration-token
RUNNER_NAME: custom-runner-1
RUNNER_WORKDIR: /tmp/github-runner
LABELS: self-hosted,linux,x64
volumes:
- /var/run/docker.sock:/var/run/docker.sock
restart: unless-stopped
5.4 課金とコスト計算(けいさん)
GitHub Actionsの料金(りょうきん)(2026年現在):
| プラン | 含まれる分数 | ストレージ | 追加分あたり(Linux) |
|---|---|---|---|
| Free | 2,000/月 | 500 MB | N/A |
| Team | 3,000/月 | 2 GB | $0.008 |
| Enterprise | 50,000/月 | 50 GB | $0.008 |
OS乗数(じょうすう):
| OS | 乗数 |
|---|---|
| Linux | 1x |
| Windows | 2x |
| macOS | 10x |
コスト最適化のヒント:
- concurrencyグループで冗長(じょうちょう)なワークフロー実行をキャンセル
- パスフィルタで不要なビルドをスキップ
- キャッシュを最大限活用(モジュール、ビルド、Dockerレイヤー)
- 絶対に必要な場合を除きmacOSランナーを避ける(10倍のコスト)
- マトリックス戦略を賢明(けんめい)に使用 -- 各エントリは別のジョブ
- 大量のリポジトリにはセルフホスト
timeout-minutesで暴走(ぼうそう)ワークフローを防止- 小さなジョブを結合してジョブ起動オーバーヘッドを削減(約15-30秒/ジョブ)
5.5 ワークフローパフォーマンスの監視
ボトルネックを特定するための主要メトリクスを追跡します。
# 主要ステップにタイミングを追加
- name: タイミング付きビルド
run: |
START_TIME=$(date +%s)
go build -o ./bin/myapp ./cmd/server/
END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))
echo "ビルドにDURATION_VAR秒かかりました"
追跡すべき主要メトリクス:
- ワークフロー全体の所要時間
- 個々のジョブとステップの所要時間
- キャッシュヒット/ミス率
- キュー待機時間(ランナーがジョブを取得するまでの時間)
- ジョブタイプ別の失敗率
- ワークフロー実行あたりのコスト
5.6 actによるローカルテスト
プッシュ前にGitHub Actionsをローカルでテストします。
# actのインストール
brew install act
# デフォルトイベント(push)の実行
act
# 特定のワークフローを実行
act -W .github/workflows/ci.yml
# 特定のジョブを実行
act -j test
# 特定のイベントを使用
act pull_request
# シークレットを渡す
act -s GITHUB_TOKEN=your-token
# より大きなランナーイメージを使用
act -P ubuntu-latest=catthehacker/ubuntu:full-latest
actの制限事項(せいげんじこう):
- servicesのサポートなし(データベースのモックが必要)
- 一部のGitHubコンテキスト変数が利用できない場合がある
- Docker-in-Dockerが問題になることがある
- 一部のアクションがGitHub-hostedランナーと同一に動作(どうさ)しない場合がある
クイズ
Q1: GitHub Actionsワークフローにおけるneedsとusesの違いは何ですか?
回答: needsはジョブの依存関係を定義します。現在のジョブが実行される前に正常に完了する必要があるジョブを指定します。例えば、needs: [lint, test]は、lintとtestの両方が完了するまでジョブが待機することを意味します。usesはアクションまたは再利用可能ワークフローを参照します。ステップ内では、uses: actions/checkout@v4がcheckoutアクションを実行します。ジョブレベルでは、uses: org/repo/.github/workflows/ci.yml@mainが再利用可能ワークフローを呼び出します。
Q2: Go DockerビルドでCGO_ENABLED=0が重要な理由は何ですか?
回答: CGO_ENABLED=0を設定すると、C言語ライブラリへの依存がない完全に静的にリンクされたバイナリが生成されます。これは、glibcを含まないscratchやdistrolessのような最小限のベースイメージを使用する場合に重要です。CGO_ENABLED=0なしでは、バイナリはlibcに動的リンクし、これらの最小限のコンテナでは実行に失敗します。また、Cクロスコンパイラツールチェーンが不要になるため、クロスコンパイルが簡単になります。
Q3: Git FlowよりもTrunk-Based Developmentを選ぶべきなのはいつですか?
回答: Trunk-Based Developmentは、1日に複数回のデプロイが必要で、チームが自動テストを含む強力なCI/CDプラクティスを持ち、未完成の機能を管理するためにフィーチャーフラグを使用できる場合に最適です。Git Flowは、正式なリリース管理が必要な場合、複数バージョンの同時サポートが必要な場合、またはCI/CDインフラが十分に成熟していない場合に適しています。重要な判断基準はデプロイ頻度です。1日に複数回デプロイするならTrunk-Basedが優れています。バージョン番号付きで月次リリースするなら、Git Flowが必要な構造を提供します。
Q4: OIDCはクラウドプロバイダー認証において従来のシークレットよりどのようにセキュリティを向上させますか?
回答: OIDC(OpenID Connect)は、GitHubとクラウドプロバイダー間のフェデレーション信頼関係を確立することで、長期間有効な静的認証情報(アクセスキー)を排除します。恒久的なアクセスキーをリポジトリシークレットとして保存する代わりに、ワークフローは特定のリポジトリ、ブランチ、環境に自動的にスコープされる短期トークンを要求します。これらのトークンは数分で期限切れとなるため、漏洩時の影響範囲が縮小されます。OIDCはどのワークフローがどの権限を要求したかの監査証跡も提供し、ローテーションや偶発的な漏洩のリスクがある認証情報が存在しません。
Q5: Go CIパイプラインにおいて、コスト対パフォーマンス比が最も高いキャッシュ戦略は何ですか?
回答: 効果の高い順にキャッシュレイヤーを並べると:(1) actions/setup-go組み込みキャッシュによるGoモジュールキャッシュ -- 依存関係のダウンロードを排除し、通常30-60秒節約。(2) actions/cacheを介したGoビルドキャッシュ -- 変更されていないパッケージの再コンパイルを回避し、45-120秒節約。(3) GitHub Actionsキャッシュバックエンド(type=gha)を使用したDockerレイヤーキャッシュ -- 変更されていないDockerレイヤーの再ビルドを回避し、60-300秒節約。(4) golangci-lintキャッシュ(アクションにより自動処理)。これらを組み合わせると、10分のパイプラインを3分未満に短縮できます。モジュールキャッシュはsetup-goに組み込まれているため無料であり、キャッシュサイズに対して最も多くの時間を節約するため、コスト対パフォーマンス比が最も高くなります。
参考文献(さんこうぶんけん)
- GitHub Actions Documentation -- https://docs.github.com/en/actions
- GitHub Actions Workflow Syntax -- https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions
- GitHub Actions Contexts and Expressions -- https://docs.github.com/en/actions/learn-github-actions/contexts
- GitHub Actions Environments -- https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment
- GitHub OIDC with Cloud Providers -- https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect
- Go Build Documentation -- https://pkg.go.dev/cmd/go#hdr-Compile_packages_and_dependencies
- Go Cross-Compilation -- https://go.dev/doc/install/source#environment
- golangci-lint -- https://golangci-lint.run/
- GoReleaser Documentation -- https://goreleaser.com/
- Docker Multi-Stage Builds -- https://docs.docker.com/build/building/multi-stage/
- Docker Build Push Action -- https://github.com/docker/build-push-action
- Git Flow by Vincent Driessen -- https://nvie.com/posts/a-successful-git-branching-model/
- GitHub Flow -- https://docs.github.com/en/get-started/using-github/github-flow
- Trunk-Based Development -- https://trunkbaseddevelopment.com/
- Kubernetes Deployment Strategies -- https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
- GitHub Actions Caching -- https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows
- GitHub Actions Self-Hosted Runners -- https://docs.github.com/en/actions/hosting-your-own-runners
- GitHub Actions Reusable Workflows -- https://docs.github.com/en/actions/using-workflows/reusing-workflows
- GitHub Repository Rulesets -- https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets
- GitHub Actions Billing -- https://docs.github.com/en/billing/managing-billing-for-github-actions
- act - Run GitHub Actions Locally -- https://github.com/nektos/act
- CODEOWNERS Documentation -- https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
- Codecov GitHub Action -- https://github.com/codecov/codecov-action
- dorny/paths-filter -- https://github.com/dorny/paths-filter