NixOSで好きなコンテナランタイム・CNIを使用してKubernetesを構築する

2025/06/19

はじめに

NixOS は宣言的に構成を定義できるLinuxディストリビューションです。

KubernetesもNixOS上で宣言的に構築できるのですが、この方法を使用した場合、コンテナランタイムにContainerd、CNIにFlannelを使用する構成に限定されてしまいます。

デフォルトで設定されるContainerdやFlannelを明示的に無効化したり別途他のコンテナランタイムやCNIを有効化することはできますが、 Kubernetesと組み合わせて動作させることができませんでした。 (このあたりこのあたりを見る限り、ContainerdやFlannelを使うことが前提とされているのだと思います。)

当方ではコンテナランタイムとしてCRI-O、CNIとしてCiliumを使用したかったので、NixOSでこれらを使用するKubernetesを構築しました。

NixOSのバージョンは25.05です。

一言でいうと

NixOSでの構成はKubeletやKubeadm、およびSystemd service unit fileを設定するにとどめ、クラスタ自体はKubeadmで構築する。

configuration.nix

パッケージとしてkubectlやkubernetes、cilium-cliを設定し、コマンドを使用できるようにします。

  environment.systemPackages = with pkgs; [

(中略)

    cri-o
    kubectl
    kubernetes
    cilium-cli
  ];

コンテナランタイムであるCRI-Oを有効化します。storageDriverはお好みですが、当環境ではbtrfsを使用しています。また後ほどCiliumをインストールするため、そのインストール先となる /opt/cni/bin をCNIプラグインのパスに設定します。

  virtualisation.cri-o = {
    enable = true;
    storageDriver = "btrfs";

    settings.crio.network.plugin_dirs = [ "/opt/cni/bin" ];
  };

KubeletをSystemdで起動できるようにします。以下の内容はKubeletの配布物のUnitファイルKubeadmでセットアップする際のDrop-inを反映した内容にしています。これにより、後でKubeadmを使ってKubernetesクラスタをセットアップしたときに使用できる状態にします。

  systemd.services.kubelet = {
    enable = true;
    description = "kubelet: The Kubernetes Node Agent";
    documentation = [ "https://kubernetes.io/docs/" ];

    path =
      with pkgs;
      [
        util-linux
        iproute2
        ethtool
        iptables
        kubernetes
      ];

    wants = [ "network-online.target" ];
    after = [ "network-online.target" ];

    serviceConfig = {
      Environment= [
        "\"KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf\""
        "\"KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml\""
      ];
      EnvironmentFile = [
        "/var/lib/kubelet/kubeadm-flags.env"
      ];

      Restart = "always";
      RestartSec = "10";
      ExecStart = "${pkgs.kubernetes}/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS";
    };
    unitConfig = {
      StartLimitInterval = "0";
    };

    wantedBy = [ "multi-user.target" ];
  };

kubeadm

あとはKubernetesのドキュメント にあるように通常通りkubeadmによってクラスターを作成します。

当方ではコンフィグファイルで作成しています。

# kubeadm init --config=kubeadm-init.yaml

設定等はお好みですが、当方ではCRI-Oを使用するためにCRIのソケットとしてCRI-Oのパスを設定しています。

$ cat kubeadm-init.yaml
---
apiVersion: kubeadm.k8s.io/v1beta4
kind: InitConfiguration

(中略)

nodeRegistration:
  criSocket: unix:///var/run/crio/crio.sock

CNIをインストールします。当方ではCiliumを使うためCiliumのCLIでインストールします。

$ cilium install

おわりに

宣言型を守れなかったよ。。。