Skip to content

Commit df2af90

Browse files
refactor: optimize Docker image build via pre-compiled binaries and replace separate background service with integrated evaluation script in cloudbuild.
1 parent 6f8c58c commit df2af90

2 files changed

Lines changed: 71 additions & 50 deletions

File tree

Dockerfile

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,16 @@
1-
# --- Stage 1: Build the binary from source (Latest Nightly) ---
2-
FROM golang:1.25 AS builder
3-
4-
WORKDIR /build
5-
6-
# Clone the official genai-toolbox source code (always latest main branch)
7-
RUN git clone --depth 1 https://github.com/googleapis/genai-toolbox.git .
8-
9-
# Compile the binary with CGO ENABLED to support all upstream database drivers (Oracle, etc.)
10-
RUN CGO_ENABLED=1 GOOS=linux GOARCH=amd64 go build -o toolbox .
11-
12-
# --- Stage 2: Final Lightweight Runtime Image ---
13-
# Using the exact same image (golang:1.25) for runtime to perfectly match GLIBC versions
1+
# --- Final Lightweight Runtime Image ---
142
FROM golang:1.25
153

16-
17-
# Install necessary runtime certificates and standard C libraries for CGO binary
18-
RUN apt-get update && apt-get install -y ca-certificates libc6 && rm -rf /var/lib/apt/lists/*
4+
# Install necessary runtime certificates, curl, and standard C libraries
5+
RUN apt-get update && apt-get install -y ca-certificates libc6 curl && rm -rf /var/lib/apt/lists/*
196

207
WORKDIR /app
218

22-
# Copy the freshly compiled binary from the builder stage
23-
COPY --from=builder /build/toolbox /app/toolbox
24-
RUN chmod +x /app/toolbox
9+
# Automatically fetch the latest release version and download the pre-compiled binary
10+
RUN LATEST_TAG=$(curl -sL https://api.github.com/repos/googleapis/genai-toolbox/releases/latest | grep -o '"tag_name": "[^"]*"' | cut -d'"' -f4) && \
11+
echo "Downloading toolbox version: $LATEST_TAG" && \
12+
curl -o /app/toolbox "https://storage.googleapis.com/mcp-toolbox-for-databases/$LATEST_TAG/linux/amd64/toolbox" && \
13+
chmod +x /app/toolbox
2514

2615
# Copy the extension's skills and configuration into the container
2716
COPY skills/ ./skills/
@@ -32,5 +21,3 @@ RUN touch tools.yaml
3221

3322
# Expose HTTP API and UI endpoints to successfully pass Cloud Run health checks
3423
ENTRYPOINT ["/app/toolbox", "--prebuilt", "cloud-sql-postgres", "--address=0.0.0.0", "--port=8080", "--enable-api", "--ui"]
35-
36-

cloudbuild.yaml

Lines changed: 63 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -27,38 +27,72 @@ steps:
2727
- '--timeout=300'
2828
- '--set-env-vars=CLOUD_SQL_POSTGRES_PROJECT=omkar-playground,CLOUD_SQL_POSTGRES_INSTANCE=omkar-demo-postgres-1,CLOUD_SQL_POSTGRES_REGION=us-central1,CLOUD_SQL_POSTGRES_DATABASE=postgres,CLOUD_SQL_POSTGRES_USER=postgres,CLOUD_SQL_POSTGRES_PASSWORD=7`[EP^`U"_frcD;q,CLOUD_SQL_POSTGRES_IP_TYPE=PUBLIC'
2929

30-
# --- STEP 3: Run Eval Server in Background ---
31-
- name: 'gcr.io/cloud-builders/docker'
30+
# --- STEP 3: Fully Integrated Evaluation to Persist Results ---
31+
- name: 'us-central1-docker.pkg.dev/omkar-playground/toolbox-evals/eval_server:latest'
32+
entrypoint: 'bash'
3233
args:
33-
- 'run'
34-
- '-d'
35-
- '--network=cloudbuild'
36-
- '--name=eval_server'
37-
- 'us-central1-docker.pkg.dev/omkar-playground/toolbox-evals/eval_server:latest'
34+
- '-c'
35+
- |
36+
set -e
37+
cd /evalbench
38+
39+
echo "Compiling protobuf files..."
40+
python3 -m grpc_tools.protoc --proto_path=evalbench/evalproto --python_out=evalbench/evalproto --grpc_python_out=evalbench/evalproto evalbench/evalproto/*.proto
41+
42+
echo "Patching client to use insecure credentials..."
43+
# sed -i 's/"localhost:50051"/"127.0.0.1:50051"/g' evalbench/client/eval_client.py
44+
sed -i 's/grpc.alts_channel_credentials()/None/g' evalbench/client/eval_client.py
45+
sed -i 's/grpc.aio.secure_channel(address, channel_creds)/grpc.aio.insecure_channel(address)/g' evalbench/client/eval_client.py
46+
47+
echo "Patching server to listen on all IPv4 interfaces (0.0.0.0)..."
48+
sed -i 's/"\[::\]:%s"/"0.0.0.0:%s"/g' /evalbench/evalbench/eval_server.py
49+
echo "Checking bind success in server (writing to stderr)..."
50+
sed -i 's|server.add_insecure_port("0.0.0.0:%s" % PORT)|bound_port = server.add_insecure_port("0.0.0.0:%s" % PORT)\n import sys\n sys.stderr.write(f"BOUND_PORT: {bound_port}\\n")\n if bound_port == 0: raise RuntimeError("Failed to bind to port!")|' /evalbench/evalbench/eval_server.py
3851
39-
# --- STEP 4: Run Evalbench Evaluation Client ---
40-
# - name: 'python:3.10'
41-
# entrypoint: 'bash'
42-
# args:
43-
# - '-c'
44-
# - |
45-
# # Clone Evalbench
46-
# git clone https://github.com/GoogleCloudPlatform/evalbench.git
47-
# cd evalbench
52+
echo "Patching eval_service.py to fix TypeError in get_reporters..."
53+
sed -i 's|reporters = get_reporters(config.get("reporting"), job_id, run_time)|reporters = get_reporters(config.get("reporting") or {}, job_id, run_time)|' /evalbench/evalbench/eval_service.py
54+
55+
echo "Patching util/session.py to make ADK import lazy..."
56+
sed -i 's|from google.adk.sessions import VertexAiSessionService||' /evalbench/evalbench/util/session.py
57+
sed -i 's| def __init__(self, config):| def __init__(self, config):\n from google.adk.sessions import VertexAiSessionService|' /evalbench/evalbench/util/session.py
58+
echo "Patching databases/util.py to make SecretManagerClient lazy..."
59+
sed -i 's|CLIENT = secretmanager_v1.SecretManagerServiceClient()|CLIENT = None\ndef get_client():\n global CLIENT\n if CLIENT is None:\n CLIENT = secretmanager_v1.SecretManagerServiceClient()\n return CLIENT|' /evalbench/evalbench/databases/util.py || echo "Failed to patch databases/util.py"
60+
sed -i 's|CLIENT.access_secret_version|get_client().access_secret_version|' /evalbench/evalbench/databases/util.py || echo "Failed to patch databases/util.py usage"
61+
cd evalbench
62+
export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python
63+
export PYTHONPATH=./evalproto:.
64+
export CLOUD_RUN=True
65+
export PORT=50051
66+
67+
68+
69+
echo "Starting Evaluation Server in background..."
70+
# NEW: Added </dev/null in case it was waiting for input
71+
python3 -u ./eval_server.py --localhost </dev/null &
72+
SERVER_PID=$$!
4873
49-
# # Install Dependencies
50-
# pip install -r requirements.txt
74+
echo "Waiting for port 50051 to open..."
75+
python3 -c "
76+
import socket
77+
import time
78+
for i in range(20):
79+
try:
80+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
81+
s.connect(('127.0.0.1', 50051))
82+
print('Port is open!')
83+
exit(0)
84+
except Exception as e:
85+
print(f'Port not open yet: {e}')
86+
time.sleep(1)
87+
print('Port failed to open')
88+
exit(1)
89+
" || { echo "Server failed to bind port. Check logs above."; exit 1; }
5190
52-
# # Setup Environment Variables
53-
# export EVAL_GCP_PROJECT_ID=omkar-playground
54-
# export EVAL_GCP_PROJECT_REGION=us-central1
55-
# export EVAL_CONFIG=../evals/run_config.yaml
91+
echo "Server is running. Launching Evaluation Client..."
92+
cd /evalbench
93+
export PYTHONPATH=./evalbench:./evalbench/evalproto
94+
export EVAL_GCP_PROJECT_ID=omkar-playground
95+
export EVAL_GCP_PROJECT_REGION=us-central1
5696
57-
# # Compile required protobuf modules and Run Evaluation Client against the eval_server container
58-
# make proto
59-
# ./run_client.sh --endpoint=eval_server:50051
60-
97+
python3 evalbench/client/eval_client.py --experiment=/workspace/evals/run_config.yaml --endpoint=local || { echo "Client failed! Server logs:"; cat /evalbench/evalbench/server.log; exit 1; }
6198
62-
options:
63-
env:
64-
- 'DOCKER_BUILDKIT=1'

0 commit comments

Comments
 (0)