기존 배치방식 및 문제점

기존까지 배치 작업은 Jenkins를 통해서 구동하였다.
Jenkins를 이용하니 아래와 같은 문제점이 있었다.

  • 신규 배치가 추가될 때마다 EC2 사양 수정 (관리 부담)
  • 배치가 돌아가는 시간이 각각 다르니 서버가 24/7 운영되어야 함 (비용적 문제 발생)
  • 같은 시간대에 돌아가는 배치가 있을 경우 환경 충돌 (Queue 부재)
  • 모니터링, 알럿 및 로그 관리 기능 제한적

따라서 기존 Jenkins에서 구동되던 Spring Batch를 AWS Batch로 이관하는 작업을 진행했다.

AWS Batch 란?

(AWS Batch Image)
AWS Batch는 완전 관리형 배치 처리 서비스이다.
EC2, Spot, Fargate 등 컴퓨팅 서비스가 사용되며 사용된 컴퓨팅 리소스에 대해서만 비용이 부과된다.
구성요소로는 작업, 작업정의, 작업 대기열, 컴퓨팅 환경이 있는데 자세한 내용은 아래에서 설명하겠다.

AWS Batch를 이용한 배치 작업

구현하고자 한 내용은 다음과 같다.

  • Batch 소스코드를 Local에서 Batch Repo로 Push
  • Pipeline은 특정 브랜치 명으로 Push가 올 경우 Trigger가 됨
  • Pipeline이 동작하면 해당 소스코드로 Docker Image Build 및 ECR로 Push
  • AWS Batch는 기존 설정된 ECR에서 latest 태그가 부착된 이미지를 사용하여 ECS로 배치 프로세스 진행
  • AWS Batch는 EventBridge에 설정된 일정에 따라 실행
  • Batch 실패 시 Slack으로 Alert

Dockerfile

# 런타임 이미지
FROM {사용되는 JDK 버전}

# 컨테이너 빌드 디렉토리
WORKDIR /app

