Post

Cut Your GPU Spot Instance Costs by 40% With Pod-Level Checkpointing

Cut Your GPU Spot Instance Costs by 40% With Pod-Level Checkpointing: hands-on walkthrough with commands, expected outputs and a checklist. Learn how.

Cut Your GPU Spot Instance Costs by 40% With Pod-Level Checkpointing

Spot instance terminations destroy long-running training jobs mid-epoch, forcing teams to fall back on expensive on-demand GPUs. You can try wiring up manual PyTorch state-saving loops to object storage, but that heavily pollutes your application code and slows down active training. Kubernetes 1.37 native checkpoint/restore fixes this at the container runtime level, letting you aggressively run spot instances without data loss.

TL;DR: Native Container Checkpoint/Restore pauses a running pod, dumps its exact memory state to disk, and resumes it on a new node when a spot instance is preempted. By upgrading to Kubernetes 1.37 and containerd 1.7.20, you can slash your GPU bill by 40% without rewriting a single line of PyTorch code. This post shows you how to configure the CRI and deploy a resilient training job.

What you’ll walk away with:

  • The exact containerd configuration required to enable checkpointing.
  • A kubectl workflow to dump PyTorch memory state before node preemption.
  • A restoration sequence that resumes a training loop exactly where it paused.
  • A comparison of recovery times against manual object storage saving.

Why Do GPU Spot Instances Break AI Training Pipelines?

GPU spot instances break AI pipelines because cloud providers terminate them with only a two-minute warning, which is rarely enough time for heavy models to flush memory state to object storage. If the instance dies before the upload completes, the pod restarts from the last epoch. This completely wastes hours of expensive compute time.

Aicademy recently saw their AWS bill explode when they moved all model fine-tuning back to on-demand A100s. Their custom training scripts were writing checkpoints to S3 every 15 minutes, but random spot terminations repeatedly corrupted the large uploads. The engineering team spent 20 hours a week just manually restarting stalled PyTorch Elastic runs.

Warning: Relying on application-level checkpointing to S3 for spot interruptions means you are paying GPU rates for network I/O. A 50GB model state takes minutes to upload, almost guaranteeing failure during a standard 120-second spot termination notice.

By shifting state management to the container runtime interface (CRI), the application no longer knows or cares about spot interruptions. The Kubernetes node simply freezes the container and writes the memory dump to a local mounted volume. This volume is instantly re-attached to a new node, dropping recovery time from 15 minutes to under 30 seconds.

Migrate your state-saving logic out of your application and into the infrastructure layer to maximize spot instance uptime.

What Is Container Checkpoint/Restore In Kubernetes 1.37?

Container Checkpoint/Restore in Kubernetes 1.37 is a kubelet feature that commands the underlying container runtime to dump a container’s entire memory, CPU registers, and file system state to a local tar archive. This archive is then used to initialize a new pod with the exact same runtime context.

The core technology relies on CRI integration with Checkpoint/Restore In Userspace (CRIU). First introduced as alpha earlier, this feature is highly stable in Kubernetes 1.37 when paired with containerd 1.7.20. It completely bypasses the application layer and requires no library dependencies.

Here is how the control flow operates during a preemption event:

sequenceDiagram
    participant Node as "Spot Node (k8s 1.37)"
    participant Kubelet
    participant CRI as "containerd (1.7.20)"
    participant Storage as "Persistent Volume"

    Node ->> Kubelet: "SIGTERM (Spot Preemption)"
    Kubelet ->> CRI: "Checkpoint Container"
    CRI ->> Storage: "Write Memory State Dump"
    Kubelet ->> Node: "Terminate Pod"
    Storage -->> CRI: "Restore on New Node"

This mechanism pairs exceptionally well with advanced scheduling setups. In fact, relying on checkpointing is a foundational tactic for Kubernetes Cost Optimization: Smart Strategies for AWS & Azure in 2026.

Use native checkpointing for large monolithic training jobs, but stick to PyTorch DDP state management for distributed multi-node training where state is shared concurrently.

How Do You Configure Containerd For Native Checkpointing?

You configure containerd for native checkpointing by enabling the CheckpointRestore feature gate in the kubelet configuration and adding the stream_server block to your container configuration. Both the kubelet and containerd services must be restarted to apply the changes. This process explicitly exposes the Checkpoint API to the node.

You must manually configure your runtime to accept checkpoint commands. By default, containerd disables this listener to minimize the attack surface of the node. Modify your configuration file, typically located at /etc/containerd/config.toml.

1
2
3
4
5
6
  [plugins."io.containerd.grpc.v1.cri"]
    sandbox_image = "registry.k8s.io/pause:3.9"
+   [plugins."io.containerd.grpc.v1.cri".stream_server]
+     stream_server_address = "127.0.0.1"
+     stream_server_port = "0"
+     stream_idle_timeout = "4h0m0s"

Next, enable the feature gate on your Kubernetes 1.37 kubelet. If you manage nodes manually, append this exact flag to your kubelet arguments and restart the service:

1
--feature-gates=ContainerCheckpoint=true

