Google Cloud에서 Helm으로 배포(Deploy on Google Cloud with Helm)

Google Cloud에서 Helm으로 배포(Deploy on Google Cloud with Helm)

인프라가 준비되면, Terraform 출력값을 사용해 confident-ai Helm 차트를 설치하고, Google 관리 인증서로 HTTPS에 노출해요. 차트는 Confident AI 레지스트리에서 이미지를 가져오고 앱과 클러스터 내부 ClickHouse를 설치해요.

출처: 문서

본문

권장 설정은 앱 시크릿을 Google Secret Manager에 두고 (External Secrets Operator가 동기화) Redis를 Memorystore에서 실행하는 거예요. 둘 다 Terraform 모듈이 프로비저닝해요. 클러스터 내부 Redis와 Kubernetes Secret은 더 간단한 대안으로 지원되며, 더 간단한 옵션을 참고하세요.

Enterprise 라이선스와 함께 Confident AI에서 두 가지를 받아요:

  • 이미지 풀 자격 증명: 클러스터가 퍼스트파티 이미지를 가져올 수 있게 하는 AWS access key ID와 시크릿. 차트가 이 자격 증명으로 풀 시크릿을 자동으로 만들고 갱신해요.
  • 라이선스 키 (CONFIDENT_LICENSE_KEY): 플랜의 기능을 활성화하는 서명된 키.

OPENAI_API_KEY에 대해: Confident AI의 내장 평가 제공자가 OpenAI에서 실행되는데, 이를 뒷받침해요. 선택 사항이에요. 생략하면 자체 모델 제공자를 연결하거나, 앱의 AI Connections에서 프로젝트별 LLM 게이트웨이를 연결하면 돼요.

도메인을 한 번 설정해요. 도메인에 네 개의 서브도메인을 노출할 거예요: 대시보드·API용 app.·api., 평가·트레이스 수집 엔드포인트용 evals.·otel.:

export DOMAIN=yourdomain.com

고정 IP 예약과 DNS 지정

gcloud compute addresses create confident-ip --global
gcloud compute addresses describe confident-ip --global --format='value(address)'

DNS 제공자에서 app.$DOMAIN, api.$DOMAIN, evals.$DOMAIN, otel.$DOMAIN용 A 레코드를 모두 그 IP를 가리키도록 만들어요. 관리 인증서는 이것들이 확인된 후에만 Active가 되므로, 지금 모두 설정하세요.

네임스페이스와 관리 인증서 생성

kubectl create namespace confident-ai

kubectl apply -f - <<EOF
apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
  name: confident-cert
  namespace: confident-ai
spec:
  domains:
    - app.$DOMAIN
    - api.$DOMAIN
    - evals.$DOMAIN
    - otel.$DOMAIN
EOF

Secret Manager에 시크릿 넣기

DATABASE_URL은 Terraform에서 바로 나와요. 이 JSON 객체의 각 키는 앱 시크릿이 돼요:

printf '{"DATABASE_URL":"%s","BETTER_AUTH_SECRET":"%s","OPENAI_API_KEY":"sk-...","CONFIDENT_LICENSE_KEY":"..."}' \
  "$(terraform output -raw database_url)" "$(openssl rand -hex 32)" \
  | gcloud secrets versions add "$(terraform output -raw secret_manager_secret_id)" --data-file=-

이것은 confident_create_secret_manager = true로 Terraform이 만든 시크릿을 사용해요. 활성화하지 않았다면 켜고 다시 적용하거나, 더 간단한 옵션을 쓰세요.

External Secrets Operator 설치

Terraform이 이미 ESO 서비스 계정을 confident-ai/external-secrets-sa에 Workload Identity로 바인딩했어요:

helm repo add external-secrets https://charts.external-secrets.io && helm repo update
helm install external-secrets external-secrets/external-secrets \
  -n external-secrets --create-namespace --set installCRDs=true

kubectl create serviceaccount external-secrets-sa -n confident-ai
kubectl annotate serviceaccount external-secrets-sa -n confident-ai \
  iam.gke.io/gcp-service-account=$(terraform output -raw eso_service_account_email)

values 파일 작성

values.gcp.yaml로 저장해요. 대괄호 값들은 Terraform 출력값과 Confident AI가 준 자격 증명으로 채우세요. 차트가 일치하는 앱 버전을 번들하므로 image.tag 오버라이드가 필요 없어요.

