K3s and k3d Orchestration within Docker Environments

The convergence of lightweight Kubernetes distributions and containerization technologies has revolutionized the landscape of local development and edge computing. At the center of this shift is K3s, a CNCF-certified Kubernetes distribution and Sandbox project meticulously engineered for low-resource environments. By distributing the software as a single binary, K3s minimizes the operational overhead typically associated with Kubernetes, requiring under 512MB of RAM to function. This efficiency allows K3s to operate effectively in constrained environments where traditional Kubernetes would be prohibitively resource-intensive.

Building upon the foundation of K3s is k3d, a specialized tool designed to run K3s clusters within Docker containers. This architecture allows for the creation of throwaway Kubernetes clusters anywhere Docker is installed. By utilizing Docker images built from the K3s repository, k3d enables the deployment of multiple K3s nodes as containers on a single physical or virtual machine, referred to as the Docker Host. This capability allows a developer to maintain multiple simultaneous K3s clusters, each consisting of its own server and agent nodes, without the need for multiple virtual machines or physical hardware.

The primary objective of this ecosystem is to facilitate local development on Kubernetes with minimal hassle. By providing a production-like environment on a development machine, developers can achieve faster iteration times. This is a significant improvement over traditional local development patterns, such as using docker-compose, as it allows the developer to test orchestration logic, networking, and state management within a real Kubernetes framework before deploying to production.

K3s Architecture and Resource Specifications

K3s is designed to be a lightweight alternative to standard Kubernetes, removing unnecessary legacy code and optimizing the binary for performance and size. This design philosophy ensures that the distribution can run on a wide variety of hardware, from powerful workstations to edge devices.

Specification Detail
Certification CNCF-certified Kubernetes distribution
Distribution Format Single binary
RAM Requirement Under 512MB
Project Status Sandbox project

The impact of the single-binary distribution is profound for the end user, as it simplifies the installation process and reduces the potential for dependency conflicts. In a real-world scenario, this means a developer can spin up a cluster on a laptop or a Raspberry Pi without worrying about the complex configuration of multiple system components. Contextually, this lightweight nature is what allows k3d to wrap K3s inside Docker containers without incurring the heavy resource penalties that would accompany a full Kubernetes installation.

Deploying K3s via Docker Runtime

While k3d provides a high-level abstraction for cluster management, K3s can be run directly using Docker images. This is particularly useful for users who require granular control over the container runtime or who are integrating K3s into existing Docker-based orchestration pipelines.

Rancher provides specific Docker images to run the K3s server and agent. The images are hosted on Docker Hub under the rancher/k3s repository. For example, a user might pull a specific version such as rancher/k3s:v1.36.1-k3s1.

To deploy a K3s server using the docker run command, the following configuration is required:

bash sudo docker run \ --privileged \ --name k3s-server-1 \ --hostname k3s-server-1 \ -p 6443:6443 \ -d rancher/k3s:v1.24.10-k3s1 \ server

In this command, the --privileged flag is critical as it allows the container to access the host's kernel features necessary for Kubernetes to manage networking and storage. The port mapping -p 6443:6443 exposes the Kubernetes API server to the host machine, enabling communication between the host and the cluster.

There are strict requirements regarding image tags. Users must specify a valid K3s version as the tag because the latest tag is not maintained. Furthermore, due to Docker's tagging restrictions, the + sign is not permitted in tags; developers must use a - instead. Failure to adhere to these naming conventions will result in image pull failures.

Once the K3s server is operational, the admin kubeconfig must be extracted from the container to allow kubectl to interact with the cluster. This is achieved using the docker cp command:

bash sudo docker cp k3s-server-1:/etc/rancher/k3s/k3s.yaml ~/.kube/config

This action moves the configuration file from the internal container path /etc/rancher/k3s/k3s.yaml to the local user's .kube/config directory, effectively granting the user administrative access to the K3s cluster.

k3d Functional Capabilities and Use Cases

k3d acts as a wrapper around K3s, automating the complexities of container orchestration. Since the release of version v4.0.0 in January 2021, k3d has expanded its feature set to include comprehensive cluster lifecycle management.

The core abilities of k3d include:

  • Create, stop, start, and delete K3s clusters and individual nodes.
  • Grow or shrink the size of existing clusters by adding or removing nodes.
  • Manage cluster configuration via command line flags or configuration files.
  • Interact with and manage container registries for use within the cluster.
  • Automate the management of Kubeconfigs for various clusters.
  • Import images from the local Docker daemon directly into the container runtime used by the cluster.

These features allow developers to treat Kubernetes clusters as ephemeral resources. The ability to "grow" or "shrink" a cluster enables the testing of scaling scenarios without needing to provision new physical hardware. The image import feature is particularly impactful, as it removes the need to push images to a remote registry before they can be used in the cluster, thereby accelerating the development cycle.

The primary use case is local development. By utilizing k3d, developers avoid the "it works on my machine" syndrome by running a production-like environment locally. This contrasts with using docker-compose, which only tests container isolation and networking but does not test Kubernetes-specific concepts like Pods, Deployments, Services, and Ingress.

k3d Cluster Deployment Strategies

k3d provides multiple ways to spawn clusters, ranging from simple defaults to sophisticated, highly configured environments.

