# Codebuild 연동하기

## Codebuild란 무엇인가?

{% embed url="<https://www.beautiful.ai/player/-NzhRhLNat-M7XlL3QbJ/Introduction-to-AWS-CodeBuild>" %}

## Why Codebuild ?

{% file src="/files/SJ7SWXMEdj5tTQ93318b" %}

## Jenkins와 Codebuild

Jenkins와 Codebuild를 연동하게 되면, 빌드 또는 배포 job 은 jenkins에서 생성하고 실제 작업은 Codebuild를 통해서 진행하실 수 있습니다. Jenkins에서 Job이 실행되면 AWS 상에 독립적인 codebuild job이 생성 됩니다.

### 장점

* 각 Job을 독립적인 환경에서 빌드/배포할 수 있습니다.
* AWS Codebuild 특성상 특정 VPC내에서 실행하실 수 있기 때문에, 접근제어 또는 다른 서비스와의 연동 시 용이합니다.
* Codebuild의 모든 로그를 Amazon CloudWatch Logs를 통해서 보실 수 있고, 기존의 빌드 및 배포 이력을 손쉽게 찾아보실 수 있습니다.

{% hint style="info" %}
본 실습에서는 artp(prod) 계정에서 동일 환경에 배포해보겠습니다.
{% endhint %}

## 사전 준비 사항

* Jenkins와 Codebuild에 연동할 **Github 토큰**
* Jenkins에서 사용할 AWS IAM User 및 Credentials&#x20;
  * AWS\_ACCESS\_KEY\_ID
  * AWS\_SECRET\_ACCESS\_KEY

### Github 토큰

* Github 에서 `Settings` --> `Developer settings`  --> `Personal access tokens` 를 들어갑니다.
* `Generate new token` 을 클릭합니다.
* 이름을 넣고 `repo` 와 `read:org`권한을 추가한 후에 토큰을 발급합니다.
* 발급받은 토큰은 임시로 안전한 곳에 저장해두시기 바랍니다.

![](/files/-MSsDGNihjE_LBGJJhNA)

### IAM User 생성

