ci-cd について
.NET プロジェクト向けの CI/CD 実践ガイドで、GitHub Actions と Azure DevOps Pipelines の例を扱います。パイプラインのコード化、テストによるデプロイ制御、単一成果物の環境間昇格を重視します。
主な機能
- 01GitHub Actions でのビルドとテスト
- 02Azure DevOps のパイプライン例
- 03Docker イメージと NuGet の公開
- 04単一成果物の環境間昇格
- 05テスト、フォーマット、シークレット管理
活用シーン
- 01main ブランチやプルリクエストのテスト自動化
- 02リリースタグでの NuGet パッケージ公開
- 03同じ成果物の開発環境から本番環境への昇格
- 04CI での Docker イメージのビルドと公開
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ codewithmukesh/ dotnet-claude-kit --skill ci-cdインストール後、Claude Code で/ci-cdを入力して読み込まれたか確認します。
詳細
CI/CD
基本原則
- パイプラインをコードとして管理 — YAML パイプラインをリポジトリにコミットします。UI での手動操作は行いません。
- 迅速なフィードバック — プッシュのたびにビルドとテストを実行します。NuGet パッケージをキャッシュし、問題があればすぐに失敗させます。
- ビルドは一度、デプロイは何度でも — 成果物は一度だけビルドし、環境間(開発 → ステージング → 本番)で昇格させます。
- テストを省略しない — テストをパイプラインのゲートにします。テストに合格しない限りデプロイしません。
パターン
GitHub Actions — ビルド + テスト
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
DOTNET_VERSION: '10.0.x'
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
jobs:
build-and-test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:18
env:
POSTGRES_DB: testdb
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v5
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: ${{ env.DOTNET_VERSION }}
- name: Restore
run: dotnet restore
- name: Build
run: dotnet build --no-restore --configuration Release
- name: Format check
run: dotnet format --verify-no-changes --no-restore
- name: Test
run: dotnet test --no-build --configuration Release --logger trx --results-directory TestResults
env:
ConnectionStrings__Default: "Host=localhost;Database=testdb;Username=postgres;Password=postgres"
- name: Publish test results
uses: actions/upload-artifact@v5
if: always()
with:
name: test-results
path: TestResults/*.trx
GitHub Actions — ビルド + Docker イメージの公開
# .github/workflows/publish.yml
name: Publish
on:
push:
tags: ['v*']
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v5
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract version from tag
id: version
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: |
ghcr.io/${{ github.repository }}:${{ steps.version.outputs.VERSION }}
ghcr.io/${{ github.repository }}:latest
Azure DevOps — ビルド + テスト
GitHub Actions と同じ、復元 → ビルド → フォーマット → テストの流れです。主な違いは次のとおりです。
# azure-pipelines.yml
trigger:
branches:
include: [main]
paths:
exclude: ['*.md', docs/]
pool:
vmImage: 'ubuntu-latest' # vs runs-on: ubuntu-latest
variables:
dotnetVersion: '10.0.x'
# Key task differences from GitHub Actions:
# Setup .NET: task: UseDotNet@2 (inputs: version: $(dotnetVersion))
# Test results: task: PublishTestResults@2 (testResultsFormat: VSTest)
# Steps use `script:` + `displayName:` instead of `- name:` + `run:`
# Services (e.g., Postgres) require a separate Docker task or pipeline service connection
NuGet パッケージの公開
# Part of GitHub Actions workflow
- name: Pack
run: dotnet pack src/MyLibrary -c Release -o ./nupkg --no-build
- name: Push to NuGet
run: dotnet nuget push ./nupkg/*.nupkg --api-key ${{ secrets.NUGET_API_KEY }} --source https://api.nuget.org/v3/index.json
アンチパターン
環境ごとに異なる成果物をビルドしない
# BAD — building separately for each environment
- script: dotnet publish -c Debug # for dev
- script: dotnet publish -c Release # for prod
# GOOD — build once, deploy everywhere
- script: dotnet publish -c Release -o ./publish
# Then deploy the same ./publish artifact to dev, staging, prod
CI でフォーマットチェックを省略しない
# BAD — no format enforcement
steps:
- run: dotnet build
- run: dotnet test
# GOOD — format check catches style issues early
steps:
- run: dotnet build
- run: dotnet format --verify-no-changes
- run: dotnet test
パイプラインにシークレットをハードコードしない
# BAD — secret in pipeline YAML
env:
DB_PASSWORD: "my-secret-password"
# GOOD — use pipeline secrets
env:
DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
判断ガイド
| シナリオ | 推奨事項 |
|---|---|
| オープンソースプロジェクト | GitHub Actions |
| Azure を利用するエンタープライズ | Azure DevOps Pipelines |
| Docker デプロイ | CI でマルチステージビルドを行い、コンテナレジストリにプッシュ |
| NuGet ライブラリ | タグ付け時にビルド → テスト → パック → プッシュ |
| データベースのマイグレーション | CI のテストステージで実行し、本番環境用にスクリプトを用意 |
| 環境間の昇格 | 同じ成果物を使い、構成を切り替える |
コメント
Markdown 対応