Claude Platform Docs
Managed Agents자체 호스팅 Managed Agents

Kubernetes에 배포하기

릴리스 아카이브에 포함된 두 개의 Helm 차트로 Kubernetes 클러스터에 자체 호스팅 Claude Managed Agents 서버와 샌드박스를 설치한 다음, 샌드박스 파드에서 첫 세션을 실행합니다.

이 페이지에서는 비어 있는 Google Kubernetes Engine(GKE) 클러스터에서 시작하여 샌드박스 파드에서 도구를 실행하는 세션까지 진행합니다. 릴리스 아카이브에 포함된 두 개의 Helm 차트를 사용하며, 이 차트들은 클러스터에서 전체 스택을 실행합니다.

  • cma-server: cma-server 네임스페이스에서 데이터베이스 스키마를 적용하고 Service 뒤에서 두 개의 서버를 실행합니다.
  • cma-sandboxes: cma 네임스페이스에서 디스패처와 샌드박스 파드를 실행합니다. 디스패처는 서버에 작업을 폴링하고 각 세션에 전용 샌드박스 파드를 할당하며, 이 파드에서 워커가 에이전트의 셸 및 파일 도구를 실행합니다.

PostgreSQL 데이터베이스는 두 차트 모두의 외부에 둡니다. 다른 종류의 클러스터에서도 단계는 동일하지만, 클러스터 사전 요구 사항과 일부 차트 값이 다릅니다. 기타 클러스터를 참조하세요.

사전 요구 사항

  • 클러스터: 다음을 갖춘 Kubernetes 1.30 이상.
    • Agent Sandbox 컨트롤러(GKE에서는 Agent Sandbox 애드온)
    • gVisor를 실행하는 노드(GKE에서는 GKE Sandbox 노드 풀)
    • NetworkPolicy를 적용하는 네트워크 플러그인(GKE에서는 Dataplane V2 또는 Calico)
  • 데이터베이스: 클러스터에서 접근할 수 있는 PostgreSQL 16 이상.
  • 레지스트리: 클러스터가 이미지를 가져올 수 있는 레지스트리. 이미지는 직접 빌드합니다.
  • Claude API 키: 서버가 모델 호출에 사용합니다. 다른 제공자를 사용하려면 추론 제공자를 참조하세요.
  • 권한: 클러스터 관리자 권한 또는 그에 상응하는 권한. 설치 과정에서 네임스페이스, Role, ClusterRoleBinding이 생성됩니다.
  • 로컬 머신의 도구: helm, kubectl, docker buildx, openssl, 그리고 ant CLI.
  • 릴리스 아카이브: 다운로드 액세스를 요청하려면 Anthropic 계정 팀에 문의하세요. 아카이브의 압축을 해제하세요. 이 페이지의 모든 명령은 아카이브의 최상위 디렉터리에서 실행하세요.

스택 설치하기

  1. 이미지 빌드 및 푸시

    다음 변수를 사용자의 값으로 설정하세요. PLATFORM은 노드의 아키텍처입니다. TAG는 릴리스 버전으로, 아카이브 이름에서 v 뒤에 있습니다. 두 차트 모두 이 버전을 태그로 가진 이미지를 사용합니다.

    REGISTRY=us-docker.pkg.dev/my-project/cma
    TAG=1.2.3
    PLATFORM=linux/amd64

    그런 다음 세 개의 이미지를 빌드하고 푸시하세요.

    docker buildx build --platform "$PLATFORM" -f kubernetes/server/Dockerfile -t "$REGISTRY/cma-server-image:$TAG" --push .
    docker buildx build --platform "$PLATFORM" -f kubernetes/dispatcher/Dockerfile -t "$REGISTRY/cma-dispatcher:$TAG" --push .
    docker buildx build --platform "$PLATFORM" -t "$REGISTRY/cma-sandbox:$TAG" --push kubernetes/sandbox
  2. 시크릿 파일 및 데이터베이스 생성

    생성된 데이터베이스 비밀번호와 Claude API 키용 자리 표시자가 담긴 파일을 생성합니다.

    cat > secrets.env <<EOF
    PG_PASSWORD=$(openssl rand -hex 32)
    UPSTREAM_KEY=sk-ant-...
    EOF
    chmod 600 secrets.env

    편집기에서 secrets.env를 열고 sk-ant-...를 Claude API 키로 바꾸세요. 그런 다음 psql 등을 사용해 관리자로 데이터베이스 서버에 연결하세요. ... 자리에 PG_PASSWORD 값을 넣어 다음 SQL을 실행하세요.

    CREATE ROLE cma_server LOGIN PASSWORD '...';
    GRANT cma_server TO CURRENT_USER;
    CREATE DATABASE cma_server OWNER cma_server;
  3. 서버의 네임스페이스와 Secret 생성

    서버의 네임스페이스와 해당 Secret을 생성하세요.

    source secrets.env
    ENCRYPTION_KEY=$(openssl rand -base64 32)
    kubectl create namespace cma-server
    kubectl label namespace cma-server pod-security.kubernetes.io/enforce=restricted pod-security.kubernetes.io/enforce-version=latest
    kubectl -n cma-server create secret generic cma-server-db \
      --from-literal=PGPASSWORD="$PG_PASSWORD"
    kubectl -n cma-server create secret generic cma-server-keys \
      --from-literal=CMA_SERVER__API_KEY="$(openssl rand -hex 32)" \
      --from-literal=CMA_STORE__CREDENTIALS_ENCRYPTION_KEY="$ENCRYPTION_KEY"
    kubectl -n cma-server create secret generic cma-server-upstream \
      --from-literal=ANTHROPIC_API_KEY="$UPSTREAM_KEY"

    echo "$ENCRYPTION_KEY"로 암호화 키를 출력하고, 클러스터 외부에 사본을 보관하세요. 서버는 이 키를 사용해 자신이 저장하는 자격 증명을 암호화하며, 복원한 데이터베이스에 이 키가 필요합니다. 그런 다음 secrets.env를 삭제하세요. 데이터베이스 비밀번호는 cma-server-db Secret에 보관됩니다.

  4. 샌드박스의 네임스페이스와 인증서 생성

    샌드박스의 네임스페이스와, 디스패처가 제공하고 샌드박스가 신뢰하는 인증서를 생성하세요.

    kubectl create namespace cma
    kubectl label namespace cma pod-security.kubernetes.io/enforce=restricted pod-security.kubernetes.io/enforce-version=latest
    openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes -days 825 \
      -subj "/CN=cma-dispatcher.cma.svc" \
      -addext "subjectAltName=DNS:cma-dispatcher.cma.svc,DNS:cma-dispatcher.cma.svc.cluster.local" \
      -keyout tls.key -out tls.crt
    kubectl -n cma create secret tls cma-dispatcher-tls --cert=tls.crt --key=tls.key --dry-run=client -o yaml | kubectl apply -f -
    kubectl -n cma create configmap cma-dispatcher-ca --from-file=ca.crt=tls.crt --dry-run=client -o yaml | kubectl apply -f -
  5. 서버 설치

    다음 내용을 사용자의 레지스트리와 데이터베이스 주소로 채워 cma-server-values.yaml로 저장하세요.

    earlierNames: false   # a new install
    image:
      registry: us-docker.pkg.dev/my-project/cma   # REGISTRY in the build commands
    database:
      url: host=10.20.0.5 port=5432 user=cma_server dbname=cma_server sslmode=require   # your database's address
    environments:
      - name: default
        namespace: cma

    그런 다음 차트를 설치하세요.

    helm install cma-server kubernetes/server/chart --namespace cma-server -f cma-server-values.yaml --wait
    kubectl -n cma-server logs job/cma-server-environment-default

    설치 과정에서 default 환경을 생성하고 해당 환경 키를 cma 네임스페이스의 cma-environment Secret에 저장합니다. 두 번째 명령은 filled Secret cma/cma-environment로 시작하는 한 줄을 출력합니다. 첫 번째 helm install이 실패하면 다시 설치하기 전에 해당 릴리스에 대해 helm uninstall을 실행하세요.

  6. 차단할 클러스터 주소 찾기

    이 설치에서는 샌드박스가 공용 인터넷에 접근할 수 있습니다. 클러스터의 API 엔드포인트는 일반적으로 공용 주소를 가지므로 샌드박스가 여기에도 접근할 수 있습니다. 이를 차단하려면 다음 단계에서 egress.clusterCIDRs 아래에 해당 주소를 나열합니다.

    주소를 출력하려면 클러스터 이름을 넣어 gcloud container clusters describe my-cluster --format 'value(endpoint)'를 실행하세요.

    차트 자체는 사설 범위 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 100.64.0.0/10을 차단합니다. 클러스터에 이 네 범위 밖의 파드, 서비스 또는 노드 범위가 있다면 해당 범위도 나열하세요.

  7. 샌드박스 설치

    다음 내용을 사용자의 레지스트리와 이전 단계의 주소로 채워 cma-values.yaml로 저장하세요.

    platform: gke
    image:
      registry: us-docker.pkg.dev/my-project/cma   # REGISTRY in the build commands
    egress:
      mode: publicInternet
      clusterCIDRs:
        - 203.0.113.10/32                          # the cluster's API endpoint
      cmaServer:
        pods:
          namespace: cma-server
          matchLabels:
            anthropic.com/role: server
        port: 8400

    egress.cmaServer는 서버로 가는 경로를 엽니다. publicInternet을 다른 두 모드와 비교하려면 샌드박스가 접근할 수 있는 대상을 참조하세요.

    클러스터가 다음 DNS 설정 중 하나를 사용한다면 파일에 한 줄을 추가하세요.

    • Autopilot 클러스터가 사용하는 Cloud DNS for GKE: gke: {dns: cloudDns}
    • NodeLocal DNSCache: gke: {dns: nodeLocalCache, kubeDnsUpstreamIP: <address>}. 주소를 출력하려면 kubectl -n kube-system get svc kube-dns-upstream -o jsonpath='{.spec.clusterIP}'를 실행하세요.

    그런 다음 차트를 설치하세요.

    helm install cma kubernetes/chart --namespace cma -f cma-values.yaml --wait

