Kubeconfig and CNI Setup¶
Part of: Install a Kubernetes Cluster with kubeadm
Post-init — Final two manual steps — Configures kubectl access for your user and installs a CNI plugin so nodes reach Ready state. The cluster is fully operational after this.
Prerequisite: Cluster Bootstrap must be complete — kubeadm init must have succeeded. Next: Cluster is ready. See Maintenance & Reset for teardown procedures.
After kubeadm init completes, the cluster is running but two manual steps remain before it is usable: configuring kubectl access and installing a CNI plugin. Neither is performed automatically by the entrypoint scripts.
Scripts¶
| Script | Path |
|---|---|
| kubeconfig setup | cluster/kubeconfig-helper.sh |
| kubeconfig library | lib/ensure_kubeconfig.sh |
| CNI installer (dispatcher) | cni/install-cni.sh |
| Install Calico | cni/install-calico.sh |
| Install Flannel | cni/install-flannel.sh |
Part 1 — kubeconfig Setup¶
Why This Step Is Manual¶
kubeadm init writes /etc/kubernetes/admin.conf as root. Before kubectl can be used as a normal user, this file must be copied to ~/.kube/config with correct ownership. bootstrap-controlplane.sh does not do this automatically — it prints the helper URL instead and defers to the operator.
Running the Helper¶
curl -fsSL https://raw.githubusercontent.com/ibtisam-iq/silver-stack/main/scripts/kubernetes/cluster/kubeconfig-helper.sh | bash
When running as root (not via sudo), the script requires --allow-root to proceed:
What the Script Does¶
User detection (sudo-aware):
| Context | Detected user | kubeconfig written to |
|---|---|---|
sudo bash | $SUDO_USER (the real user) | /home/<user>/.kube/config |
root without sudo | root | /root/.kube/config (only with --allow-root) |
| Normal user | $(whoami) | $HOME/.kube/config |
Steps:
- Detects the real user using
$SUDO_USERwhen run via sudo - Prompts for confirmation before writing (shows which user will be configured)
- Creates
~/.kube/directory - Copies
/etc/kubernetes/admin.confto~/.kube/config - Sets ownership with
chown <user>:<user>and permissions withchmod 600 - Waits 10 seconds for the API server to stabilize, then runs
kubectl cluster-info - Checks for CNI configuration in
/etc/cni/net.d/— if absent, prints the CNI installer command
Verify:
The node will show NotReady until a CNI plugin is installed. This is expected.
Part 2 — CNI Installation¶
Why CNI Is Required¶
Without a CNI plugin, pods cannot receive IP addresses and cannot communicate. The node remains in NotReady state and the scheduler does not place any workloads.
Running the CNI Dispatcher¶
curl -fsSL https://raw.githubusercontent.com/ibtisam-iq/silver-stack/main/scripts/kubernetes/cni/install-cni.sh | sudo bash
install-cni.sh runs a 5-phase safety flow before installing anything:
Phase 1 — Cluster detection: Calls ensure_kubeconfig (from lib/ensure_kubeconfig.sh) then runs kubectl get ns kube-system. If the cluster is not reachable, prints the control plane init command and exits.
Phase 2 — CNI binaries check: Checks if /opt/cni/bin/ is populated. If not, runs runtime/install-cni-binaries.sh automatically before proceeding.
Phase 3 — Filesystem residue detection: Checks /etc/cni/net.d/ for existing .conf or .conflist files. If found, prompts to remove them before continuing to avoid CNI configuration conflicts.
Phase 4 — Active CNI pod detection: Checks for calico-node DaemonSet in calico-system and kube-flannel-ds DaemonSet in kube-flannel. If either is found, requires typed YES confirmation and then runs the corresponding reset script before proceeding.
Phase 5 — CNI selection:
Calico (install-calico.sh)¶
Calico is installed via the Tigera Operator pattern.
What the script does:
- Verifies cluster access
- Detects Pod CIDR from the cluster's
kubeadm-configConfigMap (kube-system/kubeadm-config→ClusterConfiguration.podSubnet) - Checks for an existing
installation.operator.tigera.io/defaultresource — if found, waits up to 60 seconds for it to be removed before continuing - Prompts for encapsulation mode (default:
VXLAN, can override withIPIP) - Resolves the latest Calico version from GitHub API (fallback:
v3.31.2) -
Applies Tigera Operator CRDs:
-
Downloads
custom-resources.yamlto/tmp/calico-install/ - Patches
cidr:andencapsulation:fields usingsed - Applies the patched manifest
- Waits for
calico-systemnamespace to appear - Waits for
calico-kube-controllersDeployment andcalico-nodeDaemonSet to become ready (timeout: 300 seconds each)
Verify:
If the Tigera operator gets stuck on an existing Installation/default resource, the script prints explicit manual recovery commands:
kubectl scale deployment tigera-operator -n tigera-operator --replicas=0
kubectl patch installation.operator.tigera.io default --type=json -p='[{"op":"remove","path":"/metadata/finalizers"}]'
kubectl delete installation.operator.tigera.io default --grace-period=0 --force
Flannel (install-flannel.sh)¶
Flannel is installed via a manifest-patching approach — simpler than Calico's operator model.
What the script does:
- Verifies cluster access
- Detects Pod CIDR from
kubeadm-configConfigMap (same method as Calico) - Downloads the latest Flannel manifest from:
https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml - Patches the
"Network":value in the ConfigMap section of the manifest with the detected Pod CIDR usingsed - Applies the patched manifest with
kubectl apply -f - Waits for
kube-flannelnamespace to appear - Waits for
kube-flannel-dsDaemonSet to be ready (timeout: 300 seconds, polled every 15 seconds)
Verify:
Choosing Between Calico and Flannel¶
| Aspect | Calico | Flannel |
|---|---|---|
| Architecture | Tigera Operator + CRDs | Single manifest (DaemonSet + ConfigMap) |
| Network policy | Full Kubernetes NetworkPolicy + Calico-specific policies | Basic (no native NetworkPolicy enforcement) |
| Encapsulation | VXLAN (default) or IPIP | VXLAN |
| Complexity | Higher (operator, CRDs, namespaces: calico-system, tigera-operator) | Lower (single namespace: kube-flannel) |
| Reset complexity | High — CRDs, finalizers, interfaces, iptables chains | Moderate — namespace, interfaces, routes |
| Best for | Production, NetworkPolicy enforcement, multi-tenant | Simple clusters, labs, single-tenant |
ensure_kubeconfig Library¶
lib/ensure_kubeconfig.sh is a helper function sourced by install-cni.sh, install-calico.sh, and install-flannel.sh. It resolves the correct KUBECONFIG path:
ensure_kubeconfig() {
if [[ -n "${SUDO_USER:-}" ]]; then
export KUBECONFIG="$(getent passwd $SUDO_USER | cut -d: -f6)/.kube/config"
else
export KUBECONFIG="$HOME/.kube/config"
fi
[[ -f "$KUBECONFIG" ]] || error "Kubeconfig not found at: $KUBECONFIG"
}
This prevents kubectl from defaulting to /root/.kube/config when the CNI scripts are run with sudo, which would cause cluster access failures if kubeconfig was set up for a non-root user.