Install K3s With MetalLB and Ingress NGINX Controller

Why should we change the Loadbalancer and Ingress Controller for k3s ? If you want to use your network IPs and use multiple tcp/udp ports, the standard ServiceLB and the configured k3s Traefik Ingress Controller will not do the job.

In this post I will explain how you can install k3s with MetalLB and Ingress NGINX Controller .

Configure Network Interface

First of all, we should configure our local interface to support multiple local IPs.

For that, we will create following file /etc/network/interfaces.d/metallb. In this example, our interface is enp0s5 and we want to configure the range 10.10.0.151-10.10.0.162

 1  auto enp0s5
 2  allow-hotplug enp0s5
 3  iface enp0s5 inet dhcp
 4  up ip addr add 10.10.0.151/24 dev $IFACE label $IFACE:0
 5  down ip addr del 10.10.0.151/24 dev $IFACE label $IFACE:0
 6  up ip addr add 10.10.0.152/24 dev $IFACE label $IFACE:1
 7  down ip addr del 10.10.0.152/24 dev $IFACE label $IFACE:1
 8  up ip addr add 10.10.0.153/24 dev $IFACE label $IFACE:2
 9  down ip addr del 10.10.0.153/24 dev $IFACE label $IFACE:2
10  up ip addr add 10.10.0.154/24 dev $IFACE label $IFACE:3
11  down ip addr del 10.10.0.154/24 dev $IFACE label $IFACE:3
12  up ip addr add 10.10.0.155/24 dev $IFACE label $IFACE:4
13  down ip addr del 10.10.0.155/24 dev $IFACE label $IFACE:4
14  up ip addr add 10.10.0.156/24 dev $IFACE label $IFACE:5
15  down ip addr del 10.10.0.156/24 dev $IFACE label $IFACE:5
16  up ip addr add 10.10.0.157/24 dev $IFACE label $IFACE:6
17  down ip addr del 10.10.0.157/24 dev $IFACE label $IFACE:6
18  up ip addr add 10.10.0.158/24 dev $IFACE label $IFACE:7
19  down ip addr del 10.10.0.158/24 dev $IFACE label $IFACE:7
20  up ip addr add 10.10.0.159/24 dev $IFACE label $IFACE:8
21  down ip addr del 10.10.0.159/24 dev $IFACE label $IFACE:8
22  up ip addr add 10.10.0.160/24 dev $IFACE label $IFACE:9
23  down ip addr del 10.10.0.160/24 dev $IFACE label $IFACE:9
24  up ip addr add 10.10.0.161/24 dev $IFACE label $IFACE:10
25  down ip addr del 10.10.0.161/24 dev $IFACE label $IFACE:10
26  up ip addr add 10.10.0.162/24 dev $IFACE label $IFACE:11
27  down ip addr del 10.10.0.162/24 dev $IFACE label $IFACE:11

Install Helm

We will use Helm for the installation of MetalLB and Ingress NGINX Controller .

If you already have Helm , you can skip this. We are using Debian on our system, if you are using another Linux Distribution look at the Helm installation documentation .

1  curl https://baltocdn.com/helm/signing.asc | sudo apt-key add -
2  sudo apt-get install apt-transport-https --yes
3  echo "deb https://baltocdn.com/helm/stable/debian/ all main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list
4  sudo apt-get update
5  sudo apt-get install helm

Install k3s

Now we can install k3s , where we need to make sure, that we disable the ServiceLB and Traefik .

At this point we will also configure the local storage path, in this case it would be /mnt/data/k3s/storage.

1  curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable traefik --disable servicelb --default-local-storage-path /mnt/data/k3s/storage" sh -

To make sure, that kubectl is using the right configuration, we need to set the environment variable KUBECONFIG to /etc/rancher/k3s/k3s.yaml.

You can add it to your .profile or set it for the current session:

1  export KUBECONFIG=/etc/rancher/k3s/k3s.yaml

Install MetalLB

First of all, we need the configuration file (metallb.yaml) for MetalLB , were we configure the IP range which we want to use. In our case 10.10.0.151-10.10.0.162

1  configInline:
2    address-pools:
3      - name: default
4        protocol: layer2
5        addresses:
6          - 10.10.0.151-10.10.0.162

Now we can install MetalLB using Helm and our configuration file.

1  helm upgrade --install metallb metallb \
2  --repo https://metallb.github.io/metallb \
3  -f metallb.yaml

Thats it, MetalLB is now installed and configured for our k3s installation.

Install Ingress NGINX Controller

I choosed the Ingress NGINX Controller , because for my use case at home, it provides all what I need, without needing complicated configuration. As an alternative, you could install your own configured Traefik Ingress Controller , which provides more options than the preconfigured from k3s .

We need a small configuration to make it the default ingress controller, put this into the file nginx.yaml.

1  controller:
2    ingressClassResource:
3      default: true

And now install Ingress NGINX Controller using Helm .

1helm upgrade --install ingress-nginx ingress-nginx \
2  --repo https://kubernetes.github.io/ingress-nginx \
3  --namespace ingress-nginx --create-namespace \
4  -f nginx.yaml

One more thing: Certmanager

