이 가이드에서는 AWS의 CodeSeries 서비스들을 활용하여 Java 애플리케이션을 위한 자동화된 CI/CD 파이프라인을 구축하는 방법을 상세히 알아보겠습니다.
우리가 구축할 파이프라인은 다음과 같은 흐름으로 동작합니다:
파이프라인 구축을 시작하기 전에 다음 사항들이 준비되어 있어야 합니다:
먼저 Java 애플리케이션 빌드를 위한 buildspec 파일을 설정합니다:
version: 0.2
phases:
install:
runtime-versions:
java: corretto17
build:
commands:
- chmod +x ./demo/gradlew
- cd ./demo
- ./gradlew build
- cp build/libs/demo-0.0.1-SNAPSHOT.jar ../
artifacts:
files:
- '**/*'
- 'demo-0.0.1-SNAPSHOT.jar'
base-directory: '.'
discard-paths: no
Java 프로젝트 빌드를 위한, Codebuild 설정을 진행합니다.
[이미지 3: Java CodeBuild 기본/소스 설정 화면]
bjh-java-buildjava-repo-test
[이미지 4: CodeBuild 빌드 환경 이미지 설정 화면]
이미지가 제공하는 런타임 정보는 https://docs.aws.amazon.com/codebuild/latest/userguide/available-runtimes.html 에서 확인할 수 있습니다.
[이미지 5: CodeBuild Java Buildspec 설정 화면]
Docker 이미지 빌드 및 푸시를 위한 buildspec 파일:
version: 0.2
env:
variables:
AWS_DEFAULT_REGION: "ap-northeast-2"
AWS_ACCOUNT_ID: "634371522187"
IMAGE_REPO_NAME: "bjh-docker-build"
IMAGE_TAG: "v1.0.0"
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 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
- printf '{"ImageURI":"%s"}' $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG > imageDetail.json
buildspec_dk.yml : 코드를 도커 이미지로 만들어서 AWS의 이미지 저장소(ECR)에 자동으로 올려주는 설정파일입니다.
bjh-docker-build
[이미지 6: 소스 설정을 이전 Codebuild 출력 아티펙트의 S3로 설정]
[이미지 7: Docker 빌드 환경 설정 화면]
[이미지 8: Docker 빌드 Buildspec 설정 화면]
[이미지 9: CodeDeploy 애플리케이션 생성 화면]
{
"family": "spring-app-task",
"executionRoleArn": "arn:aws:iam::<account_id>:role/ecsTaskExecutionRole",
"networkMode": "awsvpc",
"containerDefinitions": [
{
"name": "spring-app",
"image": "<IMAGE1_NAME>",
"portMappings": [
{
"containerPort": 8080,
"protocol": "tcp"
}
],
"essential": true,
"environment": [
{
"name": "SERVER_PORT",
"value": "8080"
}
],
"logConfiguration": {
"logDriver": "awslogs",
"options": {
"awslogs-group": "/ecs/bjh_task_test",
"awslogs-region": "ap-northeast-2",
"awslogs-stream-prefix": "ecs"
}
},
"memory": 512,
"cpu": 256
}
],
"requiresCompatibilities": [
"FARGATE"
],
"cpu": "256",
"memory": "512",
"runtimePlatform": {
"operatingSystemFamily": "LINUX"
}
}
taskdef.json : ECS 내부적으로 사용할 테스크 정의를 작성합니다. 정의값을 참조하여 Deploy 과정에서 테스크를 생성해냅니다. <IMAGE1_NAME>의 경우, Codepipline 에서 설정 시, imageDetail.json을 참조하면 자동으로 값이 대체됩니다.
version: 0.0
Resources:
- TargetService:
Type: AWS::ECS::Service
Properties:
TaskDefinition: "<TASK_DEFINITION>"
LoadBalancerInfo:
ContainerName: "spring-app"
ContainerPort: 8080
appspec.yml: CodeDeploy에서 애플리케이션을 어떻게 배포할지 정의하는 설정 파일입니다. 배포<TASK_DEFINITION> 블록은 이후 taskdef.json을 통해 생성된 task에 의해 대체됩니다.
[이미지 10: CodeDeploy 서비스 역할 설정 화면]
[이미지 11: CodeDeploy 배포 그룹 설정 화면]
java-test-deploy이제 모든 구성 요소들을 하나의 파이프라인으로 연결합니다:
소스 스테이지 (CodeCommit) - 기존 소스코드가 들어있는 Git Repository를 선택합니다.
빌드 스테이지 1 (Java 빌드) - 기존에 생성했던 Java를 Jar 파일로 빌드하는 Codebuild 프로젝트를 선택합니다.
빌드 스테이지 2 (Docker 빌드) - 기존에 생성했던 Docker 파일을 Push하는 Codebuild 프로젝트를 선택합니다.
배포 스테이지 (CodeDeploy) - 이전에 생성한 CodeDeploy 및 작업 공급자를 ECS(Blue/Green)으로 선택합니다. 또한 ECS 작업 정의 및 Appspec.yml 파일 설정하는 란에 기존 CodeDeploy시에 만들었던 파일(taskdef.json, appspec.yml)로 대체합니다. 그리고 작업 정의 자리 표시자 텍스트를 taskdef.json에서 image name을 대체하려고 설정했던 텍스트로 변경합니다 (IMAGE1_NAME).
[이미지 14: 완성된 파이프라인 실행 화면]
파이프라인 구성이 완료되면 다음 사항들을 확인합니다:
이렇게 구성된 CI/CD 파이프라인은 다음과 같은 이점을 제공합니다:
주의할 점은 각 설정 파일의 값들(ARN, 계정 ID, 리전 등)을 자신의 환경에 맞게 수정해야 한다는 것입니다. 또한, 보안을 위해 IAM 역할의 권한은 최소 권한 원칙에 따라 설정하는 것이 좋습니다.