세션 실행

이 단계에서는 새로 설치할 때의 이름을 사용합니다. 서버 values 파일에 earlierNames: true가 있다면, 대신 사용할 이름을 Kubernetes: 객체의 이름에서 확인하세요.

  1. 서버 포트 포워딩

    한 터미널에서 서버의 포트를 로컬 머신으로 포워딩하세요.

    kubectl -n cma-server port-forward svc/cma-server 8400:8400
  2. CLI가 서버를 가리키도록 설정

    두 번째 터미널에서 ant CLI가 포워딩된 포트를 가리키도록 설정하고 cma-server-keys Secret에서 서버 API 키를 읽어 오세요:

    export ANTHROPIC_BASE_URL=http://127.0.0.1:8400
    export ANTHROPIC_API_KEY=$(kubectl -n cma-server get secret cma-server-keys -o jsonpath='{.data.CMA_SERVER__API_KEY}' | base64 -d)
  3. 에이전트 생성 및 명령 실행 요청

    빠른 시작의 첫 세션 실행에 나오는 세 단계, 즉 에이전트 생성, 세션 시작, 에이전트에게 명령 실행 요청을 따르세요. 세션 시작 단계에서는 compose-sandbox를 차트가 생성하는 환경의 이름인 default로 바꾸세요.

  4. 샌드박스 파드 찾기

    에이전트는 명령을 실행한 파드의 호스트 이름으로 응답합니다. 세 번째 터미널에서 kubectl -n cma get pods를 실행하면 디스패처의 파드와 함께 해당 이름의 파드가 표시됩니다. 기본적으로 이 파드는 에이전트의 턴이 끝나고 약 5분 후에 사라집니다. 목록에 없다면 에이전트에게 hostname을 다시 실행하도록 요청하세요.

    채팅을 종료하려면 Ctrl+C를 누르세요.

