# Setting up a private Kubernetes cluster with k0sctl

In my continuing quest for the easiest, fastest way to set up a private Kubernetes cluster (e.g. on home lab server), a solution finally exists: [k0sctl](https://docs.k0sproject.io/v1.21.2+k0s.1/k0sctl-install/). This is an automation to run [k0s](https://github.com/k0sproject/k0s) on nodes that you have SSH access to, e.g. your laptop.

As an optional brief background info, see the previous [private Kubernetes setup guide with plain k0s](/blog/engineering/setting-up-a-private-ml-kubernetes-cluster-with-k0s.md).

## Prerequisites

First, setup the machines that will become nodes in the Kubernetes cluster as [Ubuntu servers](https://ubuntu.com/tutorials/install-ubuntu-server#1-overview). See this previous guide:

{% content-ref url="/pages/-MAHofXnS8nc7OEwb1Mz" %}
[Ubuntu GPU Server Setup](/blog/engineering/ubuntu-gpu-server-setup.md)
{% endcontent-ref %}

Check the [node requirements by k0sctl](https://github.com/k0sproject/k0sctl#spechosts-sequence-required), e.g. the host account must be `root` or have passwordless root access. To do the latter on the node:

1. SSH into the node
2. open sudoers file: `sudo nano /etc/sudoers`
3. below the line `includedir /etc/sudoers.d`, add: `<username> ALL=(ALL) NOPASSWD: ALL` (replace \<username>)

## Installation

[Install k0sctl](https://github.com/k0sproject/k0sctl#package-managers) and [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl-macos/#install-with-homebrew-on-macos) on your laptop (e.g. MacOS) with SSH access to the nodes:

```bash
brew install k0sproject/tap/k0sctl
brew install kubectl
```

## Create Kubernetes cluster

Then, follow the [k0sctl guide](https://docs.k0sproject.io/v1.21.2+k0s.1/k0sctl-install/):

1. Create initial config file.

```bash
k0sctl init > k0sctl.yaml
```

2. Configure nodes in the `hosts` fields, e.g. [choose the appropriate roles](https://github.com/k0sproject/k0sctl#host-fields). Additionally:
   1. Default setup with kuberouter has issues, use Calico instead
   2. Add the [builtin openEBS](https://docs.k0sproject.io/v1.26.2+k0s.1/storage/) for persistent storage (PVC)
   3. Add other Helm charts: cert-manager, Prometheus stack, Grafana

```yaml
apiVersion: k0sctl.k0sproject.io/v1beta1
kind: Cluster
metadata:
  name: k0s-cluster
spec:
  hosts:
    - ssh:
        address: 192.168.12.34
        user: root
        port: 22
        keyPath: ~/.ssh/id_rsa
      role: controller+worker
    - ssh:
        address: 192.168.12.35
        user: root
        port: 22
        keyPath: ~/.ssh/id_rsa
      role: worker
  k0s:
    config:
      apiVersion: k0s.k0sproject.io/v1beta1
      kind: ClusterConfig
      metadata:
        name: k0s-cluster
      spec:
        network:
          provider: calico
        extensions:
          storage:
            type: openebs_local_storage
          helm:
            repositories:
              - name: openebs-cstor
                url: https://openebs.github.io/cstor-operators
            charts:
              - name: openebs-cstor
                chartname: openebs-cstor/cstor
                version: "3.1.0"
                values: |
                  csiNode:
                    kubeletDir: /var/lib/k0s/kubelet/
                namespace: openebs
```

3. Apply to [deploy the cluster](https://docs.k0sproject.io/v1.21.2+k0s.1/k0sctl-install/#3-deploy-the-cluster).

```bash
k0sctl apply --config k0sctl.yaml
```

4. Once cluster is set up, get the kubeconfig for kubectl to access the cluster.

```bash
mkdir -p ~/.kube
k0sctl kubeconfig --config cluster/k0sctl.yaml > ~/.kube/config && chmod go-r ~/.kube/config
# see nodes
kubectl get nodes
# make openebs-hostpath the default storage class
kubectl patch storageclass openebs-hostpath -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
```

That's all! See the [k0sctl doc](https://docs.k0sproject.io/v1.21.2+k0s.1/k0sctl-install/#3-deploy-the-cluster) for more operations, e.g. add nodes, upgrade, reset.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://kengz.gitbook.io/blog/setting-up-a-private-kubernetes-cluster-with-k0sctl.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
