AWS CodeBuild는
• Fully managed build service
완전관리형 빌드 서비스이며
• Alternative to other build tools such as Jenkins
Jenkins와 같은 빌드툴의 대체재 이며
• Continuous scaling (no servers to manage or provision – no build queue)
프로비저닝이 필요없이 지속적으로 스케일링 관릭 되며
• Pay for usage: the time it takes to complete the builds
빌드 수행 시간 만큼 과금하며
• Secure: Integration with KMS for encryption of build artifacts, IAM for build permissions, and VPC for network security, CloudTrail for API calls logging
KMS, IAM, VPC의 보안세팅을 이용할 수 있는 향상된 보안
CodeBuild 활용방안
• Source Code from GitHub / CodeCommit / CodePipeline / S3…
GitHub, CodeCommit 등과 같은 다양한 레파지토리 또는 저장장치를 Source로 지정할 수 있다.
• Build instructions can be defined in code (buildspec.yml file)
Buildspec.yml 파일을 이용해 빌드 설명을 정의할 수 있음
• Output logs to Amazon S3 & AWS CloudWatch Logs
• Metrics to monitor CodeBuild statistics
• Use CloudWatch Events to detect failed builds and trigger notifications
• Use CloudWatch Alarms to notify if you need “thresholds” for failures
• CloudWatch Events / AWS Lambda as a Glue
• SNS notification
CloudWatch와 AWS SNS를 이용해 Notification이 용이
CodeBuild 사용법
1. [CodeBuild]-[빌드프로젝트] 에서 빌드프로젝트 생성 클릭
2. 기본정보를 입력하고 '소스'란에 나의 레포지토리 정보와 동일하게 세팅
(필자의 경우 CodeCommit을 레파지토리로 사용하였고, 브랜치를 기준으로 빌드를 수행코자합니다.)
3. CodeBuild 실행하는 데 사용하는 운영 체제, 프로그래밍 언어 실행 시간 및 도구의 조합을 나타냅니다.
4. 가장 중요한 부분으로 Buildspec.yml 을 Read토록 한다. (디폴트로 buildspec.yml로 설정되어 있으니 혹시 이름/경로가 다른경우 입력하길)
5. 그리고 빌드 수행하면 시작됩니다.
BuildSpec 사용법
공식 Doc
https://docs.aws.amazon.com/ko_kr/codebuild/latest/userguide/build-spec-ref.html
CodeBuild의 빌드 사양 참조 - AWS CodeBuild
지정한 경우runtime-versions섹션에서 Ubuntu 표준 이미지 2.0 이상 또는 Amazon Linux 2 (AL2) 표준 이미지 1.0 이상 외의 이미지를 사용하는 경우, 빌드에서” 라는 경고가 발생합니다.Skipping install of runtimes.
docs.aws.amazon.com
buildspec 파일은 YAML 형식으로 표시해야 합니다.
version(필수)
buildspec 버전을 나타냅니다. 0.2를 사용할 것을 권장합니다.
run-as(옵션)
선택적 시퀀스. Linux 사용자만 사용할 수 있습니다. 이 buildspec 파일에서 명령을 실행하는 Linux 사용자를 지정합니다.run-as는 지정된 사용자에게 읽기 및 실행 권한을 부여합니다. buildspec 파일 처음에 run-as를 지정할 경우 모든 명령에 전역적으로 적용됩니다. 모든 buildspec 파일 명령에 대한 사용자를 지정하지 않으려는 경우 phases 블록 중 하나에 run-as를 사용하여 단계에 명령에 대한 사용자를 지정할 수 있습니다. run-as를 지정하지 않으면 모든 명령이 루트 사용자로 실행됩니다.
env(옵션, 중요)
선택적 시퀀스. 하나 이상의 사용자 지정 환경 변수에 대한 정보를 나타냅니다.
env/shell
선택적 시퀀스. Linux 또는 Windows 운영 체제에 대해 지원되는 셸을 지정합니다.
env/variables
env가 지정된 경우 및 사용자 지정 환경 변수를 일반 텍스트로 정의하려고 할 때 필요합니다.
env/parameter-store
Amazon EC2 Systems Manager 파라미터 스토어에 저장된 단일 사용자 지정 환경 변수를 나타냅니다.
env/secrets-manager
AWS Secrets Manager에 저장된 사용자 지정 환경 변수를 검색하려고 할 때 필요합니다.
<key>: <secret-id>:<json-key>:<version-stage>|<version-id>
env/exported-variables
내보낼 환경 변수를 나열하는 데 사용됩니다. 내보낼 변수는 빌드 중에 컨테이너에서 사용할 수 있어야 합니다.
env/git-credential-helper
CodeBuild 가 Git 자격 증명 헬퍼를 사용하여 Git 자격 증명을 제공하는지를 나타내는 데 사용됩니다
proxy(옵션)
명시적 프록시 서버에서 빌드를 실행할 경우 설정을 나타내는 데 사용됩니다.
phases(필수)
빌드의 각 단계 동안 CodeBuild가 실행하는 명령을 나타냅니다.
phases/*/run-as
해당 명령을 실행하는 Linux 사용자를 지정
phases/*/실패 시
단계 중에 오류가 발생할 경우 수행할 작업을 지정합니다. .
phases/*/finally
명령 후에 실행 되는commands블록을 설정합니다. JAVA의 try/catch/finally 와 같은 역할
phases/install
빌드 환경에서 패키지를 설치하는 경우에만 install 단계를 사용하는 것이 좋습니다.
phases/install/runtime-versions
빌드 사양 파일에 런타임을 지정하지 않은 경우 CodeBuild가 사용하는 이미지에서 사용할 수 있는 기본 런타임을 선택합니다. 하나 이상의 런타임을 지정하는 경우 CodeBuild 는 해당 런타임만 사용합니다.
phases/install/commands
스칼라 시퀀스를 포함하며, 각 스칼라는 설치 중에 CodeBuild 가 실행하는 단일 명령을 나타냅니다. CodeBuild 는 처음부터 끝까지 한 번에 하나씩 나열된 순서로 각 명령을 실행합니다.
phases/pre_build
빌드 전에 CodeBuild가 실행하는 명령을 나타냅니다
phases/build
빌드 중에 CodeBuild가 실행하는 명령을 나타냅니다
phases/post_build
빌드 후에 CodeBuild가 실행하는 명령을 나타냅니다
phases/build(pre_, post_ 동일)/commands
xx_build를 지정한 경우 필수 시퀀스입니다. CodeBuild 는 처음부터 끝까지 한 번에 하나씩 나열된 순서로 각 명령을 실행합니다.
reports(필수)
report-group-name-or-arn
보고서를 전송할 보고서 그룹을 지정합니다.
reports/<report-group>/files
보고서에 의해 생성된 테스트 결과의 원시 데이터가 포함된 위치를 나타냅니다.
reports/<report-group>/file-format
보고서 파일 형식을 나타냅니다. 지정하지 않으면 JUNITXML가 사용됩니다.
reports/<report-group>/base-directory
빌드 위치에 상대적인 하나 이상의 최상위 디렉터리를 나타냅니다.
reports/<report-group>/discard-paths
보고서 파일 디렉터리가 출력시 /로 압축되는지 여부를 지정합니다.(보안을 위해)
artifacts(옵션, 중요)
CodeBuild 출력을 찾을 수 있는 위치 및 S3 출력 버킷에 업로드하기 위해 빌드 출력을 준비하는 방식에 대한 정보를 나타냅니다. Docker 이미지를 빌드하여 Amazon ECR에 푸시하는 경우 또는 소스 코드에 단위 테스트를 실행하고 빌드는 하지 않는 경우 등에는 이 시퀀스가 필요하지 않습니다.
artifacts/files
빌드 환경의 빌드 출력 결과물을 포함하는 위치를 나타냅니다.
artifacts/name
빌드 결과물의 이름을 지정합니다.
artifacts/discard-paths
빌드 아티팩트 디렉터리가 출력에서 평면화(/로 퉁치는)되는지 여부를 지정합니다.
artifacts/base-directory
CodeBuild Build가 빌드 출력 결과물에 포함할 파일 및 하위 디렉터리를 결정할 때 사용하는 원래 빌드 위치를 기준으로 하나 이상의 최상위 디렉터리를 나타냅니다. 유
artifacts/exclude-paths
출력시 제외할 경로
artifacts/enable-symlinks
내부 심볼 링크가 출력되는 ZIP 파일에 유지되는지 여부를 지정합니다. yes로 설정하면 소스의 모든 내부 심볼 링크가 아티팩트 ZIP 파일에 보존됩니다.
artifacts/s3-prefix
S3버킷 출력경로의 prefix를 정할때 사용. 객체가 Amazon S3 버킷으로 출력되고 네임스페이스 유형이 BUILD_ID.일때 버킷의 출력 경로는<s3-prefix>/<build-id>/<name>.zip 이다.
artifacts/secondary-artifacts
선택적 시퀀스. 1개 이상의 아티팩트 정의를 아티팩트 식별자와 아티팩트 정의를 연결하는 매핑으로 나타냅니다.
cache(옵션)
CodeBuild 가 S3 캐시 버킷을 사용하여 업로드할때 준비 정보를 나타냅니다.
cache/paths
캐시의 위치를 나타냅니다.
↓ buildspec.yml기본 구성
version: 0.2
run-as: Linux-user-name
env:
shell: shell-tag
variables:
key: "value"
key: "value"
parameter-store:
key: "value"
key: "value"
exported-variables:
- variable
- variable
secrets-manager:
key: secret-id:json-key:version-stage:version-id
git-credential-helper: no | yes
proxy:
upload-artifacts: no | yes
logs: no | yes
batch:
fast-fail: false | true
# build-list:
# build-matrix:
# build-graph:
phases:
install:
run-as: Linux-user-name
on-failure: ABORT | CONTINUE
runtime-versions:
runtime: version
runtime: version
commands:
- command
- command
finally:
- command
- command
pre_build:
run-as: Linux-user-name
on-failure: ABORT | CONTINUE
commands:
- command
- command
finally:
- command
- command
build:
run-as: Linux-user-name
on-failure: ABORT | CONTINUE
commands:
- command
- command
finally:
- command
- command
post_build:
run-as: Linux-user-name
on-failure: ABORT | CONTINUE
commands:
- command
- command
finally:
- command
- command
reports:
report-group-name-or-arn:
files:
- location
- location
base-directory: location
discard-paths: no | yes
file-format: report-format
artifacts:
files:
- location
- location
name: artifact-name
discard-paths: no | yes
base-directory: location
exclude-paths: excluded paths
enable-symlinks: no | yes
s3-prefix: prefix
secondary-artifacts:
artifactIdentifier:
files:
- location
- location
name: secondary-artifact-name
discard-paths: no | yes
base-directory: location
artifactIdentifier:
files:
- location
- location
discard-paths: no | yes
base-directory: location
cache:
paths:
- path
- path
AWS에서 Merge요청등으로 발생한 Pull request를 승인하는 프로세스
준비사항
Lambda Functions, Codebuild, Cloudwatch Events, IAM Roles, CodeCommit
Architecture
- PullRequest is created 또는 existing PullRequest is updated 발생
- Cloudwatch의 레파지토리 모니터링 event 활성화됨
- event가 lambda function에 관련 데이터 전송
- 마지막 Commit버전에 대한 CodeBuild의 프로젝트를 유발해서 Test를 Run한다.
- PullRequest의 코멘트 섹션에 빌드시작을 알리고 Timestamp와 빌드로그의 링크를 게시하는 등 커스텀 메시지를 남긴다.
- CodeBuild가 완료되면 Cloudewatch가 빌드결과를 Lambda function에 보냄
- 이 Lambda function은 PullRequest에 결과를 코멘트 할 것이다.
아래는 Lambda Function 예시이다.
const AWS = require('aws-sdk');
const codecommit = new AWS.CodeCommit();
const codebuild = new AWS.CodeBuild();
exports.handler = async (event) => {
try {
console.log('Received Event: ', event);
const { destinationCommit } = event.detail;
const { sourceCommit } = event.detail;
const { pullRequestId } = event.detail;
const pullRequestName = event.detail.title;
const sourceBranch = event.detail.sourceReference.split('/').pop();
const triggerCodeBuildParameters = {
sourceBranch, sourceCommit, destinationCommit, pullRequestId, pullRequestName
};
const codeBuildResult = await triggerCodebuild(triggerCodeBuildParameters);
const buildId = codeBuildResult.build.id;
const postBuildStartedCommentOnPRParameters = {
sourceCommit, destinationCommit, pullRequestId, buildId
}
await postBuildStartedCommentOnPR(postBuildStartedCommentOnPRParameters);
return {
statusCode: 200
};
}
catch (error) {
console.log('An Error Occured', error);
return {
error
};
}
};
async function postBuildStartedCommentOnPR(postBuildStartedCommentOnPRParameters) {
const { sourceCommit, destinationCommit, pullRequestId, buildId } = postBuildStartedCommentOnPRParameters;
const logLink = `https://${process.env.REGION}.console.aws.amazon.com/codesuite/codebuild/projects/ValidatePullRequest/build/${buildId}`;
const parameters = {
afterCommitId: sourceCommit,
beforeCommitId: destinationCommit,
content: `Build For Validating The Pull Request has been started.
Timestamp: **${Date.now()}**
Check [CodeBuild Logs](${logLink})`,
pullRequestId,
repositoryName: process.env.REPOSITORY_NAME
};
const request = await codecommit.postCommentForPullRequest(parameters);
const promise = request.promise();
return promise.then(
(data) => data,
(error) => {
console.log('Error In Commenting To Pull Request', error);
throw new Error(error);
}
);
}
async function triggerCodebuild(triggerCodeBuildParameters) {
const { sourceBranch, sourceCommit, destinationCommit, pullRequestId, pullRequestName } = triggerCodeBuildParameters;
console.log(`Triggering Codebuild, Branch: ${sourceBranch}`);
const parameters = {
projectName: process.env.CODEBUILD_PROJECT,
sourceVersion: `refs/heads/${sourceBranch}^{${sourceCommit}}`,
environmentVariablesOverride: [
{
name: 'pullRequestId',
value: pullRequestId,
type: 'PLAINTEXT'
},
{
name: 'sourceCommit',
value: sourceCommit,
type: 'PLAINTEXT'
},
{
name: 'destinationCommit',
value: destinationCommit,
type: 'PLAINTEXT'
},
{
name: 'pullRequestName',
value: pullRequestName,
type: 'PLAINTEXT'
}
]
};
const request = await codebuild.startBuild(parameters);
const promise = request.promise();
return promise.then(
(data) => data,
(error) => {
console.log('Error In Starting Codebuild', error);
throw new Error(error);
}
);
}
[TriggerCodeBuildStart-index.js]
const AWS = require('aws-sdk');
const codecommit = new AWS.CodeCommit();
exports.handler = async (event) => {
try {
console.log('Event', event);
const parameters = await getParameters(event);
console.log('Parameters For Comment:', parameters);
await commentCodeBuildResultOnPR(parameters);
return { statusCode: 200 };
}
catch (error) {
console.log('An Error Occured', error);
return { error };
}
};
async function getParameters(event) {
try {
const buildId = event.detail['build-id'].split('/')[1];
const buildStatus = event.detail['build-status'];
const environmentVariableList = event.detail['additional-information'].environment['environment-variables'];
let afterCommitId, beforeCommitId, content, pullRequestId;
for (element of environmentVariableList) {
if (element.name === 'pullRequestId') pullRequestId = element.value;
if (element.name === 'sourceCommit') afterCommitId = element.value;
if (element.name === 'destinationCommit') beforeCommitId = element.value;
if (element.name === 'pullRequestName') pullRequestName = element.value;
}
const logLink = `https://${process.env.REGION}.console.aws.amazon.com/codesuite/codebuild/projects/ValidatePullRequest/build/${buildId}`;
content = `Build Result: **${buildStatus}**
Timestamp: **${Date.now()}**
Check [CodeBuild Logs](${logLink})`;
return {
afterCommitId,
beforeCommitId,
content,
pullRequestId,
repositoryName: process.env.REPOSITORY_NAME
};
} catch (error) {
throw error;
}
}
async function commentCodeBuildResultOnPR(parameters) {
const request = await codecommit.postCommentForPullRequest(parameters);
const promise = request.promise();
return promise.then(
(data) => data,
(error) => {
console.log('Error In Commenting To Pull Request', error);
throw new Error(error);
}
);
}
[TriggerCodeBuildResult - index.js]
buildspec에 관한 use-case는 아래 링크에서 확인할 수 있다.
https://docs.aws.amazon.com/ko_kr/ko_kr/codebuild/latest/userguide/use-case-based-samples.html
CodeBuild 사용 사례 기반 샘플 - AWS CodeBuild
이 페이지에 작업이 필요하다는 점을 알려 주셔서 감사합니다. 실망시켜 드려 죄송합니다. 잠깐 시간을 내어 설명서를 향상시킬 수 있는 방법에 대해 말씀해 주십시오.
docs.aws.amazon.com
이중에 특히 Docker 관련 샘플을 보자
version: 0.2
phases:
pre_build:
commands:
- 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
build:
commands:
- echo Build started on `date`
- echo Building the Docker image...
- docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .
- docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
post_build:
commands:
- echo Build completed on `date`
- echo Pushing the Docker image...
- docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG
여기서 주목할 만한점은 왜 ECR로그인을 Pre-build에 하는가 이다.
왜냐하면, Build가 무지오래 걸릴 수가 있기때문에 오류가능성이 있는 것을 Pre-build에 선 검증하고 빌드해야 똑똑한 CICD인것..
빌드시 사용하는 환경변수는 아래 링크에서 확인할 수 있다.
https://docs.aws.amazon.com/ko_kr/ko_kr/codebuild/latest/userguide/build-env-ref-env-vars.html
빌드 환경의 환경 변수 - AWS CodeBuild
Webhook pull 요청 이벤트에서 트리거하는 GitHub 또는 GitHub Enterprise Server 빌드의 경우 pr/pull-request-number입니다.
docs.aws.amazon.com
환경변수를 직접 커스텀 하고 싶다면, 이전에 배운 Buildspec의 env를 이용하거나,
CodeBuild에서 Build 수정을 통해 변수를 커스터 마이징한다.
간혹 도커빌드를 하다보면 DB_PASSWORD나 DB_HOST등을 환경변수로 빼는 경우가 많은데 이런경우 유용하게 사용할 수 있다.
'IaaS > 퍼블릭클라우드' 카테고리의 다른 글
(AWS) CodeDeploy를 위한 appspec.yml (0) | 2022.01.07 |
---|---|
(AWS) CodeDeploy 란? (0) | 2022.01.07 |
(AWS) CodeCommit 의 개발보안향상 및 Amazon-SNS 설정 (0) | 2021.12.28 |
(AWS) Code-Commit이란? (0) | 2021.12.27 |
(아키텍처) 하이브리드 환경을 위한 Amazon Route 53 DNS Resolver 신규 기능 (0) | 2021.10.18 |