Kubernetes
NixOS
Containerization
DevOps
System Administration

Setting up Kubernetes on NixOS

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Setting up Kubernetes on NixOS is different from a conventional Linux distribution because the cluster configuration is declared in configuration.nix rather than assembled from imperative install steps. The NixOS Kubernetes module can enable the control-plane and node services directly, which makes a small development cluster reproducible once the module options are correct.

Start with the Built-In NixOS Module

For a straightforward single-node development cluster, the built-in services.kubernetes module is the simplest place to start. NixOS supports enabling cluster components individually, but for most first setups the role-based configuration is easier.

A minimal single-node configuration looks like this:

nix
1{ config, pkgs, ... }:
2
3{
4  environment.systemPackages = with pkgs; [
5    kubectl
6    kubernetes
7  ];
8
9  services.kubernetes = {
10    roles = [ "master" "node" ];
11    masterAddress = "localhost";
12    easyCerts = true;
13    addons.dns.enable = true;
14  };
15}

The important option here is masterAddress. The NixOS module requires it, and every node in the cluster must be able to resolve and reach that address. For a local single-node cluster, localhost is acceptable.

Apply the Configuration

After editing /etc/nixos/configuration.nix, rebuild the system:

bash
sudo nixos-rebuild switch

Then check the services:

bash
systemctl status kube-apiserver
systemctl status kubelet
systemctl status etcd

Service names can vary depending on the enabled components, but the main goal is to confirm that the API server, kubelet, and supporting services started without certificate or networking errors.

Access the Cluster with kubectl

When easyCerts is enabled, NixOS generates an administrative kubeconfig for the cluster. Export it before using kubectl as an administrator:

bash
export KUBECONFIG=/etc/kubernetes/cluster-admin.kubeconfig
kubectl get nodes

On a working single-node setup, you should see the local machine listed as a node. This kubeconfig is typically owned by root, so administrative access usually happens from a root shell or with sudo.

A Multi-Node Shape

For a worker node, the module configuration is smaller. The host only needs the node role plus a reachable master address.

Example worker configuration:

nix
1{ config, pkgs, ... }:
2
3{
4  services.kubernetes = {
5    roles = [ "node" ];
6    masterAddress = "kube-master.example.internal";
7    easyCerts = true;
8  };
9}

After the worker machine is rebuilt, NixOS provides a helper script named nixos-kubernetes-node-join. The usual flow is:

  1. obtain the bootstrap token from the master
  2. feed that token to nixos-kubernetes-node-join on the worker
  3. let certificate services issue and install the required keypairs

That is much less manual than hand-assembling kubeconfigs, but it still depends on working DNS and network reachability.

Networking and Firewall Reality

Most early failures are not about Kubernetes itself. They are about networking:

  • 'masterAddress does not resolve on the worker'
  • the firewall blocks pod or control-plane traffic
  • container networking is up, but DNS inside the cluster is not

If the cluster looks half alive, inspect logs before editing random options:

bash
journalctl -u kubelet -n 100
journalctl -u kube-apiserver -n 100

For a simple local development cluster, some users choose to relax firewall rules while proving the setup works, then harden them afterward. The exact rule set depends on the cluster topology and CNI behavior.

When to Use K3s Instead

The built-in Kubernetes module is powerful, but it is still a full Kubernetes stack. If your real goal is "a lightweight local cluster on NixOS," K3s is often easier operationally because it packages more of the control-plane complexity for you.

That is not a criticism of the NixOS module. It is just the practical distinction:

  • use the built-in module when you want a more direct Kubernetes layout on NixOS
  • use K3s when you want a smaller and easier local cluster

For learning or testing declarative NixOS service configuration, the built-in module is still valuable because everything is visible in one place.

Keep the Configuration Reproducible

One of the main advantages of NixOS is that the cluster configuration is declared in code. Take advantage of that:

  • keep configuration.nix under version control
  • add kubectl and related tools explicitly to environment.systemPackages
  • avoid one-off manual changes that are not represented declaratively

If the cluster stops working after a later change, you can diff the Nix configuration rather than guessing what someone installed by hand weeks ago.

Common Pitfalls

The most common mistake is omitting masterAddress. The NixOS Kubernetes module expects it, and workers need a value they can actually resolve and reach.

Another frequent issue is forgetting to export KUBECONFIG to the cluster-admin kubeconfig generated by the module. kubectl then appears broken when the real problem is authentication context.

Networking is the next big source of pain. A node can boot with Kubernetes services running and still fail to join correctly because DNS, routing, or firewall rules are wrong.

Finally, do not choose a full Kubernetes deployment path when a lightweight local cluster would meet the need. On NixOS, that design choice matters as much as the individual options.

Summary

  • NixOS can run Kubernetes declaratively through services.kubernetes.
  • For a single-node dev cluster, roles = [ "master" "node" ], masterAddress, and easyCerts are the key starting options.
  • Rebuild with nixos-rebuild switch and use the generated cluster-admin kubeconfig with kubectl.
  • For multi-node setups, workers use the node role and join with nixos-kubernetes-node-join.
  • Most setup failures come from address resolution, certificates, or firewall and networking issues rather than from NixOS itself.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.