Verify the feature is active by querying the node’s proxy endpoint.

1
kubectl get --raw /api/v1/nodes/ip-10-0-1-50.ec2.internal/proxy/configz | jq '.kubeletconfig.featureGates'
1
2
3
{
  "ContainerCheckpoint": true
}

If you miss this step, your node eviction process will default to sending a SIGKILL after the grace period, destroying the pod. Read more about why missing this ruins data integrity in Why Your Kubernetes AI Workloads Lose 48 Hours of Progress on Node Failure.

Always enforce stream_server_address = "127.0.0.1" to prevent unauthorized network access to the CRI stream server.

How Do You Survive Node Preemption With Checkpoint/Restore?

You survive node preemption by using a pre-stop hook that intercepts the spot termination notice, triggers the kubelet checkpoint API, and writes the state to a persistent volume claim (PVC) shared across your GPU nodegroup. The replacement pod mounts this PVC and specifies the archive in its deployment annotation.

Let’s look at the infrastructure implementation for the Aicademy training workload. First, we need a network file system or a CSI driver capable of ReadWriteMany access to hold the checkpoint.

View the detailed YAML configuration for the Checkpoint PVC
1
2
3
4
5
6
7
8
9
10
11
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: training-checkpoint-pvc
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: efs-sc
  resources:
    requests:
      storage: 100Gi

When the cloud provider signals preemption, we issue a manual API call to the kubelet to dump the container. This API call requires administrative privileges on the cluster.

1
2
3
curl -sk -X POST "https://localhost:10250/checkpoint/aicademy-ns/pytorch-trainer/trainer-container" \
  --cert /var/lib/kubelet/pki/kubelet-client-current.pem \
  --key /var/lib/kubelet/pki/kubelet-client-current.pem

The node writes the archive to the host, which must be mapped to your PVC. Now, deploy the replacement pod using the restored archive. Notice the specific alpha.kubernetes.io/restore-from annotation pointing directly to the tar file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: v1
kind: Pod
metadata:
  name: pytorch-trainer-restored
  annotations:
    alpha.kubernetes.io/restore-from: "/checkpoints/checkpoint-pytorch-trainer.tar"
spec:
  containers:
  - name: trainer-container
    image: pytorch/pytorch:2.1.0-cuda11.8-cudnn8-runtime
    volumeMounts:
    - mountPath: /checkpoints
      name: checkpoint-vol
  volumes:
  - name: checkpoint-vol
    persistentVolumeClaim:
      claimName: training-checkpoint-pvc

This fundamentally alters how you manage 5 Flagship AI Engineering Projects. You no longer engineer custom state management logic; you treat your containers like virtual machines that can be paused and relocated on demand.

Checklist for a successful spot migration:

  • Kubelet feature gate enabled on all Spot instances.
  • Containerd config.toml updated with stream server settings.
  • RBAC permissions granted for the /checkpoint subresource.
  • RWX storage provisioned and mounted to /checkpoints.

Here is a breakdown of the old approach versus the new native checkpointing approach:

Strategy Checkpoint Time Spot Survival Rate Application Changes Required Winner
S3 PyTorch Checkpoints 5-15 Minutes < 40% Yes (Custom Hooks) Native Checkpointing
CRI Checkpoint/Restore 10-30 Seconds > 95% None Native Checkpointing

Test your recovery times under load; checkpointing a container with 80GB of active memory still takes roughly 20 seconds of disk I/O on fast NVMe drives.

Bottom Line

Running AI workloads on spot instances is financial suicide if you rely on application-level saving to object storage. Kubernetes 1.37 gives you a native, runtime-level pause button that eliminates data loss during spot interruptions. Stop modifying your PyTorch training loops to handle infrastructure problems, configure containerd to handle checkpointing natively, and slash your compute bill immediately.

FAQ

Does Kubernetes checkpointing work with GPUs attached?

Yes, provided you are using NVIDIA device plugin versions compatible with CRIU. The GPU memory state is saved and restored exactly like CPU memory, though it requires identical GPU hardware on the destination node.

Where are the container checkpoint archives stored by default?

By default, the kubelet writes the tar archives to /var/lib/kubelet/checkpoints/ on the local node. You must use a hostPath volume or a DaemonSet to move these files to shared storage so they survive actual node termination.

What happens if the spot instance is terminated before the checkpoint finishes?

If the node is forcefully powered off before the memory dump completes, the checkpoint archive will be corrupted. Trigger the API call immediately upon receiving the cloud provider’s 120-second preemption warning to avoid partial writes.

Can I restore a checkpoint on a different container runtime?

No. Checkpoints created by containerd 1.7.20 cannot be restored on CRI-O or Docker Engine. Both the source and destination nodes must run identical container runtimes and minor Kubernetes versions.

Next up in the series: we will configure Kueue to automatically handle this checkpointing lifecycle for batch processing workloads.

Further Reading


🚀 Ready to get hands-on? Spin up an interactive AI or Kubernetes Sandbox at Aicademy Labs for free.

This post is licensed under CC BY 4.0 by the author.