Skip to content

Commit 8774dae

Browse files
ADK Agent Container Image
1 parent c0faba9 commit 8774dae

22 files changed

Lines changed: 1813 additions & 0 deletions
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
2+
### Python ###
3+
# Byte-compiled / optimized / DLL files
4+
__pycache__/
5+
*.py[cod]
6+
*$py.class
7+
8+
# C extensions
9+
*.so
10+
11+
# Distribution / packaging
12+
.Python
13+
env/
14+
build/
15+
develop-eggs/
16+
dist/
17+
downloads/
18+
eggs/
19+
.eggs/
20+
lib/
21+
lib64/
22+
parts/
23+
sdist/
24+
var/
25+
*.egg-info/
26+
.installed.cfg
27+
*.egg
28+
29+
# PyInstaller
30+
# Usually these files are written by a python script from a template
31+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
32+
*.manifest
33+
*.spec
34+
35+
# Installer logs
36+
pip-log.txt
37+
pip-delete-this-directory.txt
38+
39+
# Unit test / coverage reports
40+
htmlcov/
41+
.tox/
42+
.coverage
43+
.coverage.*
44+
.cache
45+
nosetests.xml
46+
coverage.xml
47+
*,cover
48+
.hypothesis/
49+
50+
# Translations
51+
*.mo
52+
*.pot
53+
54+
# Django stuff:
55+
*.log
56+
local_settings.py
57+
58+
# Flask stuff:
59+
instance/
60+
.webassets-cache
61+
62+
# Scrapy stuff:
63+
.scrapy
64+
65+
# Sphinx documentation
66+
docs/_build/
67+
68+
# PyBuilder
69+
target/
70+
71+
# Jupyter Notebook
72+
.ipynb_checkpoints
73+
74+
# pyenv
75+
.python-version
76+
77+
# celery beat schedule file
78+
celerybeat-schedule
79+
80+
# dotenv
81+
.env
82+
83+
# virtualenv
84+
.venv/
85+
venv/
86+
ENV/
87+
88+
# Spyder project settings
89+
.spyderproject
90+
91+
# Rope project settings
92+
.ropeproject
93+
94+
95+
### Linux ###
96+
*~
97+
98+
# temporary files which can be created if a process still has a handle open of a deleted file
99+
.fuse_hidden*
100+
101+
# KDE directory preferences
102+
.directory
103+
104+
# Linux trash folder which might appear on any partition or disk
105+
.Trash-*
106+
107+
# .nfs files are created when an open file is removed but is still being accessed
108+
.nfs*
109+
110+
111+
### OSX ###
112+
*.DS_Store
113+
.AppleDouble
114+
.LSOverride
115+
116+
# Icon must end with two \r
117+
Icon
118+
# Thumbnails
119+
._*
120+
# Files that might appear in the root of a volume
121+
.DocumentRevisions-V100
122+
.fseventsd
123+
.Spotlight-V100
124+
.TemporaryItems
125+
.Trashes
126+
.VolumeIcon.icns
127+
.com.apple.timemachine.donotpresent
128+
# Directories potentially created on remote AFP share
129+
.AppleDB
130+
.AppleDesktop
131+
Network Trash Folder
132+
Temporary Items
133+
.apdisk
134+
135+
136+
### Windows ###
137+
# Windows image file caches
138+
Thumbs.db
139+
ehthumbs.db
140+
141+
# Folder config file
142+
Desktop.ini
143+
144+
# Recycle Bin used on file shares
145+
$RECYCLE.BIN/
146+
147+
# Windows Installer files
148+
*.cab
149+
*.msi
150+
*.msm
151+
*.msp
152+
153+
# Windows shortcuts
154+
*.lnk
155+
156+
157+
### Vagrant ###
158+
.vagrant/
159+
### Local rules, see .gitignore.tail to override! ###
160+
shippable
161+
.git
162+
163+
tmp/
164+
sessions.db
165+
.adk/
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# This file tells gcloud builds submit which files to exclude from the upload.
2+
# Without it, gcloud ignores .dockerignore and uploads everything (including .venv).
3+
4+
.git
5+
.venv/
6+
venv/
7+
ENV/
8+
__pycache__/
9+
*.py[cod]
10+
*$py.class
11+
*.so
12+
*.egg-info/
13+
*.egg
14+
dist/
15+
build/
16+
.tox/
17+
.cache/
18+
.coverage
19+
htmlcov/
20+
*.log
21+
.env
22+
.adk/
23+
sessions.db
24+
tmp/
25+
.DS_Store
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# Kubernetes Benchmark Agent API
2+
3+
## Endpoints
4+
5+
### `GET /healthz`
6+
Liveness probe.
7+
**Response:**
8+
```json
9+
{
10+
"status": "ok"
11+
}
12+
```
13+
14+
### `POST /benchmark/python/density`
15+
Runs the Python density benchmark.
16+
**Request Schema:**
17+
* `sample_count` (integer): Sample count per sandbox session.
18+
* `sample_warmup` (integer): Warmup iterations per sandbox session.
19+
* `concurrent_sessions` (integer): Number of parallel sandbox sessions.
20+
* `sandbox_exec_timeout_s` (integer): Sandbox command execution timeout in seconds.
21+
22+
**Request Example:**
23+
```json
24+
{
25+
"sample_count": 100,
26+
"sample_warmup": 5,
27+
"concurrent_sessions": 1,
28+
"sandbox_exec_timeout_s": 60
29+
}
30+
```
31+
**Response Schema:**
32+
Returns aggregate metrics and a list of session results containing `orchestrator_cel`, `sandbox_total_cel`, and RSS memory metrics.
33+
34+
### `POST /benchmark/python/payload`
35+
Runs the payload transfer benchmark.
36+
**Request Schema:**
37+
* `payload_size_mb` (float): Payload size in MB.
38+
* `payload_iterations` (integer): Number of transfer iterations.
39+
* `concurrent_sessions` (integer): Number of parallel sandbox sessions.
40+
* `sandbox_exec_timeout_s` (integer): Sandbox command execution timeout in seconds.
41+
42+
**Request Example:**
43+
```json
44+
{
45+
"payload_size_mb": 1.0,
46+
"payload_iterations": 20,
47+
"concurrent_sessions": 1,
48+
"sandbox_exec_timeout_s": 60
49+
}
50+
```
51+
**Response Schema:**
52+
Returns aggregate metrics and a list of session results containing `sandbox_transfer_time_mean_ms` and throughput metrics.
53+
54+
### `POST /benchmark/python/qps`
55+
Runs the QPS saturation benchmark.
56+
**Request Schema:**
57+
* `target_qps` (float): Target requests per second.
58+
* `duration_s` (float): Duration of the QPS burst in seconds.
59+
* `sandbox_exec_timeout_s` (integer): Sandbox command execution timeout in seconds.
60+
61+
**Request Example:**
62+
```json
63+
{
64+
"target_qps": 10.0,
65+
"duration_s": 60.0,
66+
"sandbox_exec_timeout_s": 30
67+
}
68+
```
69+
**Response Schema:**
70+
Returns `actual_qps` achieved and aggregate metrics for `ttfe_ms` and `claim_ms`.
71+
72+
### `POST /benchmark/chromium/density`
73+
Runs the Chromium density benchmark.
74+
**Request Schema:**
75+
* `task_count` (integer): Iterations per Chromium session.
76+
* `warmup_tasks` (integer): Warmup iterations excluded from stats.
77+
* `concurrent_sessions` (integer): Number of parallel Chromium sessions.
78+
* `sandbox_exec_timeout_s` (integer): Sandbox command execution timeout in seconds.
79+
80+
**Request Example:**
81+
```json
82+
{
83+
"task_count": 10,
84+
"warmup_tasks": 2,
85+
"concurrent_sessions": 1,
86+
"sandbox_exec_timeout_s": 120
87+
}
88+
```
89+
**Response Schema:**
90+
Returns aggregate metrics and a list of session results containing interaction, navigate, evaluate, click, and screenshot latencies.
91+
92+
### `POST /run`
93+
Raw ADK agent interaction.
94+
**Request Schema:**
95+
* `prompt` (string): The prompt to send to the agent.
96+
97+
**Request Example:**
98+
```json
99+
{
100+
"prompt": "(Unused now, as agent has a MockLLM)"
101+
}
102+
```
103+
**Response Schema:**
104+
```json
105+
{
106+
"response": "Agent output string"
107+
}
108+
```
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
FROM python:3.13-slim
2+
WORKDIR /app
3+
4+
# Install kubectl (required by k8s-agent-sandbox for port-forwarding to sandbox pods)
5+
# Uses TARGETARCH (injected by BuildKit) to download the correct binary for amd64 or arm64
6+
RUN apt-get update && \
7+
apt-get install -y --no-install-recommends curl ca-certificates && \
8+
ARCH=$(dpkg --print-architecture) && \
9+
curl -LO "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/${ARCH}/kubectl" && \
10+
install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl && \
11+
rm kubectl && \
12+
apt-get purge -y curl && \
13+
apt-get autoremove -y && \
14+
rm -rf /var/lib/apt/lists/*
15+
16+
COPY requirements.txt .
17+
RUN pip install --no-cache-dir -r requirements.txt
18+
19+
RUN adduser --disabled-password --gecos "" myuser && \
20+
chown -R myuser:myuser /app
21+
22+
COPY . .
23+
24+
USER myuser
25+
26+
ENV PATH="/home/myuser/.local/bin:$PATH"
27+
28+
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]
29+
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# ADK Agent Container
2+
3+
FastAPI service deployed inside the Kubernetes cluster that serves as the
4+
orchestrator for Agent Sandbox benchmarks. PKB benchmark modules
5+
communicate with this service via HTTP to trigger benchmark runs.
6+
7+
## Architecture
8+
9+
```
10+
PKB (host machine) Kubernetes Cluster
11+
----------------- -----------
12+
benchmark.Run()
13+
-> HTTP POST /benchmark/... --> main.py (FastAPI)
14+
-> Runner(agent=root_agent)
15+
-> MockLlm yields code
16+
-> BenchmarkExecutor
17+
-> SandboxClient.create_sandbox()
18+
-> sandbox.files.write("script.py", code)
19+
-> sandbox.commands.run("python3 script.py")
20+
-> SandboxClient.delete_sandbox()
21+
```
22+
23+
## Components
24+
25+
| File | Purpose |
26+
|------|---------|
27+
| `main.py` | FastAPI service with benchmark endpoints |
28+
| `performance_agent/agent.py` | ADK agent definition with MockLlm and BenchmarkExecutor |
29+
| `sandboxed_apps/python_test_app/benchmark_density.py` | Python density benchmark (runs inside gVisor sandbox) |
30+
| `sandboxed_apps/python_test_app/benchmark_payload.py` | Payload transfer benchmark (runs inside gVisor sandbox) |
31+
| `sandboxed_apps/python_test_app/benchmark_qps.py` | QPS validation script (runs inside gVisor sandbox) |
32+
33+
## Endpoints
34+
35+
| Method | Path | Description |
36+
|--------|------|-------------|
37+
| GET | `/healthz` | Liveness probe |
38+
| POST | `/benchmark/python/density` | Python sandbox density measurement |
39+
| POST | `/benchmark/python/payload` | Payload transfer measurement |
40+
| POST | `/benchmark/python/qps` | QPS saturation measurement |
41+
| POST | `/benchmark/chromium/density` | Chromium browser density measurement |
42+
| POST | `/run` | Raw ADK agent interaction |
43+
44+
## Building
45+
46+
The image is built automatically by PKB during the provision stage via
47+
`container_specs`. For ARM64, use the `cloudbuild-arm64.yaml` config
48+
with `gke_prerequisites.py --target_arch=arm64`.
49+
50+
## Dependencies
51+
52+
See `requirements.txt`. Key packages:
53+
- `google-adk[gke,extensions]` -- Google Agent Development Kit
54+
- `k8s-agent-sandbox` -- Sandbox lifecycle client
55+
- `fastapi` + `uvicorn` -- HTTP service
56+
- `playwright` -- Chromium CDP automation (orchestrator-side)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# ADK Agent package

perfkitbenchmarker/data/docker/agentic/adk-agent/api/__init__.py

Whitespace-only changes.

perfkitbenchmarker/data/docker/agentic/adk-agent/api/routes/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)