Test environment#
The test environment is based upon virtual machines and created with Vagrant and libvirt. You need a quiet powerful machine to run the full test environment. It can create up to three systems with the following configuration:
Virtual Machine Specifications#
- k3svm1: The server node of the k3s cluster
- 4096MB RAM
- 4 CPU threads
- Role: k3s server (control plane)
- k3svm2: The first worker node of the k3s cluster
- 2048MB RAM
- 2 CPU threads
- Role: k3s server (control plane)
- k3svm3: The second worker node of the k3s cluster
- 2048MB RAM
- 2 CPU threads
- Role: k3s agent (worker)
Total resources required: 8192MB RAM and 8 CPU threads when running all three VMs.
Architecture Decision#
I decided to base the test environment on virtual machines because I also test different network plugins. This is much easier to do with virtual machines than with containers. Another requirement is ansible, which I use to initially install k3s. This also needs to be tested. During deployment Vagrant uses the same ansible playbook to provision the system(s) as the one used for the production environment. Just the vars are a bit different and can be adjusted in the ansible/inventory/vagrant/group_vars/all/main.yaml file.
File Organization#
In the subfolder ./shared/${HOSTNAME}/ are files for the configuration of the k3s cluster, like the kubeconfig.
The folder ./shared gets also mounted to the virtual machines. This is the place where you can put files you want to share with the virtual machines. Though this requires memory_backing_dir = "/dev/shm" in /etc/libvirt/qemu.conf.
libvirt Configuration Required
The shared folder mounting requires the following configuration in /etc/libvirt/qemu.conf:
Prerequisites#
Before setting up the test environment, ensure you have:
- Virtualization support: CPU with VT-x/AMD-V enabled in BIOS
- libvirt: KVM/QEMU virtualization platform installed
- Vagrant: Version 2.3.0 or higher
- Sufficient resources: At least 8GB free RAM and 8 CPU threads for full cluster
- Disk space: Minimum 20GB free for VM images and data
Setting up vagrant#
At first install vagrant for your system. This wont be covered here. Please refer to the vagrant documentation.
Add the libvirt plugin:
Using Docker Container (Recommended)
If you have, like me, dependency problems with the libvirt plugin, you can use the vagrant-libvirt docker container. I recommend you to use my extended vagrant-libvirt-ansible container with added ansible. Ansible is required for provisioning and by default not installed in the standard vagrant-libvirt container.
To use the container:
Starting the Test Environment#
Full Cluster Deployment#
Start the complete test environment with all three nodes:
This will:
- Create three VMs (k3svm1, k3svm2, k3svm3)
- Run the Ansible playbook
ansible/playbooks/install.yaml - Install k3s on the server node
- Join worker nodes to the cluster
- Copy kubeconfig to
shared/k3svm1/k3s.yaml
Provisioning Time
The initial provisioning can take 10-15 minutes depending on your system resources and internet connection. After the Vagrant provisioning completes, allow an additional 2-3 minutes for k3s to fully initialize.
Single Node Deployment#
Start only the server node (which is enough for many tests):
This creates a single-node cluster that is sufficient for testing:
- Application deployments
- ArgoCD functionality
- Kustomize configurations
- Secret management with SOPS
- Basic networking
Accessing the Cluster#
After the installation is finished, it can still take some time till the k3s service is up and running.
The ansible ansible/playbooks/install.yaml playbook, which vagrant automatically runs, will copy the kubeconfig from the server node to shared/k3svm1/k3s.yaml. You can use this file to access the test k3s cluster.
Set the KUBECONFIG environment variable:
Verify cluster access:
Adding additional Nodes#
Start the worker nodes separately if needed. Ansible will automatically join the worker nodes to the k3s cluster.
When to Use Worker Nodes
Worker nodes are useful for testing:
- Multi-node scheduling
- Pod anti-affinity rules
- Node selectors and taints
- Storage replication (Longhorn)
- High availability scenarios
SSH Access#
Once your virtual machine is up and running, you can log in to it:
Useful commands inside the VM:
Destroying the Environment#
Destroy the test environment and reclaim resources:
To destroy a specific VM:
Testing Workflows#
Deploying Applications#
Once the cluster is running, you can test application deployments:
Testing ArgoCD#
Deploy ArgoCD to the test cluster:
Port-forward to access ArgoCD UI:
Testing Network Policies#
When testing Cilium network policies, use Hubble:
Vagrant Snapshots#
Create snapshots for quick rollback:
Troubleshooting#
Vagrant Issues#
Sometimes vagrant has conflicts with OS packages resulting in messages like this:
conflicting dependencies date (= 3.2.2) and date (= 3.3.4)
Set the following environment variable to ignore gem versions or directly use my vagrant-libvirt-ansible container:
VM Won't Start#
Check libvirt status:
View libvirt logs:
k3s Service Not Starting#
SSH into the VM and check k3s status:
Kubeconfig Not Working#
Ensure the kubeconfig file exists:
If missing, manually copy from VM:
Cleaning Up#
If VMs are in an inconsistent state:
Performance Optimization#
Reducing Resource Usage#
For limited hardware, modify the Vagrantfile to reduce resources: