> ## Content Index
> Fetch the complete content index at: https://chrisjmccall.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Dell Control Plane
- URL: https://chrisjmccall.com/dell-control-plane/
- Published: 2026-08-26T23:44:30.000Z
- Updated: 2026-08-27T02:07:07.000Z
- Author: Chris McCall

My friend had given me this Dell laptop a while back, he was about to throw it out and I couldn't pass up a free laptop. Up until now I had just used it to play with some amateur radio stuff. It's more recent than my old Mac Mini, so this is my control plane.

### Specs

Dell Inspiron 13-7378  
Intel(R) Core(TM) i7-7500U CPU @ 2.70GHz 2 Core  
Intel HD Graphics 620  
12GB RAM

### Install Ubuntu & Prepare for the Cluster

Download the Ubuntu 26.04 image and write it to a usb drive with Balena Etcher. These are steps to prepare a node that will be joining my cluster that uses cilium as a CNI and gateway. For a different CNI the install can change slightly.

##### Apply Kernel Network Settings

```shell
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables  = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF

# Apply
sudo sysctl --system
```

##### Disable Swap

```shell
sudo swapoff -a

# swapoff won't survive a restart so apply a permanent fix.
# Look for a swap line(look near the last line) and delete any that you see.
sudo vi /etc/fstab/

sudo systemctl daemon-reload
```

##### Install the Container Runtime

You can install from source using the directions [here](https://github.com/containerd/containerd/blob/main/docs/getting-started.md?ref=chrisjmccall.com), but the apt install is much faster.

```shell
sudo apt-get update
sudo apt install containerd
```

Enable the file system overlay module

```shell
sudo modprobe overlay
```

Create the default config file, then edit it so that runc will use the systemd cgroup driver.

```shell
sudo mkdir /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml

# Search the file for
# "plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options"
# and look for the "SystemdCgroup = false" setting and change 
# it to "SystemdCgroup = true"

vi /etc/containerd/config.toml

# Restart containerd
systemctl restart containerd
```

##### Install Kubernetes components

```shell
# Configure apt for the kubernetes repo
sudo apt-get update
sudo apt-get install -y apt-transport-https ca-certificates curl gpg

curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.36/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.36/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list

# Update with the new repo
sudo apt-get update

sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl

sudo systemctl enable --now kubelet
```

##### Use Kubeadm to Initialize the Control Plane

```shell
# Since I'll be using cilium, I don't need kube-proxy
kubeadm init --skip-phases=addon/kube-proxy
```

Copy the join command that kubeadm prints out, you'll be using it later on the worker nodes.

Install the kubeconfig to the default location on the control plane. You can also copy this file locally to use kubectl from your own machine.

```shell
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
```

### Install Cilium

We will use the cilium cli to install cilium.

```shell
# Install the cilium cli
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
CLI_ARCH=amd64
if [ "$(uname -m)" = "aarch64" ]; then CLI_ARCH=arm64; fi
curl -L --fail --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}
sha256sum --check cilium-linux-${CLI_ARCH}.tar.gz.sha256sum
sudo tar xzvfC cilium-linux-${CLI_ARCH}.tar.gz /usr/local/bin
rm cilium-linux-${CLI_ARCH}.tar.gz{,.sha256sum}
```

With the cli installed, now install cilium.

```shell
# Install cilium via the cli
cilium install \
  --helm-set kubeProxyReplacement=true  \
  --helm-set k8sServiceHost=<API_SERVER_IP> \
  --helm-set k8sServicePort=6443
  
# If kube-proxy is removed, cilium should automatically use kubeProxyReplacement
cilium install

# If you want to use BGP Control Plane
cilium install 1.20.1 --set bgpControlPlane.enabled=true

# Verify
cilium status --wait
```

I am going to be using the gatewayAPI to create httpRoutes for my services, so let's get those CRDs installed.

```shell
# GatewayAPI Standard channel
kubectl apply --server-side -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.1/standard-install.yaml

# Update cilium to include gatewayAPI
cilium upgrade --version 1.20.0 \
    --set kubeProxyReplacement=true \
    --set gatewayAPI.enabled=true \
    --set hubble.enabled=false \
```

Starting off, I'm going to use L2 Announcements along with a <myhouse>.internal domain to access services on my local network. 

```shell
# Update cilium to enable l2announcements
cilium upgrade --version 1.20.0 \
    --set kubeProxyReplacement=true \
    --set gatewayAPI.enabled=true \
    --set hubble.enabled=false \
    --set l2announcements.enabled=true \
```

### Good to Go?

These are quick steps to get this node up, but there is more configuration needed for how I would like this machine to function. I will write this up in another post so that this one can stay focused on Kubernetes.