# The chart mints and refreshes the ECR pull secret from these credentials.
imagePullSecrets:
  - name: ecr-registry-credentials
imagePullSecretRefresh:
  enabled: true
  region: us-east-1
  awsAccessKeyId: "<from Confident AI>"
  awsSecretAccessKey: "<from Confident AI>"

config:
  cloudProvider: GCP
  frontendUrl: https://app.yourdomain.com
  backendUrl: https://api.yourdomain.com
  subdomain: yourdomain.com

serviceAccount:
  create: true
  annotations:
    iam.gke.io/gcp-service-account: <app_service_account_email>

storage:
  testCasesBucket: <test_cases_bucket>
  payloadsBucket: <payloads_bucket>
  gcp:
    projectId: <your-gcp-project>
    region: us-central1

# Recommended: app secrets come from Google Secret Manager via ESO.
secrets:
  externalSecrets:
    enabled: true
    provider: gcpsm
    createStore: true
    remoteKey: <secret_manager_secret_id>
    serviceAccountRef:
      name: external-secrets-sa
    gcp:
      projectId: <your-gcp-project>
      clusterLocation: us-central1
      clusterName: <cluster_name>

clickhouse:
  internal: true
  password: "<choose-a-password>"

# Recommended: managed Redis (Memorystore) from Terraform.
redis:
  internal: false
  externalUrl: "<redis_url>"

# Required for code-based and transformer metrics (Cloud Run sandbox from Terraform).
codeExecutor:
  provider: GCP_CLOUD_FUNCTIONS
  gcp:
    functionUrl: <code_executor_function_url>

ingress:
  enabled: true
  # GKE's L7 controller claims Ingresses via the ingress.class annotation, not
  # ingressClassName (this cluster has no "gce" IngressClass). Leave className
  # empty, or the Ingress is ignored and never gets an ADDRESS.
  className: ""
  annotations:
    kubernetes.io/ingress.class: gce
    kubernetes.io/ingress.global-static-ip-name: confident-ip
    networking.gke.io/managed-certificates: confident-cert
  hosts:
    evals: evals.yourdomain.com
    otel: otel.yourdomain.com

차트 설치

차트는 OCI 아티팩트로 GHCR에 게시돼요:

helm install confident-ai \
  oci://ghcr.io/confident-ai/charts/confident-ai \
  --version 0.2.0 \
  -n confident-ai \
  -f values.gcp.yaml

kubectl get pods -n confident-ai -w

ClickHouse 오퍼레이터가 먼저 시작되고, 마이그레이션 작업이 실행된 다음 앱 파드가 올라와요. 몇 분 걸려요.

인증서를 기다린 뒤 검증

Google 관리 인증서는 DNS가 확인된 후 프로비저닝에 15-60분이 걸려요:

kubectl get managedcertificate -n confident-ai   # STATUS moves Provisioning -> Active
kubectl get ingress -n confident-ai              # ADDRESS should match your static IP
kubectl get externalsecret -n confident-ai       # STATUS should be SecretSynced

인증서가 Active가 되면 https://app.$DOMAIN을 열어 로그인하세요. 쿠키는 .$DOMAIN에 설정돼서 모든 서브도메인이 공유해요.

더 간단한 옵션: 클러스터 내부 Redis와 Kubernetes Secret

클라우드 시크릿 스토어나 관리형 Redis를 운영하고 싶지 않다면, 차트가 Kubernetes Secret에 시크릿을 담고 Redis를 클러스터 안에서 실행할 수 있어요. 프로덕션 하드닝은 덜 되지만(시크릿이 클러스터 안에 있고 Redis에 관리형 백업이 없음), ESO와 Memorystore 단계를 없애요. 위의 3·4단계는 건너뛰고 values 파일의 secrets와 redis 블록을 이렇게 바꿔 주세요:

secrets:
  data:
    DATABASE_URL: "<database_url>"
    BETTER_AUTH_SECRET: "<openssl rand -hex 32>"
    OPENAI_API_KEY: "sk-..."
    CONFIDENT_LICENSE_KEY: "<your license key>"

redis:
  internal: true

ClickHouse 백업 (권장)

프로덕션에서는 매일 밤 ClickHouse를 GCS로 백업해요. 백업 버킷과 GCS HMAC 키가 담긴 Secret이 필요하며, 그 일회성 설정은 Disaster Recovery 페이지에 있어요. 준비되면 기존 clickhouse: 블록 아래에 추가하고 helm upgrade로 적용하세요:

clickhouse:
  backup:
    enabled: true
    provider: gcs
    schedule: "0 2 * * *"          # nightly at 02:00 UTC
    gcs:
      bucket: <clickhouse_backup_bucket>
    credentialsSecret: clickhouse-backup-creds

문제 해결(Troubleshooting)

증상 원인과 조치
externalsecret가 SecretSynced에 도달하지 못함 ESO가 Secret Manager를 읽지 못해요. external-secrets-sa 어노테이션과 confident_create_secret_manager = true를 다시 확인하세요. kubectl describe externalsecret -n confident-ai.
앱 파드가 잠깐 CreateContainerConfigError ESO가 아직 시크릿을 동기화하지 않았어요. externalsecret이 SecretSynced를 보이면 스스로 복구돼요.
Ingress가 ADDRESS를 얻지 못함 GKE의 L7 컨트롤러가 ingressClassName이 아니라 kubernetes.io/ingress.class: gce 어노테이션으로 Ingress를 차지해요. 보여준 대로 className: ""을 유지하세요.
인증서가 Provisioning에 갇힘 DNS가 아직 고정 IP로 확인되지 않거나, 로드 밸런서가 서빙하지 않아요. A 레코드를 확인하고 kubectl get ingress가 고정 IP를 보이는지 확인하세요.
백엔드 UNHEALTHY, 브라우저가 502 표시 GKE가 각 Service를 헬스 체크해요. 새 설치에서는 차트의 readiness 프로브가 헬스 체크 경로를 자동 설정하므로 몇 분 주세요. 이미 만든 로드 밸런서에 프로브를 추가했다면 GKE가 경로를 다시 도출하지 않아요. gcloud compute health-checks update http <name> --request-path=/health로 업데이트하세요.
ClickHouse 파드가 Listen [::]... Address family not supported로 크래시 GKE 노드는 IPv4 전용이에요. 차트가 ClickHouse를 0.0.0.0으로 청취하도록 설정하며, clickhouse.extraConfig를 오버라이드한 경우에만 관련돼요.
ClickHouse Keeper가 Not authenticated 로그 이전 실패한 설치의 오래된 PersistentVolumeClaim이에요. helm uninstall, kubectl delete pvc -n confident-ai --all, 그 다음 재설치하세요.
프론트엔드가 ENOTFOUND confident-backend로 500을 반환 프론트엔드가 차트 접두사 이름으로 백엔드 서비스를 확인해요. fullnameOverride: confident(차트 기본값)를 유지하세요. 바꾸지 마세요.
코드 지표가 403으로 실패 앱 서비스 계정에 Cloud Run 샌드박스의 run.invoker가 없어요. iam.gke.io/gcp-service-account 어노테이션과 Terraform이 invoker 바인딩을 부여했는지 확인하세요.
데이터셋 골든 열 때 iam.serviceAccounts.signBlob 거부로 500 앱이 GCS URL에 서명하는데, Workload Identity에서 IAM Credentials API를 호출해요. 앱 서비스 계정에 자기 자신에 대한 roles/iam.serviceAccountTokenCreator와 활성화된 iamcredentials.googleapis.com API가 필요해요. Terraform 모듈이 이걸 부여해요. 그 변경 이전에 프로비저닝했다면 gcloud iam service-accounts add-iam-policy-binding으로 수동 추가하세요.

업데이트와 제거

  • 앱 변경: values.gcp.yaml를 편집한 뒤 helm upgrade confident-ai oci://ghcr.io/confident-ai/charts/confident-ai --version 0.2.0 -n confident-ai -f values.gcp.yaml.
  • 시크릿 회전: Secret Manager에 새 버전을 작성하세요. ESO가 다시 동기화하고, 파드를 재시작해 변경사항을 반영해요(시크릿을 환경 변수로 보유하다가 재시작할 때까지): kubectl rollout restart deployment -n confident-ai.
  • 인프라 변경: Terraform 설정을 편집하고 terraform apply.
  • 모두 제거: helm uninstall confident-ai -n confident-ai, helm uninstall external-secrets -n external-secrets, 그 다음 terraform destroy, 고정 IP와(Terraform이 소유하지 않았다면) Infrastructure 페이지의 네트워크를 삭제하세요.

더 알아보기