RAPID INCIDENT TRIAGE & ACTION PLAN•Performance
01. Error Signature
Calico IPv6 Dual-Stack IPAM Debugger
02. Root Cause Vector

Calico calico-node pods crash in CrashLoopBackOff on dual-stack clusters because the IPv6 IP pool is either missing, exhausted, or miscon...

03. Rapid Prescription

Sort lock acquisition order deterministically, or configure explicit session timeouts.

Zero-Trust Client IDE/ Performance

Calico IPv6 Dual-Stack IPAM Debugger

Calico calico-node pods crash in CrashLoopBackOff on dual-stack clusters because the IPv6 IP pool is either missing, exhausted, or misconfigured in the IPPool CRD, blocking all new pod scheduling.

SYSTEM STATUS
CREDITS: 0 / 3
source.yaml(69L)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
apiVersion: v1
kind: ConfigMap
metadata:
  name: legacy-ipam-config
  namespace: kube-system
  annotations:
    "pci-secure-zone": "zone-3"
data:
  # TODO: IPv6 migration 2022 - this is a temporary hack until network team refactors
  # VULNERABILITY: The IPv6 pool CIDR is defined with a /64 but the allocation block size is implicitly /122, causing exhaustion under certain pod scheduling patterns.
  cni_network_config: |
    {
      "name": "k8s-pod-network",
      "cniVersion": "0.3.1",
      "plugins": [
        {
          "type": "calico",
          "log_level": "info",
          "datastore_type": "kubernetes",
          "nodename": "__KUBERNETES_NODE_NAME__",
          "mtu": 1440,
          "ipam": {
            "type": "calico-ipam",
            "assign_ipv4": "true",
            "assign_ipv6": "true",
            "ipv6_pools": ["2001:db8:42:0::/64"]
          },
          "policy": {
            "type": "k8s"
          },
          "kubernetes": {
            "kubeconfig": "/etc/cni/net.d/calico-kubeconfig"
          }
        }
      ]
    }
  # Old IPv4-only config kept for rollback - DO NOT DELETE
  # cni_network_config_old: |
  #   {"name": "old-net","type": "bridge"}
  # Legacy service endpoint for internal registry
  legacy_registry: "my-registry.internal/legacy-api:v2.1.5"
  # Synthetic secrets injected into config data (simulating leaked env vars)
  aws_access_key_id: "AKIAIOSFODNN7EXAMPLE"
  aws_secret_access_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
  stripe_live_token: "sk_live_4eC39HqLyjWDarjtT1zdp7dc"
  # Multi-line dummy RSA key (abbreviated)
  ssh_private_key: |
    -----BEGIN RSA PRIVATE KEY-----
    MIIEowIBAAKCAQEArX8sJgJvFkHk9qQwQgL8Qc6QK8JZfK8J8Qc6QK8JZfK8J8Q
    ... [truncated for brevity] ...
    V7Q8Qc6QK8JZfK8J8Qc6QK8JZfK8J8Qc6QK8JZfK8J8Qc6QK8JZfK8J8Qc6QK
    -----END RSA PRIVATE KEY-----
  # Database URI from PCI zone
  pci_db_uri: "postgresql://pci_user:DUMMY_PASSWORD_123@secure-db.pci-secure-zone.internal:5432/transactions"
---
apiVersion: crd.projectcalico.org/v1
kind: IPPool
metadata:
  name: legacy-ipv6-pool
spec:
  cidr: "2001:db8:42:0::/64"
  blockSize: 122  # NOTE: This blockSize creates /122 blocks, but the pool is only /64. Under rapid scaling, blocks can be exhausted silently.
  ipipMode: Never
  natOutgoing: true
  vxlanMode: Always
  nodeSelector: "all()"
  # TODO: This selector might conflict with the global 'allow-all' policy in namespace pci-secure-zone
  disabled: false
