kt-event-marketing/claude/deploy-k8s-back.md
wonho df04f85346 백엔드 서비스 AKS 배포 및 설정 완료
- 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>
2025-10-29 10:59:09 +09:00

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에 맞게 적절히 지정
  • 체크 리스트로 수행결과 검증: 반드시 수행하고 그 결과를 배포 가이드에 포함

    • 객체이름 네이밍룰 준수 여부
    • 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)에 정의된 전체 환경변수를 빠짐없이 체크
      • 체크 방법:
        1. 각 {서비스명}.run.xml 파일에서 <entry key="환경변수명" value="값"/> 형태로 정의된 모든 환경변수 추출
        2. 추출된 환경변수 전체를 대상으로 매핑 테이블 작성 (일부만 하면 안됨)
        3. 서비스명 | 환경변수 | 지정 객체명 | 환경변수값 컬럼으로 전체 환경변수 체크
      • 매핑 테이블 예시 (전체 환경변수 기준):
        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 {네임스페이스}  
        
    • 매니페스트 적용 가이드
      kubectl apply -f deployment/k8s/common
      kubectl apply -f deployment/k8s/{서비스명}
      
    • 객체 생성 확인 가이드

[결과파일]

  • 배포방법 가이드: deployment/k8s/deploy-k8s-guide.md
  • 공통 매니페스트 파일: deployment/k8s/common/*
  • 서비스별 매니페스트 파일: deployment/k8s/{서비스명}/*