Spring 백엔드 서버 배포는 두 단계로 진행한다
- 모놀로식 서버 배포: 단일 Spring 애플리케이션을 Kubernetes에 배포
- MSA 아키텍처 배포: Spring Cloud 기반의 마이크로서비스를 Kubernetes에 배포
MSA와 Kubernetes를 같이 사용하는 이유
MSA 아키텍처는 Kubernetes와 궁합이 매우 잘 맞는다
- 대규모 시스템: MSA를 채택하는 기업은 대부분 대규모 시스템을 운영
- 다수의 컨테이너: 여러 마이크로서비스가 각각 컨테이너로 실행됨
- 컨테이너 오케스트레이션: Kubernetes가 다수의 컨테이너를 효율적으로 관리
따라서 MSA 아키텍처를 사용하는 기업에서는 Kubernetes(특히 EKS)로 배포 환경을 구성하는 경우가 많다. MSA 서버 배포까지 경험해야 Kubernetes 배포를 제대로 이해했다고 할 수 있다
전체 아키텍처 구성
| 구성요소 | 역할 | 구현 방식 |
| Spring Pod | 백엔드 애플리케이션 | Deployment (Replicas: 2) |
| Worker Node | Pod가 실행되는 물리적 서버 | Amazon EC2 2대 |
| Database | 영구 데이터 저장 | Amazon RDS |
| Redis | 캐시/세션 저장소 | Kubernetes Pod |
| 이미지 저장소 | Docker 이미지 관리 | Amazon ECR |
| CI/CD | 빌드/배포 자동화 | Github Actions |
RDS vs Redis Pod
RDS를 사용하는 이유(데이터베이스)
- 데이터의 영속성과 안정성이 매우 중요
- Pod는 언제든재 재생성될 수 있어 데이터 손실 위험
- RDS는 자동 백업, 복제, 장애 조치 등 관리형 서비스 제공
Pod로 구성하는 이유 (Redis)
- 캐시 데이터는 상대적으로 휘발성이 허용됨
- Pod 재시작 시 캐시가 초기화되어도 서비스에 치명적이지 않음
- 필요시 Redis도 AWS ElastiCache로 개체 가능
배포 프로세스 상세
Spring 프로젝트의 문제점
application-local.yaml
spring:
config:
activate:
on-profile: local
redis:
host: localhost
port: 6379
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ordersystem?useSSL=false&allowPublicKeyRetrieval=true
username: root
password: 1234
```
**문제점:** Redis와 MySQL을 `localhost`로 참조하고 있습니다. 이 상태로 Pod를 배포하면 **Pod 내부에 Redis와 MySQL이 없기 때문에 에러가 발생**합니다.
### 3.2 해결 방안
```
[기존 - 로컬 개발 환경]
Spring → localhost:6379 (Redis)
Spring → localhost:3306 (MySQL)
[변경 - Kubernetes 환경]
Spring Pod → Redis Service → Redis Pod
Spring Pod → RDS Endpoint → Amazon RDS
```
- **Redis**: 별도의 Pod + Service로 구성하고, Spring에서 Service 이름으로 접근
- **RDB**: AWS RDS를 생성하고, Spring에서 RDS 엔드포인트로 접근
### 3.3 배포 순서
```
1. 사전 준비 (선행 작업)
├── Redis Pod + Service 생성
└── Amazon RDS 생성
2. Spring 배포
├── Docker 이미지 빌드
├── ECR에 이미지 업로드
├── Deployment 적용 (Pod 생성)
├── Service 적용
└── Ingress 적용 (HTTPS 포함)
3. CI/CD 자동화
└── GitHub Actions 설정
문제점: Redis와 MySQL을 `localhost`로 참조하고 있다. 이 상태로 Pod를 배포하면 Pod 내부에 Redis와 MySQL이 없기 때문에 에러가 발생한다
해결 방안
[기존 - 로컬 개발 환경] Spring → localhost:6379 (Redis) Spring → localhost:3306 (MySQL) [변경 - Kubernetes 환경] Spring Pod → Redis Service → Redis Pod Spring Pod → RDS Endpoint → Amazon RDS
- Redis: 별도의 Pod + Service로 구성하고, Spring에서 Service 이름으로 접근
- RDB: AWS RDS를 생성하고, Spring에서 RDS 엔드포인트로 접근
배포 순서
1. 사전 준비 (선행 작업) ├── Redis Pod + Service 생성 └── Amazon RDS 생성 2. Spring 배포 ├── Docker 이미지 빌드 ├── ECR에 이미지 업로드 ├── Deployment 적용 (Pod 생성) ├── Service 적용 └── Ingress 적용 (HTTPS 포함) 3. CI/CD 자동화 └── GitHub Actions 설정
이미지 관리와 배포 흐름
수동 배포 프로세스
개발자가 소스코드를 변경했을 때 수행해야 하는 작업
Docker 이미지 빌드
docker build -t my-spring-app:latest .
ECR에 이미지 업로드
docker tag my-spring-app:latest <ECR-URI>/my-spring-app:latest docker push <ECR-URI>/my-spring-app:latest
Pod 재생성 (이미지 갱신)
kubectl rollout restart deployment/<deployment-name> -n <namespace>
rollout restart가 필요한 이유
이미지 태크를 `latest`로 사용할 경우, Deployment YAML 자체는 변경되지 않는다. Kubernetes는 변경 사항이 없으면 Pod를 재생성하지 않는다. 따라서 새 이미지를 반영하려면 Kubernetes rollout restart 명령어로 ReplicaSet을 새로 생성해야 한다
문제점
위 과정은 소스코드가 변경될 때마다 반복해야 한다
- 회사의 소스코드는 지속적으로 변경된다
- 매번 이미지 빌드 → 업로드 → rollout restart를 수동으로 수행한다
- 반복적이고 실수가 발생하기 쉬운 작업이다
CI/CD 자동화
- Continuous Integration (CI): 지속적 통합 – 코드 변경 시 자동으로 빌드 및 테스트
- Continuous Deployment/Delivery (CD): 지속적 배포 – 빌드된 결과물을 자동으로 서버에 배포
CI/CD 자동화의 핵심: 프로젝트를 빌드하고, 이미지를 만들어서, 서버에 배포하는 작업을 자동화하는 것
Github Actions를 통한 자동화
개발자가 main 브랜치에 push/merge
↓
GitHub Actions 트리거
↓
┌────────────────────┐
│ 1. 소스코드 체크아웃 │
│ 2. 프로젝트 빌드 │
│ 3. Docker 이미지 빌드 │
│ 4. ECR에 이미지 푸시 │
│ 5. kubectl rollout │
│ restart 실행 │
└────────────────────┘
↓
새로운 Pod 자동 생성
지속적으로 변경되는 것 vs 한 번만 설정하는 것
- 한 번만 설정: Deployment, Service, Ingress YAML – 거의 변경 없음
- 지속적 변경: Spring 소스코드 → Docker 이미지 → Pod – 빈번하게 변경
따라서 CI/CD 자동화의 대상은 이미지 빌드 → 업로드 → Pod 재생성 과정이다
Amazon ECR vs Docker Hub
ECR을 사용하는 이유
| 비교 항목 | Docker Hub | Amazon ECR |
| 소유 | Docker Inc. | AWS |
| EKS 연동 | 별도 설정 필요 | 네이티브 통합 |
| IAM 권한 | 지원 안 함 | AWS IAM 기반 권한 관리 |
| 비용 | 무료 티어 제한적 | AWS 사용량 기반 |
| 실무 사용 | EKS 환경에서는 드묾 | EKS와 함께 많이 사용 |
AWS 생태계(EKS, RDS 등)를 사용한다면 서비스의 통일성과 보안 관리 측면에서 ECR 사용이 권장된다. 실무에서 EKS를 사용하면서 Docker Hub를 사용하는 경우는 많지 않다
전체 흐름 요약
사용자 요청 흐름
사용자 → Route53 → Load Balancer → Ingress → Service → Pod (Spring)
↓
┌───────────┴───────────┐
↓ ↓
Redis Service Amazon RDS
↓
Redis Pod
개발자 배포 흐름
개발자 → GitHub (push) → GitHub Actions → ECR (이미지) → EKS (Pod 재생성)