最終確認: 2026年5月
DOP-C02 試験の対象となる AWS サービスを、プレーンな Terraform を使用して構築します。1 ブロックずつ、それぞれ試験ドメインに関連付けられています。同じコードが OpenTofu でも動作します。
このラボの終了までに、プレーンなTerraformを使用して、完全なコードから本番環境へのパイプライン(CodeCommit Gitリポジトリ、テストスイートを実行してアーティファクトをパッケージ化するCodeBuildプロジェクト、ターゲットに展開するCodeDeployアプリケーション、ソース→ビルド→展開を連鎖させるCodePipelineパイプライン、およびデプロイされたエンドポイントを監視し、応答停止時にアラームを鳴らすCloudWatch Syntheticsカナリア)をプロビジョニングします。これは、DOP-C02リファレンスアーキテクチャの5つのブロックです。
すべてのリソースはプレーンなTerraformです。これらのスニペットを単一の main.tf にドロップし、terraform init を実行し、その後 terraform apply をステップバイステップで実行します。
>= 1.5 または OpenTofu >= 1.6。us-east-1 用にAWS CLIが認証済みであること。https://example.com を使用しますが、本番環境ではアプリケーションのヘルスチェックエンドポイントとなります。aws_s3_bucket に置き換えてください(CodePipelineはS3ソースをサポートしています)。ほとんどが従量課金制で、大幅なアイドル料金は発生しません:
BUILD_GENERAL1_SMALL でビルド1分あたり$0.005。ラボのビルドは数セント。スタック全体を稼働させても月額5ドル未満です。完了したら削除してください。
標準的な開始です。Code* サービスはリージョン固有であるため、ソースリポジトリとターゲット環境が共有するリージョンを選択してください。このラボでは us-east-1 をデフォルトとします。
terraform {
required_version = ">= 1.5"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.60"
}
}
}
provider "aws" {
region = "us-east-1"
default_tags {
tags = {
Project = "certlabpro-dop-c02"
ManagedBy = "terraform"
}
}
}
resource "aws_s3_bucket" "artifacts" {
bucket_prefix = "certlabpro-dop-c02-artifacts-"
}
resource "aws_s3_bucket_public_access_block" "artifacts" {
bucket = aws_s3_bucket.artifacts.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}CodeCommitはAWSのGitホストです。DOP-C02では、Code* スイートが緊密に統合されたストーリーとしてエンドツーエンドでテストされます。最も一般的な試験問題では、特定の結果を達成するためにどのAWSネイティブサービスを組み合わせるかを問い、その答えはほとんどの場合CodeCommitから始まります。
default_branch = "main" は最新のGitのデフォルトと一致します(CodeCommitは以前 master を作成していました)。作成したリポジトリは apply 後は空です。実際の使用では、ルートに buildspec.yml と appspec.yml を含む最初のコミットをプッシュします。これらはCodeBuild(ステップ3)とCodeDeploy(ステップ4)がパイプラインの実行ごとに読み取るファイルです。
resource "aws_codecommit_repository" "app" {
repository_name = "certlabpro-dop-c02-app"
description = "Application source for the DOP-C02 lab pipeline."
default_branch = "main"
}CodeBuildは buildspec.yml からビルドとテストのステップを実行します。DOP-C02では、ここではマネージドイメージとカスタムイメージのトレードオフがテストされます。マネージドイメージはメンテナンス不要ですが起動が遅く、カスタムイメージはコールドスタートが速く、再現可能なツールチェーンを提供します。このラボでは、Node、Python、Java、Go、.NET、Rubyをすぐに利用できるマネージドイメージ aws/codebuild/standard:7.0 を使用します。
IAMロールは、CodeBuildにCloudWatch Logsへの書き込み(ビルド出力用)、CodeCommitからのソースの読み取り、およびステップ1のS3バケットへのアーティファクトの書き込みの許可を与えます。LINUX_CONTAINER + BUILD_GENERAL1_SMALL は、ビルド1分あたり$0.005で最も安価なティアです。
resource "aws_iam_role" "codebuild" {
name = "certlabpro-dop-c02-codebuild"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "codebuild.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
}
resource "aws_iam_role_policy" "codebuild" {
name = "build-permissions"
role = aws_iam_role.codebuild.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = ["logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents"]
Resource = "*"
},
{
Effect = "Allow"
Action = ["s3:GetObject", "s3:PutObject", "s3:ListBucket"]
Resource = [aws_s3_bucket.artifacts.arn, "${aws_s3_bucket.artifacts.arn}/*"]
},
{
Effect = "Allow"
Action = "codecommit:GitPull"
Resource = aws_codecommit_repository.app.arn
},
]
})
}
resource "aws_codebuild_project" "build" {
name = "certlabpro-dop-c02-build"
service_role = aws_iam_role.codebuild.arn
source {
type = "CODEPIPELINE"
buildspec = "buildspec.yml"
}
artifacts {
type = "CODEPIPELINE"
}
environment {
type = "LINUX_CONTAINER"
image = "aws/codebuild/standard:7.0"
compute_type = "BUILD_GENERAL1_SMALL"
privileged_mode = false
}
}CodeDeployは、EC2、Lambda、またはECSへの実際のロールアウトを処理します。DOP-C02では、デプロイ戦略の軸が繰り返しテストされます。AllAtOnce(最も安価で最も恐ろしい)、HalfAtATime、OneAtATime、CodeDeployDefault.LambdaCanary10Percent5Minutes(Lambdaカナリアパターン)、およびCodeDeployDefault.ECSAllAtOnceです。このラボでは、EC2インスタンスが実際に存在する必要がないため、Lambdaコンピューティングプラットフォームを選択します。これにより、ラボは安価でスコープが厳密に保たれます。
デプロイ設定 CodeDeployDefault.LambdaAllAtOnce は、Lambda戦略の中で最もシンプルです。本番環境では、LambdaCanary10Percent5Minutes がリスク軽減デプロイメントに最も頻繁に推奨されるDOP-C02の回答です。これは、トラフィックの10%を新しいバージョンに移行し、CloudWatchアラームがトリガーされないか5分間待機し、何も問題がなければ残りのトラフィックを移行します。
resource "aws_iam_role" "codedeploy" {
name = "certlabpro-dop-c02-codedeploy"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "codedeploy.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
}
resource "aws_iam_role_policy_attachment" "codedeploy_lambda" {
role = aws_iam_role.codedeploy.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSCodeDeployRoleForLambda"
}
resource "aws_codedeploy_app" "app" {
name = "certlabpro-dop-c02-app"
compute_platform = "Lambda"
}
resource "aws_codedeploy_deployment_group" "lambda" {
app_name = aws_codedeploy_app.app.name
deployment_group_name = "default"
service_role_arn = aws_iam_role.codedeploy.arn
deployment_config_name = "CodeDeployDefault.LambdaAllAtOnce"
deployment_style {
deployment_option = "WITH_TRAFFIC_CONTROL"
deployment_type = "BLUE_GREEN"
}
auto_rollback_configuration {
enabled = true
events = ["DEPLOYMENT_FAILURE"]
}
}CodePipelineは、これまでの3つのステップ(CodeCommitからのソース、CodeBuildでのビルド、CodeDeployでのデプロイ)を単一のグラフに連携させるオーケストレーターです。すべての移行はフックポイントであり、手動承認、並行テストステージ、および任意の2つのステージ間の通知を追加できます。DOP-C02の構成管理とIaCドメインでは、このステージとアクションの構造が繰り返しテストされます。
パイプラインが存在すれば、CI/CDが利用できます。最後の要素であるCloudWatch Syntheticsは、デプロイメントの可観測性のループを閉じます。カナリアは、スケジュールに基づいて実行され、成功/失敗をCloudWatchに報告するマネージドのヘッドレスブラウザスクリプト(Puppeteerベース)です。DOP-C02のモニタリングとログ記録ドメインでは、このパターンが強く重視されます。変更をデプロイする → カナリアが数分以内にリグレッションを検知する → CodeDeployの自動ロールバック(ステップ4で設定済み)がカナリアのCloudWatchアラームからトリガーされる、という流れです。
以下のカナリアスクリプトは https://example.com を5分ごとにポーリングします。本番環境では、アプリケーションのヘルスエンドポイントに向け、HTTP 200だけでなく、応答ボディやヘッダーに対するアサーションを含めるでしょう。
# ── CodePipeline ──────────────────────────────────────────────
resource "aws_iam_role" "codepipeline" {
name = "certlabpro-dop-c02-codepipeline"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "codepipeline.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
}
resource "aws_iam_role_policy" "codepipeline" {
name = "pipeline-permissions"
role = aws_iam_role.codepipeline.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = [
"codecommit:*",
"codebuild:*",
"codedeploy:*",
"s3:*",
"iam:PassRole",
]
Resource = "*"
}]
})
}
resource "aws_codepipeline" "main" {
name = "certlabpro-dop-c02"
role_arn = aws_iam_role.codepipeline.arn
artifact_store {
location = aws_s3_bucket.artifacts.bucket
type = "S3"
}
stage {
name = "Source"
action {
name = "Source"
category = "Source"
owner = "AWS"
provider = "CodeCommit"
version = "1"
output_artifacts = ["source"]
configuration = {
RepositoryName = aws_codecommit_repository.app.repository_name
BranchName = "main"
}
}
}
stage {
name = "Build"
action {
name = "Build"
category = "Build"
owner = "AWS"
provider = "CodeBuild"
version = "1"
input_artifacts = ["source"]
output_artifacts = ["build"]
configuration = {
ProjectName = aws_codebuild_project.build.name
}
}
}
}
# ── Synthetics canary ─────────────────────────────────────────
resource "aws_iam_role" "canary" {
name = "certlabpro-dop-c02-canary"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = { Service = "lambda.amazonaws.com" }
Action = "sts:AssumeRole"
}]
})
}
resource "aws_iam_role_policy_attachment" "canary_logs" {
role = aws_iam_role.canary.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}
data "archive_file" "canary_src" {
type = "zip"
output_path = "${path.module}/build/canary.zip"
source {
filename = "nodejs/node_modules/index.js"
content = <<-EOT
const synthetics = require("Synthetics");
exports.handler = async () => {
const page = await synthetics.getPage();
const res = await page.goto("https://example.com", { waitUntil: "domcontentloaded" });
if (!res.ok()) throw new Error("Status code " + res.status());
};
EOT
}
}
resource "aws_synthetics_canary" "endpoint" {
name = "certlabpro-dop-c02-endpoint"
artifact_s3_location = "s3://${aws_s3_bucket.artifacts.bucket}/canary/"
execution_role_arn = aws_iam_role.canary.arn
handler = "index.handler"
zip_file = data.archive_file.canary_src.output_path
runtime_version = "syn-nodejs-puppeteer-9.0"
start_canary = true
schedule {
expression = "rate(5 minutes)"
}
}terraform destroy はこのラボ内のすべてを削除します。2点注意があります:
destroy の前に空にする(aws s3 rm s3://<bucket> --recursive)か、バケットリソースに force_destroy = true を使用し、削除する前にもう一度 apply を実行してください。start_canary = true が設定されており、apply の瞬間から5分間隔で継続的に実行されます。1回の実行あたり約$0.0012。もしラボのカナリアを削除し忘れ、1週間実行し続けた場合、約$0.25かかります。安価ではありますが、実際の費用です。完了したら削除してください。DOP-C02は、マルチアカウント/マルチリージョンのIaC向けCloudFormation StackSets、Service Catalog、AWS Configルール+修復、Systems Manager OpsCenter + Patch Manager、AWS Health Dashboardオートメーション、Trusted Advisorチェック、AWS Backup、EventBridge Pipes、サービス間オーケストレーション向けStep Functions、分散トレーシング向けX-Rayなど、幅広い専門分野をカバーしています。
このラボではエンドツーエンドのCI/CDパイプラインに焦点を当てます。これは試験で最も頻繁にテストされるアーキテクチャであり、他のDOP-C02パターン(修復を供給するConfigルール、SNS経由のSyntheticsページング、CodePipeline経由で展開されるStackSets)はすべてこの基盤の上に構築されます。まずソースからデプロイまでのチェーンを習得し、基本が機械的に感じられるようになったら、マルチアカウントStackSetsやクロスリージョンオーケストレーションを重ねていきましょう。
ここでプロビジョニングされていない分野については、この認定ページの閲覧、プレイブック、およびEditorialセクションで概念的なカバーがされています。CloudFormation StackSets + Config Rules + Systems Manager Patch Managerを追加する追加のラボは、大規模なオペレーション管理のドメインを網羅するでしょう。