Spring 프로파일 설정 이해
프로파일 구조
Spring 프로젝트에는 환경별로 다른 설정을 사용하기 위한 프로파일 시스템이 있다
src/main/resources/ ├── application.yml # 기본 설정 (어떤 프로파일을 사용할지 지정) ├── application-local.yml # 로컬 개발 환경 설정 └── application-prod.yml # 프로덕션(Kubernetes) 환경 설정
프로파일 활성화 메커니즘
application.yml
spring:
profiles:
default: local # 기본값: local 프로파일 사용
이 설정을 prod로 변경하면
spring:
profiles:
default: prod # prod 프로파일 사용
application-local.yml
spring:
config:
activate:
on-profile: local # 이 파일은 'local' 프로파일일 때 활성화
application-prod.yml
spring:
config:
activate:
on-profile: prod # 이 파일은 'prod' 프로파일일 때 활성화
핵심: application.yml의 default 값과 각 프로파일 파일의 on-profile 값이 일치하면 해당 파일이 적용된다
Kubernetes 환경을 위한 설정 (application-prod.yml)
Redis 연결 설정
로컬 환경 (application-local.yml)
spring:
redis:
host: localhost # 로컬 PC에 설치된 Redis
port: 6379
Kubernetes 환경 (application-prod.yml)
spring:
redis:
host: redis-service # Kubernetes Service 이름
port: 6379
Kubernetes 클러스터 내부
┌─────────────────┐ ┌─────────────────┐
│ Spring Pod │ │ Redis Pod │
│ │ │ │
│ redis: │ │ port: 6379 │
│ host: │─────────│ │
│ redis-service │ ↓ │ │
└─────────────────┘ │ └─────────────────┘
│
┌─────┴─────────┐
│ Service │
│ redis-service │
│ port: 6379 │
└───────────────┘
redis.yml
apiVersion: v1
kind: Service
metadata:
name: redis-service # ← Spring에서 이 이름으로 접근
namespace: hyeok
spec:
ports:
- port: 6379 # ← Service 포트
targetPort: 6379 # ← Pod의 containerPort와 일치
selector:
app: redis
통신 흐름
- Spring이 http://redis-service:6379
- Kubernetes DNS가 redis-service를 Service IP로 변환
- Service가 요청을 Redis Pod로 전달
RDS 연결 설정 및 보안 관리
로컬 환경 (application-local.yml)
spring:
datasource:
url: jdbc:mysql://localhost:3306/ordersystem?useSSL=false&allowPublicKeyRetrieval=true
username: root
password: 1234
Kubernetes 환경 (application-prod.yml)
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${DB_HOST}:3306/ordersystem?useSSL=false&allowPublicKeyRetrieval=true
username: admin
password: ${DB_PW}
변수로 처리하는 이유
- redis-service: 직접 입력 – 클러스터 내부에서만 접근 가능, 외부 노출 안 됨
- DB_HOST: 변수 처리 – RDS는 퍼블릭 엑세스 허용, 호스트 주소 노출 시 보안 위험
- DB_PW: 변수 처리 – 암호 노출 시 누구나 DB 접근 가능
Kubernetes Secret을 통한 정보 관리
보안 정보 관리 전략
코드 작성 단계
├── application-prod.yml (변수만 정의)
│ ├── ${DB_HOST}
│ └── ${DB_PW}
└── GitHub에 Push (안전)
이미지 빌드 단계
└── Docker 이미지 생성 (변수 상태 유지)
Pod 실행 단계
├── Kubernetes Secret에서 값 조회
│ ├── DB_HOST: database-1.xxxxx.ap-northeast-2.rds.amazonaws.com
│ └── DB_PW: 실제암호
└── Pod 환경 변수로 주입 → Spring 실행 시 값 대체
이렇게 관리하는 이유
| 시나리오 | 위험도 | 해결 방법 |
| GitHub Public 저장소에 올림 | 높음 | Secret 사용으로 코드에는 변수만 존재 |
| private 저장소에 올림 | 중간 | 일반 개발자도 암호를 볼 수 있음 |
| Kubernetes Secret 사용 | 낮음 | 권한 있는 사람만 Secret 접근 가능 |
실무 보안 관리
- 보안 관리자 또는 팀 리더가 Kubernetes Secret 생성 및 관리
- 일반 개발자는 암호를 모르는 상태로 개발 가능
- 포트폴리오로 GitHub 공개해도 안전
JWT Secret Key 관리
application-prod.yml
jwt: expiration: 1000 secretKey: aaa # 학습 단계에서는 직접 입력 (선택) expirationRt: 288000 secretKeyRt: bbb # 실무에서는 Secret으로 관리 권장
JWT Secret Key 노출 시 위험
- 토큰 조작 가능 (권한 변조, 만료 기간 연장 등)
- 서비스 무단 사용 가능
학습 단계에서는 YAML에 직접 입력 가능하다. 그 이유는 중요한 데이터가 없고 누구나 가입 가능한 테스트 서비스일 확률이 높다. 실무에서는 Kubernetes Secret를 활용해서 실제 사용자 데이터 보호가 필요하여 필수이다
Docker 이미지 빌드 및 ECR 업로드
ECR 로그인
ECR은 권한 있는 사용자만 이미지를 업로드할 수 있도록 로그인 절차가 필요하다
명령어 구조
aws ecr get-login-password --region ap-northeast-2 | \ docker login --username AWS --password-stdin <ECR-URI>
실제 명령어 예시
aws ecr get-login-password --region ap-northeast-2 | \ docker login --username AWS --password-stdin \ 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/order-backend
ECR URI 확인 방법
- AWS Console → ECR → 리포지토리
- 생성한 리포지토리 클릭
- URI 복사 (예: 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/order-backend)

