Tips on Using Templating with K3s in KURL

As you may know, we recently started to look at supporting k3s and rke2 to our kURL open source project.

We recently switched our labs to use K3s and I was curious how the Distribution license context template function and the Kubernetes Distribution analyzer would work in this scenario.

First, I used the following kURL spec:

apiVersion: kurl.sh/v1beta1
kind: Installer
metadata:
  name: 'myapp'
spec: 
  k3s: 
    version: "v1.23.3+k3s1"
  registry: 
    version: "latest"
  kotsadm: 
    version: "latest"
    uiBindPort: 30880
    disableS3: true

To test the Distribution license context template function, I added the following label config item:

apiVersion: kots.io/v1beta1
kind: Config
metadata:
  name: example-config
spec:
  groups:
    - name: example_settings
      title: My Example Config
      description: Configuration to serve as an example for creating your own. See [https://kots.io/reference/v1beta1/config/](https://kots.io/reference/v1beta1/config/) for configuration docs. In this case, we provide example fields for configuring an Ingress object.
      items:
      - name: dist
        type: label
        title: "You are Deploying to 'repl{{ Distribution}}'"

Here is the result:

As you can see, the Distribution license context template function resolves to k3s.

Next, what if I want to make sure my application is NOT deployed to k3s? For this we look at the Kubernetes Distribution analyzer.

I first added this preflight spec:

apiVersion: troubleshoot.sh/v1beta2
kind: Preflight
metadata:
  name: example-preflight-checks
spec:
  analyzers:
    - distribution:
        outcomes:
          - fail:
              when: "== docker-desktop"
              message: The application does not support Docker Desktop clusters.
          - fail:
              when: "== microk8s"
              message: The application does not support MicroK8s clusters.
          - fail:
              when: "== minikube"
              message: The application does not support minikube clusters.
          - pass:
              when: "== kurl"
              message: kURL is a supported distribution.      
          - fail:
              when: "== k3s"
              message: K3S is a supported distribution.      
          - pass:
              when: "== eks"
              message: EKS is a supported distribution.
          - pass:
              when: "== gke"
              message: GKE is a supported distribution.
          - pass:
              when: "== aks"
              message: AKS is a supported distribution.
          - warn:
              message: Unable to determine the distribution of Kubernetes.

The above preflight ends up passing:

However, if you put K3s first like so:

apiVersion: troubleshoot.sh/v1beta2
kind: Preflight
metadata:
  name: example-preflight-checks
spec:
  analyzers:
    - distribution:
        outcomes:
          - fail:
              when: "== docker-desktop"
              message: The application does not support Docker Desktop clusters.
          - fail:
              when: "== microk8s"
              message: The application does not support MicroK8s clusters.
          - fail:
              when: "== minikube"
              message: The application does not support minikube clusters.         
          - fail:
              when: "== k3s"
              message: K3S is a supported distribution.
          - pass:
              when: "== kurl"
              message: kURL is a supported distribution.       
          - pass:
              when: "== eks"
              message: EKS is a supported distribution.
          - pass:
              when: "== gke"
              message: GKE is a supported distribution.
          - pass:
              when: "== aks"
              message: AKS is a supported distribution.
          - warn:
              message: Unable to determine the distribution of Kubernetes.

This time we see the result we were looking for (I forgot to update the message):

Based on these results, looks like when we use the analyzer it returns true for both KURL and k3s. Also, based on the results, you can see that the order each outcome matters. The reason is that as the docs state:

Outcomes are evaluated in order until one returns true for the analyzer. Once an outcome returns true, no additional outcomes are evaluated for the analyzer. This allows you to write outcomes as you would a "select" or "switch" statement when programming. If there is no when attribute on an outcome, it will always return true when executed and be the displayed result.

So in our case, since we wanted to fail on k3s (regardless of how it was deployed) we put it before any distribution we would pass, like KURL). A good reminder when working with analyzers in general with multiple conditions to be evaluated for an outcome.

1 Like

Worth noting that if you would like to determine if the k3s cluster was deployed by Kurl or not, you still have the IsKurl Static Context. For example, if we add another label to our Config like this:

apiVersion: kots.io/v1beta1
kind: Config
metadata:
  name: example-config
spec:
  groups:
    - name: example_settings
      title: My Example Config
      description: Configuration to serve as an example for creating your own. See [https://kots.io/reference/v1beta1/config/](https://kots.io/reference/v1beta1/config/) for configuration docs. In this case, we provide example fields for configuring an Ingress object.
      items:
      - name: dist
        type: label
        title: "You are Deploying to 'repl{{ Distribution}}'"
      - name: is-kurl
        type: label
        title: "Provided to you by kURL"
        when: 'repl{{ IsKurl }}'

It will be rendered like this: