Howto expand the /24 MicroK8s Service CIDR

d33psky
Thu, 20 Nov 2025 11:04:07 +0000
microk8s

Hope this might be useful to someone:

# Expanding MicroK8s Service CIDR Without Downtime

## Check Current Usage

```bash

# Get service CIDR from API

CIDR=$(echo ‘{“apiVersion”:“v1”,“kind”:“Service”,“metadata”:{“name”:“tst”},“spec”:{“clusterIP”:“1.1.1.1”,“ports”:[{“port”:443}]}}’ | kubectl apply -f - 2>&1 | sed ‘s/.*valid IPs is //’)

# Count used IPs

USED=$(kubectl get svc --all-namespaces -o jsonpath=‘{.items[*].spec.clusterIP}’ | tr ’ ’ ‘\n’ | grep -v “None” | wc -l)

# Calculate capacity

PREFIX=${CIDR#*/}

TOTAL=$(( (1 << (32 - PREFIX)) - 2 ))

echo “CIDR: $CIDR | Used: $USED / $TOTAL”

```

## Expand to /20

Expands from 254 IPs to 4,094 IPs (16x capacity). Works on live clusters with **zero downtime**.

Kubernetes validates existing service IPs against the new CIDR on startup. Since we’re **expanding** the range (not moving it), all existing IPs remain valid. The `kubernetes` service stays at `.183.1` - no certificate updates needed.

### Procedure (Per Node)

**1. Backup configs**

```bash

NODE=devk8s1-ehv # Change for each node

ssh $NODE “sudo cp /var/snap/microk8s/current/args/cni-env{,.bak}”

ssh $NODE “sudo cp /var/snap/microk8s/current/args/kube-apiserver{,.bak}”

ssh $NODE “sudo cp /var/snap/microk8s/current/args/kube-controller-manager{,.bak}”

```

**2. Update CIDR (change /24 to /20)**

```bash

ssh $NODE “sudo sed -i ‘s|IPv4_SERVICE_CIDR=10.152.183.0/24|IPv4_SERVICE_CIDR=10.152.176.0/20|’ /var/snap/microk8s/current/args/cni-env”

ssh $NODE “sudo sed -i ‘s|service-cluster-ip-range=10.152.183.0/24|service-cluster-ip-range=10.152.176.0/20|’ /var/snap/microk8s/current/args/kube-apiserver”

ssh $NODE “sudo sed -i ‘s|service-cluster-ip-range=10.152.183.0/24|service-cluster-ip-range=10.152.176.0/20|’ /var/snap/microk8s/current/args/kube-controller-manager”

```

**3. Verify changes**

```bash

ssh $NODE “grep -E ‘SERVICE_CIDR|service-cluster-ip-range’ /var/snap/microk8s/current/args/{cni-env,kube-apiserver,kube-controller-manager}”

# All should show: 10.152.176.0/20

```

**4. Restart just kubelite, PODs stay where they are**

```bash

ssh $NODE “sudo snap restart microk8s.daemon-kubelite”

sleep 60

kubectl get nodes # Verify node is Ready

```

**5. Repeat for remaining nodes** (rolling restart keeps cluster available)

### Verify Success

```bash

# Check kubernetes service IP unchanged

kubectl get svc kubernetes -n default -o jsonpath=‘{.spec.clusterIP}’

# Should still be: 10.152.183.1

# Test new allocation works

kubectl create service clusterip test-expansion --tcp=80:80

kubectl get svc test-expansion -o jsonpath=‘{.spec.clusterIP}’

# Should get IP in 10.152.176-191.x range

kubectl delete svc test-expansion

```

### Rollback option

```bash

ssh $NODE “sudo cp /var/snap/microk8s/current/args/cni-env{.bak,}”

ssh $NODE “sudo cp /var/snap/microk8s/current/args/kube-apiserver{.bak,}”

ssh $NODE “sudo cp /var/snap/microk8s/current/args/kube-controller-manager{.bak,}”

ssh $NODE “sudo snap restart microk8s.daemon-kubelite”

```

## Impact

- Zero pod restarts

- Zero service disruptions

- All existing service IPs preserved

- Cluster remains available during rolling restarts

- No certificate updates required

## References

- Kubernetes source: `pkg/registry/core/service/ipallocator/controller/repair.go`

- Tested on: MicroK8s v1.30.14, 6-node cluster

1 post - 1 participant