12.3 Prebuilt & Custom Serving Containers

Key Takeaways

  • Prebuilt inference containers serve TensorFlow SavedModels, PyTorch archives named model.mar, scikit-learn files named model.joblib, and XGBoost files named model.bst or model.joblib.
  • A custom serving container must run an HTTP server that answers health checks with 200 OK within 10 seconds and accepts prediction requests with an instances array and optional parameters.
  • Agent Platform tells custom containers where to listen and route through AIP_HTTP_PORT (default 8080), AIP_HEALTH_ROUTE, and AIP_PREDICT_ROUTE, and where artifacts are through AIP_STORAGE_URI.
  • Custom prediction routines (CPR) let you add preprocessing and postprocessing in a Predictor class without writing a model server or Dockerfile.
  • The optimized TensorFlow runtime is backward compatible with prebuilt TensorFlow Serving containers and can lower serving cost and latency without code changes.
Last updated: September 2026

The exam guide lists packaging and serving models from different frameworks (for example, PyTorch and XGBoost) using prebuilt and custom containers. Many questions reduce to: does a prebuilt container support this model as-is, or do I need custom code?

Prebuilt Inference Containers

Google maintains HTTP inference servers per framework and version, stored in Artifact Registry. Like training images, they follow a support schedule with end-of-patch and end-of-availability dates, and you must use the latest tag.

FrameworkArtifact requirementServing technology
TensorFlowA SavedModel directory (saved_model.pb plus variables). Optional config/batching_parameters_config enables server-side request batchingTensorFlow Serving, or the optimized TensorFlow runtime
PyTorchA TorchServe archive named exactly model.mar (model-name set to model)TorchServe
scikit-learnA file named exactly model.joblib (estimators or pipelines)Google's inference server
XGBoostA file named exactly model.bst (Booster save_model) or model.joblibGoogle's inference server

Upload the artifact directory to Cloud Storage, register the Model with the matching prebuilt image, and deploy. The framework version in the image should match the training version.

Optimized TensorFlow runtime

The optimized TensorFlow runtime is a drop-in serving image that uses Google's proprietary and open-source technologies to cut inference cost and latency compared with open-source TensorFlow Serving containers. It's backward compatible, so you switch images with no code changes.

When Prebuilt Isn't Enough

NeedSolution
Preprocessing or postprocessing around the model (tokenize text, scale features, map class IDs to labels)Custom prediction routine (CPR)
A framework or version with no prebuilt image, or special system librariesCustom container
Non-JSON request formats or custom HTTP behaviorCustom container, or CPR with a custom Handler
Several models or frameworks in one GPU server with dynamic batchingNVIDIA Triton container
LLM serving with high throughputPrebuilt vLLM, Hex-LLM, SGLang, TGI, or TensorRT-LLM containers

Custom Container Contract

A custom container must run an HTTP server that follows these rules:

RequirementDetail
PortListen on AIP_HTTP_PORT (default 8080)
Health routeAIP_HEALTH_ROUTE, set from containerSpec.healthRoute. Return 200 OK within 10 seconds when ready to serve. Return anything else (for example, 503) while loading. After an unhealthy result, up to 3 more checks run at 10-second intervals
Predict routeAIP_PREDICT_ROUTE, set from containerSpec.predictRoute
Request body{"instances": [...], "parameters": {...}}. parameters is optional
Response body{"predictions": [...]}, in the same order as instances
Model artifactsRead from AIP_STORAGE_URI, which points to a copy of your artifact directory
Size limitsRequests and responses up to 1.5 MB on shared public endpoints. Dedicated and private endpoints allow up to 10 MB

Build the image, push it to Artifact Registry, upload a Model that references the image and routes, then deploy.

Custom Prediction Routines (CPR)

CPR gives you custom logic without writing a web server or Dockerfile:

  1. Implement a Predictor with load (read artifacts), preprocess, predict, and postprocess.
  2. Optionally implement a Handler for raw request access, custom headers, or non-JSON payloads. Google recommends keeping web logic in the Handler and ML logic in the Predictor.
  3. Build the container with the SDK: LocalModel.build_cpr_model(src_dir, image_uri, predictor=..., handler=..., requirements_path=...).
  4. Test locally with deploy_to_local_endpoint(...) before pushing, which speeds up iteration.
  5. Push, upload, and deploy like any custom container.
class ChurnPredictor(Predictor):
    def load(self, artifacts_uri):
        prediction_utils.download_model_artifacts(artifacts_uri)
        self._model = joblib.load("model.joblib")
        self._scaler = joblib.load("scaler.joblib")
    def preprocess(self, request):
        return self._scaler.transform(request["instances"])
    def predict(self, instances):
        return self._model.predict_proba(instances)[:, 1]
    def postprocess(self, scores):
        return {"predictions": [{"churn_prob": float(s), "tier": "high" if s > 0.7 else "low"} for s in scores]}

Putting preprocessing in the serving container keeps training and serving transformations consistent when they share code (Chapter 15).

Testing Containers Before Deployment

  1. Run locally with the same environment variables Agent Platform sets (AIP_HTTP_PORT, AIP_HEALTH_ROUTE, AIP_PREDICT_ROUTE, AIP_STORAGE_URI), or use CPR's deploy_to_local_endpoint.
  2. Send sample requests in the exact instances format your clients will use, including edge cases such as missing fields.
  3. Measure startup time so health checks and minimum replicas are set realistically.
  4. Load-test a staging endpoint to choose machine type and autoscaling targets (Chapter 14).
  5. Scan the image in Artifact Registry for vulnerabilities, and pin base image versions.

Choosing a Container Strategy

ScenarioChoice
Standard XGBoost model saved as model.bstPrebuilt XGBoost container
TensorFlow model where cost and latency matterOptimized TensorFlow runtime
scikit-learn model needing input normalization and label mappingCPR with a custom Predictor
Model in a framework with no prebuilt image (for example, a custom C++ runtime)Custom container meeting the HTTP contract
Several TensorFlow, PyTorch, and ONNX models sharing one GPU with dynamic batchingTriton container
Serving an open LLM with high throughputPrebuilt vLLM container through Model Garden

Exam Traps

  • Naming artifacts incorrectly, such as model.pkl for a scikit-learn prebuilt container that expects model.joblib, or a PyTorch archive not named model.mar.
  • Returning 200 OK on the health route before the model finishes loading. Requests then fail during startup.
  • Choosing a full custom container when a prebuilt container plus CPR would do.
  • Sending large payloads, such as base64 images, to a shared public endpoint over the 1.5 MB limit. Use dedicated or private endpoints, or pass Cloud Storage URIs instead.
Test Your Knowledge

A data scientist uploads a scikit-learn pipeline saved as model.pkl and deploys it with the prebuilt scikit-learn inference container, but the model fails to load. What is the most likely fix?

A
B
C
D
Test Your Knowledge

A team's custom serving container returns 200 OK on its health route as soon as the web server starts, but the 12 GB model takes 3 minutes to load, and early requests fail after deployment. What should they change?

A
B
C
D
Test Your Knowledge

A company needs to scale inputs and map numeric class IDs to business labels around a scikit-learn model, and wants to avoid writing an HTTP server or Dockerfile. Which approach fits best?

A
B
C
D