- Kubernetes 매니페스트 파일 생성 (7개 서비스) * user-service, event-service, ai-service, content-service * participation-service, analytics-service, distribution-service * 공통 리소스: Ingress, ConfigMap, Secret, ImagePullSecret - analytics-service 배포 문제 해결 * Hibernate PostgreSQL dialect 추가 * DB 자격증명 수정 (eventuser/Hi5Jessica!) * analytics_db 데이터베이스 생성 - content-service Probe 경로 수정 * Context path 포함 (/api/v1/content/actuator/health) - distribution-service 신규 배포 * Docker 이미지 빌드 및 ACR 푸시 * K8s 매니페스트 생성 및 배포 * Ingress 경로 추가 (/distribution) - Gradle bootJar 설정 추가 * 5개 서비스에 archiveFileName 설정 - 배포 가이드 문서 추가 * deployment/k8s/deploy-k8s-guide.md * claude/deploy-k8s-back.md * deployment/container/build-image.md 업데이트 배포 완료: 모든 백엔드 서비스(7개) 정상 실행 중 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
11 KiB
백엔드 배포 가이드
[요청사항]
- 백엔드 서비스를 쿠버네티스에 배포하기 위한 매니페스트 파일 작성
- 매니페스트 파일 작성까지만 하고 실제 배포는 수행방법만 가이드
- '[결과파일]'에 수행한 명령어를 포함하여 배포 가이드 레포트 생성
[작업순서]
-
실행정보 확인
프롬프트의 '[실행정보]'섹션에서 아래정보를 확인- {ACR명}: 컨테이너 레지스트리 이름
- {k8s명}: Kubernetes 클러스터 이름
- {네임스페이스}: 배포할 네임스페이스
- {파드수}: 생성할 파드수
- {리소스(CPU)}: 요청값/최대값
- {리소스(메모리)}: 요청값/최대값 예시)
[실행정보] - ACR명: acrdigitalgarage01 - k8s명: aks-digitalgarage-01 - 네임스페이스: tripgen - 파드수: 2 - 리소스(CPU): 256m/1024m - 리소스(메모리): 256Mi/1024Mi -
시스템명과 서비스명 확인
settings.gradle에서 확인.- 시스템명: rootProject.name
- 서비스명: include 'common'하위의 include문 뒤의 값임
예시) include 'common'하위의 4개가 서비스명임.
rootProject.name = 'tripgen' include 'common' include 'user-service' include 'location-service' include 'ai-service' include 'trip-service' -
매니페스트 작성 주의사항
- namespace는 명시: {네임스페이스}값 이용
- Database와 Redis의 Host명은 Service 객체 이름으로 함
- 공통 Secret의 JWT_SECRET 값은 반드시 openssl명령으로 생성하여 지정
- 매니페스트 파일 안에 환경변수를 사용하지 말고 실제 값을 지정
예) host: "tripgen.${INGRESS_IP}.nip.io" => host: "tripgen.4.1.2.3.nip.io" - Secret 매니페스트에서 'data' 대신 'stringData'를 사용
- 객체이름 네이밍룰
- 공통 ConfigMap: cm-common
- 공통 Secret: secret-common
- 서비스별 ConfigMap: cm-{서비스명}
- 서비스별 Secret: secret-{서비스명}
- Ingress: {시스템명}
- Service: {서비스명}
- Deployment: {서비스명}
-
공통 매니페스트 작성: deployment/k8s/common/ 디렉토리 하위에 작성
-
Image Pull Secret 매니페스트 작성: secret-imagepull.yaml
- name: {시스템명}
- USERNAME과 PASSWORD을 아래 명령으로 구하여 매니페스트 파일 작성
USERNAME=$(az acr credential show -n ${ACR명} --query "username" -o tsv) PASSWORD=$(az acr credential show -n ${ACR명} --query "passwords[0].value" -o tsv) - USERNAME과 PASSWORD의 실제 값을 매니페스트에 지정
-
Ingress 매니페스트 작성: ingress.yaml
-
중요: Ingress Host는 반드시 아래 명령으로 실제 External IP를 확인하여 사용할 것. {Ingress External IP}는 실제 확인한 EXTERNAL-IP값.
kubectl get svc ingress-nginx-controller -n ingress-nginx출력 예시: EXTERNAL-IP 컬럼에서 실제 IP 확인 (예:20.214.196.128)
-
ingressClassName: nginx
-
host: {시스템명}-api.{Ingress External IP}.nip.io 잘못된 예: tripgen-api.임의IP.nip.io ❌ 올바른 예: tripgen-api.20.214.196.128.nip.io ✅
-
path: 각 서비스 별 Controller 클래스의 '@RequestMapping'과 클래스 내 메소드의 매핑정보를 읽어 지정
-
pathType: Prefix
-
backend.service.name: {서비스명}
-
backend.service.port.number: 80
-
중요: annotation에 'nginx.ingress.kubernetes.io/rewrite-target' 설정 절대 하지 말것.
-
-
공통 ConfigMap과 Secret 매니페스트 작성
- 각 서비스의 실행 프로파일({서비스명}/.run/{서비스명}.run.xml)을 읽어 공통된 환경변수를 추출.
- 보안이 필요한 환경변수(암호, 인증토큰 등)는 Secret 매니페스트로 작성: secret-common.yaml(name:cm-common)
- 그 외 일반 환경변수 매니페스트 작성: cm-common.yaml(name:secret-common)
- Redis HOST명은 IP가 아닌 Service 객체명으로 함.
아래 명령으로 'redis'가 포함된 서비스 객체를 찾고 'ClusterIP'유형인 서비스명을 Host명으로 사용
kubectl get svc | grep redis - REDIS_DATABASE는 각 서비스별 ConfigMap에 지정
- 주의) Database는 공통 ConfigMap/Secret으로 작성 금지
- 공통 ConfigMap에 CORS_ALLOWED_ORIGINS 설정: 'http://localhost:8081,http://localhost:8082,http://localhost:8083,http://localhost:8084,http://{시스템명}.{Ingress External IP}.nip.io'
-
-
서비스별 매니페스트 작성: deployment/k8s/{서비스명}/ 디렉토리 하위에 작성
- ConfigMap과 Secret 매니페스트 작성
- 각 서비스의 실행 프로파일({서비스명}/.run/{서비스명}.run.xml)을 읽어 환경변수를 추출.
- cm-common.yaml과 secret-common.yaml에 있는 공통 환경변수는 중복해서 작성하면 안됨
- 보안이 필요한 환경변수(암호, 인증토큰 등)는 Secret 매니페스트로 작성: secret-{서비스명}.yaml(name:cm-{서비스명})
- 그 외 일반 환경변수 매니페스트 작성: cm-{서비스명}.yaml(name:secret-{서비스명})
- Database HOST명은 IP가 아닌 Service 객체명으로 함.
아래 명령으로 '{서비스명}'과 'db'가 포함된 서비스 객체를 찾고 'ClusterIP'유형인 서비스명을 Host명으로 사용kubectl get svc | grep {서비스명} - REDIS_DATABASE는 실행 프로파일에 지정된 값으로 서비스별 ConfigMap에 지정
- Service 매니페스트 작성
- name: {서비스명}
- port: 80
- targetPort: 실행 프로파일의 SERVER_PORT값
- type: ClusterIP
- Deployment 매니페스트 작성
- name: {서비스명}
- replicas: {파드수}
- ImagePullPolicy: Always
- ImagePullSecrets: {시스템명}
- image: {ACR명}.azurecr.io/{시스템명}/{서비스명}:latest
- ConfigMap과 Secret은 'env'대신에 'envFrom'을 사용하여 지정
- envFrom:
- configMapRef: 공통 ConfigMap 'cm-common'과 각 서비스 ConfigMap 'cm-{서비스명}'을 지정
- secretRef: 공통 Secret 'secret-common'과 각 서비스 Secret 'secret-{서비스명}'을 지정
- resources:
- {리소스(CPU)}: 요청값/최대값
- {리소스(메모리)}: 요청값/최대값
- Probe:
- Startup Probe: Actuator '/actuator/health'로 지정
- Readiness Probe: Actuator '/actuator/health/rediness'로 지정
- Liveness Probe: Actuator '/actuator/health/liveness'로 지정
- initialDelaySeconds, periodSeconds, failureThreshold를 Probe에 맞게 적절히 지정
- ConfigMap과 Secret 매니페스트 작성
-
체크 리스트로 수행결과 검증: 반드시 수행하고 그 결과를 배포 가이드에 포함
- 객체이름 네이밍룰 준수 여부
- Redis Host명을 ClusterIP 타입의 Service 객체로 했는가? 'kubectl get svc | grep redis' 명령으로 재확인
- Database Host명을 ClusterIP타입의 Service 객체로 했는가? 'kubectl get svc | grep {서비스명}' 명령으로 재확인
- Secret 매니페스트에서 'data' 대신 'stringData'를 사용 했는가?
- JWT_SECRET을 openssl 명령으로 생성해서 지정했는가?
- 매니페스트 파일 안에 환경변수를 사용하지 않고 실제 값을 지정 했는가?
- Image Pull Secret에 USERNAME과 PASSWORD의 실제 값을 매니페스트에 지정 했는가?
- Image명이 '{ACR명}.azurecr.io/{시스템명}/{서비스명}:latest' 형식인지 재확인
- Ingress Controller External IP 확인 및 매니페스트에 반영 확인
kubectl get svc ingress-nginx-controller -n ingress-nginx
EXTERNAL-IP 컬럼의 실제 값이 ingress.yaml의 host에 정확하게 설정되었는지 재확인할 것 - Ingress 매니페스트의 각 서비스 backend.service.port.number와 Service 매니페스트의 port가 "80"으로 동일한가 ?
- Ingress의 path는 각 서비스 별 Controller 클래스의 '@RequestMapping'과 클래스 내 메소드의 매핑정보를 읽어 지정했는가?
- 보안이 필요한 환경변수는 Secret 매니페스트로 지정했는가?
- REDIS_DATABASE는 각 서비스마다 다르게 지정했는가?
- ConfigMap과 Secret은 'env'대신에 'envFrom'을 사용하였는가?
- (중요) 실행 프로파일 매핑 테이블로 누락된 환경변수 체크
- 필수: 각 서비스의 실행 프로파일({서비스명}/.run/{서비스명}.run.xml)에 정의된 전체 환경변수를 빠짐없이 체크
- 체크 방법:
- 각 {서비스명}.run.xml 파일에서
<entry key="환경변수명" value="값"/>형태로 정의된 모든 환경변수 추출 - 추출된 환경변수 전체를 대상으로 매핑 테이블 작성 (일부만 하면 안됨)
- 서비스명 | 환경변수 | 지정 객체명 | 환경변수값 컬럼으로 전체 환경변수 체크
- 각 {서비스명}.run.xml 파일에서
- 매핑 테이블 예시 (전체 환경변수 기준):
user-service | SERVER_PORT | cm-user-service | 8081 user-service | DB_HOST | secret-user-service | user-db-service user-service | DB_PASSWORD | secret-user-service | tripgen_user_123 user-service | REDIS_DATABASE | cm-user-service | 0 user-service | JWT_SECRET | secret-common | (base64 encoded) user-service | CACHE_TTL | cm-user-service | 1800 location-service | SERVER_PORT | cm-location-service | 8082 location-service | GOOGLE_API_KEY | secret-location-service | (base64 encoded) location-service | REDIS_DATABASE | cm-location-service | 1 ai-service | CLAUDE_API_KEY | secret-ai-service | (base64 encoded) ai-service | SERVER_PORT | cm-ai-service | 8084 ... (실행프로파일의 모든 환경변수 나열) - 주의: 일부 환경변수만 체크하면 누락 발생, 반드시 실행프로파일 전체 환경변수 대상으로 수행
- 누락된 환경변수가 발견되면 해당 ConfigMap/Secret에 추가
-
배포 가이드 작성
- 배포가이드 검증 결과
- 사전확인 방법 가이드
- Azure 로그인 상태 확인
az account show - AKS Credential 확인:
kubectl cluster-info - namespace 존재 확인
kubectl get ns {네임스페이스}
- Azure 로그인 상태 확인
- 매니페스트 적용 가이드
kubectl apply -f deployment/k8s/common kubectl apply -f deployment/k8s/{서비스명} - 객체 생성 확인 가이드
[결과파일]
- 배포방법 가이드: deployment/k8s/deploy-k8s-guide.md
- 공통 매니페스트 파일: deployment/k8s/common/*
- 서비스별 매니페스트 파일: deployment/k8s/{서비스명}/*