WorkCASE STUDY 02KUBERNETES PLATFORM

Elastic Beanstalk에서 EKS로 서비스 전환

WAR 중심의 Elastic Beanstalk 환경을 서비스별 컨테이너와 EKS로 전환하고, 실제 트래픽 이관부터 기존 환경 정리까지 완료했습니다.

주요 작업 기간
2024.07–2025.09
팀
FORCS - eformsign 인프라팀
역할
기획·아키텍처 설계·주요 기능 구현 주도

OUTCOMEEKS로 실제 서비스 트래픽을 전환하고 기존 Elastic Beanstalk 환경 정리까지 완료했습니다.

배포 단위
WAR → 컨테이너 이미지
실행 환경
서비스별 Kubernetes 리소스
전환
트래픽 이관·EB 정리 완료

배경과 역할

서비스별로 배포와 확장을 제어할 수 있는 컨테이너 운영 환경을 구축했습니다.

플랫폼 중심에서 서비스 중심으로

Elastic Beanstalk의 애플리케이션 버전과 환경을 기준으로 하던 배포를, 서비스별 이미지와 Kubernetes 리소스를 기준으로 관리하도록 전환했습니다. 배포·실행·관측의 관리 단위를 함께 재설계했습니다.

전환 전 과정 담당

EKS 선행 구성과 검토, Terraform·Kubernetes 리소스 작성, 이미지 배포와 운영 전환을 진행했습니다. 실제 서비스 트래픽을 이관한 뒤 기존 EB 환경을 정리했습니다.

전환 전후 아키텍처

배포 산출물과 서비스 실행 구조가 어떻게 달라졌는지 비교합니다.

전환 전 · Elastic Beanstalk

WAR 산출물을 S3에 올리고 application version을 통해 환경에 배포했습니다. 플랫폼 변경과 애플리케이션 배포가 서비스 운영에 미치는 영향을 함께 관리해야 했습니다.

전환 후 · EKS

ECR의 컨테이너 이미지를 EKS에서 서비스별로 실행하고 ALB·Ingress를 통해 요청을 연결했습니다. 클러스터와 노드 구성은 Terraform으로, 애플리케이션 실행 정책은 Kubernetes 매니페스트로 관리했습니다.

DIAGRAM요청 진입부터 소스 번들 배포와 애플리케이션 실행까지
DIAGRAMEKS 전환 완료 후 운영 구조

핵심 구현

클러스터 기반과 애플리케이션의 실행 정책을 구분해 구성했습니다.

EKS 기반 구성

클러스터와 노드 그룹, IAM 및 네트워크 연결을 코드로 작성했습니다. 애플리케이션의 리소스 요구와 운영 방식을 Kubernetes에서 표현할 수 있도록 기반을 마련했습니다.

서비스별 배포 명세

Deployment에 이미지, 리소스, 환경 설정과 실행 조건을 선언했습니다. 서비스별 매니페스트를 통해 배포 대상을 식별하고 변경 범위를 분리했습니다.

Private EKS Cluster 구성

클러스터 API와 노드를 Private 네트워크에 배치하고 접근 인증 방식을 명시했습니다. 실행 환경의 네트워크 경계와 운영자의 접근 경로를 함께 설계했습니다.

eks.tfhcl
#### cluster
resource "aws_eks_cluster" "seoul_cluster" {
  name                          = var.cluster_name
  role_arn                      = data.aws_iam_role.eks_cluster_role.arn
  version                       = var.cluster_version
  bootstrap_self_managed_addons = false
  enabled_cluster_log_types     = []

  access_config {
    authentication_mode                         = "API_AND_CONFIG_MAP"
    bootstrap_cluster_creator_admin_permissions = true
  }

  vpc_config {
    security_group_ids      = [data.aws_security_group.control-plane-sg.id]
    endpoint_public_access  = false
    endpoint_private_access = true
    # public_access_cidrs = ["<CIDR>"]
    subnet_ids = [for s in data.aws_subnet.private_subnets : s.id]
  }

  kubernetes_network_config {
    service_ipv4_cidr = "<CIDR>"
  }

  zonal_shift_config {
    enabled = false
  }

  tags = {
    Name                                   = var.cluster_name
    "alpha.eksctl.io/cluster-oidc-enabled" = "true"
    "AWS.SSM.AppManager.EKS.Cluster.ARN"   = "arn:aws:eks:<REGION>:<ACCOUNT_ID>:cluster/<CLUSTER_NAME>"
  }
}