To handle our SSL certificates automatically, we will use Certmanager , which can use Let’s Encrypt to generate and renew our certificates.

Certmanager provides a ready to use k8s configuration. You just need to make sure, that you are using the latest version (currently it’s version 1.10.1).

1  kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.10.1/cert-manager.yaml

Now we need to configure Let’s Encrypt and the validation method. In our case, we are using Cloudflare DNS validation .

We will need a secret (cf-secret.yaml) were we will save our Cloudflare API token. (Unfortunately, I was not able to get it working with encoded secret)

1  apiVersion: v1
2  kind: Secret
3  metadata:
4    name: cloudflare-api-token
5    namespace: cert-manager
6  type: Opaque
7  stringData:
8    api-token: TOKEN_IN_PLAIN_TEXT

Now we need to configure the ClusterIssuer and to avoid baning, we will configure staging and production environments. We can put both in one file called issuer.yaml.

 1  apiVersion: cert-manager.io/v1
 2  kind: ClusterIssuer
 3  metadata:
 4    name: letsencrypt-staging
 5  spec:
 6    acme:
 7      # The ACME server URL
 8      server: https://acme-staging-v02.api.letsencrypt.org/directory
 9      # Email address used for ACME registration
10      email: [email protected]
11      # Name of a secret used to store the ACME account private key
12      privateKeySecretRef:
13        name: letsencrypt-staging
14      # Enable the HTTP-01 challenge provider
15      solvers:
16      - dns01:
17          cloudflare:
18            email: [email protected]
19            apiTokenSecretRef:
20              name: cloudflare-api-token
21              key: api-token
22        selector:
23          dnsZones:
24          - 'mydomain.com'
25
26  ---
27  apiVersion: cert-manager.io/v1
28  kind: ClusterIssuer
29  metadata:
30    name: letsencrypt-prod
31  spec:
32    acme:
33      # The ACME server URL
34      server: https://acme-v02.api.letsencrypt.org/directory
35      # Email address used for ACME registration
36      email: [email protected]
37      # Name of a secret used to store the ACME account private key
38      privateKeySecretRef:
39        name: letsencrypt-prod
40      # Enable the HTTP-01 challenge provider
41      solvers:
42      - dns01:
43          cloudflare:
44            email: [email protected]
45            apiTokenSecretRef:
46              name: cloudflare-api-token
47              key: api-token
48        selector:
49          dnsZones:
50          - 'mydomain.com'

Make sure to use the correct admin email for Let’s Encrypt and the correct user email for Cloudflare .

Last step is to push our configuration to the cluster.

1  kubectl apply -f cf-secret.yaml
2  kubectl apply -f issuer.yaml

Example usage

Now that we have everything installed and configured, we can use it in our applications.

Here is an example were install AdGuard Home and use TCP and UDP ports.

Certificate configuration

The file adguard-cert.yaml is to tell Certmanager to generate and renew the certificate for dns.mydomain.com.

 1  apiVersion: cert-manager.io/v1
 2  kind: Certificate
 3  metadata:
 4    name: adguard-cert
 5    namespace: adguard
 6  spec:
 7    secretName: adguard-tls
 8    issuerRef:
 9      name: letsencrypt-prod
10      kind: ClusterIssuer
11    commonName: dns.mydomain.com
12    dnsNames:
13    - dns.mydomain.com

Save it and just apply it on the cluster.

1kubectl apply -f adguard-cert.yaml

Helm configuration

We are using the chart from k8s-at-home , and we need to make some custom configuration.

You can look which options are available for values.yaml configuration and which volumes are created at AdGuard Home values.yaml

We will use the IP 10.10.0.152 and the domain dns.mydomain.com.

 1service:
 2  main:
 3    annotations:
 4      metallb.universe.tf/allow-shared-ip: app.kubernetes.io/instance=k8s-at-home,app.kubernetes.io/name=adguard-home
 5    type: LoadBalancer
 6    loadBalancerIP: 10.10.0.152
 7    externalTrafficPolicy: Local
 8  dns-tcp:
 9    annotations:
10      metallb.universe.tf/allow-shared-ip: app.kubernetes.io/instance=k8s-at-home,app.kubernetes.io/name=adguard-home
11    type: LoadBalancer
12    loadBalancerIP: 10.10.0.152
13    externalTrafficPolicy: Local
14  dns-udp:
15    annotations:
16      metallb.universe.tf/allow-shared-ip: app.kubernetes.io/instance=k8s-at-home,app.kubernetes.io/name=adguard-home
17    type: LoadBalancer
18    loadBalancerIP: 10.10.0.152
19    externalTrafficPolicy: Local
20ingress:
21  main:
22    enabled: true
23    hosts:
24    - host: dns.mydomain.com
25        paths:
26          - path: /
27    tls:
28    - secretName: "adguard-tls"

Install everything using Helm .

1helm upgrade --install k8s-at-home adguard-home \
2--repo https://k8s-at-home.com/charts/ \
3--namespace adguard --create-namespace \
4-f values.yaml

After waiting to get the pods running, you will be able to access https://dns.mydomain.com with a valid certificate and can use 10.10.0.152 or dns.mydomain.com as your DNS Server.


Privacy Policy
comments powered by Disqus