9. BYO Agent를 kind에 배포하기
이 장에서 처음 나오는 말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 Agent | BYO Agent |
|---|---|---|
| Agent logic | systemMessage와 resource 조합 | application code와 framework |
| runtime | kagent가 표준 runtime 구성 | image 안에 포함 |
| protocol | kagent runtime이 제공 | image가 A2A server 계약 구현 |
| dependency | kagent 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가 자동으로 볼 수 있다고 가정하지 않는다.
project 만들기
섹션 제목: “project 만들기”cluster와 별개인 작업 디렉터리에서 실행한다. 생성물에는 별도 Git 저장소를 만들 필요가 없다.
mkdir -p /tmp/kagent-lab-byocd /tmp/kagent-lab-byokagent init adk python labbyo \ --model-provider OpenAI \ --model-name gpt-4.1-minicd 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을 지원하는지도 다시 확인한다.
build와 local run
섹션 제목: “build와 local run”-
선택한 model credential이 현재 shell에 있는지 확인한다
터미널 창 if test -n "$OPENAI_API_KEY" || test -n "$LITELLM_API_KEY"; thenecho "model API key is set"fi -
project image를 만든다
터미널 창 kagent build --image lab-byo:lab -
로컬 terminal UI에서 실행한다
터미널 창 kagent run -
generated Agent의 기본 tool을 한 번 호출하고 응답을 본다. 종료는
Ctrl+C다. -
code나 instructions 한 줄을 바꾼 뒤 다시
kagent build --image lab-byo:lab,kagent run해 image build가 변경 경계임을 확인한다.
로컬 성공은 code와 model 연결을 빠르게 검증한다. Kubernetes scheduling, registry pull, ServiceAccount, NetworkPolicy, Secret reference, A2A route까지 검증한 것은 아니다.
배포 manifest를 먼저 검사하기
섹션 제목: “배포 manifest를 먼저 검사하기”다음 질문에 모두 답할 수 있을 때만 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.yamlsed -n '1,240p' Dockerfilekagent 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를 명시적으로 적용한다.
kind node에 image와 Secret 준비하기
섹션 제목: “kind node에 image와 Secret 준비하기”host Docker의 image를 kind node container runtime으로 복사한다.
docker image inspect lab-byo:labkind load docker-image lab-byo:lab --name kagent-labdocker 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 -kubectl -n kagent create secret generic lab-byo-model \ --from-literal=LITELLM_MODEL="$LITELLM_MODEL" \ --from-literal=LITELLM_BASE_URL="$LITELLM_BASE_URL" \ --from-literal=LITELLM_API_KEY="$LITELLM_API_KEY" \ --dry-run=client -o yaml | kubectl apply -f -Secret의 key 이름만 확인한다. -o yaml로 값을 출력하지 않는다.
kubectl -n kagent describe secret lab-byo-modelBYO resource를 배포하기
섹션 제목: “BYO resource를 배포하기”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/v1alpha2kind: Agentmetadata: name: lab-byo namespace: kagentspec: 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: 1GiEOFkubectl apply -f - <<'EOF'apiVersion: kagent.dev/v1alpha2kind: Agentmetadata: name: lab-byo namespace: kagentspec: type: BYO byo: deployment: image: lab-byo:lab imagePullPolicy: IfNotPresent env: - name: LITELLM_MODEL valueFrom: secretKeyRef: name: lab-byo-model key: LITELLM_MODEL - name: LITELLM_BASE_URL valueFrom: secretKeyRef: name: lab-byo-model key: LITELLM_BASE_URL - name: LITELLM_API_KEY valueFrom: secretKeyRef: name: lab-byo-model key: LITELLM_API_KEY resources: requests: cpu: 100m memory: 256Mi limits: cpu: "1" memory: 1GiEOFkagent가 image를 실행해 주더라도 Agent logic·dependency·secret 사용·A2A implementation은 image 제작자의 책임이다. 이것이 Declarative에서 BYO로 넘어갈 때 넓어지는 신뢰 경계다.
Ready와 A2A까지 확인하기
섹션 제목: “Ready와 A2A까지 확인하기”-
BYO Agent condition과 생성된 workload를 기다린다.
터미널 창 kubectl -n kagent wait --for=condition=Accepted agent/lab-byo --timeout=2mkubectl -n kagent wait --for=condition=Ready agent/lab-byo --timeout=5mkubectl -n kagent get agent lab-byo -o yamlkubectl -n kagent get pods -
7장의 controller port-forward가 없으면 다시 연다.
터미널 창 kubectl -n kagent port-forward svc/kagent-controller 8083:8083 -
Agent Card를 읽고 task를 호출한다.
터미널 창 curl --fail --silent --show-error \http://localhost:8083/api/a2a/kagent/lab-byo/.well-known/agent.jsonkagent 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가 ImagePullBackOff | kind load 대상 cluster·image 이름, imagePullPolicy: IfNotPresent |
Ready=False | Agent condition과 Pod log — A2A server가 port 8080에서 준비되는지 |
| LiteLLM인데 요청이 public OpenAI로 나감 | create_model()의 api_base와 compose의 환경 변수 전달 |
LiteLLM 호출이 400 | model 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:labimage를 kind node에 적재하고lab-byo가Ready=True가 됐다.- controller의 BYO Agent Card와 A2A invoke가 성공했다.
- kind의 local tag·
IfNotPresent와 온프렘의 immutable registry digest를 구분한다.
참고 자료
섹션 제목: “참고 자료”- kagent local development —
init·build·run·MCP 추가·deploy 흐름 - BYO ADK Agent — image·Secret·A2A endpoint 계약
- Google ADK
LiteLlm—api_base·api_key를 completion 인자로 전달하는 wrapper kagent init— 지원 framework·language·model flag- Agent 배포 플랫폼 — kagent 격리와 공급망 — production target에서 더할 통제