콘텐츠로 이동
Study Notekagent 실습

9. BYO Agent를 kind에 배포하기

결론부터
BYO Agent 실습은 local run에서 끝나지 않으며 같은 image를 kind에 올려 Ready와 controller A2A route까지 검증해야 Declarative Agent와의 책임 차이가 드러난다
이 장에서 처음 나오는 말4개
BYO AgentBring Your Own Agent
framework code를 담은 container image를 kagent가 Agent workload로 관리하는 방식이다.
ADKAgent Development Kit
이 실습의 generated project가 사용하는 Agent framework다.
image registryContainer Image Registry
cluster node가 pull할 수 있도록 image를 저장하고 배포하는 서비스다.
A2A serverAgent-to-Agent Server
BYO process가 kagent controller와 client에 제공해야 하는 Agent Card와 task endpoint다.
항목Declarative AgentBYO Agent
Agent logicsystemMessage와 resource 조합application code와 framework
runtimekagent가 표준 runtime 구성image 안에 포함
protocolkagent runtime이 제공image가 A2A server 계약 구현
dependencykagent release가 주로 고정project lockfile·image가 고정
공급망CR·prompt·tool reference 검토code·dependency·base image·SBOM까지 검토

이 장 자체는 선택 실습이지만 시작했다면 project 생성 → image build → 로컬 실행 → kind 적재 → BYO resource → A2A invoke까지가 완료 범위다. localhost image를 kind node가 자동으로 볼 수 있다고 가정하지 않는다.

cluster와 별개인 작업 디렉터리에서 실행한다. 생성물에는 별도 Git 저장소를 만들 필요가 없다.

터미널 창
mkdir -p /tmp/kagent-lab-byo
cd /tmp/kagent-lab-byo
kagent init adk python labbyo \
--model-provider OpenAI \
--model-name gpt-4.1-mini
cd labbyo

/tmp의 생성물은 임시 학습 파일이다. 필요한 code는 직접 검토한 뒤 별도 project로 옮기고, API key나 .env 파일은 옮기지 않는다.

labbyo/
├── labbyo/ # Agent code와 Agent Card
├── kagent.yaml # build·run·deploy metadata
├── pyproject.toml # Python dependency
├── docker-compose.yaml # local runtime
└── README.md

실제 생성 결과가 이 목록과 다르면 설치된 CLI version의 README를 원본으로 삼는다.

사내 LiteLLM을 쓰면 generated code도 바꾼다

섹션 제목: “사내 LiteLLM을 쓰면 generated code도 바꾼다”

Declarative Agent의 ModelConfig는 BYO image 안의 model client에 자동 적용되지 않는다. v0.9.9의 OpenAI template은 LiteLlm(model="openai/<이름>")과 OPENAI_API_KEY만 생성하므로 그대로 실행하면 public OpenAI endpoint를 향한다. OpenAI API를 직접 쓸 수 없다면 labbyo/agent.py의 create_model()을 명시적으로 바꾼다.

import os
from google.adk.models.lite_llm import LiteLlm
def create_model():
return LiteLlm(
model=f"openai/{os.environ['LITELLM_MODEL']}",
api_base=os.environ["LITELLM_BASE_URL"],
api_key=os.environ["LITELLM_API_KEY"],
)

generated docker-compose.yaml의 Agent service에도 세 변수를 전달한다.

environment:
- LITELLM_MODEL=${LITELLM_MODEL}
- LITELLM_BASE_URL=${LITELLM_BASE_URL}
- LITELLM_API_KEY=${LITELLM_API_KEY}

이 변경은 ModelConfig 재사용이 아니라 BYO application code의 model client 설정이다. build 전에 diff를 읽고, LiteLLM alias가 tool calling을 지원하는지도 다시 확인한다.

  1. 선택한 model credential이 현재 shell에 있는지 확인한다

    터미널 창
    if test -n "$OPENAI_API_KEY" || test -n "$LITELLM_API_KEY"; then
    echo "model API key is set"
    fi
  2. project image를 만든다

    터미널 창
    kagent build --image lab-byo:lab
  3. 로컬 terminal UI에서 실행한다

    터미널 창
    kagent run
  4. generated Agent의 기본 tool을 한 번 호출하고 응답을 본다. 종료는 Ctrl+C다.

  5. code나 instructions 한 줄을 바꾼 뒤 다시 kagent build --image lab-byo:lab, kagent run해 image build가 변경 경계임을 확인한다.

로컬 성공은 code와 model 연결을 빠르게 검증한다. Kubernetes scheduling, registry pull, ServiceAccount, NetworkPolicy, Secret reference, A2A route까지 검증한 것은 아니다.

다음 질문에 모두 답할 수 있을 때만 cluster deploy로 넘어간다.

  • image 이름과 실제 build 결과가 같은가?
  • kind에서는 kind load와 IfNotPresent를 쓰고, 온프렘에서는 registry digest로 바꿀 계획이 있는가?
  • deploy CLI를 쓸 경우 임시 env file을 조직의 secret 도구로 만들고 Git에서 제외할 계획이 있는가?
  • generated kagent.yaml의 Agent 이름·namespace·port·A2A 설정을 검토했는가?
  • image를 non-root와 제한된 filesystem·resource로 실행할 수 있는가?

