이 가이드에서는 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-build
java-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 역할의 권한은 최소 권한 원칙에 따라 설정하는 것이 좋습니다.