My First Experience with Kubernetes
TheJoeCoder
728 Words … ⏲ Reading Time:3 Minutes, 18 Seconds
2025-10-24 19:10 +0100
I’ve never really looked at Kubernetes before. My home servers run all my services on Docker via docker compose, and that’s about it. But hey, it’s about time I try to install it - and I’ll learn about Debian preseeding and Ansible while I’m there.
Operating System Installation
Step 1: what operating system are we going to use? My choice is Debian because… it’s what I’ve always used and it’s worked fine.
Debian has a way of auto-installing via a preseed config file - it’s like the Windows autounattend.xml but for Debian. It’s called preseed.cfg, and it’s stored in either the root of the installation drive, or at a URL which can be specified via the install config or DHCP.
It’s of this format:
#_preseed_V1
# Preseeding only locale sets language, country and locale.
d-i debian-installer/locale string en_GB.UTF-8
# Any hostname and domain names assigned from dhcp take precedence over
# values set here. However, setting the values still prevents the questions
# from being shown, even if values come from dhcp.
d-i netcfg/get_hostname string unassigned-hostname
d-i netcfg/get_domain string unassigned-domain
d-i netcfg/hostname string somehost
# Mirror protocol
d-i mirror/country string manual
d-i mirror/http/hostname string uk.mirrors.clouvider.net
d-i mirror/http/directory string /debian
d-i mirror/http/proxy string
# Skip creation of a root account (normal user account will be able to
# use sudo).
d-i passwd/root-login boolean false
# To create a normal user account.
d-i passwd/user-fullname string User
d-i passwd/username string user
d-i passwd/user-password password insecure
d-i passwd/user-password-again password insecure
Check the docs for more info.
You can also specify an encrypted password. Use mkpasswd -m sha-512 from the whois package, and then put it in d-i passwd/user-password-crypted password [crypt(3) hash] in the file.
For my purposes, though, it boils down to:
- Copy the files from the Debian install ISO to a FAT32-formatted USB drive.
- Create the
preseed.cfgfile in the root of the drive boot/grub/grub.cfg, edit the menu entry for graphical install to use the preseed file:
menuentry --hotkey=g 'Graphical install (Preseed)' {
set background_color=black
linux /install.amd/vmlinuz vga=788 language=en country=GB preseed/file=/cdrom/preseed.cfg --- quiet
initrd /install.amd/gtk/initrd.gz
}
k3s Installation
Now that Debian is installed, we can install k3s.
Luckily someone has done the work for us and has created Ansible playbooks for installing and upgrading the cluster, etc.
Before anything, let’s install kubectl on our local machine, and since my laptop runs Manjaro I’ll do this through pacman:
sudo pacman -S kubectl
In my repo for these experiments, I have an ansible directory already set up with everything.
All that’s needed is to copy the inventory-sample.yml file to inventory.yml and add your hosts. Oh, and create a new file called ssh_pubkey with your SSH key in.
Then run the playbooks:
# Get the base set up
ansible-playbook pre-install-k3s.yaml -i inventory.yml -kK
# Install ansible k3s requirements
ansible-galaxy install -r roles/requirements.yml
# Run the setup playbook
ansible-playbook k3s.orchestration.site -i inventory.yml -K
That should be it!
And now we can set our cluster environment and see what we’ve got:
kubectl config use-context k3s-ansible
kubectl get nodes
Hmm. Context doesn’t exist. I was having some problems with it copying the config to my local machine, so I’ll set it up manually:
# First copy /etc/rancher/k3s/k3s.yaml on the primary node to ~/.kube/config on your local machine
# Then:
sed -i 's/default/k3s-ansible/g' ~/.kube/config
kubectl config set-context k3s-ansible --user=k3s-ansible --cluster=k3s-ansible
kubectl config use-context k3s-ansible
kubectl config set-cluster k3s-ansible --server=https://master.kubernetes.com:6443
And now run kubectl get nodes and…
NAME STATUS ROLES AGE VERSION
ingrid Ready control-plane 22m v1.34.1+k3s1
torgny Ready <none> 21m v1.34.1+k3s1
Woohoo! We have nodes!
Let’s run an example deployment, courtesy of NetworkChuck:
kubectl create deploy networkchuckcoffee --image=thenetworkchuck/nccoffee:pourover --port=80
kubectl get pods
And when we get pods, we can find this:
NAME READY STATUS RESTARTS AGE
networkchuckcoffee 1/1 Running 0 2m5s
But you’ll notice we can’t get to the app on port 80 of any of the nodes. That’s because we need to expose it:
kubectl expose deploy networkchuckcoffee --type=NodePort --port=80 --protocol=TCP --name=nccoffee-web
Then find the port to connect to:
kubectl get svc nccoffee-web -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
nccoffee-web NodePort 10.43.181.57 <none> 80:31927/TCP 3s app=networkchuckcoffee
Connect to any host port 31927, and we get a web page!
Conclusion
That’s it for now - I’ll either make a new post or update this one when I keep working on this. I plan to run some deployments, then get some Helm charts up and running!