Skip to content

Fixed address for a pod or VM

By the end of this guide a pod in your subnet holds a reserved address, and a replacement pod comes back on the same one.

For why a pod's address changes and what the claim does about it, see the overview. A virtual machine needs none of this - it has a claim already.

Prerequisites

  • A subnet. <subnet> below is its name, which is also the name of its project
  • The admin or edit role on that project

1. Create the claim

cat <<EOF | oc apply -f -
apiVersion: k8s.cni.cncf.io/v1alpha1
kind: IPAMClaim
metadata:
  name: <claim>
  namespace: <subnet>
spec:
  network: cluster_udn_<subnet>
  interface: ""
EOF
ipamclaim.k8s.cni.cncf.io/<claim> created

network is the subnet's name with the prefix cluster_udn_. interface is required and stays empty. The claim holds no address yet - one is reserved the first time a pod names it.

2. Name the claim on the pod template

Add the annotation k8s.ovn.org/primary-udn-ipamclaim to the pod template, with the claim's name as its value. It goes on the template, not on the workload's own metadata, so it works for anything that creates pods from a template. It has been verified with a Deployment and with a StatefulSet.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: <workload>
  namespace: <subnet>
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: <workload>
  template:
    metadata:
      labels:
        app: <workload>
      annotations:
        k8s.ovn.org/primary-udn-ipamclaim: <claim>
    spec:
      containers:
      - name: main
        image: registry.access.redhat.com/ubi9/ubi-minimal:latest
        command: ["sleep", "infinity"]
        resources:
          requests:
            cpu: 10m
            memory: 32Mi
          limits:
            cpu: 100m
            memory: 64Mi

replicas: 1 and strategy: Recreate are part of the mechanism, not a sizing choice. One claim serves one pod, and Recreate stops the old pod before starting the new one.

Adding the annotation to a running workload changes its address once

The pod is replaced to pick the annotation up, and the replacement takes the claim's address, not the one the old pod had. Update whatever was configured with the old address. From then on it does not change.

3. Read the address

oc -n <subnet> rollout status deploy/<workload>
oc -n <subnet> get ipamclaims.k8s.cni.cncf.io <claim> -o jsonpath='{.status.ips}'

The second command prints a list with one entry, the address and the subnet's prefix length. That address is on the pod's ovn-udn1 interface:

oc -n <subnet> get pod <pod> \
  -o jsonpath='{.metadata.annotations.k8s\.v1\.cni\.cncf\.io/network-status}'

The output lists two interfaces. ovn-udn1 carries the address from the claim. eth0 carries a cluster-internal address, and that one still changes with every pod.

4. Verify that the address survives the pod

Delete the pod and let the Deployment replace it:

oc -n <subnet> delete pod <pod>
oc -n <subnet> rollout status deploy/<workload>
oc -n <subnet> get ipamclaims.k8s.cni.cncf.io <claim> -o jsonpath='{.status.ips}'

The replacement pod has a new name and the claim reports the same address as in step 3. Repeat the network-status command against the new pod to see it on ovn-udn1.

List

oc -n <subnet> get ipamclaims.k8s.cni.cncf.io

Claims named <vm>.<network> belong to virtual machines and are managed for you. Leave them alone.

Change

A claim has nothing to edit: the address is not a field, and the network cannot change.

A second pod on the same claim does not start

Scaling the workload above one replica, or switching it to a rolling update, creates a pod that names a claim already in use. That pod stays in ContainerCreating and reports an ErrorAllocatingPod event. The first pod keeps running. Scale back to one replica to clear it.

Delete

Delete the workload first, then the claim:

oc -n <subnet> delete deploy <workload>
oc -n <subnet> delete ipamclaims.k8s.cni.cncf.io <claim>

Deleting the claim gives the address up

A claim created afterwards, even under the same name, receives whichever address is free. Keep the claim for as long as anything is configured with its address, including while the workload is scaled to zero.