Codebuild 연동하기
Codebuild란 무엇인가?
Why Codebuild ?
Jenkins와 Codebuild
Jenkins와 Codebuild를 연동하게 되면, 빌드 또는 배포 job 은 jenkins에서 생성하고 실제 작업은 Codebuild를 통해서 진행하실 수 있습니다. Jenkins에서 Job이 실행되면 AWS 상에 독립적인 codebuild job이 생성 됩니다.
장점
각 Job을 독립적인 환경에서 빌드/배포할 수 있습니다.
AWS Codebuild 특성상 특정 VPC내에서 실행하실 수 있기 때문에, 접근제어 또는 다른 서비스와의 연동 시 용이합니다.
Codebuild의 모든 로그를 Amazon CloudWatch Logs를 통해서 보실 수 있고, 기존의 빌드 및 배포 이력을 손쉽게 찾아보실 수 있습니다.
사전 준비 사항
Jenkins와 Codebuild에 연동할 Github 토큰
Jenkins에서 사용할 AWS IAM User 및 Credentials
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
Github 토큰
Github 에서
Settings
-->Developer settings
-->Personal access tokens
를 들어갑니다.Generate new token
을 클릭합니다.이름을 넣고
repo
와read:org
권한을 추가한 후에 토큰을 발급합니다.발급받은 토큰은 임시로 안전한 곳에 저장해두시기 바랍니다.

IAM User 생성
Jenkins를 배포할 계정의 IAM directory를 찾아서 들어갑니다.
예시 :
terraform/iam/art-prod
없으신 경우에는 이전 IAM 환경 구성을 참조하셔서 먼저 환경 세팅을 해주시기 바랍니다.
GetLogEvents
와Codebuild:*
에 관한 권한은 반드시 필요합니다. 다른 권한은 필요에 따라 추가/삭제하셔도 됩니다.아래와 같이 테라폼 코드를 작성하시고 나서, terraform apply 를 통해 배포하시면 콘솔에서 유저를 찾으실 수 있습니다.
# 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를 발급 받습니다. 발급받으신 키는 반드시 안전한 곳에 보관하시기 바랍니다.

CodeBuild 생성
이제 연동할 Codebuild 프로젝트를 생성하도록 하겠습니다. Codebuild 프로젝트를 위해서는 아래의 리소스가 필요합니다.
Codebuild에서 사용할 IAM 역할
Codebuild의 기본 베이스가 되는 Docker image
Codebuild에서 사용할 보안그룹
Codebuild 프로젝트
IAM 역할 생성
Codebuild에서 사용할 역할이므로, 실제 빌드/배포에 필요한 권한을 가지고 있어야 합니다.
Codebuild를 생성할 계정의 IAM 디렉토리로 가서 생성을 진행합니다. (
terraform/iam/art-prod
)
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
}
Docker Image 생성(optional)
Codebuild는 컨테이너로 생성되므로 어떤 이미지를 사용하여 Job을 돌릴지 정해주어야 합니다.
본 가이드에서는 필요한 이미지를 빌드해서 ECR에 저장하도록 하겠습니다.
ECR 레포지토리를 생성하는 디렉토리에 리소스를 추가합니다.
terraform/ecr/art-prod/prod_apnortheast2
Policy 에 Account ID는 자신의 계정 번호를 넣어주시면 됩니다.
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
}
ECR 레포지토리 생성이 완료되면, 각자 원하는 Docker Image를 생성해서 해당 Repository에 푸시합니다. (샘플 이미지는 올려놓았습니다!)
terraform/ecr/art-prod/prod_apnortheast2/Dockerfile-art-build-amazon
보안그룹 생성
VPC를 생성했던 곳으로 가서 Security Group을 생성합니다. (
terraform/vpc/artp_apnortheast2
)만약 다른 곳에서 관리하고 계신 경우에는 해당 디렉토리에서 생성하시면 됩니다.
생성한 Security Group을 외부에서 참조할 수 있도록 output에도 추가합니다.
# 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"]
}
}
output "aws_security_group_codebuild_default_id" {
value = aws_security_group.codebuild_default.id
}
Codebuild에 github 인증하기
AWS CodeBuild 콘솔로 들어갑니다.

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

인증을 마치신 후에는
Cancel
누르고 빠져나오셔도 됩니다. 실제 프로젝트는 terraform 코드를 이용해서 생성할 예정입니다.
Codebuild Project 생성
Jenkins에서 사용할 Codebuild 프로젝트를 생성합니다.
Codebuild 프로젝트와 관련된 전체 코드는 아래 디렉토리에 module 형태로 올려놓았으니 참조해주시기 바랍니다.
terraform/codebuild/
변경이 필요한 부분은 아래 주석으로 표시해 놓았습니다.
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"
}
Jenkins 설정
이제 Codebuild 연동을 위해서 Jenkins 세팅을 진행하도록 하겠습니. 본 세팅은 따로 코드로 정의하지 않았고, 아래 가이드를 통해서 한 번 설정하시고 나면 특별한 일이 없는 이상은 바꾸실 일이 거의 없습니다.
플러그인 설치
Manage Jenkins
->Manage Plugins
를 클릭합니다.

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

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

Github 연동
Manage Jenkins
->Configure System
를 클릭합니다.

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

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

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

정상적으로 테스트가 끝나면
Save
버튼을 누르셔서 현재 세팅을 저장합니다.
Codebuild 연동
메인화면에서
New Item
을 선택합니다.Freestyle project
를 선택하시고, 이름을 입력하신 후 ok를 클릭합니다.저는 hello production 어플리케이션을 배포할 예정입니다.

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

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

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

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

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

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

설정이 완료되었으면 save 버튼을 누릅니다.
Codebuild 사용하기
Build with Parameters
를 클릭하셔서 Codebuild job을 실행합니다.

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

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

Last updated
Was this helpful?