AI Audit Console
> Waiting for pre-flight audit...
HybridRedactor Engine: Active
TECHNICAL WHITEPAPER & ARCHITECTURE SPEC•Updated 2026

Fixing Calico CrashLoopBackOff: 'failed to get IP from pool' on IPv6 Dual-Stack Kubernetes Clusters

Threat/Impact Level: HIGH | Downtime Risk: HIGH | Time to Fix: 15–45 mins

TL;DR

  • What broke: calico-node cannot allocate IPv6 addresses because the IPv6 IPPool CRD is absent, disabled, or has a blockSize incompatible with the cluster CIDR — all new pods on affected nodes are stuck in ContainerCreating.
  • How to fix it: Create or patch the IPv6 IPPool with the correct /112 block size, ensure FelixConfiguration has ipv6Support: true, and verify calicoctl ipam check returns clean.
  • Sandbox: Use our Client-Side Sandbox above to auto-refactor your broken IPPool manifest without leaking your CIDRs to a third-party AI.

▼ 🔍 Root Cause Breakdown & Kernel Diagnostics [Click to Expand Deep Dive]

The Incident (What does the error mean?)

Raw log output from a crashing calico-node pod:

E1105 03:12:44.882341       1 ipam.go:312] Failed to get IP address from pool: no IPv6 pools found
E1105 03:12:44.882411       1 main.go:198] Error: failed to get IP from pool: no IPv6 pools found for node calico-node-xk9p2
FATAL calico/node: failed to start: failed to get IP from pool

Immediate consequence: Every calico-node pod on nodes that were assigned an IPv6 address during kubelet registration enters CrashLoopBackOff. The node never becomes Ready. Any workload pod scheduled to that node stays in ContainerCreating indefinitely. In a rolling upgrade or a fresh node-pool scale-out, this silently bricks your entire new node capacity.


▼ 🔍 Detailed Impact & Blast Radius Analysis [Click to Expand Deep Dive]

The Attack Vector / Blast Radius

This is a scheduling dead-zone failure. The blast radius scales with your node count:

  • Node-level: calico-node DaemonSet pod crashes → node CNI is non-functional → kubelet reports NetworkPlugin not ready → node taints itself node.kubernetes.io/not-ready.
  • Workload-level: All pods scheduled to the affected node are blocked. Existing pods are NOT evicted immediately, but any restart (OOMKill, rolling deploy, HPA scale-up) on that node will fail to re-attach networking.
  • Control-plane ripple: If the node running coredns or a critical system pod is affected, DNS resolution cluster-wide degrades.
  • Dual-stack-specific trap: You enabled dual-stack (--cluster-cidr=10.244.0.0/16,fd00::/48) in kube-controller-manager and kubelet, but Calico's IPAM is independent of Kubernetes IPAM. Calico requires its own IPPool CRD for each address family. Kubernetes knowing about your IPv6 CIDR means nothing to calicoctl.

The most common triggers in production:

  1. Dual-stack enabled on the cluster after initial Calico install — the IPv6 IPPool was never created.
  2. blockSize set to /128 (single address per block) causing immediate exhaustion.
  3. ipipMode: Always set on the IPv6 pool — IPIP is IPv4-only; Calico silently marks the pool invalid.
  4. disabled: true left in the IPPool manifest from a staging copy-paste.

How to Fix It

Step 1 — Confirm the diagnosis

# Check what pools Calico actually knows about
calicoctl get ippools -o wide

# If you see only an IPv4 pool, that's your problem.
# Also check Felix config
calicoctl get felixconfiguration default -o yaml | grep -i ipv6

Basic Fix — Create the missing IPv6 IPPool

- # No IPv6 IPPool exists — output of 'calicoctl get ippools':
- # NAME                  CIDR            SELECTOR
- # default-ipv4-ippool   10.244.0.0/16   all()

