In this guide, we show how to serve Gemma 4 IT models (e.g., google/gemma-4-31B-it) with vLLM on Ironwood (TPU v7x) using GKE.
Note: These setup instructions are specifically for Gemma 4 on TPU and may not work for other models as it uses custom wheels and source builds for vllm and transformers.
The following larger Gemma 4 models are verified for deployment on TPU.
| Model | Parameters | Min TPUs (Chips) | HuggingFace |
|---|---|---|---|
| Gemma 4 31B IT | 31B | 1× | google/gemma-4-31B-it |
| Gemma 4 26B-A4B IT (MoE) | 26B (4B active) | 1× | google/gemma-4-26B-A4B-it |
Note
Gemma 4 E2B IT, Gemma 4 E4B IT are currently not verified for TPU deployment.
Before deploying the vLLM workload, ensure your GKE cluster is configured with the necessary networking and identity features.
# Set variables
export CLUSTER_NAME=<YOUR_CLUSTER_NAME>
export PROJECT_ID=<YOUR_PROJECT_ID>
export REGION=<YOUR_REGION>
export ZONE=<YOUR_ZONE>
export NODEPOOL_NAME=<YOUR_NODEPOOL_NAME>Create a TPU v7 (Ironwood) nodepool.
gcloud container node-pools create ${NODEPOOL_NAME} \
--project=${PROJECT_ID} \
--location=${REGION} \
--node-locations=${ZONE} \
--num-nodes=1 \
--machine-type=tpu7x-standard-4t \
--cluster=${CLUSTER_NAME}-
Configure kubectl to communicate with your cluster
gcloud container clusters get-credentials ${CLUSTER_NAME} --location=${ZONE}
-
Create a Kubernetes Secret for Hugging Face credentials
export HF_TOKEN=YOUR_TOKEN kubectl create secret generic hf-secret \ --from-literal=hf_api_token=${HF_TOKEN}
-
Apply the vLLM manifest using the provided
gemma4-server.yamlfile in this directory:
Tip
If you are using pre-built images optimized for Gemma 4 (which have the required custom wheels baked in), the environment variables for vision stability (VLLM_WORKER_MULTIPROC_METHOD=fork, etc.) are already set inside the image. If you are using a standard image, you must define them in the env: section of the container spec.
`
-
Apply the vLLM manifest
kubectl apply -f vllm-tpu.yaml
-
Interact with the model using curl
kubectl port-forward service/vllm-service 8000:8000 curl http://localhost:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "google/gemma-4-31B-it", "messages": [ { "role": "user", "content": [ { "type": "image_url", "image_url": { "url": "https://images.unsplash.com/photo-1501594907352-04cda38ebc29?auto=format&fit=crop&w=800&q=80" } }, { "type": "text", "text": "Describe the image above" } ] } ], "max_tokens": 300, "temperature": 0.0, "top_p": 1.0 }'
To benchmark the server, we use the InferenceX client from SemiAnalysisAI. Reference: https://github.com/SemiAnalysisAI/InferenceX.
First, download the client code: git clone https://github.com/SemiAnalysisAI/InferenceX.git
-
Execute a short benchmark against the server using one of the following workloads.
Save the following manifest as
vllm-benchmark-1k500.yamland apply it usingkubectl apply -f vllm-benchmark-1k500.yaml.apiVersion: v1 kind: Pod metadata: name: vllm-bench-1k500 namespace: gemma4-test spec: terminationGracePeriodSeconds: 60 containers: - name: vllm-bench image: vllm/vllm-tpu:gemma4 command: ["/bin/bash", "-c"] args: - | git clone https://github.com/SemiAnalysisAI/InferenceX.git /ubench/inferencex && \ cd /ubench/inferencex && \ git checkout 89ce6098ef2bc4576a735c43f39c7d972b091cfc && \ python3 /ubench/inferencex/utils/bench_serving/benchmark_serving.py \ --backend=vllm \ --request-rate=inf \ --host=vllm-service \ --port=8000 \ --model=google/gemma-4-31B-it \ --tokenizer=google/gemma-4-31B-it \ --dataset-name=random \ --random-input-len=1024 \ --random-output-len=500 \ --num-prompts=1280 \ --ignore-eos env: - name: HUGGING_FACE_HUB_TOKEN valueFrom: secretKeyRef: key: hf_api_token name: hf-secret
Save the following manifest as
vllm-benchmark-1k8k.yamland apply it usingkubectl apply -f vllm-benchmark-1k8k.yaml.apiVersion: v1 kind: Pod metadata: name: vllm-bench-1k8k namespace: gemma4-test spec: terminationGracePeriodSeconds: 60 containers: - name: vllm-bench image: vllm/vllm-tpu:gemma4 command: ["/bin/bash", "-c"] args: - | git clone https://github.com/SemiAnalysisAI/InferenceX.git /ubench/inferencex && \ cd /ubench/inferencex && \ git checkout 89ce6098ef2bc4576a735c43f39c7d972b091cfc && \ python3 /ubench/inferencex/utils/bench_serving/benchmark_serving.py \ --backend=vllm \ --request-rate=inf \ --host=vllm-service \ --port=8000 \ --model=google/gemma-4-31B-it \ --tokenizer=google/gemma-4-31B-it \ --dataset-name=random \ --random-input-len=1024 \ --random-output-len=8192 \ --random-range-ratio=0.8 \ --num-prompts=320 \ --ignore-eos env: - name: HUGGING_FACE_HUB_TOKEN valueFrom: secretKeyRef: key: hf_api_token name: hf-secret
Save the following manifest as
vllm-benchmark-8k1k.yamland apply it usingkubectl apply -f vllm-benchmark-8k1k.yaml.apiVersion: v1 kind: Pod metadata: name: vllm-bench-8k1k namespace: gemma4-test spec: terminationGracePeriodSeconds: 60 containers: - name: vllm-bench image: vllm/vllm-tpu:gemma4 command: ["/bin/bash", "-c"] args: - | git clone https://github.com/SemiAnalysisAI/InferenceX.git /ubench/inferencex && \ cd /ubench/inferencex && \ git checkout 89ce6098ef2bc4576a735c43f39c7d972b091cfc && \ python3 /ubench/inferencex/utils/bench_serving/benchmark_serving.py \ --backend=vllm \ --request-rate=inf \ --host=vllm-service \ --port=8000 \ --model=google/gemma-4-31B-it \ --tokenizer=google/gemma-4-31B-it \ --dataset-name=random \ --random-input-len=8192 \ --random-output-len=1024 \ --random-range-ratio=0.8 \ --num-prompts=320 \ --ignore-eos env: - name: HUGGING_FACE_HUB_TOKEN valueFrom: secretKeyRef: key: hf_api_token name: hf-secret
-
Check the progress of benchmark:
kubectl logs -f vllm-bench-1k500 # For 1k/500 workloadExample Output:
============ Serving Benchmark Result ============ Successful requests: 1280 Benchmark duration (s): xx.xx Total input tokens: xxxx Total generated tokens: xxxx Request throughput (req/s): xx.xx Output token throughput (tok/s): xxxx.xx Total Token throughput (tok/s): xxxx.xx ---------------Time to First Token---------------- Mean TTFT (ms): xxxx.xx Median TTFT (ms): xxxx.xx P99 TTFT (ms): xxxx.xx -----Time per Output Token (excl. 1st token)------ Mean TPOT (ms): xx.xx Median TPOT (ms): xx.xx P99 TPOT (ms): xx.xx ---------------Inter-token Latency---------------- Mean ITL (ms): xx.xx Median ITL (ms): xx.xx P99 ITL (ms): xx.xx ================================================== -
Clean up
kubectl delete -f vllm-benchmark-1k500.yaml kubectl delete -f vllm-benchmark-1k8k.yaml kubectl delete -f vllm-benchmark-8k1k.yaml