이번 글에서는 백엔드 프로덕션 환경을 기록합니다.
데브서버의 단순히 빠른 개발 적용 서버와 다르게 비용, 보안, 확장성까지 모두 고려해서 설계한 풀스택 인프라 구축기입니다.
(ECR, EC2, RDS, ALB, ASG, CloudFront, GitHub Actions까지 다 활용했다)

구성 개요
핵심 컨셉
- 프라이빗 서브넷 기반 EC2 (Auto Scaling Group)
- ALB로 외부 트래픽 관리
- RDS는 프라이빗으로 운영
- NAT Gateway를 통해 외부 통신 허용
- GitHub Actions로 CI/CD 자동화
아키텍처를 이렇게 선택한 이유
(초기 시도) 퍼블릭 서브넷 + 보안 그룹
처음에는 비용 아끼려고 EC2와 RDS를 퍼블릭 서브넷에 넣고, 보안 그룹으로 외부 접근만 막는 전략을 썼다.
나쁘진 않았는데 문제는…
- 퍼블릭 IP가 있으면 아무리 보안 그룹을 잘 짜도 위험이 남는다.
- IAM 키 유출이나 설정 미스 났을 때, 바로 공격 타깃 될 수 있다.
그래서 퍼블릭 구조는 포기.
(결론) 프라이빗 서브넷 + NAT Gateway
지금은 EC2, RDS 모두 프라이빗 서브넷에 두고,
외부 통신은 NAT Gateway로만 시킨다.
덕분에:
- 퍼블릭 IP가 아예 없어서 외부 직접 침입 가능성 차단
- NAT Gateway 요금이 추가되긴 하지만 보안을 위해 투자할 가치 있음
EC2 Role + AMI 최적화
- EC2 IAM Role을 붙여서, ECR에서 인증 없이 Docker pull 가능
- 커스텀 AMI를 만들어 Docker 설치 & 기본 이미지 pull까지 완료된 상태로 시작
- 인스턴스 부팅 후 바로 docker run으로 서비스 기동!
CI/CD 파이프라인 (백엔드)
메인 브랜치 푸시하면 자동 배포
- GitHub Actions에서 Docker 빌드
- ECR로 이미지 push (prod / commit-hash 태그 둘 다)
- 기존 prod 이미지는 prod-stable로 백업
- ASG 롤링 배포(Instance Refresh) 로 무중단 배포
- 만약 실패하면 prod-stable 이미지로 롤백
name: CI/CD Pipeline for ECR and ASG
on:
push:
branches:
- main
jobs:
build-and-deploy:
name: Build, Push to ECR, Deploy on EC2
runs-on: ubuntu-22.04
env:
ECR_REGISTRY: 418272768555.dkr.ecr.ap-northeast-2.amazonaws.com
ECR_REPOSITORY: modie/modie-be-prod
COMMIT_HASH: "${{ github.sha }}"
ASG_NAME: modie-be-auto
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set short COMMIT_HASH
run: echo "COMMIT_HASH=$(echo $GITHUB_SHA | cut -c1-7)" >> $GITHUB_ENV
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v3
with:
aws-access-key-id: ${{ secrets.ECR_USER_ACCESS_KEY }}
aws-secret-access-key: ${{ secrets.ECR_USER_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-2
- name: Login to Amazon ECR
run: |
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin $ECR_REGISTRY
- name: Build, tag, and push image to Amazon ECR
run: |
set -e # 오류 발생 시 즉시 종료
echo "Building Docker image..."
docker build -q -t $ECR_REGISTRY/$ECR_REPOSITORY:$COMMIT_HASH \
-t $ECR_REGISTRY/$ECR_REPOSITORY:prod .
echo "Saving previous stable version..."
aws ecr batch-get-image --repository-name $ECR_REPOSITORY --image-ids imageTag=prod \
--query 'images[].imageManifest' --output text > stable_manifest.json
aws ecr put-image --repository-name $ECR_REPOSITORY --image-tag prod-stable \
--image-manifest file://stable_manifest.json || echo "✅ prod-stable 태그 업데이트 완료!"
echo "Pushing Docker image to ECR..."
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$COMMIT_HASH &
docker push $ECR_REGISTRY/$ECR_REPOSITORY:prod &
wait # 모든 Push 완료될 때까지 대기
echo "✅ Image pushed successfully!"
- name: 기존 EC2 인스턴스 점진적 교체 (롤링 업데이트)
run: |
echo "🚀 시작: Auto Scaling Group 롤링 배포"
aws autoscaling start-instance-refresh --auto-scaling-group-name $ASG_NAME
echo "⏳ 롤링 배포 진행 중..."
sleep 10 # 배포 시작 대기
# 배포 진행 상태 확인
STATUS=$(aws autoscaling describe-instance-refreshes --auto-scaling-group-name $ASG_NAME \
--query "InstanceRefreshes[0].Status" --output text)
echo "현재 배포 상태: $STATUS"
if [[ "$STATUS" != "InProgress" && "$STATUS" != "Successful" ]]; then
echo "❌ 배포 실패! 자동 롤백 실행..."
aws autoscaling cancel-instance-refresh --auto-scaling-group-name $ASG_NAME
echo "🔄 이전 `prod-stable` 이미지로 복구"
aws ecr batch-get-image --repository-name $ECR_REPOSITORY --image-ids imageTag=prod-stable \
--query 'images[].imageManifest' --output text > rollback_manifest.json
aws ecr put-image --repository-name $ECR_REPOSITORY --image-tag prod \
--image-manifest file://rollback_manifest.json
echo "🚀 롤백 완료! 배포 종료"
exit 1
fi
echo "✅ 롤링 배포 성공!"
Dockerfile (Spring Boot)
FROM bellsoft/liberica-openjdk-alpine:17 AS builder
WORKDIR /app
COPY . .
RUN ./gradlew clean build -x test
FROM bellsoft/liberica-openjdk-alpine:17
WORKDIR /app
COPY --from=builder /app/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
인프라 구성 시 고민한 것들
- EC2 인스턴스: t3.medium (Spring Boot 애플리케이션 운영에 필요한 메모리(4GiB)와 vCPU(2개)를 적절히 제공)
- 가격은 시간당 약 $0.0416
- 월 $30 정도로 충분히 쓸 수 있음
- 성능 테스트: 초당 300~500 요청 버텨냄
- CPU 사용률 60% 수준 유지
- 부팅 속도:
- AMI 최적화 덕분에 40~50초면 새 인스턴스 올라옴
- 롤백 대비:
- CI/CD에 자동 롤백 프로세스 내장
마무리
이번 구축은 단순히 서버 한 대 띄우는 게 아니라,
비용, 보안, 자동화, 확장성, 장애 대응까지 종합적으로 고려한 인프라 구축을 목표로 했습니다.
S3 + CloudFront + EC2 + RDS + ECR + ASG + GitHub Actions
이 조합으로, 추가 관리 거의 없이도 안정적이고 신뢰할 수 있는 배포/운영 환경을 완성했습니다.
아쉬운 점
아무리 Auto Scaling Group(ASG)으로 서버를 구성했더라도,
트래픽이 급격하게 몰릴 때는 여전히 한계가 느껴진다.
- 새로운 인스턴스가 추가되더라도
- EC2가 부팅되고 애플리케이션이 완전히 기동될 때까지 걸리는 웜업 타임이 있기 때문
즉, 스케일 아웃 신호가 오더라도
즉각적으로 부하를 분산시키지 못하고 몇 분간 서비스가 버벅거릴 수 있는 문제가 있다.
쿠버네티스 도입 고민
이런 문제를 해결하는 방법 중 하나로,
K8s를 도입하는 걸 고려할 수 있습니다.
- 쿠버네티스에서는 애플리케이션을 컨테이너 단위로 관리하기 때문에
- 새 인스턴스를 띄우는 대신, 기존 노드에 빠르게 Pod를 스케일링할 수 있다.
- 부하가 몰리더라도, 훨씬 빠르게(수 초~수 십 초 단위로) 대응할 수 있게 된다.
특히 EKS 같은 매니지드 쿠버네티스 서비스를 사용하면,
- 오토스케일링도 훨씬 세밀하게 설정할 수 있고
- 롤링 업데이트나 롤백 같은 작업도 훨씬 안전하게 처리할 수 있다.
요약
- ASG는 편하고 관리가 간단하지만, 급격한 트래픽 변화 대응에는 한계가 있다.
- Kubernetes는 더 빠른 스케일 아웃과 유연한 리소스 관리가 가능하다.
- 추후 트래픽 패턴이 더 복잡해진다면, 쿠버네티스 전환을 고려할 예정!
'DevOps' 카테고리의 다른 글
[DevOps] 모니터링 환경 구축 Prometeus, Grafana, Loki, Promtail - Modie (0) | 2025.04.11 |
---|---|
[DevOps] 백엔드 DEV서버 단일 EC2 기반 Blue/Green 배포 자동화 - Modie (0) | 2025.04.07 |
[DevOps] 프로젝트 Dev/Prod 서버 아키텍처 설계 경험 정리 (1) | 2025.04.07 |
GitHub Actions 머리 박치기 (0) | 2024.12.11 |
이번 글에서는 백엔드 프로덕션 환경을 기록합니다.
데브서버의 단순히 빠른 개발 적용 서버와 다르게 비용, 보안, 확장성까지 모두 고려해서 설계한 풀스택 인프라 구축기입니다.
(ECR, EC2, RDS, ALB, ASG, CloudFront, GitHub Actions까지 다 활용했다)

구성 개요
핵심 컨셉
- 프라이빗 서브넷 기반 EC2 (Auto Scaling Group)
- ALB로 외부 트래픽 관리
- RDS는 프라이빗으로 운영
- NAT Gateway를 통해 외부 통신 허용
- GitHub Actions로 CI/CD 자동화
아키텍처를 이렇게 선택한 이유
(초기 시도) 퍼블릭 서브넷 + 보안 그룹
처음에는 비용 아끼려고 EC2와 RDS를 퍼블릭 서브넷에 넣고, 보안 그룹으로 외부 접근만 막는 전략을 썼다.
나쁘진 않았는데 문제는…
- 퍼블릭 IP가 있으면 아무리 보안 그룹을 잘 짜도 위험이 남는다.
- IAM 키 유출이나 설정 미스 났을 때, 바로 공격 타깃 될 수 있다.
그래서 퍼블릭 구조는 포기.
(결론) 프라이빗 서브넷 + NAT Gateway
지금은 EC2, RDS 모두 프라이빗 서브넷에 두고,
외부 통신은 NAT Gateway로만 시킨다.
덕분에:
- 퍼블릭 IP가 아예 없어서 외부 직접 침입 가능성 차단
- NAT Gateway 요금이 추가되긴 하지만 보안을 위해 투자할 가치 있음
EC2 Role + AMI 최적화
- EC2 IAM Role을 붙여서, ECR에서 인증 없이 Docker pull 가능
- 커스텀 AMI를 만들어 Docker 설치 & 기본 이미지 pull까지 완료된 상태로 시작
- 인스턴스 부팅 후 바로 docker run으로 서비스 기동!
CI/CD 파이프라인 (백엔드)
메인 브랜치 푸시하면 자동 배포
- GitHub Actions에서 Docker 빌드
- ECR로 이미지 push (prod / commit-hash 태그 둘 다)
- 기존 prod 이미지는 prod-stable로 백업
- ASG 롤링 배포(Instance Refresh) 로 무중단 배포
- 만약 실패하면 prod-stable 이미지로 롤백
name: CI/CD Pipeline for ECR and ASG
on:
push:
branches:
- main
jobs:
build-and-deploy:
name: Build, Push to ECR, Deploy on EC2
runs-on: ubuntu-22.04
env:
ECR_REGISTRY: 418272768555.dkr.ecr.ap-northeast-2.amazonaws.com
ECR_REPOSITORY: modie/modie-be-prod
COMMIT_HASH: "${{ github.sha }}"
ASG_NAME: modie-be-auto
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set short COMMIT_HASH
run: echo "COMMIT_HASH=$(echo $GITHUB_SHA | cut -c1-7)" >> $GITHUB_ENV
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v3
with:
aws-access-key-id: ${{ secrets.ECR_USER_ACCESS_KEY }}
aws-secret-access-key: ${{ secrets.ECR_USER_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-2
- name: Login to Amazon ECR
run: |
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin $ECR_REGISTRY
- name: Build, tag, and push image to Amazon ECR
run: |
set -e # 오류 발생 시 즉시 종료
echo "Building Docker image..."
docker build -q -t $ECR_REGISTRY/$ECR_REPOSITORY:$COMMIT_HASH \
-t $ECR_REGISTRY/$ECR_REPOSITORY:prod .
echo "Saving previous stable version..."
aws ecr batch-get-image --repository-name $ECR_REPOSITORY --image-ids imageTag=prod \
--query 'images[].imageManifest' --output text > stable_manifest.json
aws ecr put-image --repository-name $ECR_REPOSITORY --image-tag prod-stable \
--image-manifest file://stable_manifest.json || echo "✅ prod-stable 태그 업데이트 완료!"
echo "Pushing Docker image to ECR..."
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$COMMIT_HASH &
docker push $ECR_REGISTRY/$ECR_REPOSITORY:prod &
wait # 모든 Push 완료될 때까지 대기
echo "✅ Image pushed successfully!"
- name: 기존 EC2 인스턴스 점진적 교체 (롤링 업데이트)
run: |
echo "🚀 시작: Auto Scaling Group 롤링 배포"
aws autoscaling start-instance-refresh --auto-scaling-group-name $ASG_NAME
echo "⏳ 롤링 배포 진행 중..."
sleep 10 # 배포 시작 대기
# 배포 진행 상태 확인
STATUS=$(aws autoscaling describe-instance-refreshes --auto-scaling-group-name $ASG_NAME \
--query "InstanceRefreshes[0].Status" --output text)
echo "현재 배포 상태: $STATUS"
if [[ "$STATUS" != "InProgress" && "$STATUS" != "Successful" ]]; then
echo "❌ 배포 실패! 자동 롤백 실행..."
aws autoscaling cancel-instance-refresh --auto-scaling-group-name $ASG_NAME
echo "🔄 이전 `prod-stable` 이미지로 복구"
aws ecr batch-get-image --repository-name $ECR_REPOSITORY --image-ids imageTag=prod-stable \
--query 'images[].imageManifest' --output text > rollback_manifest.json
aws ecr put-image --repository-name $ECR_REPOSITORY --image-tag prod \
--image-manifest file://rollback_manifest.json
echo "🚀 롤백 완료! 배포 종료"
exit 1
fi
echo "✅ 롤링 배포 성공!"
Dockerfile (Spring Boot)
FROM bellsoft/liberica-openjdk-alpine:17 AS builder
WORKDIR /app
COPY . .
RUN ./gradlew clean build -x test
FROM bellsoft/liberica-openjdk-alpine:17
WORKDIR /app
COPY --from=builder /app/build/libs/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
인프라 구성 시 고민한 것들
- EC2 인스턴스: t3.medium (Spring Boot 애플리케이션 운영에 필요한 메모리(4GiB)와 vCPU(2개)를 적절히 제공)
- 가격은 시간당 약 $0.0416
- 월 $30 정도로 충분히 쓸 수 있음
- 성능 테스트: 초당 300~500 요청 버텨냄
- CPU 사용률 60% 수준 유지
- 부팅 속도:
- AMI 최적화 덕분에 40~50초면 새 인스턴스 올라옴
- 롤백 대비:
- CI/CD에 자동 롤백 프로세스 내장
마무리
이번 구축은 단순히 서버 한 대 띄우는 게 아니라,
비용, 보안, 자동화, 확장성, 장애 대응까지 종합적으로 고려한 인프라 구축을 목표로 했습니다.
S3 + CloudFront + EC2 + RDS + ECR + ASG + GitHub Actions
이 조합으로, 추가 관리 거의 없이도 안정적이고 신뢰할 수 있는 배포/운영 환경을 완성했습니다.
아쉬운 점
아무리 Auto Scaling Group(ASG)으로 서버를 구성했더라도,
트래픽이 급격하게 몰릴 때는 여전히 한계가 느껴진다.
- 새로운 인스턴스가 추가되더라도
- EC2가 부팅되고 애플리케이션이 완전히 기동될 때까지 걸리는 웜업 타임이 있기 때문
즉, 스케일 아웃 신호가 오더라도
즉각적으로 부하를 분산시키지 못하고 몇 분간 서비스가 버벅거릴 수 있는 문제가 있다.
쿠버네티스 도입 고민
이런 문제를 해결하는 방법 중 하나로,
K8s를 도입하는 걸 고려할 수 있습니다.
- 쿠버네티스에서는 애플리케이션을 컨테이너 단위로 관리하기 때문에
- 새 인스턴스를 띄우는 대신, 기존 노드에 빠르게 Pod를 스케일링할 수 있다.
- 부하가 몰리더라도, 훨씬 빠르게(수 초~수 십 초 단위로) 대응할 수 있게 된다.
특히 EKS 같은 매니지드 쿠버네티스 서비스를 사용하면,
- 오토스케일링도 훨씬 세밀하게 설정할 수 있고
- 롤링 업데이트나 롤백 같은 작업도 훨씬 안전하게 처리할 수 있다.
요약
- ASG는 편하고 관리가 간단하지만, 급격한 트래픽 변화 대응에는 한계가 있다.
- Kubernetes는 더 빠른 스케일 아웃과 유연한 리소스 관리가 가능하다.
- 추후 트래픽 패턴이 더 복잡해진다면, 쿠버네티스 전환을 고려할 예정!
'DevOps' 카테고리의 다른 글
[DevOps] 모니터링 환경 구축 Prometeus, Grafana, Loki, Promtail - Modie (0) | 2025.04.11 |
---|---|
[DevOps] 백엔드 DEV서버 단일 EC2 기반 Blue/Green 배포 자동화 - Modie (0) | 2025.04.07 |
[DevOps] 프로젝트 Dev/Prod 서버 아키텍처 설계 경험 정리 (1) | 2025.04.07 |
GitHub Actions 머리 박치기 (0) | 2024.12.11 |