# 빌드파일 복사
COPY build/libs/*.jar app.jar

# 타임존 UST -> KST
ENV TZ Asia/Seoul

# 배치 실행 명령
CMD ["java", "-jar", "-Dspring.profiles.active={ENV}", "-DskipTests=true", "app.jar", "--spring.batch.job.enabled=true"]

여기서 유의할 점은 2가지가 있다.

타임존

코드에서 ZoneDateTime 을 사용하지 않았다면 Dockefile에서 타임존을 설정하여야한다.
따로 설정을 하지 않을 경우 배치 작업은 KST로 시작되나 인스턴스 안에서 배치 코드는 UTC로 시간을 인식해서 DB에 정상적으로 데이터가 적재되지 않을 수 있다.

실행 명령어

배치 실행 명령어는 2가지로 정의할 수 있다.

  • CMD: 배치 작업정의 또는 작업에서 명령어를 덮어쓰기를 할 경우
  • ENTRYPOINT: 배치 작업정의 또는 작업에서 명령어를 추가할 경우

파이프라인

파이프라인 내용은 아래와 같다.

//bitbucket-pipelines.yml

image: {사용되는 JDK 버전}

pipelines:
  branches:
    {브랜치 명}: // 트리거가 되는 브랜치
      - step:
          name: Build and Deploy
          services:
            - docker
          caches:
            - docker
          script:
            - echo "Updating packages and installing dependencies"
            - apt-get update && apt-get install -y unzip curl
            - echo "Installing Gradle"
            - apt-get install -y gradle
            - echo "Installing AWS CLI"
            - curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
            - unzip awscliv2.zip
            - ./aws/install
            - echo "Setting executable permissions for gradlew"
            - chmod +x ./gradlew
            - echo "Building the application with Gradle"
            - ./gradlew clean bootJar
            - echo "Building Docker image"
            - docker build -t {Repository 이름} .
            - echo "Tagging Docker image"
            - docker tag {Repository 이름}:latest $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/{Repository 이름}:latest
            - 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
            - echo "Pushing Docker image to Amazon ECR"
            - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/{Repository 이름}:latest
            - echo "Success"

{브랜치 명}으로 Push가 되면 위 파이프라인이 실행된다.
내용은 필요 패키지 다운로드 → Gradle Build → Docker Build → Image push 이다.

유의할 사항으로는 환경변수 값들을 미리 Repository에서 선언해야 하며 ECR을 미리 생성해야한다.

AWS Batch 구성

컴퓨팅 환경

배치가 실행될 컴퓨팅 환경을 구성해야한다.

  • Fargate, EC2, EKS 등을 선택할 수 있는데 현재 워크로드상 실행되는 배치들은 특정 시간대에 큰 컴퓨팅 리소스 없이 구동되기때문에 Fargate를 선택했다.

  • Fargate 스팟 용량 사용은 일반 Fargate와 동일한 서비스 환경을 제공하지만 AWS 측에서 인스턴스를 필요에 따라 종료할 수 있다.
  • 대신 일반 Fargate에 비해 최대 70% 할인된 가격으로 이용할 수 있다.
  • 일반적으로 종료 2분전에 알람을 보내주며 비용적으로 2분내로 종료되는 배치들에 적용하면 비용 효율적으로 이용할 수 있다.
  • 최대 vCPU는 서버리스 방식으로 리소스 요구사항에 따라 동적으로 조정되며 필요시 전까지 최대 vCPU에 도달하지 않는다.

  • 배치가 구동되는 VPC, 서브넷 및 보안그룹을 설정하면 된다.

작업 대기열

하나의 배치 프로젝트에 여러개의 Job이 같은 시간에 실행될 경우 Queue를 통해 우선순위를 정한다.

  • 예약 정책 ARN은 작업이 어떤 방식으로 실행될지 결정하는 규칙을 정의하는 역할을 한다.
  • 예약 정책을 통해 작업의 우선순위, 실행 순서, 자원 할당 방법 등을 제어할 수 있다.
  • 연결된 컴퓨팅 환경에는 직전에 생성한 컴퓨팅 환경과 연결하면 된다.

작업 정의

작업을 실행하는 방법, IAM Role이나 리소스 등을 결정한다.

  • 레거시 containerProperties 구조 사용은 AWS Batch의 초기 컨테이너 설정 방법으로, 현재는 최신 속성 구조에 비해 기능이 제한적일 수 있다.
  • 체크박스를 선택, 해제에 따라 설정하는 방법이 다르며 해당 글에서는 레거시 구조를 사용하는 경우로 작성하겠다.

  • 이름, 실행 제한 시간, 우선 순위등을 설정한다.

  • 플랫폼 관련 설정을 진행하며, 통상 배치 서비스들이 퍼블릭 IP를 가지고 있을 필요가 없으니 해제하고 설정을 진행한다. (만약 퍼블릭 IP가 필요할 경우 컴퓨팅 환경이 퍼블릭 서브넷에 위치해야한다.)
  • 실행 역할은 IAM에서 설정을 진행한다.

  • 이미지는 ECR에 올라와있는 URL은 입력하면된다.
  • 명령의 경우 Dockerfile에서 정의하였다면 추가로 정의할필요는 없다.
    - 현재 우리는 하나의 배치에서 여러개의 Job들로 실행되는 시간 및 작업이 분류된 경우가 많아 Dockerfile에서 실행 명령어를 정의하지않고 위 명령 설정으로 정의하는 케이스가 많다.

작업

작업정의를 바탕으로 작업이 실행되나 특정 작업별로 다른 설정값을 줘야할 경우에 내용을 추가할 수 있다.

  • 작업 이름, 작업 정의, 작업 대기열을 선택한다.

EventBridge 구성

Amazon EventBridge -> 일정에서 배치 스케쥴링을 설정한다.

  • 일정 이름, 설명, 그룹등을 설정한다.

  • 반복 일정으로 설정하고 Cron 표현식으로 일정을 설정한다.

  • 대상은 위와같이 작업 제출 API를 대상으로 선택한다.

  • 작업 정의, 작업 이름, 작업 대기열 순으로 입력한다.

Batch 실패 알럿 구성

Batch 실패 → CloudWatch → EventBridge → SNS → Chatbot → Slack

와 같은 워크플로로 구현했다.

  • SNS
  • CloudWatch / EventBridge

  • 배치 실패 시 작동해야하므로 이벤트 패턴이 있는 규칙으로 선택한다.

  • 배치 실패 시 이벤트가 발생하도록 설정하였다.

  • 위에서 생성한 SNS 주제를 선택한다.

  • Chatbot

  • Slack을 대상으로 클라이언트를 구성한다.

  • 생성한 SNS 주제에서 구독을 생성하고 해당 Chatbot 엔드포인트 주소를 입력한다.

  • 실패했을 경우 위처럼 알럿이 오게된다.
profile
Junior DevOps Engineer

0개의 댓글