The "Simple" Way involves a basic command:

bash k3d cluster create

Executing this command results in the deployment of two containers: a Kubernetes control-plane node (server) and a load balancer (serverlb). The load balancer is placed in front of the server to manage traffic. These components are isolated within a dedicated Docker network. The Kubernetes API is exposed on a randomly chosen free port on the Docker host to avoid collisions with other services.

By default, if no name is provided, the cluster is named k3s-default. The resulting containers follow a specific naming convention: k3d-<-role>-<#>. For example, the load balancer would be named k3d-k3s-default-serverlb and the server would be k3d-k3s-default-server-0.

k3d automates the post-deployment configuration by pulling the Kubeconfig from the cluster and merging it with the user's default Kubeconfig, typically located at $HOME/.kube/config or the path specified by the KUBECONFIG environment variable.

The "Simple but Sophisticated" Way allows for granular control over the cluster's architecture. A comprehensive example is:

bash k3d cluster create mycluster --api-port 127.0.0.1:6445 --servers 3 --agents 2 --volume '/home/me/mycode:/code@agent[*]' --port '8080:80@loadbalancer'

This command generates a six-container architecture:

  • 1 load balancer
  • 3 servers (control-plane nodes)
  • 2 agents (worker nodes)

The --api-port 127.0.0.1:6445 flag maps the internal Kubernetes API port (6443) to the host's port 6445. The --volume flag mounts a local directory (/home/me/mycode) into the agent nodes at /code, enabling live code updates. The --port flag maps host port 8080 to the load balancer's port 80.

Installation and Environment Configuration

The installation of K3s and k3d requires a Docker-enabled environment. For users who do not have Docker installed, Rancher provides a script to facilitate the installation:

bash curl https://releases.rancher.com/install-docker/20.10.sh | sh -

Once Docker is operational, K3s can be installed using the --docker option, which tells K3s to use Docker as the container runtime:

bash curl -sfL https://get.k3s.io | sh -s - --docker -

To verify the cluster's health and the status of the pods, users can run:

bash sudo k3s kubectl get pods --all-namespaces

The output of this command provides a detailed view of the running system components, such as the local-path-provisioner, metrics-server, coredns, and traefik. For instance, traefik serves as the ingress controller, enabling external traffic to reach services within the cluster.

Verification of the underlying Docker containers is performed using:

bash sudo docker ps

This command reveals the actual containers running on the host, including rancher/klipper-lb for load balancing and rancher/pause for pod infrastructure.

SELinux Integration and Security

On systems where SELinux (Security-Enhanced Linux) is enabled by default, such as CentOS, K3s requires specific SELinux policies to function correctly. Without these policies, the container runtime may be blocked from performing necessary operations, leading to cluster failure.

K3s supports two methods of SELinux policy installation:

  • Automatic Installation: The K3s install script automatically installs the required SELinux RPM from the Rancher RPM repository if the system is compatible and not performing an air-gapped installation.
  • Manual Installation: Users can manually install the policies if automatic installation is not applicable.

This integration ensures that the security posture of the host system is maintained while allowing the Kubernetes distribution to operate with the necessary permissions.

Detailed Analysis of k3d Implementation

The operational logic of k3d is centered on the concept of "Containers in Containers" or "Clusters in Containers." When a user creates a cluster, k3d creates a dedicated Docker network to ensure isolation between different clusters on the same host.

A critical component of this is the named Docker volume created in the background. This volume serves as a staging area for image imports. When a user imports a local Docker image into the cluster, k3d utilizes this volume to transfer the image from the host's Docker daemon to the container runtime running inside the K3s node.

Another advanced configuration is the use of k3d-dind (Docker-in-Docker). In this scenario, the user only has a single container running on the Docker host, which in turn runs an entire K3s/Kubernetes cluster inside. This provides an additional layer of isolation and is particularly useful for CI/CD pipelines where a completely clean environment is required for every test run.

To manage these environments, k3d provides a comprehensive set of CLI tools. Users can list their current infrastructure using:

bash k3d cluster list

bash k3d node list

bash k3d registry list

These commands allow for rapid auditing of the current state of the local development environment, enabling the user to identify which clusters are active and which nodes are operational.

Conclusion

The integration of K3s within Docker, augmented by the k3d toolset, represents a paradigm shift in how Kubernetes is accessed and utilized for development. By reducing the resource footprint to under 512MB of RAM and consolidating the distribution into a single binary, K3s removes the traditional barriers to entry for Kubernetes. The ability to run these clusters as Docker containers allows for an unprecedented level of flexibility, enabling developers to spawn, scale, and destroy complex multi-node environments in seconds.

The strategic advantage of this approach lies in the ability to mirror production environments—including load balancers, multiple control planes, and worker nodes—on a single local machine. This eliminates the gap between development and production, reducing the risk of deployment failures. Furthermore, the support for SELinux and the automation of Kubeconfig management ensure that the experience is seamless across different Linux distributions. As the industry moves further toward edge computing and microservices, the capacity to run lightweight, containerized Kubernetes clusters will remain a critical competency for DevOps engineers and software developers alike.

Sources

  1. Introduction to k3d: Run K3s in Docker
  2. K3s Advanced Documentation
  3. Docker Hub: rancher/k3s

Related Posts