서버 앞에 TLS 두기

서버는 포트 8400에서 일반 HTTP로 통신하며, 애플리케이션의 요청에는 서버 API 키가 포함됩니다. 클러스터 외부의 클라이언트가 연결하기 전에 cma-server Service 앞에 TLS를 종료하는 로드 밸런서 또는 인그레스를 두세요. 이는 다음 조건을 충족해야 합니다.

  • 요청 경로를 변경 없이 그대로 전달합니다.
  • 최대 32 MiB의 요청 본문을 허용합니다.
  • 응답을 버퍼링 없이 전달합니다.
  • 기본 읽기 타임아웃을 2분으로 설정합니다. Git 요청의 경우 ^/cma-[a-z]+/git/와 일치하는 경로에 대해 읽기 타임아웃을 10분으로 설정합니다.
  • 준비된 서버로만 트래픽을 보냅니다. cma-server Service는 이미 이렇게 동작합니다. 파드에 직접 연결하는 로드 밸런서는 각 파드의 /cma-server/readyz를 검사하고 503을 반환하는 파드는 건너뛰어야 합니다.
  • 서버가 이미 수락한 POST를 절대 다시 보내지 않습니다.
  • 응답을 절대 캐시하지 않습니다.

클러스터 외부에서 확인하려면 curl -s https://<host>/cma-server/healthz를 실행하세요. 응답은 {"status":"ok"}입니다.

샌드박스가 접근할 수 있는 대상

cma-values.yaml에서 egress.mode: publicInternet은 샌드박스가 공용 인터넷에 접근할 수 있도록 합니다.

이 표에서 이 모드를 다른 두 모드와 비교합니다.

egress.mode샌드박스가 접근할 수 있는 대상
closed, 기본값서버와 디스패처만 접근할 수 있으며, DNS 서버에는 접근할 수 없음
publicInternet서버, 디스패처, DNS 서버, 공용 인터넷
gateway서버, 디스패처, 그리고 “egress gateway”(이그레스 게이트웨이)를 통해 사용자가 나열한 호스트. Kubernetes에서 게이트웨이 켜기를 참조하세요.

기타 클러스터

cma-values.yaml의 platform을 Amazon EKS의 경우 eks로, Azure Kubernetes Service(AKS)의 경우 aks로, 그 밖의 클러스터의 경우 generic으로 설정하세요. 세 경우 모두 확장 기능을 포함한 업스트림 Agent Sandbox 컨트롤러와 NetworkPolicy를 적용하는 네트워크 플러그인이 필요합니다. 또한 다음이 필요합니다.

  • Amazon EKS: gVisor의 runsc가 runsc라는 이름의 containerd 핸들러로 등록된 노드 그룹. 노드에 cma.anthropic.com/sandbox-node=true 레이블을 지정하고, cma.anthropic.com/sandbox-node=true:NoSchedule 테인트를 지정하세요. 차트는 해당 핸들러에 대해 gvisor RuntimeClass를 등록합니다.
  • AKS: Amazon EKS와 동일한 레이블과 테인트를 지정한, Pod Sandboxing이 적용된 노드 풀. 클러스터의 네트워크 정책 엔진 이름(cilium, calico 또는 azure)을 aks.networkPolicy에 입력하세요. 차트가 AKS에서 허용하는 유일한 모드인 egress.mode: publicInternet을 유지하세요. 에이전트가 실제 작업을 수행하기 전에 사용자의 클러스터에서 차트를 테스트하세요.
  • 그 밖의 클러스터: gVisor 또는 다른 샌드박스 런타임용 RuntimeClass. 그 이름을 runtimeClass.name에 입력하세요.

