sodcalculator

10 Tech How-To

Cloud Native AI Software Distribution Guide

Guide 10-12426 · Updated · Step by step

This guide walks enterprise teams through packaging, deploying, and managing AI software on cloud-native infrastructure. You’ll learn the core patterns—containerization, orchestration, CI/CD, and scaling—so your models and services run reliably in production. The focus is on practical, actionable steps that work across major cloud providers and Kubernetes distributions.

What You’ll Need

  • A container runtime (Docker, containerd, or Podman) installed on your build machine
  • Access to a Kubernetes cluster (managed like EKS, AKS, GKE, or self-hosted)
  • A container registry (Docker Hub, ECR, GCR, ACR, or a private registry)
  • Helm 3 installed for package management
  • Basic familiarity with YAML, Dockerfiles, and command-line tools
  • Source code for your AI model and serving code (e.g., TensorFlow Serving, PyTorch Serve, or a custom FastAPI service)
  • CI/CD tooling (GitHub Actions, GitLab CI, Jenkins, or similar)

Step-by-Step

  1. Containerize your AI model and serving code. Create a Dockerfile that copies your model artifacts (weights, tokenizers, configs) and the serving code. Use a slim base image like python:3.11-slim for Python services. Install only the dependencies your model needs—not the full training stack. For example, if you use PyTorch, install torch and torchserve, not torchvision unless required. Pin exact versions in requirements.txt to ensure reproducible builds.
  2. Optimize the image size and startup time. Use multi-stage builds: compile any native extensions in a builder stage, then copy only the compiled artifacts to the final image. For large models (over 1 GB), consider storing weights in a separate volume or object store and downloading them at pod startup, rather than baking them into the image. This speeds up image pulls and lets you update weights without rebuilding. Set ENV PYTHONUNBUFFERED=1 and ENV PYTHONDONTWRITEBYTECODE=1 to reduce log latency and avoid .pyc files.
  3. Push the image to your container registry. Tag the image with a unique version—use the Git commit SHA or a semantic version like 1.2.3. Run docker build -t your-registry/ai-service:1.2.3 . then docker push your-registry/ai-service:1.2.3. Never use the latest tag for production deployments; always pin to an immutable tag. If you use a private registry, configure Kubernetes image pull secrets so the cluster can authenticate.
  4. Create Kubernetes manifests for your service. Start with a Deployment that defines the pod spec: container image, resource requests/limits, environment variables (model path, API keys), and health check probes. Set livenessProbe to check if the service is alive (e.g., hitting /health endpoint) and readinessProbe to check if it can serve traffic (e.g., model loaded). For GPU workloads, add resources.limits.nvidia.com/gpu: 1 and ensure your cluster has the NVIDIA device plugin installed.
  5. Expose the service with a Service and Ingress. Create a ClusterIP Service to give the pods a stable internal DNS name. Then create an Ingress resource to route external HTTP traffic to the service. Configure TLS termination at the Ingress using a certificate from your CA or cert-manager. For internal-only services, skip the Ingress and use the ClusterIP directly.
  6. Package with Helm for repeatable deployments. Create a Helm chart that parameterizes the image tag, replica count, resource limits, and environment variables. This lets your team deploy to dev, staging, and production with the same chart, just different values.yaml files. Use helm create my-ai-service to scaffold the structure, then edit templates/deployment.yaml and templates/service.yaml. Store the chart in a Git repository and release it to a chart repository (like ChartMuseum or OCI registry) for team-wide reuse.
  7. Set up CI/CD pipeline. In your CI tool, add steps to: run unit tests on your serving code, build the Docker image, push it to the registry, and then run helm upgrade --install my-ai-service ./chart --namespace prod --values values-prod.yaml. For automated rollouts, use Argo CD or Flux to sync the Git repo with the cluster—when you merge a change to the manifests, the cluster updates automatically. Add a manual approval step for production deployments if your team requires it.
  8. Configure autoscaling. Use the Horizontal Pod Autoscaler (HPA) to scale pods based on CPU, memory, or custom metrics like request latency. For AI workloads, CPU-based scaling is often enough for CPU inference. For GPU models, scale on GPU utilization if your metrics server supports it. Set minReplicas to 2 for high availability and maxReplicas based on your cluster capacity. Example HPA manifest:
    apiVersion: autoscaling/v2
    kind: HorizontalPodAutoscaler
    metadata:
      name: ai-service-hpa
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: ai-service
      minReplicas: 2
      maxReplicas: 10
      metrics:
      - type: Resource
        resource:
          name: cpu
          target:
            type: Utilization
            averageUtilization: 70
    
  9. Implement rolling updates and rollbacks. By default, Kubernetes performs rolling updates: it creates new pods, waits for them to become ready, then terminates old pods. Set strategy.rollingUpdate.maxUnavailable: 0 and maxSurge: 1 to avoid downtime. If a deployment fails, run kubectl rollout undo deployment/ai-service to revert to the previous revision. Keep the last 10 revisions with revisionHistoryLimit: 10.
  10. Monitor and log your service. Deploy Prometheus for metrics collection and Grafana for dashboards. Export request latency, error rates, and model inference time as Prometheus metrics from your service code. Use Loki or the ELK stack for centralized logging—send stdout/stderr from pods to a log aggregator. Set up alerts for high error rates, pod restarts, or model latency exceeding thresholds.

