Day17: CI/CDツール:AWS CodePipeline vs Azure DevOps
皆さん、こんにちは。エンジニアのAkrです。
「徹底比較! AWS vs Azure」シリーズ、Day17へようこそ。
今回は、ソフトウェア開発における自動化の要、CI/CD(継続的インテグレーション・継続的デリバリー)ツールに焦点を当てます。AWSのCodePipelineと、AzureのAzure DevOpsは、どちらも開発プロセスの効率化に欠かせない強力なツールです。
CI/CDとは?
CI/CDとは、現代のソフトウェア開発において不可欠なプラクティスです。
CI(継続的インテグレーション)
開発者がコードの変更を頻繁に共有リポジトリにマージし、自動でテストを実行するプロセスです。これにより、バグの早期発見と修正が可能になります。
CD(継続的デリバリー/デプロイ)
テストに合格したコードを、本番環境に自動でリリースするプロセスです。手動デプロイのリスクを排除し、リリース頻度を向上させます。
CI/CDの効果
- 開発速度の向上: 手動作業の自動化により開発サイクルが短縮
- 品質の向上: 自動テストによる継続的な品質チェック
- リスクの軽減: 小さな変更を頻繁にデプロイすることでリスクを分散
- 開発者の生産性向上: 単純作業の自動化により創造的な作業に集中可能
サービス概要と基本アーキテクチャ
AWS CodePipeline
アプローチ: オーケストレーション型
AWS CodePipelineは、CI/CDの各ステップを他のAWSサービスと連携させるオーケストレーションツールとして設計されています。
主要構成サービス:
- CodeCommit: Gitベースのソースコードリポジトリ
- CodeBuild: フルマネージドなビルドサービス
- CodeDeploy: アプリケーションの自動デプロイサービス
- CodePipeline: 上記サービスを連携させるワークフロー管理
Azure DevOps
アプローチ: 統合プラットフォーム型
Azure DevOpsは、開発ライフサイクル全体をカバーする統合プラットフォームとして設計されています。
主要構成サービス:
- Azure Repos: Gitおよび Team Foundation Version Control (TFVC)
- Azure Pipelines: CI/CDパイプライン(ビルド・リリース)
- Azure Boards: アジャイルプロジェクト管理
- Azure Artifacts: パッケージ管理
- Azure Test Plans: テスト管理
詳細機能比較
機能 | AWS CodePipeline | Azure DevOps |
---|---|---|
ソースコード管理 | CodeCommit(Git) GitHub、Bitbucket連携 |
Azure Repos(Git/TFVC) GitHub、外部Git連携 |
ビルド環境 | CodeBuild(Linux/Windows) カスタムDockerイメージ対応 |
Azure Pipelines(Linux/Windows/macOS) セルフホストエージェント対応 |
デプロイ対象 | AWS特化(EC2、ECS、Lambda等) 外部環境は限定的 |
マルチクラウド対応 (AWS、Azure、GCP、オンプレミス) |
プロジェクト管理 | 非対応(外部ツール連携) | Azure Boards内蔵 (スクラム、カンバン対応) |
テスト管理 | 第三者ツール連携 | Azure Test Plans内蔵 |
パッケージ管理 | 第三者ツール連携 | Azure Artifacts内蔵 |
料金体系 | パイプライン実行課金 (月1,000実行まで無料) |
並行ジョブ数課金 (月1,800分まで無料) |
運用面での比較
学習コストと習得難易度
観点 | AWS CodePipeline | Azure DevOps |
---|---|---|
初期学習コスト | 中程度(複数サービスの理解が必要) | 高め(多機能だが統合されている) |
設定の複雑さ | シンプル(各ステップが明確) | 中程度(豊富な設定オプション) |
トラブルシューティング | サービス間の連携が複雑な場合あり | 統合環境のため原因特定が比較的容易 |
拡張性とカスタマイズ
観点 | AWS CodePipeline | Azure DevOps |
---|---|---|
カスタムアクション | AWS Lambda関数で拡張可能 サードパーティアクション対応 |
豊富なMarketplace拡張 カスタムタスク作成可能 |
並列実行 | ステージ内の並列アクション対応 | 高度な並列実行制御 依存関係の詳細設定 |
条件分岐 | 基本的な条件分岐 Lambda関数での高度制御 |
豊富な条件分岐オプション 承認ワークフロー内蔵 |
実際の使用例
AWS CodePipeline の典型的なパイプライン
AWS CodeBuildで使用するbuildspec.ymlの詳細な例を以下に示します。このファイルは、ビルドプロセスの各段階を定義し、Dockerイメージの構築からECRレジストリへのプッシュまでを自動化します。
# buildspec.yml - AWS CodeBuild設定ファイル
# CodeBuildプロジェクトのルートディレクトリに配置する
# buildspecのバージョンを指定(現在は0.2が最新)
version: 0.2
# 環境変数の定義(オプション)
env:
variables:
# アプリケーション固有の環境変数
APP_NAME: "my-web-app"
ENVIRONMENT: "production"
# Parameter StoreやSecrets Managerから取得する機密情報
parameter-store:
# DATABASE_URL: "/myapp/database/url"
# API_KEY: "/myapp/api/key"
# ビルドの各段階(フェーズ)を定義
phases:
# インストールフェーズ:必要なランタイムやツールのインストール
install:
runtime-versions:
# 使用するNode.jsのバージョンを指定
nodejs: 16
# Pythonが必要な場合は追加
# python: 3.9
commands:
# 必要なツールのインストール
- echo "Installing dependencies..."
- npm install -g @angular/cli # 例:Angularプロジェクトの場合
# - pip install awscli # AWS CLIが必要な場合
# ビルド前の準備フェーズ
pre_build:
commands:
# ECR(Elastic Container Registry)にログイン
- echo "Logging in to Amazon ECR..."
- aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
# 依存関係のインストール
- echo "Installing application dependencies..."
- npm install
# テストの実行(オプション)
- echo "Running tests..."
- npm run test
# 環境変数の設定
- echo "Setting up environment variables..."
- export IMAGE_TAG=${CODEBUILD_RESOLVED_SOURCE_VERSION:-latest}
- export IMAGE_URI=$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
# メインビルドフェーズ
build:
commands:
# ビルド開始のログ
- echo "Build started on $(date)"
# アプリケーションのビルド
- echo "Building the application..."
- npm run build
# Dockerイメージのビルド
- echo "Building Docker image..."
- docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .
# ECR用のタグ付け
- echo "Tagging image for ECR..."
- docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $IMAGE_URI
# ビルド後の処理フェーズ
post_build:
commands:
# ビルド完了のログ
- echo "Build completed on $(date)"
# DockerイメージをECRにプッシュ
- echo "Pushing Docker image to ECR..."
- docker push $IMAGE_URI
# イメージの詳細情報を出力
- echo "Docker image pushed successfully"
- echo "Image URI: $IMAGE_URI"
# デプロイメント用の設定ファイルを更新(ECS/EKSの場合)
- printf '[{"name":"'$APP_NAME'","imageUri":"'$IMAGE_URI'"}]' > imagedefinitions.json
# ビルド成果物(アーティファクト)の設定
artifacts:
files:
# ECSデプロイ用の設定ファイル
- imagedefinitions.json
# その他必要なファイル
- appspec.yml # CodeDeployを使用する場合
# - '**/*' # 全ファイルを含める場合
# アーティファクトの出力先を指定(オプション)
base-directory: .
# キャッシュの設定(ビルド時間短縮のため)
cache:
paths:
# Node.js依存関係のキャッシュ
- '/root/.npm/**/*'
# Dockerレイヤーキャッシュ(Docker-in-Dockerの場合)
- '/var/lib/docker/**/*'
buildspec.ymlの主要な構成要素の説明:
-
phases: ビルドプロセスを段階的に定義
-
install
: 必要なランタイムやツールのインストール -
pre_build
: ECRログイン、依存関係インストール、テスト実行 -
build
: アプリケーションビルド、Dockerイメージ作成 -
post_build
: イメージプッシュ、成果物の準備
-
-
env: 環境変数の定義
-
variables
: 通常の環境変数 -
parameter-store
: AWS Systems Manager Parameter Storeから取得
-
-
artifacts: ビルド成果物の指定
- 次のステージ(デプロイ)で使用するファイルを定義
-
cache: ビルド時間短縮のためのキャッシュ設定
Azure DevOps の典型的なパイプライン
Azure Pipelinesで使用するazure-pipelines.ymlの詳細な例を以下に示します。このファイルは、マルチステージパイプラインを定義し、ビルドからデプロイまでの全工程を自動化します。
# azure-pipelines.yml - Azure DevOpsパイプライン設定ファイル
# リポジトリのルートディレクトリに配置する
# パイプラインをトリガーするブランチを指定
trigger:
branches:
include:
- main
- develop
paths:
# 特定のパスの変更のみをトリガーする場合
exclude:
- README.md
- docs/*
# Pull Requestによるトリガー設定
pr:
branches:
include:
- main
paths:
exclude:
- README.md
# パイプライン全体で使用する変数
variables:
# ビルド設定
buildConfiguration: 'Release'
vmImageName: 'ubuntu-latest'
# コンテナレジストリ情報
containerRegistry: 'myregistry.azurecr.io'
imageRepository: 'myapp'
dockerfilePath: '$(Build.SourcesDirectory)/Dockerfile'
# Azure接続情報
azureServiceConnection: 'azure-service-connection'
webAppName: 'my-web-app-prod'
resourceGroupName: 'my-resource-group'
# パイプラインの実行ステージを定義
stages:
# =====================================
# ビルドステージ
# =====================================
- stage: Build
displayName: 'Build and Test'
jobs:
- job: BuildJob
displayName: 'Build Job'
pool:
vmImage: $(vmImageName)
steps:
# ソースコードのチェックアウト(デフォルトで実行されるが明示的に記載)
- checkout: self
displayName: 'Checkout source code'
# Node.js環境のセットアップ
- task: NodeTool@0
displayName: 'Install Node.js'
inputs:
versionSpec: '16.x'
# 依存関係のインストール
- script: |
npm cache clean --force
npm install
displayName: 'Install dependencies'
# コードの静的解析(ESLint)
- script: |
npm run lint
displayName: 'Run ESLint'
continueOnError: false # エラー時にパイプラインを停止
# 単体テストの実行
- script: |
npm run test:ci
displayName: 'Run unit tests'
env:
# テスト用の環境変数
NODE_ENV: 'test'
# テスト結果の公開
- task: PublishTestResults@2
displayName: 'Publish test results'
inputs:
testResultsFormat: 'JUnit'
testResultsFiles: '$(System.DefaultWorkingDirectory)/test-results.xml'
mergeTestResults: true
condition: always() # テストが失敗しても結果を公開
# コードカバレッジの公開
- task: PublishCodeCoverageResults@1
displayName: 'Publish code coverage'
inputs:
codeCoverageTool: 'Cobertura'
summaryFileLocation: '$(System.DefaultWorkingDirectory)/coverage/cobertura-coverage.xml'
# アプリケーションのビルド
- script: |
npm run build
displayName: 'Build application'
# Dockerイメージのビルド
- task: Docker@2
displayName: 'Build Docker image'
inputs:
command: 'build'
repository: '$(imageRepository)'
dockerfile: '$(dockerfilePath)'
containerRegistry: '$(azureServiceConnection)'
tags: |
$(Build.BuildId)
latest
arguments: |
--build-arg NODE_ENV=production
--build-arg BUILD_VERSION=$(Build.BuildId)
# セキュリティスキャン(Trivy使用例)
- script: |
# Trivyのインストール
sudo apt-get update
sudo apt-get install wget apt-transport-https gnupg lsb-release -y
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt-get update
sudo apt-get install trivy -y
# イメージのスキャン
trivy image --exit-code 0 --severity HIGH,CRITICAL $(imageRepository):$(Build.BuildId)
displayName: 'Security scan'
# Dockerイメージのプッシュ
- task: Docker@2
displayName: 'Push Docker image'
inputs:
command: 'push'
repository: '$(imageRepository)'
containerRegistry: '$(azureServiceConnection)'
tags: |
$(Build.BuildId)
latest
# ビルドアーティファクトの公開
- task: PublishBuildArtifacts@1
displayName: 'Publish build artifacts'
inputs:
pathToPublish: '$(Build.SourcesDirectory)/deploy'
artifactName: 'drop'
# =====================================
# ステージング環境デプロイステージ
# =====================================
- stage: DeployStaging
displayName: 'Deploy to Staging'
# ビルドステージが成功した場合のみ実行
dependsOn: Build
condition: succeeded()
# ステージング環境専用の変数
variables:
environmentName: 'staging'
webAppNameStaging: 'my-web-app-staging'
jobs:
- deployment: DeployJob
displayName: 'Deploy to Staging Environment'
# デプロイメント環境の指定(承認フローなどを設定可能)
environment: 'staging'
pool:
vmImage: $(vmImageName)
strategy:
# デプロイ戦略の定義
runOnce:
deploy:
steps:
# ビルドアーティファクトのダウンロード
- download: current
artifact: drop
displayName: 'Download build artifacts'
# Azure Web Appへのデプロイ
- task: AzureWebAppContainer@1
displayName: 'Deploy to Azure Web App (Staging)'
inputs:
azureSubscription: '$(azureServiceConnection)'
appName: '$(webAppNameStaging)'
resourceGroupName: '$(resourceGroupName)'
imageName: '$(containerRegistry)/$(imageRepository):$(Build.BuildId)'
# コンテナの起動時間設定
containerStartUpTimeOut: '600'
# デプロイ後のヘルスチェック
- script: |
echo "Waiting for application to start..."
sleep 30
# ヘルスチェックエンドポイントの確認
for i in {1..5}; do
if curl -f https://$(webAppNameStaging).azurewebsites.net/health; then
echo "Health check passed"
exit 0
else
echo "Health check failed, retry $i/5"
sleep 10
fi
done
echo "Health check failed after 5 attempts"
exit 1
displayName: 'Health check'
# =====================================
# 本番環境デプロイステージ
# =====================================
- stage: DeployProduction
displayName: 'Deploy to Production'
# ステージングデプロイが成功した場合のみ実行
dependsOn: DeployStaging
condition: succeeded()
variables:
environmentName: 'production'
jobs:
- deployment: DeployJob
displayName: 'Deploy to Production Environment'
# 本番環境(手動承認が必要)
environment: 'production'
pool:
vmImage: $(vmImageName)
strategy:
# Blue-Greenデプロイメント戦略の例
runOnce:
deploy:
steps:
- download: current
artifact: drop
# 本番環境へのデプロイ
- task: AzureWebAppContainer@1
displayName: 'Deploy to Azure Web App (Production)'
inputs:
azureSubscription: '$(azureServiceConnection)'
appName: '$(webAppName)'
resourceGroupName: '$(resourceGroupName)'
imageName: '$(containerRegistry)/$(imageRepository):$(Build.BuildId)'
# スロット設定(Blue-Greenデプロイ)
deployToSlotOrASE: true
slotName: 'staging'
# 本番前テスト
- script: |
echo "Running production smoke tests..."
# スモークテストの実行
npm run test:smoke -- --baseUrl=https://$(webAppName)-staging.azurewebsites.net
displayName: 'Smoke tests'
# 手動承認後のスロットスワップ
- task: AzureAppServiceManage@0
displayName: 'Swap deployment slots'
inputs:
azureSubscription: '$(azureServiceConnection)'
action: 'Swap Slots'
webAppName: '$(webAppName)'
resourceGroupName: '$(resourceGroupName)'
sourceSlot: 'staging'
targetSlot: 'production'
# デプロイ完了通知
- script: |
echo "Deployment completed successfully!"
echo "Application URL: https://$(webAppName).azurewebsites.net"
displayName: 'Deployment notification'
azure-pipelines.ymlの主要な構成要素の説明:
-
trigger/pr: パイプラインの実行条件
- ブランチやパスベースのトリガー設定
- Pull Request時の自動実行設定
-
variables: パイプライン全体またはステージ固有の変数定義
- 環境固有の設定値を管理
-
stages: パイプラインの論理的な段階
- Build, DeployStaging, DeployProduction の3段階構成
- 各ステージの依存関係と実行条件を定義
-
jobs/deployment: 実際の作業単位
-
job
: 通常のビルドタスク -
deployment
: デプロイメント専用(環境との紐づけ、承認フロー対応)
-
-
steps/tasks: 具体的な実行内容
- スクリプトの実行、Azure サービスとの連携
- テスト結果やアーティファクトの公開
-
environment: デプロイ環境の管理
- 承認フロー、デプロイ履歴の管理
- 環境固有の設定
この設定により、コードプッシュから本番デプロイまでの全工程が自動化され、品質管理とリリース管理が統合されます。
エコシステムとの連携
AWS CodePipeline のエコシステム連携
連携先 | 連携度 | 特徴 |
---|---|---|
AWS サービス | ★★★★★ | ネイティブ統合、設定が簡単 |
GitHub | ★★★★☆ | ウェブフック連携、OAuth認証対応 |
サードパーティ | ★★★☆☆ | Lambda関数経由で拡張可能 |
オンプレミス | ★★☆☆☆ | CodeDeploy Agentで限定的に対応 |
Azure DevOps のエコシステム連携
連携先 | 連携度 | 特徴 |
---|---|---|
Azure サービス | ★★★★★ | ネイティブ統合、豊富なタスク |
GitHub | ★★★★★ | Microsoft買収により完全統合 |
AWS・GCP | ★★★★☆ | 専用拡張機能で対応 |
オンプレミス | ★★★★☆ | セルフホストエージェントで柔軟対応 |
選択の指針
AWS CodePipeline が適している場面
シナリオ | 理由 |
---|---|
AWS中心のインフラ | AWSサービスとの連携が最も効率的 |
シンプルなパイプライン | 複雑な機能が不要な場合はコスト効率が良い |
既存AWSワークフロー | 既にAWSエコシステムを活用している場合 |
Azure DevOps が適している場面
シナリオ | 理由 |
---|---|
マルチクラウド戦略 | 複数のクラウドプロバイダーを利用する場合 |
統合開発環境 | プロジェクト管理からデプロイまで一元管理したい場合 |
Microsoft エコシステム | Visual Studio、GitHubを活用している場合 |
大規模チーム | 豊富なプロジェクト管理機能が必要な場合 |
移行とハイブリッド運用
段階的移行戦略
既存のCI/CDシステムからの移行を検討する場合は、以下のアプローチが効果的です。
- パイロットプロジェクトでの検証
- 機能別の段階的移行(ビルド→テスト→デプロイ)
- 既存システムとの並行運用期間の設定
- チームトレーニングの実施
ハイブリッド運用の可能性
- Azure DevOps: AWS環境へのデプロイも可能
- AWS CodePipeline: GitHub ActionsやJenkinsとの連携も可能
コスト分析
AWS CodePipeline の料金構造
- 基本料金: アクティブパイプライン1つあたり月額$1
- 実行料金: 1回の実行あたり$0.0025(1,000回まで無料)
- 関連サービス: CodeBuild、CodeCommit等の利用料が別途発生
Azure DevOps の料金構造
- 基本ユーザー: 月額$6/ユーザー(5ユーザーまで無料)
- 並行ジョブ: Microsoft-hostedで月額$40/ジョブ
- 無料枠: 月1,800分のビルド時間
まとめ
CI/CDツールの選択は、単純な機能比較だけでなく、組織の開発プロセス全体を考慮して決定すべきです。
AWS CodePipelineは、AWSエコシステム内での効率的なCI/CDに特化しており、シンプルで直感的な操作が魅力です。一方、Azure DevOpsは、開発プロセス全体を統合的に管理できる包括的なプラットフォームとして優れています。
重要なのは、自社の開発チームの規模、技術スタック、そして長期的な戦略に最も適したツールを選択することです。どちらを選んでも、適切に活用すれば開発効率とソフトウェア品質の大幅な向上が期待できます。
次回のDay18では、サーバーレスコンピューティングに焦点を当て、AWS LambdaとAzure Functionsを徹底比較します。お楽しみに!
参考資料