성공 메시지: Login Succeeded
Docker 이미지 빌드
Docker 이미지를 ECR에 업로드하려면 이미지 이름이 ECR URI를 포함해야 한다
형식 <ECR-URI>:<태그> 예시 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/order-backend:latest │ │ │ └───────────────────────── 이미지 이름 ───────────────────────────┘ └─태그
빌드 명령어
기본 형식
docker build -t <이미지명:태그> -f <Dockerfile 경로> <빌드 컨텍스트>
프로젝트 루트에서 실행 시
docker build -t 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/order-backend:latest \ -f ./ordersystem/Dockerfile ./ordersystem
프로젝트 폴더 내부에서 실행 시
cd ordersystem docker build -t 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/order-backend:latest .
💀 pod status ErrImagePull
- 다음 강의에서 pod의 status ErrImagePull가 발생하였다
- 이미지의 CPU 아키텍처(Platform)와 서버의 CPU 아키텍처가 달라서 실행할 수 없기 때문에 발생한 에러이다.
# 이미지 다시 빌드 docker build --platform linux/amd64 -t 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/order-backend:latest . # 이미지 다시 푸시 (ECR) docker push 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/order-backend:latest
참고: 현재 디렉토리에 Dockerfile 이 있으면 -f 옵션 생략 가능
Dockerfile 구조 (멀티스테이지 빌드)
# Stage 1: 빌드 단계 # FROM openjdk:17-jdk-alpine 기존 명령어 에러로 인해서 아래 명령어로 수정 FROM eclipse-temurin:17-jdk-jammy as stage1 WORKDIR /app # 소스 코드 및 빌드 파일 복사 COPY gradle gradle COPY src src COPY build.gradle . COPY settings.gradle . COPY gradlew . # Gradle 빌드 실행 RUN chmod +x gradlew RUN ./gradlew bootJar # Stage 2: 실행 단계 # FROM openjdk:17-jdk-alpine 기존 명령어 에러로 인해서 아래 명령어로 수정 FROM eclipse-temurin:17-jdk-jammy WORKDIR /app # Stage 1에서 빌드한 JAR 파일만 복사 COPY --from=stage1 /app/build/libs/*.jar app.jar # 컨테이너 실행 시 JAR 실행 ENTRYPOINT ["java", "-jar", "app.jar"]
오류 발생시
- Cannot connect to the Docker daemon 에러가 나면 Docker Desktop을 실행하지 않은 것이다. Docker Desktop을 실행한 후 다시 다시 시도
멀티스테이지 빌드의 장점
- Stage 1: 빌드에 필요한 도구 포함 (용량 큼)
- Stage 2: 실행에 필요한 파일만 포함 (용량 작음)
- 최종 이미지 크기 최소화
이미지 확인
docker images 출력 예시 REPOSITORY TAG IMAGE ID CREATED SIZE 123456789012.d.e.ap.a/order-backend latest 99cbe9e9de9b 3 minutes ago 750MB redis latest cc2dfb8f9999 3 months ago 222MB mysql latest 999bfb9044dc 4 months ago 1.27GB
ECR에 이미지 Push
docker push 123456789012.dkr.ecr.ap-northeast-2.amazonaws.com/order-backend:latest
Push 진행 상황
Pushing [==============> ] 45.2MB/150MB ... Pushed
ECR에서 확인
- AWS Console → ECR → 리포지토리
- order-backend 클릭 (생성한 ecr 이나 이미지 push한 ecr)
- 이미지 목록에 latest 태그가 보이면 성공
Push 전 ECR

Push 후 ECR

수동 작업의 한계
지금까지 프로세스는 수동으로 진행
- 소스 코드 수정 → Docker 빌드 → ECR Push
문제점
- 소스 코드가 변경될 때 마다 반복
- 명령어가 복잡하고 실수하기 쉬움
- 시간 소모적
이러한 문제점으로 인해 GitGub Actions(혹은 다른 툴)를 통한 CI/CD 자동화가 필요하다