Kubernetes Service Deployment

Replica, 스케줄링 조건, readiness 검사와 리소스 설정을 Deployment에 정의했습니다. 애플리케이션의 실행 조건과 트래픽 수신 준비 상태를 선언적으로 관리합니다.

SserviceDeployment.yamlyaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: service
  namespace: test-seoul
spec:
  selector:
    matchLabels:
      app: service
  replicas: 1
  template:
  # ... template metadata/toleration 중간 설정 생략 ...
      containers:
      - name: service
        image: <IMAGE_URI>
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
          protocol: TCP
        readinessProbe:
          httpGet:
            path: /
            port: 8080
          initialDelaySeconds: 120
          periodSeconds: 30
          failureThreshold: 5
        resources:
          requests:
            cpu: 10m
            memory: 1024Mi
          limits:
            cpu: 500m
            memory: 2048Mi

배포와 운영 전환

사내 소스 패키징과 CodeBuild 이미지 빌드부터 서비스 확인, 트래픽 전환과 이전 환경 정리까지 연결했습니다.

빌드·배포·서비스 확인

사내 소스 보관 정책에 따라 원본 저장소는 사내에 유지했습니다. Jenkins·GitLab CI에서 소스를 패키징해 S3에 업로드한 뒤 CodeBuild를 트리거하고, CodeBuild가 이 패키지로 컨테이너 이미지를 만들어 ECR에 저장하도록 구성했습니다. 이후 Kubernetes 리소스를 반영하고, 배포 상태와 서비스 연결을 확인한 다음 트래픽을 전환했습니다.

확장과 관측

Pod 수 조정과 CloudWatch 기반 관측 구성을 함께 작성했습니다. 서비스 실행 상태와 부하를 확인하며 운영 대상과 확장 단위를 관리했습니다.

DIAGRAM이미지 배포·트래픽 전환·EB 정리

HPA 확장 이벤트의 설정 조회

HPA 이벤트의 last-applied 설정에서 최소·최대 replica 수를 읽습니다. 확장 이벤트를 관측하고 알림에 필요한 정보를 해석하는 함수입니다.

lambda_function.pypython
def get_max_replicas_from_message(message: str):
    try:
        evt = json.loads(message)

        ann = (
            evt.get("involvedObject", {})
               .get("annotations", {})
        )
        raw_last_applied = ann.get("kubectl.kubernetes.io/last-applied-configuration")
        if not raw_last_applied:
            return None

        last_applied = json.loads(raw_last_applied)

        return last_applied.get("spec", {}).get("maxReplicas"), last_applied.get("spec", {}).get("minReplicas")
    except (json.JSONDecodeError, TypeError, AttributeError):
        return None

문제 해결

실행 플랫폼을 바꾸면서 서비스의 연결과 운영 조건도 함께 옮겼습니다.

실행 환경 차이 반영

기존 플랫폼에서 제공하던 설정을 컨테이너와 Kubernetes의 실행 조건으로 다시 표현했습니다. 네트워크, 저장소와 애플리케이션 설정을 함께 점검해 환경 차이를 조정했습니다.

배포 완료 이후의 확인

리소스가 생성됐다는 사실만으로 전환을 끝내지 않았습니다. 서비스 응답과 트래픽 경로를 확인하고 기존 환경 정리까지 전환 작업에 포함했습니다.

결과

서비스별 컨테이너 운영 구조로 전환을 마무리했습니다.

실제 트래픽 전환 완료

EKS 환경으로 실제 서비스 트래픽을 전환했습니다. 이후 기존 Elastic Beanstalk 환경을 정리해 운영 대상을 새로운 플랫폼으로 모았습니다.

운영 단위의 명확화

서비스별 이미지·매니페스트·확장·관측 구성을 마련했습니다. 인프라 기반과 애플리케이션 배포를 구분해 변경을 관리할 수 있도록 했습니다.