먼저 credential 없이 볼 수 있는 source와 CLI contract를 검사한다.

터미널 창
sed -n '1,240p' kagent.yaml
sed -n '1,240p' Dockerfile
kagent deploy --help

설치한 CLI가 --dry-run을 지원하고 조직의 secret 도구로 임시 env file을 준비했다면 apply 전에 rendered resource도 검사한다. dry-run 출력에는 Secret data가 포함될 수 있으므로 terminal history·공유 문서·Git에 저장하지 않는다. 존재하지 않는 .env.production을 예제 때문에 새 평문 파일로 만들지는 않는다.

공식 흐름은 registry를 준비해 kagent build --push와 kagent deploy를 사용한다. 이 kind 실습은 외부 registry credential을 전제하지 않기 위해 image를 node에 직접 적재하고, 검토한 BYO resource를 명시적으로 적용한다.

host Docker의 image를 kind node container runtime으로 복사한다.

터미널 창
docker image inspect lab-byo:lab
kind load docker-image lab-byo:lab --name kagent-lab
docker exec kagent-lab-control-plane crictl images | grep lab-byo

선택한 model 경로 하나만 실행한다. Secret 값은 출력하지 않는다.

터미널 창
kubectl -n kagent create secret generic lab-byo-model \
--from-literal=OPENAI_API_KEY="$OPENAI_API_KEY" \
--dry-run=client -o yaml | kubectl apply -f -

Secret의 key 이름만 확인한다. -o yaml로 값을 출력하지 않는다.

터미널 창
kubectl -n kagent describe secret lab-byo-model

imagePullPolicy: IfNotPresent가 있어야 node에 적재한 local image를 registry에서 다시 받으려 하지 않는다. 이 값은 kind 전용이며 온프렘 manifest에는 registry digest와 조직의 pull policy를 사용한다.

덱의 고정 버전인 v0.9.9 SharedDeploymentSpec에는 envFrom이 없으므로 필요한 Secret key를 env[].valueFrom.secretKeyRef로 하나씩 연결한다. 선택한 model 경로의 manifest 하나만 적용한다.

터미널 창
kubectl apply -f - <<'EOF'
apiVersion: kagent.dev/v1alpha2
kind: Agent
metadata:
name: lab-byo
namespace: kagent
spec:
type: BYO
byo:
deployment:
image: lab-byo:lab
imagePullPolicy: IfNotPresent
env:
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: lab-byo-model
key: OPENAI_API_KEY
resources:
requests:
cpu: 100m
memory: 256Mi
limits:
cpu: "1"
memory: 1Gi
EOF

kagent가 image를 실행해 주더라도 Agent logic·dependency·secret 사용·A2A implementation은 image 제작자의 책임이다. 이것이 Declarative에서 BYO로 넘어갈 때 넓어지는 신뢰 경계다.

  1. BYO Agent condition과 생성된 workload를 기다린다.

    터미널 창
    kubectl -n kagent wait --for=condition=Accepted agent/lab-byo --timeout=2m
    kubectl -n kagent wait --for=condition=Ready agent/lab-byo --timeout=5m
    kubectl -n kagent get agent lab-byo -o yaml
    kubectl -n kagent get pods
  2. 7장의 controller port-forward가 없으면 다시 연다.

    터미널 창
    kubectl -n kagent port-forward svc/kagent-controller 8083:8083
  3. Agent Card를 읽고 task를 호출한다.

    터미널 창
    curl --fail --silent --show-error \
    http://localhost:8083/api/a2a/kagent/lab-byo/.well-known/agent.json
    kagent invoke -n kagent -a lab-byo -S \
    -t "Roll a six-sided die and tell me whether the result is prime."

로컬 kagent run과 cluster invoke가 모두 성공해야 code·image·Secret·scheduling·A2A route가 연결된 것이다.

증상확인
kagent init이 실패CLI version과 지원 framework·language — kagent init --help
kagent build가 실패Docker daemon 실행 여부, base image pull과 프록시·registry 접근
kagent run이 바로 종료container log — model key 환경 변수 누락, 로컬 포트 충돌
Pod가 ImagePullBackOffkind load 대상 cluster·image 이름, imagePullPolicy: IfNotPresent
Ready=FalseAgent condition과 Pod log — A2A server가 port 8080에서 준비되는지
LiteLLM인데 요청이 public OpenAI로 나감create_model()의 api_base와 compose의 환경 변수 전달
LiteLLM 호출이 400model alias 뒤 upstream의 function/tool calling 지원
  • generated project의 code·kagent.yaml·compose 역할을 구분한다.
  • kagent build와 kagent run으로 local loop를 한 번 돌았다.
  • LiteLLM을 선택했다면 BYO code와 runtime에 model·api_base·credential을 별도로 전달했다.
  • lab-byo:lab image를 kind node에 적재하고 lab-byo가 Ready=True가 됐다.
  • controller의 BYO Agent Card와 A2A invoke가 성공했다.
  • kind의 local tag·IfNotPresent와 온프렘의 immutable registry digest를 구분한다.