Common Mistakes

  • Baking large model weights into the image—makes every build slow and bloats the registry. Store weights externally and load at startup.
  • Not setting resource requests/limits—pods can be evicted or starve other workloads. Always set requests for CPU/memory and limits to prevent runaway memory usage.
  • Using latest image tags—makes rollbacks impossible and deployments non-reproducible. Always pin to a version.
  • Ignoring health checks—Kubernetes will send traffic to pods that aren’t ready, causing 500 errors. Define both liveness and readiness probes.
  • Scaling to zero for stateful models—if your model loads into memory from disk, scaling down loses that state and causes cold starts. Keep at least one replica warm.
  • Missing GPU scheduling—without the device plugin and resource limits, GPU pods may fail to schedule or share GPUs unintentionally.

Tips

  • Use kubectl apply --dry-run=client -f file.yaml to validate manifests before applying them to the cluster.
  • For CPU-bound inference, consider using Knative Serving for scale-to-zero and request-based autoscaling—it’s built on Kubernetes and works well for bursty AI workloads.
  • Store model versions in a model registry (like MLflow) and pass the version as an environment variable to the pod, so you can roll back model changes without redeploying code.
  • Use kubectl port-forward to test your service locally before exposing it externally.
  • Set up a separate namespace per environment (dev, staging, prod) with ResourceQuotas to prevent one team from consuming all cluster resources.
  • For multi-tenant scenarios, use NetworkPolicies to restrict which pods can talk to your AI service.

Troubleshooting

  • Pod stuck in Pending: Check kubectl describe pod for events. Common causes: insufficient CPU/memory, GPU not available, or image pull failure. Verify node capacity with kubectl top nodes.
  • Pod CrashLoopBackOff: Read the logs with kubectl logs . If the service exits immediately, check that the model path exists and the environment variables are set correctly. Test the container locally with docker run to isolate the issue.
  • Service not reachable: Check kubectl get endpoints to see if the service has backing pods. If endpoints are empty, the selector in the Service doesn’t match the Deployment’s pod labels. Verify with kubectl get pods --show-labels.
  • High latency after scaling down: If you scale to zero, the first request after idle triggers a cold start. Increase minReplicas or use a pre-warming endpoint that loads the model before serving traffic.
  • OOMKilled: Your model exceeds the memory limit. Increase the limit, or optimize the model (quantization, batching) to reduce memory footprint. Check kubectl describe pod for the last state.
  • Rollout stuck: Run kubectl rollout status deployment/ai-service to see progress. If new pods never become ready, check readiness probe failure logs. You can force a rollback with kubectl rollout undo.

Frequently Asked Questions

Can I run AI models on CPU instead of GPU in Kubernetes?

Yes, for smaller models or batch inference, CPU is viable. Use the requests.cpu and limits.cpu fields to allocate CPU resources. Expect higher latency per request; consider batching requests to improve throughput.

How do I update the model without redeploying the service?

Store model weights in a persistent volume or object store, and mount them into the pod. When you update the weights, restart the pods (e.g., kubectl rollout restart deployment/ai-service) to reload them. Alternatively, use a sidecar that watches for new model versions and reloads them in place.

What’s the best way to handle multiple models in one cluster?

Deploy each model as a separate Deployment with its own Service. Use a single Ingress with path-based routing (e.g., /model-a, /model-b) to direct traffic. For shared infrastructure, set resource quotas per namespace.

How do I secure my AI service’s API keys?

Store secrets in Kubernetes Secrets and reference them as environment variables or mounted files. Never hardcode keys in the image or manifests. Use external secrets management (like Vault or cloud KMS) if you need rotation or audit logging.

Should I use serverless (Knative) or standard Deployments?

Knative is better for spiky, infrequent traffic because it scales to zero. Standard Deployments are better for consistent traffic or when cold starts are unacceptable. For GPU workloads, Knative is less mature—stick with Deployments and HPA.

How do I handle model versioning for A/B testing?

Deploy two versions of the service (v1 and v2) with different Deployments. Use an Ingress with a header-based routing rule (e.g., X-Model-Version: v2) to send a percentage of traffic to v2. You can also use a service mesh like Istio for fine-grained traffic splitting.

Related

General steps for current mainstream versions; menus can differ by device and version. See the disclaimer or report an error.

More in this bed

The whole Tech How-To bed →