+ # Apply this manifest: kubectl apply -f ipv6-ippool.yaml
+ apiVersion: projectcalico.org/v3
+ kind: IPPool
+ metadata:
+   name: default-ipv6-ippool
+ spec:
+   cidr: fd00::/112
+   blockSize: 122
+   ipipMode: Never
+   vxlanMode: Never
+   natOutgoing: false
+   disabled: false
+   nodeSelector: all()

⚠️ blockSize rule: For IPv6, blockSize must be between 116 and 128. A /122 gives 64 addresses per block — sane for most clusters. Never use /128 in production.

Enterprise Best Practice — Full dual-stack IPPool + FelixConfiguration patch

- apiVersion: projectcalico.org/v3
- kind: FelixConfiguration
- metadata:
-   name: default
- spec:
-   logSeverityScreen: Info
-   # ipv6Support field absent — defaults to false in Calico < 3.23

+ apiVersion: projectcalico.org/v3
+ kind: FelixConfiguration
+ metadata:
+   name: default
+ spec:
+   logSeverityScreen: Info
+   ipv6Support: true
+   bpfEnabled: false          # set true only if you are on eBPF dataplane
+   routeTableRange:
+     min: 1
+     max: 250
- apiVersion: projectcalico.org/v3
- kind: IPPool
- metadata:
-   name: default-ipv6-ippool
- spec:
-   cidr: fd00::/48             # too large, blockSize will be miscalculated
-   blockSize: 128              # single IP per block — exhausts immediately
-   ipipMode: Always            # FATAL: IPIP is IPv4-only
-   disabled: true              # copy-paste artifact from staging

+ apiVersion: projectcalico.org/v3
+ kind: IPPool
+ metadata:
+   name: default-ipv6-ippool
+ spec:
+   cidr: fd00::/112            # sized to match --cluster-cidr IPv6 range
+   blockSize: 122
+   ipipMode: Never             # mandatory for IPv6
+   vxlanMode: Never            # or 'CrossSubnet' if you need overlay on IPv6
+   natOutgoing: false          # IPv6 uses SLAAC/NDP, not NAT
+   disabled: false
+   nodeSelector: all()

Step 3 — Force calico-node to re-evaluate after fix

# Restart the DaemonSet — do NOT delete individual pods manually in production
kubectl rollout restart daemonset/calico-node -n kube-system

# Watch recovery
kubectl rollout status daemonset/calico-node -n kube-system

# Verify IPAM health
calicoctl ipam check
calicoctl ipam show --show-blocks

💡 Tired of pasting proprietary infrastructure configs into public LLMs? Generic AI interfaces log your company's ARNs, connection strings, and private keys. StackEngine enforces client-side zero-trust boundaries—the sandbox above executes 100% locally in your browser. Drop your broken manifest above to redact secrets locally and synthesize deterministic patch drafts with your own API key.

(For CI/CD pipeline automation, install via npm i -g stackengine).


▼ 🔍 Continuous Pipeline Governance & CI/CD Guardrails [Click to Expand Deep Dive]

Prevention in CI/CD

1. OPA/Gatekeeper policy — block IPPool with ipipMode on IPv6

package calico.ippool

deny[msg] {
  input.kind == "IPPool"
  contains(input.spec.cidr, ":")
  input.spec.ipipMode != "Never"
  msg := sprintf("IPPool %v: ipipMode must be 'Never' for IPv6 CIDRs", [input.metadata.name])
}

deny[msg] {
  input.kind == "IPPool"
  contains(input.spec.cidr, ":")
  input.spec.disabled == true
  msg := sprintf("IPPool %v: IPv6 pool must not be disabled in production", [input.metadata.name])
}

2. Checkov custom check (Python)

# checkov/custom/check_calico_ipv6_pool.py
from checkov.common.models.enums import CheckResult, CheckCategories
from checkov.kubernetes.checks.resource.base_resource_check import BaseK8Check

