Asked Dejan Lesjak (F9) to create a VM running Debian 13.1.
Tasks:
sudo
,studen
as part of sudo
group.labkey
to manage resources (not sudo
, but probably docker
, see how it works out with Kubernetes)labkey
user:
studen@labkey:~$ sudo mkdir /data0/labkey
studen@labkey:~$ sudo mkdir /data1/labkey
studen@labkey:~$ sudo chown labkey:labkey /data0/labkey
studen@labkey:~$ sudo chown labkey:labkey /data1/labkey
Follow installation instructions. Specifically:
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done;
deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian trixie stable
sudo apt-get install ca-certificates curl
sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
sudo vi /etc/apt/sources.list.d/docker.list
deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian trixie stable
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Add labkey
to docker
sudo usermod -G docker labkey
Now labkey
can start docker
:
studen@labkey:~$ sudo su labkey
labkey@labkey:~$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
The idea is to run a single Node with three Pods - a disk server (/data1/labkey
), database server (/data0/labkey
) and a labkey service.
Start with installing kubeadm. Made sure we are running an LTS kernel:
studen@labkey:~$ uname -r
6.12.48+deb13-amd64
Add repository:
studen@labkey:~$ sudo apt-get install -y apt-transport-https ca-certificates curl gpg
studen@labkey:~$ curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.34/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
studen@labkey:~$ cat /etc/apt/sources.list.d/kubernets.list
deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.34/deb/ /
Install kubelet
kubeadm
kubectl
:
studen@labkey:~$ sudo apt-get install -y kubelet kubeadm kubectl
studen@labkey:~$ sudo apt-mark hold kubelet kubeadm kubectl
From apt: hold is used to mark a package as held back, which will prevent the package from being automatically installed, upgraded or removed.
Kubernets abstracts docker service at the containerd level. The service containerd
is part of the docker
bundle, it gets managed by systemd
,
so status of containerd
is checked by:
studen@labkey:~$ systemctl status containerd
Docker actually ships containerd.io
package which contains both containerd
daemon as well as runc
, an injector service to start a container.
The configuration file /etc/containerd/config.toml
is docker
centric. To fit better with the instructions on container runtime,
it is better to regenerate a default containerd
configuration:
studen@labkey:~$ sudo /bin/bash -c 'containerd config default > /etc/containerd/config.toml'
Change configuration of containerd
to use systemd
driver, since Trixie is recent enough to use cgroup v2 API. Bellow we check for version of cgroup
and highlight SystemdCgroup
setting to true, whereas it was set to false originally.
studen@labkey:~$ stat -fc %T /sys/fs/cgroup/
cgroup2fs
studen@labkey:~$ grep SystemdCgroup /etc/containerd/config.toml
SystemdCgroup = true
Restarting containerd
service runs OK, just complains that there is no CNI at init, which apparently is OK since we didn't start a cluster yet:
studen@labkey:~$ sudo systemctl restart containerd
studen@labkey:~$ sudo systemctl status containerd
[...]
Sep 30 11:25:57 labkey containerd[12742]: time=[...] level=error msg="failed to load cni during init, please check CRI plugin status ..."
While selecting CNI seems to be a crucial point, it is done with kubectl
which won't work until we have the control plane up and running.
To start, disable swap and start the control plane with default parameters.
studen@labkey:~$ sudo swapofff -a
#studen@labkey:~$ sudo kubeadm init
#option to specify IP of the pods
studen@labkey:~$ sudo kubeadm init --pod-network-cidr=10.244.0.0/16
This sets swap off temporarily, at reboot, the same command should be run prior to starting kubeadm
.
Now we can start managing the cluster with kubectl
. Delegate manegement to a temporary user to prevent admin certificate corruption. First, assign cluster-admin
rights to user studen
(see how the second command uses admin.conf
created by kubeadm
). Then, create a kubeconfig
for studen
and move it to default directory for kubeconfig
, ie. ~/.kube/config
. A configuration file clusterConfig.xml
contains basic data of the cluster, which can be extracted using kubectl
and admin.conf
# this is only done once, even after cert in admin/studen.conf expires
studen@labkey:~$ sudo kubectl --kubeconfig /etc/kubernetes/admin.conf create clusterrolebinding studen --clusterrole=cluster-admin --user=studen
# check cluster configuration to generate clusterConfig.yaml
studen@labkey:~$ sudo kubectl --kubeconfig /etc/kubernetes/admin.conf get cm kubeadm-config -n kube-system -o=jsonpath="{.data.ClusterConfiguration}"
# create a temoporary certificate for studen
studen@labkey:~$ sudo kubeadm kubeconfig user --config admin/clusterConfig.yaml --client-name studen --validity-period 24h > admin/studen.conf
# make it the default config for kubectl
# from this point onwards we don't need root
studen@labkey:~$ cp admin/studen.conf .kube/config
#now studen can do administration
studen@labkey:~$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
labkey NotReady control-plane 13d v1.34.1
So there is at least the control node that is available. It seems the configuration is not complete, but at least it is there.
We can also look at config:
studen@labkey:~$ kubectl config view
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: DATA+OMITTED
server: https://178.172.43.129:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: studen
name: studen@kubernetes
current-context: studen@kubernetes
kind: Config
users:
- name: studen
user:
client-certificate-data: DATA+OMITTED
client-key-data: DATA+OMITTED
We can add CNI, which toggles Status to Ready. Some advice on selection of CNI, Flannel seems like a good candidate.
The yml
file used is the one copied from git
studen@labkey:~$ mkdir cni && cd cni
studen@labkey:~$ wget https://github.com/antrea-io/antrea/releases/download/v2.4.3/antrea.yml
# Flannel failed
# studen@labkey:~$ curl https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
#studen@labkey:~$ kubectl apply -f cni/kube-flannel.yml
studen@labkey:~$ cd
studen@labkey:~$ kubectl apply -f cni/antrea.yml
[..]
#Equivalent to docker ps -A
studen@labkey:~$ kubectl get pods -A
NAME STATUS ROLES AGE VERSION
labkey Ready control-plane 15m v1.34.1
Once CNI is applied, all pods should go to Running
stage.
Allow scheduling of pods on control-plane node (since it is a single PC setup):
studen@labkey:~$ kubectl taint nodes --all node-role.kubernetes.io/control-plane-
node/labkey untainted
Test using a sample image:
studen@labkey:~$ kubectl create deployment kubernetes-bootcamp --image=gcr.io/google-samples/kubernetes-bootcamp:v1
deployment.apps/kubernetes-bootcamp created
studen@labkey:~$ kubectl get pods -A
[..]
#after a while
NAMESPACE NAME READY STATUS RESTARTS AGE
default kubernetes-bootcamp-658f6cbd58-sthch 1/1 Running 0 28s
kube-system antrea-agent-b8nfb 2/2 Running 0 4m48s
kube-system antrea-controller-547dbb7586-r6gnv 1/1 Running 0 4m48s
kube-system coredns-66bc5c9577-6r6sw 1/1 Running 0 7m9s
kube-system coredns-66bc5c9577-rfltb 1/1 Running 0 7m9s
kube-system etcd-labkey 1/1 Running 4 7m14s
kube-system kube-apiserver-labkey 1/1 Running 4 7m14s
kube-system kube-controller-manager-labkey 1/1 Running 0 7m15s
kube-system kube-proxy-lqhw6 1/1 Running 0 7m9s
kube-system kube-scheduler-labkey 1/1 Running 14 7m14s
Further details on pod (docker inspect
, docker logs
):
studen@labkey:~$ kubectl describe pod kubernetes-bootcamp-658f6cbd58-sthch
[..]
studen@labkey:~$ kubectl logs kubernetes-bootcamp-658f6cbd58-sthch
Kubernetes Bootcamp App Started At: 2025-10-15T14:18:10.545Z | Running On: kubernetes-bootcamp-658f6cbd58-sthch
Running On: kubernetes-bootcamp-658f6cbd58-sthch | Total Requests: 1 | App Uptime: 77.342 seconds | Log Time: 2025-10-15T14:19:27.887Z
Also, if running kubectl proxy
in a separate shell, one can access ports of image directly:
studen@labkey:~$ curl http://localhost:8001/api/v1/namespaces/default/pods/kubernetes-bootcamp-658f6cbd58-sthch:8080/proxy/
Delete sample deployment:
studen@labkey:~$ kubectl delete deployment kubernetes-bootcamp