Nicklas Wiegandt

Use K3OS system Traefik with Let’s Encrypt

How to use K3OS system Traefik with Let’s Encrypt.

The problem

K3OS comes with a system Traefik. Nice so we can use it to route our services and give them with Let’s Encrypt HTTPS. Yes!

But how to configure it to do what we want? There is a configuration file: /var/lib/rancher/k3s/server/manifests/traefik.yaml

Seems to work pretty well so where is the problem? If you reboot your server or, like in my case your provider restarts your server, all Traefik configuration is lost.

The solution

K3OS has some persistent directories and /var/lib/rancher/k3s/server/manifests isn’t one. Ok but the documentation says that you can write manifests with the configuration key write_files. But there’s another stumbling block! Per default K3OS overwrites the Traefik configuration on each boot.

So here is the solution, you need to add this to your K3OS configuration:

/var/lib/rancher/k3os/config.yaml
  k3s_args:
  - server
  - "--no-deploy=traefik"

Now don’t forget to write the Traefik configuration with write_files:

/var/lib/rancher/k3os/config.yaml
write_files:
- content: |-
    apiVersion: helm.cattle.io/v1
    kind: HelmChart
    metadata:
      name: traefik
      namespace: kube-system
    spec:
      chart: https://%{KUBERNETES_API}%/static/charts/traefik-1.81.0.tgz
      set:
        rbac.enabled: "true"
        ssl.enabled: "true"
        ssl.enforced: "true"
        acme.enabled: "true"
        acme.challengeType: "tls-alpn-01"
        acme.email: "admin@yourdomain.com"
        acme.staging: "false"
        metrics.prometheus.enabled: "true"
        kubernetes.ingressEndpoint.useDefaultPublishedService: "true"
        image: "rancher/library-traefik"
  owner: root
  path: /var/lib/rancher/k3s/server/manifests/traefik.yaml
  permissions: '0755'

A complete configuration could look like this:

/var/lib/rancher/k3os/config.yaml
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
k3os:
  k3s_args:
  - server
  - "--no-deploy=traefik"
sshAuthorizedKeys:
- github:yourGithubUserName
write_files:
- content: |-
    apiVersion: helm.cattle.io/v1
    kind: HelmChart
    metadata:
      name: traefik
      namespace: kube-system
    spec:
      chart: https://%{KUBERNETES_API}%/static/charts/traefik-1.81.0.tgz
      set:
        rbac.enabled: "true"
        ssl.enabled: "true"
        ssl.enforced: "true"
        acme.enabled: "true"
        acme.challengeType: "tls-alpn-01"
        acme.email: "admin@yourdomain.com"
        acme.staging: "false"
        metrics.prometheus.enabled: "true"
        kubernetes.ingressEndpoint.useDefaultPublishedService: "true"
        image: "rancher/library-traefik"
  owner: root
  path: /var/lib/rancher/k3s/server/manifests/traefik.yaml
  permissions: '0755'

How to use it for a container

In case you are reading this and do not know how to use Traefik with your container now, here is how it works:

It’s super simple! :) Of course your domain has to be configured to point to your server for all domains you wan’t to use. Your Traefik configuration has to be correct to. How to do this is documented in the Traefik documentation and there is a example in the solution above. If these basic conditions are fulfilled it is super easy.

To instruct Traefik to route a subdomain with HTTPS to a service you just need to create a Ingress for your service:

---
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
  name: myservice-ingress
  namespace: myservice

spec:
  rules:
    - host: service.mydoma.in
      http:
        paths:
          - path: /
            backend:
              serviceName: my-service
              servicePort: 8080

A complete service description inclunding Ingress could look like this:

README.md view raw
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
apiVersion: v1
kind: Namespace
metadata:
  name: mediathekview
---
apiVersion: v1
kind: Service
metadata:
  name: zapp-backend
  namespace: mediathekview

spec:
  ports:
    - name: http
      protocol: TCP
      port: 3000
  selector:
    app: zapp-backend
---
kind: Deployment
apiVersion: apps/v1
metadata:
  namespace: mediathekview
  name: zapp-backend
  labels:
    app: zapp-backend

spec:
  replicas: 1
  selector:
    matchLabels:
      app: zapp-backend
  template:
    metadata:
      labels:
        app: zapp-backend
    spec:
      containers:
        - name: zapp-backend
          image: mediathekview/zapp-backend
          ports:
            - name: web
              containerPort: 3000
---
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
  name: zapp-backend-ingress
  namespace: mediathekview

spec:
  rules:
    - host: api.zapp.mediathekview.de
      http:
        paths:
          - path: /
            backend:
              serviceName: zapp-backend
              servicePort: 3000