아카이브의 kubernetes/chart/examples/ 폴더에는 클러스터 종류별로 완전한 values 파일이 들어 있습니다.

세션 볼륨 해제

차트의 기본값에 따라 각 세션에는 /workspace용 10 GiB 볼륨이 있습니다. 이 볼륨은 세션의 파드가 사라진 후에도 남아 있으므로, 세션의 다음 메시지에서 해당 파일을 찾을 수 있습니다.

해제할 대상방법
한 세션의 볼륨세션의 턴이 끝난 후 세션을 아카이브하세요. 디스패처는 보통 약 5분 이내에 볼륨을 삭제합니다.
아무도 아카이브하지 않는 세션의 볼륨cma-values.yaml에서 dispatcher.retentionDays를 설정하세요. 그러면 디스패처는 세션이 그 일수만큼 유휴 상태가 되면 볼륨을 삭제하고, 세션의 다음 메시지는 비어 있는 /workspace로 시작합니다. 차트의 기본값인 0은 모든 볼륨을 유지합니다.

이 섹션의 명령은 GKE용입니다. 다른 클러스터에서는 sandboxes 대신 sandboxclaims를 사용하세요.

세션을 삭제해도 해당 볼륨은 해제되지 않습니다. 먼저 세션을 아카이브하세요. kubectl -n cma get sandboxes -l anthropic.com/session-id=<session-id>가 아무것도 나열하지 않을 때에만 세션을 삭제하세요.

세션을 아카이브하지 않고 삭제했다면, 해당 볼륨을 직접 해제하세요.

  1. 디스패처의 로그에서 세션의 ID를 찾으세요. 이 명령은 삭제된 것으로 보이지만 여전히 볼륨이 있는 각 세션에 대해 한 줄씩 출력하며, ID는 session_id 뒤에 있습니다.

    kubectl -n cma logs deployment/cma-dispatcher --since=6m \
      | grep "could not check the claim's session" | grep "403 Forbidden"

    디스패처는 5분마다 이 줄들을 기록합니다. 세션이 나열되지 않으면 5분 기다린 후 명령을 다시 실행하세요.

  2. 세션이 삭제되었는지 확인하세요. 세션 실행에서처럼 포트를 포워딩하고 ANTHROPIC_API_KEY를 설정한 상태에서 ant --base-url http://127.0.0.1:8400 beta:sessions retrieve --session-id <session-id>를 실행하세요. 응답이 Session not found와 함께 404 Not Found인 경우에만 계속 진행하세요. 명령이 세션을 출력하면 중단하세요. 해당 세션은 삭제되지 않은 것입니다.

  3. 볼륨을 소유한 Kubernetes 객체를 삭제하세요. 세션의 파일도 함께 삭제됩니다.

    kubectl -n cma delete sandboxes -l anthropic.com/session-id=<session-id>

키와 인증서 갱신

환경 키는 365일 동안 유효하며, 디스패처의 인증서는 825일 동안 유효합니다. 각각 만료되기 전에 갱신하세요.

환경 키의 마지막 30일 동안, 서버는 해당 키를 사용하는 각 요청마다 경고를 로그에 기록합니다. 이 경고는 environment key is within 30 days of expiry로 시작합니다.

차트가 생성한 환경 키 갱신

키의 만료 시점을 확인하려면 kubectl -n cma describe secret cma-environment를 실행하세요.

키의 마지막 60일 이내에, 설치된 릴리스 아카이브의 최상위 디렉터리에서 다음 두 명령을 한 번 이상 실행하세요.

helm upgrade cma-server kubernetes/server/chart --namespace cma-server -f cma-server-values.yaml --wait
kubectl -n cma rollout restart deployment/cma-dispatcher

서버 차트의 helm upgrade 명령은 실행될 때마다, 키가 60일 이내에 만료되면 새 키를 Secret에 저장합니다. 그 밖에는 키를 갱신하는 것이 없습니다. 두 번째 명령은 디스패처가 새 키를 읽도록 디스패처를 재시작합니다.

디스패처 인증서 갱신

"샌드박스의 네임스페이스와 인증서 생성" 단계로 돌아가세요. 그 단계의 openssl 명령과 그 뒤의 두 kubectl 명령을 다시 실행하세요. 그런 다음 kubectl -n cma rollout restart deployment/cma-dispatcher로 디스패처를 재시작하세요.

자체 워커용 환경 키 교체

차트는 자체 키만 갱신합니다. 환경 및 환경 키 생성하기에서처럼 키를 직접 생성했다면, 관리자 CLI로 해당 키를 교체하세요. CLI는 릴리스 아카이브의 최상위에 있습니다.

ANTHROPIC_API_KEY에 서버 API 키가 들어 있는, 세션 실행의 두 번째 터미널에서 명령을 실행하세요. 첫 번째 터미널에서는 포트 포워딩을 계속 실행해 두세요. 다른 주소로 서버에 접근한다면 그 주소를 -base-url로 전달하세요. 이 경우 포트 포워딩은 필요하지 않습니다.

  1. 같은 환경에 대한 새 키 생성

    -env에는 환경의 ID를 전달하세요.

    echo "$ANTHROPIC_API_KEY" | ./cma-server-admin mint-key \
      -base-url http://127.0.0.1:8400 -env env_01595EKxaaTTGwwY3kyXdtbs -key-file -

    이 명령은 새 키를 출력하고, 키의 ID와 만료 시점은 표준 오류로 출력합니다.

  2. 워커를 새 키로 이전

    폴링하는 각 프로세스에 새 키를 ANTHROPIC_ENVIRONMENT_KEY로 설정하고 프로세스를 재시작하세요.

  3. 이전 키 폐기

    폐기된 키를 계속 사용하는 워커는 401 오류를 받고 처리 중이던 세션을 포기합니다. 이전 키의 ID를 찾으려면 같은 -base-url, -env, -key-file 플래그로 list-keys를 실행하세요. 더 이상 이전 키를 사용하는 워커가 없으면 해당 ID로 키를 폐기하세요.

    echo "$ANTHROPIC_API_KEY" | ./cma-server-admin revoke-key \
      -base-url http://127.0.0.1:8400 -env env_01595EKxaaTTGwwY3kyXdtbs \
      -key-id etok_01AbCdEfGhIjKlMnOpQrStUv -key-file -

스택 제거

샌드박스를 먼저 삭제하세요. helm uninstall은 샌드박스를 격리하는 네트워크 정책을 삭제하지만, 디스패처가 세션용으로 만든 샌드박스는 계속 실행됩니다.

이 단계들은 데이터베이스를 건드리지 않지만 Secret은 삭제합니다. 데이터베이스를 다시 사용하려면 암호화 키 사본이 필요합니다.

  1. 디스패처 중지 및 샌드박스 삭제

    kubectl -n cma scale deployment/cma-dispatcher --replicas=0
    kubectl -n cma delete sandboxwarmpool cma-sandbox
    kubectl -n cma delete sandboxclaims --all

    GKE에서는 다음 명령도 실행하세요.

    kubectl -n cma delete sandboxes --all
  2. 샌드박스가 사라질 때까지 대기

    샌드박스와 해당 파드, 볼륨이 모두 사라질 때까지 다음 명령을 반복하세요.

    kubectl -n cma get sandboxes,pods,pvc
  3. 차트 제거 및 네임스페이스 삭제

    helm uninstall cma --namespace cma
    helm uninstall cma-server --namespace cma-server
    kubectl delete namespace cma cma-server

다음 단계

이 페이지가 도움이 되었나요?