* Jenkins를 배포할 계정의 IAM directory를 찾아서 들어갑니다.
  * 예시 :  `terraform/iam/art-prod` &#x20;
  * 없으신 경우에는 이전 [IAM 환경 구성](https://devops-art-factory.gitbook.io/devops-workshop/terraform/initialization)을 참조하셔서 먼저 환경 세팅을 해주시기 바랍니다.
* `GetLogEvents` 와 `Codebuild:*`에 관한 권한은 반드시 필요합니다. 다른 권한은 필요에 따라 추가/삭제하셔도 됩니다.
* 아래와 같이 테라폼 코드를 작성하시고 나서, terraform apply 를 통해 배포하시면 콘솔에서 유저를 찾으실 수 있습니다.

```bash
# Jenkins User
resource "aws_iam_user" "jenkins_codebuild" {
  name = "jenkins-codebuild"
}

# Permissions that jenkins needs to create codebuild job
# You can change s3 bucket below if you have any bucket that jenkins use for retrieving/uploading artifact
resource "aws_iam_user_policy" "jenkins_codebuild" {
  name   = "jenkins-codebuild"
  user   = aws_iam_user.jenkins_codebuild.name
  policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Resource": ["arn:aws:logs:*:*:log-group:/aws/codebuild/*"],
            "Action": ["logs:GetLogEvents"]
        },
        {
            "Effect": "Allow",
            "Resource": ["arn:aws:s3:::art-deploy"],
            "Action": ["s3:GetBucketVersioning"]
        },
        {
            "Effect": "Allow",
            "Resource": ["arn:aws:s3:::art-deploy/*"],
            "Action": ["s3:PutObject"]
        },
        {
            "Effect": "Allow",
            "Resource": ["arn:aws:s3:::art-deploy/*"],
            "Action": ["s3:GetObject"]
        },
        {
            "Effect": "Allow",
            "Resource": ["arn:aws:codebuild:*:*:*"],
            "Action": [
                "codebuild:StartBuild",
                "codebuild:BatchGetBuilds",
                "codebuild:BatchGetProjects",
                "codebuild:StopBuild"
            ]
        }
	]
  }
EOF

}

```

생성이 완료되었으면 아래와 같이 Access Key를 발급 받습니다. 발급받으신 키는 ***반드시 안전한 곳에 보관***&#xD558;시기 바랍니다.

![](/files/-MSsDKPVLOED8Wi3Z4g9)

## CodeBuild 생성

이제 연동할 Codebuild 프로젝트를 생성하도록 하겠습니다. Codebuild 프로젝트를 위해서는 아래의 리소스가 필요합니다.&#x20;

* Codebuild에서 사용할 IAM 역할
* Codebuild의 기본 베이스가 되는 Docker image
* Codebuild에서 사용할 보안그룹
* Codebuild 프로젝트

### IAM 역할 생성

* Codebuild에서 사용할 역할이므로, 실제 빌드/배포에 필요한 권한을 가지고 있어야 합니다.
* Codebuild를 생성할 계정의 IAM 디렉토리로 가서 생성을 진행합니다. (`terraform/iam/art-prod`)

{% code title="vim terraform/iam/art-prod/codebuild-deployment.tf" %}

```bash
resource "aws_iam_role" "codebuild_deployment" {
  name               = "codebuild-deployment"
  path               = "/service-role/" assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "codebuild.amazonaws.com"
      },

      "Action": "sts:AssumeRole"

    }
  ]
}
EOF
}

resource "aws_iam_role_policy" "codebuild_deployment_operation" {
  name   = "codebuild-deployment-operation-access"
  role   = aws_iam_role.codebuild_deployment.id
  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DeploymentSecurityGroupAccess",
      "Action": [
        "ec2:CreateSecurityGroup",
        "ec2:DescribeSecurityGroups",
        "ec2:AuthorizeSecurityGroupIngress",
        "ec2:RevokeSecurityGroupIngress"
      ],
      "Effect": "Allow",
      "Resource": ["*"]
    },
    {
      "Sid": "DeploymentAMIAccess",
      "Action": [
        "ec2:RegisterImage",
        "ec2:DescribeImages"
      ],
      "Effect": "Allow",
      "Resource": ["*"]
    },
    {
      "Sid": "DeploymentSnapshotAccess",
      "Action": [
        "ec2:CreateSnapshot",
        "ec2:DeleteSnaphot",
        "ec2:DescribeSnapshots"
      ],
      "Effect": "Allow",
      "Resource": ["*"]
    },
    {
      "Sid": "DeploymentInstanceAccess",
      "Action": [
        "ec2:RunInstances",
        "ec2:StartInstances",
        "ec2:StopInstances",
        "ec2:RebootInstances",
        "ec2:TerminateInstances",
        "ec2:DescribeInstances",
        "ec2:CreateTags",
        "ec2:DescribeTags",
        "ec2:ModifyInstanceAttribute"
      ],
      "Effect": "Allow",
      "Resource": ["*"]
    },
    {
      "Sid": "DeploymentKeyPairAccess",
      "Action": [
        "ec2:DescribeKeyPairs"
      ],
      "Effect": "Allow",
      "Resource": ["*"]
    },
    {
      "Sid": "LaunchTemplates",
      "Action": [
        "ec2:DeleteLaunchTemplate",
        "ec2:CreateLaunchTemplate",
        "ec2:GetLaunchTemplateData",
        "ec2:DescribeLaunchTemplates",
        "ec2:DescribeLaunchTemplateVersions",
        "ec2:ModifyLaunchTemplate",
        "ec2:DeleteLaunchTemplateVersions",
        "ec2:CreateLaunchTemplateVersion"
      ],
      "Effect": "Allow",
      "Resource": ["*"]
    },
    {
      "Sid": "DeploymentVolumeAccess",
      "Action": [
        "ec2:AttachVolume",
        "ec2:CreateVolume",
        "ec2:DeleteVolume",
        "ec2:DescribeVolume*",
        "ec2:DetachVolume"
      ],
      "Effect": "Allow",
      "Resource": ["*"]
    },
    {
      "Sid": "DeploymentASGAccess",
      "Action": [
        "autoscaling:*"
      ],
      "Effect": "Allow",
      "Resource": ["*"]
    },
    {
      "Sid": "DeploymentVPCAccess",
      "Action": [
        "ec2:CreateNetworkInterface",
        "ec2:DescribeDhcpOptions",
        "ec2:DescribeNetworkInterfaces",
        "ec2:DeleteNetworkInterface",
        "ec2:DescribeSubnets",
        "ec2:DescribeSecurityGroups",
        "ec2:DescribeVpcs"
      ],
      "Effect": "Allow",
      "Resource": ["*"]
    },
    {
      "Effect": "Allow",
      "Action": [
        "ec2:CreateNetworkInterfacePermission"
      ],
        "Resource": "arn:aws:ec2:ap-northeast-2:${var.account_id}:network-interface/*"
    },
    {
      "Sid": "DeploymentIAMAccess",
      "Action": [
        "iam:PassRole"
      ],
      "Effect": "Allow",
      "Resource": ["*"]
    },
    {
      "Sid": "DeploymentELBAccess",
      "Action": [
        "elasticloadbalancing:DescribeLoadBalancerAttributes",
        "elasticloadbalancing:DescribeLoadBalancers",
        "elasticloadbalancing:DescribeTargetGroupAttributes",
        "elasticloadbalancing:DescribeTargetHealth",
        "elasticloadbalancing:DescribeTargetGroups",
        "elasticloadbalancing:DescribeListeners",
        "elasticloadbalancing:DescribeTags",
        "elasticloadbalancing:DescribeRules",
        "elasticloadbalancing:DescribeInstanceHealth"
      ],
      "Effect": "Allow",
      "Resource": ["*"]
    },
    {
      "Sid": "CloudwatchAccess",
      "Action": [
        "cloudwatch:PutMetricAlarm"
      ],
      "Effect": "Allow",
      "Resource": ["*"]
    },
    {
      "Sid": "SSMSendCommand",
      "Action": [
        "ssm:SendCommand",
        "ssm:ListCommandInvocations"
      ],
      "Effect": "Allow",
      "Resource": ["*"]
    }
  ]
}
EOF
}

resource "aws_iam_role_policy" "codebuild_deployment_ecr" {
  name   = "codebuild-deployment-ecr"
  role   = aws_iam_role.codebuild_deployment.id
  policy = <<EOF
{
  "Statement": [
    {
      "Sid": "AllowGetAuthTokenAccess",
      "Effect": "Allow",
      "Action": [
        "ecr:GetAuthorizationToken"
      ],
      "Resource": "*"
    },
    {
      "Sid": "AllowReadECRAccess",
      "Effect": "Allow",
        "Action": [
          "ecr:BatchCheckLayerAvailability",
          "ecr:GetDownloadUrlForLayer",
          "ecr:BatchGetImage",
          "ecr:PutImage",
          "ecr:InitiateLayerUpload",
          "ecr:UploadLayerPart",
          "ecr:CompleteLayerUpload"
        ],
        "Resource": "*"
    }

  ]
}
EOF
}

# If codebuild needs to deploy to another account
# then, it should have assume permission.
#resource "aws_iam_role_policy" "codebuild_deployment_assume_deploy" {
#  name   = "codebuild-deployment-assume-deploy"
#  role   = aws_iam_role.codebuild_deployment.id
#  policy = <<EOF
#{
#  "Statement": [
#    {
#      "Sid": "AllowAnsibleHeadDeployBucketAccess",
#      "Action": [
#        "sts:AssumeRole"
#      ],
#      "Resource": [
#        "arn:aws:iam::<target account id>:role/deployment"
#      ],
#      "Effect": "Allow"
#    }
#  ]
#}
#EOF
#}

# If you want to store secret data to AWS Parameter Store, 
# then you should give permission so that codebuild can retrieve those values for build and deployment
resource "aws_iam_role_policy" "codebuild_deployment_kms" {
  name   = "codebuild-deployment-kms-decryption"
  role   = aws_iam_role.codebuild_deployment.id
  policy = <<EOF
{
  "Statement": [
    {
      "Sid": "AllowSsmParameterAccess",
      "Action": [
        "ssm:GetParameter",
        "ssm:GetParameters"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:ssm:ap-northeast-2:${var.account_id}:parameter/CodeBuild/*"
      ]
    }
  ]
}
EOF
}

resource "aws_iam_role_policy" "codebuild_deployment_cloudwatch" {
  name   = "codebuild-deployment-cloudwatch"
  role   = aws_iam_role.codebuild_deployment.id
  policy = <<EOF
{
  "Statement": [
    {
      "Sid": "AllowCloudWatchAccess",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": [
        "arn:aws:logs:*:${var.account_id}:log-group:/aws/codebuild/*",
        "arn:aws:logs:*:${var.account_id}:log-group:/aws/codebuild/*:*",
        "arn:aws:logs:*:${var.account_id}:log-group:/*",
        "arn:aws:logs:*:${var.account_id}:log-group:/*:*",
        "arn:aws:logs:*:${var.account_id}:log-group:/*:*:*",
        "arn:aws:logs:*:${var.account_id}:log-group:*:*:*/*"
      ],
      "Effect": "Allow"
    }
  ]
}
EOF
}

resource "aws_iam_instance_profile" "codebuild_deployment" {
  name = "codebuild-deployment-profile"
  role = aws_iam_role.codebuild_deployment.name
}

resource "aws_iam_role_policy_attachment" "codebuild_deployment_attach" {
  role       = aws_iam_role.codebuild_deployment.name
  policy_arn = aws_iam_policy.app_universal.arn
}

output "codebuild_deployment_instance_profile" {
  value = aws_iam_instance_profile.codebuild_deployment.arn
}


output "codebuild_deployment_arn" {
  value = aws_iam_role.codebuild_deployment.arn
}

```

{% endcode %}

### Docker Image 생성(optional)

* Codebuild는 컨테이너로 생성되므로 어떤 이미지를 사용하여 Job을 돌릴지 정해주어야 합니다.&#x20;
* 본 가이드에서는 필요한 이미지를 빌드해서 ECR에 저장하도록 하겠습니다.
* ECR 레포지토리를 생성하는 디렉토리에 리소스를 추가합니다.
  * &#x20;`terraform/ecr/art-prod/prod_apnortheast2`
  * Policy 에 Account ID는 자신의 계정 번호를 넣어주시면 됩니다.

{% code title="vim terraform/ecr/art-prod/prod\_apnortheast2/art\_build.tf" %}

```bash
resource "aws_ecr_repository" "art_build" {
  name = "art-build"
}

resource "aws_ecr_repository_policy" "art_build" {
  repository = aws_ecr_repository.art_build.name

  policy = <<EOF
{
    "Version": "2008-10-17",
    "Statement": [
        {
            "Sid": "new policy",
            "Effect": "Allow",
            "Principal": {
              "AWS": [
                "arn:aws:iam::<your account id>:root"
              ]
            },
            "Action": [
                "ecr:GetDownloadUrlForLayer",
                "ecr:BatchGetImage",
                "ecr:BatchCheckLayerAvailability",
                "ecr:DescribeRepositories",
                "ecr:GetRepositoryPolicy",
                "ecr:ListImages"
            ]
        }
    ]
}
EOF
}
```

{% endcode %}

* ECR 레포지토리 생성이 완료되면, 각자 원하는 Docker Image를 생성해서 해당 Repository에 푸시합니다. (샘플 이미지는 올려놓았습니다!)
  * `terraform/ecr/art-prod/prod_apnortheast2/Dockerfile-art-build-amazon`

### 보안그룹 생성

* VPC를 생성했던 곳으로 가서 Security Group을 생성합니다. (`terraform/vpc/artp_apnortheast2` )
* 만약 다른 곳에서 관리하고 계신 경우에는 해당 디렉토리에서 생성하시면 됩니다.
* 생성한 Security Group을 외부에서 참조할 수 있도록 output에도 추가합니다.

{% code title="vim terraform/vpc/artp\_apnortheast2/codebuild\_sg.tf" %}

```bash
# Codebuild Default Security Group
resource "aws_security_group" "codebuild_default" {
  name        = "codebuild-default-${var.vpc_name}"
  description = "codebuild-default group for ${var.vpc_name}"
  vpc_id      = aws_vpc.default.id

  ingress {
    from_port = 0
    to_port   = 65535
    protocol  = "tcp"
    cidr_blocks = [
      "0.0.0.0/0",
    ]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
```

{% endcode %}

{% code title="vim terraform/vpc/artp\_apnortheast2/outputs.tf" %}

```bash
output "aws_security_group_codebuild_default_id" {
  value = aws_security_group.codebuild_default.id
}
```

{% endcode %}

### Codebuild에 github 인증하기

* AWS CodeBuild 콘솔로 들어갑니다.

![](/files/-MSsDQm1dcwdATrJqZf-)

* `Create build project` 를 클릭합니다.
* `Connect using OAuth` 를 클릭합니다. (Personal Access Token으로 하셔도 무방합니다)

![](/files/-MSsDVcubJOmzhd1YH0f)

* 인증을 마치신 후에는 `Cancel` 누르고 빠져나오셔도 됩니다. 실제 프로젝트는 terraform 코드를 이용해서 생성할 예정입니다.

### Codebuild Project 생성

* Jenkins에서 사용할 Codebuild 프로젝트를 생성합니다.
* Codebuild 프로젝트와 관련된 전체 코드는 아래 디렉토리에 module 형태로 올려놓았으니 참조해주시기 바랍니다.
  * `terraform/codebuild/`
* 변경이 필요한 부분은 아래 주석으로 표시해 놓았습니다.

{% hint style="info" %}
본 가이드에서는 goployer 오픈소스를 활용하여 EC2를 배포할 예정입니다. goployer를 사용하고 싶으신 분들은 아래 링크를 참조해주시기 바랍니다.

<https://github.com/DevopsArtFactory/goployer.git>
{% endhint %}

{% code title="vim terraform/codebuild/artp-apnortheast2/deployment.tf" %}

```bash
module "deployment" {
  source                = "../_modules/deployment"
  service_name          = "deployment-prod"
  shard_id              = data.terraform_remote_state.vpc.outputs.shard_id
  public_subnets        = data.terraform_remote_state.vpc.outputs.public_subnets
  private_subnets       = data.terraform_remote_state.vpc.outputs.private_subnets
  aws_region            = data.terraform_remote_state.vpc.outputs.aws_region
  target_vpc            = data.terraform_remote_state.vpc.outputs.vpc_id
  vpc_name              = data.terraform_remote_state.vpc.outputs.vpc_name
  vpc_cidr_numeral      = data.terraform_remote_state.vpc.outputs.cidr_numeral
  billing_tag           = data.terraform_remote_state.vpc.outputs.billing_tag
  env_suffix            = data.terraform_remote_state.vpc.outputs.env_suffix

  image_credentials_type = "SERVICE_ROLE"

  # Change this to your security group ID
  deployment_default_sg = data.terraform_remote_state.vpc.outputs.aws_security_group_codebuild_default_id

  # Change this to your IAM role
  service_role          = "arn:aws:iam::816736805842:role/service-role/codebuild-deployment"

  # Change this repository which you want to pull code from.
  # In this repository, it should have buildspec file that you specify below
  github_repo            = "https://github.com/DevopsArtFactory/goployer.git"

  # buildspec file name you want to use
  buildspec              = "buildspec-deploy-prod.yml"

  # Change this to your docker image that you want to use for codebuild
  build_image            = "816736805842.dkr.ecr.ap-northeast-2.amazonaws.com/art-build:latest"
}

```

{% endcode %}

## Jenkins 설정

이제 Codebuild 연동을 위해서 Jenkins 세팅을 진행하도록 하겠습니. 본 세팅은 따로 코드로 정의하지 않았고, 아래 가이드를 통해서 한 번 설정하시고 나면 특별한 일이 없는 이상은 바꾸실 일이 거의 없습니다.&#x20;

### 플러그인 설치

* `Manage Jenkins` -> `Manage Plugins` 를 클릭합니다.

![](/files/-MSsDblUxUkfpEVdmtgc)

* `Available` 항목을 가셔서 codebuild를 검색해보시면 `AWS CodBuild` 플러그인이 보이실 겁니다. 이걸 클릭하신 후에 `Install now without restart` 를 클릭합니다.&#x20;

![](/files/-MSsDffysCPGwonXg_Aw)

설치가 진행되면 Jenkins를 재실행 할 수 있도록 옵션을 클릭해주고 기다립니다. Jenkins가 설치를 마치면 알아서 재시작합니다.&#x20;

![](/files/-MSsDilUpIrW8W_8GtJ0)

### Github 연동

* `Manage Jenkins` -> `Configure System` 를 클릭합니다.

![](/files/-MSsDmh8xsFqjYDkJIhx)

* Github 란으로 가셔서 `Add Github Server` 를 클릭합니다. 이름을 입력하신 후에, Credentials 쪽에 `Add` 버튼을 클릭합니다.

![](/files/-MSsDsB10-KXa7B3N-vr)

* Kind로 `Secret text` 를 선택하시고, Secret란에 이전에 발급받으신 `github 토큰`을 입력합니다. ID는 편하신대로 입력하셔도 됩니다. 완료되었으면 `Add` 버튼을 클릭합니다.

![](/files/-MSsDusGeOoxOQ-liqw9)

* 생성하신 Credentials를 선택하고 `Test Connection`을 클릭하셔서 정상적으로 연결되었는지 확인합니다.

![](/files/-MSsE1YP-8SvgQQ1IfhG)

* 정상적으로 테스트가 끝나면 `Save` 버튼을 누르셔서 현재 세팅을 저장합니다.

### Codebuild 연동&#x20;

* 메인화면에서 `New Item` 을 선택합니다.
* `Freestyle project` 를 선택하시고, 이름을 입력하신 후 ok를 클릭합니다.
  * 저는 hello production 어플리케이션을 배포할 예정입니다.

![](/files/-MSsE5lWnRe4pJvfqMcU)

* Build 란에서 AWS Codebuild를 선택합니다.
  * AWS Codebuild가 안보이시는 경우에는 위에서 플러그인이 제대로 설치되었는지 확인해주시기 바랍니다.&#x20;

![](/files/-MSsE89FpzHNlwmeEu9_)

* `Select credentials from jenkins` 를 선택하시고 `Add` 를 클릭해서 새로운 인증키를 생성합니다.

![](/files/-MSsEAOmn5zfqLGM0-an)

* 사전에 발급받은 Jenkins User의 AWS Access Key와 AWS Secret Access Key를 입력합니다.&#x20;

![](/files/-MSsECjT5mZ-ZF15F6-P)

* Region ID를 입력하시고, 이전에 생성했던 Codebuild 이름을 입력합니다. 이후에 `Use Project Source` 를 선택합니다.  따로 값은 입력하지 않으셔도 됩니다.

![](/files/-MSsEFC-SbRsxQC6uW-L)

* (Optional) 파라미터가 필요하신 경우에는 파라미터를 (원하시는만큼)입력합니다. 해당 파라미터는 codebuild로 전달하실 수 있습니다. 참고로 맨 위쪽에서 세팅하시면 됩니다.

![](/files/-MSsEIgYm4sTP5AtxpSh)

* 위의 파라미터를 Codebuild로 전달합니다. Codebuild 설정했던 부분의 `Build Configuration` 부분에 있습니다.

![](/files/-MSsENfBEvWSSMcUX-fw)

* 설정이 완료되었으면 save 버튼을 누릅니다.&#x20;

## Codebuild 사용하기

* `Build with Parameters` 를 클릭하셔서 Codebuild job을 실행합니다.

![](/files/-MSsEQUG_ehDlMN63opw)

* &#x20;빌드 번호를 선택하시고 `Console Output` 을 보시면 Codebuild의 로그를 보실 수 있습니다.

![](/files/-MSsEUV_Yte8PAueNfJw)

* Codebuild를 확인해보시면 아래와 같이 실행되고 있는 Job을 보실 수 있습니다.

![](/files/-MSsEXy4E74viFPAr2bn)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://terraform201.devart.tv/5.-jenkins/codebuild.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