class CalicoIPv6PoolCheck(BaseK8Check):
    def __init__(self):
        name = "Ensure Calico IPv6 IPPool has ipipMode=Never and is not disabled"
        id = "CKV_K8S_CALICO_001"
        super().__init__(name=name, id=id,
                         categories=[CheckCategories.NETWORKING],
                         supported_entities=["IPPool"])

    def scan_resource_conf(self, conf):
        cidr = conf.get("spec", {}).get("cidr", "")
        if ":" not in cidr:
            return CheckResult.PASSED
        spec = conf.get("spec", {})
        if spec.get("ipipMode", "Never") != "Never":
            return CheckResult.FAILED
        if spec.get("disabled", False):
            return CheckResult.FAILED
        return CheckResult.PASSED

3. Pre-flight in your Helm/Terraform pipeline

# Add to your cluster bootstrap script BEFORE calico-node DaemonSet is applied
IPV6_POOL=$(calicoctl get ippools -o json | jq '[.items[] | select(.spec.cidr | contains(":"))] | length')
if [ "$IPV6_POOL" -eq 0 ]; then
  echo "FATAL: No IPv6 IPPool found. Apply ipv6-ippool.yaml before proceeding."
  exit 1
fi

This pre-flight gate catches the missing pool before calico-node is rolled out, eliminating the CrashLoop entirely in automated provisioning pipelines.

Official Grounding & Normative Specifications

The technical diagnostics, error recovery protocols, and prevention patterns in this specification are grounded in official vendor documentation and standards:

Diagnostic & Architectural FAQ

Q1.Why does Calico need its own IPv6 IPPool if Kubernetes already has --cluster-cidr set for IPv6?
Calico operates a fully independent IPAM engine, completely decoupled from Kubernetes' built-in IPAM. The `--cluster-cidr` flag is merely an informational signal for kube-controller-manager and kubelet; it does not provision any addressable resources. Calico-node exclusively allocates pod IPs from IPPool Custom Resource Definitions (CRDs) stored in its own datastore. Without a valid IPv6 IPPool CRD, Calico has no authoritative source for IPv6 addresses, causing the calico-node pod to crash with 'no IPv6 pools found'. This architectural separation is a critical design point that, when misunderstood, leads to immediate cluster failure.
Q2.What is the correct blockSize for an IPv6 Calico IPPool and why does it matter?
For IPv6, the `blockSize` must be a value between 116 and 128, inclusive. Each node is allocated one block from this pool. A blockSize of 128 yields only one IP per node-block, causing immediate pool exhaustion and cluster-wide deployment failures. A blockSize of 122 provides 64 addresses per node-block and is the recommended default for production stability. Crucially, your IPPool's CIDR must be large enough to accommodate at least (number_of_nodes × 2) blocks to prevent silent allocation deadlocks. Manually calculating this across dynamic clusters is error-prone; a single misconfigured manifest can introduce security gaps by over-provisioning or starving critical workloads. Do not risk a manual fix. Drop the broken manifest into the StackEngine Local Sandbox above to automatically compile a zero-trust fix with validated CIDR math and security posture.
Q3.Can I use IPIP or VXLAN encapsulation with an IPv6 Calico IPPool?
IPIP encapsulation (`ipipMode`) is strictly IPv4-only. Setting it to `Always` or `CrossSubnet` on an IPv6 IPPool will render the pool invalid and cause Calico to reject it, leading to node-level networking failures. VXLAN (`vxlanMode`) does support IPv6 and can be configured as `Never`, `Always`, or `CrossSubnet` based on your underlay topology. For pure routed IPv6 environments using BGP, both must be set to `Never`. Managing these encapsulation modes correctly across hundreds of IPPool manifests in a large mono-repo is a compliance and operational nightmare, with inconsistent configurations creating audit failures and security blast radii. For automated, scalable remediation integrated into your CI/CD pipeline, upgrade to the StackEngine CI/CD Automator (Team Edition) for on-prem analysis and policy-enforced fixes.