From 953a1edfb28e863876fcb521d636b1233028c629 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sun, 27 Jul 2025 00:23:10 +0300 Subject: more on this --- .../DRAFT-kubernetes-with-freebsd-part-7.gmi.tpl | 223 +++++++++++++++++++++ 1 file changed, 223 insertions(+) diff --git a/gemfeed/DRAFT-kubernetes-with-freebsd-part-7.gmi.tpl b/gemfeed/DRAFT-kubernetes-with-freebsd-part-7.gmi.tpl index fdc616c4..2aa29655 100644 --- a/gemfeed/DRAFT-kubernetes-with-freebsd-part-7.gmi.tpl +++ b/gemfeed/DRAFT-kubernetes-with-freebsd-part-7.gmi.tpl @@ -51,6 +51,8 @@ FreeBSD f0.lan.buetow.org 14.3-RELEASE FreeBSD 14.3-RELEASE ## Installing k3s +### Generating `K3S_TOKEN` and starting first k3s node + Generating the k3s token on my Fedora Laptop with `pwgen -n 32` and selected one. And then on all 3 `r` hosts (replace SECRET_TOKEN with the actual secret!! before running the following command) run: ```sh @@ -74,6 +76,8 @@ So on `r0` we run: [INFO] systemd: Starting k3s ``` +### Adding the remaining nodes to the cluster + And we run on the other two nodes `r1` and `r2`: ```sh @@ -98,12 +102,231 @@ NAME STATUS ROLES AGE VERSION r0.lan.buetow.org Ready control-plane,etcd,master 4m44s v1.32.6+k3s1 r1.lan.buetow.org Ready control-plane,etcd,master 3m13s v1.32.6+k3s1 r2.lan.buetow.org Ready control-plane,etcd,master 30s v1.32.6+k3s1 + +[root@r0 ~]# kubectl get pods --all-namespaces +NAMESPACE NAME READY STATUS RESTARTS AGE +kube-system coredns-5688667fd4-fs2jj 1/1 Running 0 5m27s +kube-system helm-install-traefik-crd-f9hgd 0/1 Completed 0 5m27s +kube-system helm-install-traefik-zqqqk 0/1 Completed 2 5m27s +kube-system local-path-provisioner-774c6665dc-jqlnc 1/1 Running 0 5m27s +kube-system metrics-server-6f4c6675d5-5xpmp 1/1 Running 0 5m27s +kube-system svclb-traefik-411cec5b-cdp2l 2/2 Running 0 78s +kube-system svclb-traefik-411cec5b-f625r 2/2 Running 0 4m58s +kube-system svclb-traefik-411cec5b-twrd7 2/2 Running 0 4m2s +kube-system traefik-c98fdf6fb-lt6fx 1/1 Running 0 4m58s +``` + +In order to connect with `kubect` from my Fedora Laptop, I had to copy `/etc/rancher/k3s/k3s.yaml` from `r0` to `~/.kube/config` and then replace the value of the server field with `r0.lan.buetow.org`. kubectl can now manage the cluster. Note this step has to be repeated when k3s restarts or when we want to connect to another node of the cluster (e.g. when `r0` is down). + +### Test deployment to Kubernetes + +Let's create a test namespace: + +```sh +> ~ kubectl create namespace test +namespace/test created + +> ~ kubectl get namespaces +NAME STATUS AGE +default Active 6h11m +kube-node-lease Active 6h11m +kube-public Active 6h11m +kube-system Active 6h11m +test Active 5s + +> ~ kubectl config set-context --current --namespace=test +Context "default" modified. +``` + +And let's also create an apache test pod: + +```sh +> ~ cat < apache-deployment.yaml +# Apache HTTP Server Deployment +apiVersion: apps/v1 +kind: Deployment +metadata: + name: apache-deployment +spec: + replicas: 1 + selector: + matchLabels: + app: apache + template: + metadata: + labels: + app: apache + spec: + containers: + - name: apache + image: httpd:latest + ports: + # Container port where Apache listens + - containerPort: 80 +END + +> ~ kubectl apply -f apache-deployment.yaml +deployment.apps/apache-deployment created + +> ~ kubectl get all +NAME READY STATUS RESTARTS AGE +pod/apache-deployment-5fd955856f-4pjmf 1/1 Running 0 7s + +NAME READY UP-TO-DATE AVAILABLE AGE +deployment.apps/apache-deployment 1/1 1 1 7s + +NAME DESIRED CURRENT READY AGE +replicaset.apps/apache-deployment-5fd955856f 1 1 1 7s +``` + +Let's also create a service: + +```sh +> ~ cat < apache-service.yaml +apiVersion: v1 +kind: Service +metadata: + labels: + app: apache + name: apache-service +spec: + ports: + - name: web + port: 80 + protocol: TCP + # Expose port 80 on the service + targetPort: 80 + selector: + # Link this service to pods with the label app=apache + app: apache +END + +> ~ kubectl apply -f apache-service.yaml +service/apache-service created + +> ~ kubectl get service +NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE +apache-service ClusterIP 10.43.249.165 80/TCP 4s +``` + +And also an ingress: + +```sh +> ~ cat < apache-ingress.yaml + +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: apache-ingress + namespace: test + annotations: + spec.ingressClassName: traefik + traefik.ingress.kubernetes.io/router.entrypoints: web +spec: + rules: + - host: f3s.foo.zone + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: apache-service + port: + number: 80 + - host: standby.f3s.foo.zone + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: apache-service + port: + number: 80 + - host: www.f3s.foo.zone + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: apache-service + port: + number: 80 +END + +> ~ kubectl apply -f apache-ingress.yaml +ingress.networking.k8s.io/apache-ingress created + +> ~ kubectl describe ingress +Name: apache-ingress +Labels: +Namespace: test +Address: 192.168.1.120,192.168.1.121,192.168.1.122 +Ingress Class: traefik +Default backend: +Rules: + Host Path Backends + ---- ---- -------- + f3s.foo.zone + / apache-service:80 (10.42.1.11:80) + standby.f3s.foo.zone + / apache-service:80 (10.42.1.11:80) + www.f3s.foo.zone + / apache-service:80 (10.42.1.11:80) +Annotations: spec.ingressClassName: traefik + traefik.ingress.kubernetes.io/router.entrypoints: web +Events: +``` + +Notes: + +* I've modified the ingress hosts after I'd published this blog post. This is to ensure that there aren't any bots scarping it. +* In the ingress we use plain http (web) for the traefik rule, as all the "production" traefic will routed through a WireGuard tunnel anyway as we will see later. + +So let's test the Apache webserver through the ingress rule: + +```sh +> ~ curl -H "Host: www.f3s.foo.zone" http://r0.lan.buetow.org:80 +

It works!

``` +## Make it accessible from the public internet + +Next, this should be made accessible through the public internet via the `www.f3s.foo.zone` hosts. As a reminder, refer back to part 1 of this series and review the section titled "OpenBSD/relayd to the rescue for external connectivity": + +=> ./2024-11-17-f3s-kubernetes-with-freebsd-part-1.gmi f3s: Kubernetes with FreeBSD - Part 1: Setting the stage + +> All apps should be reachable through the internet (e.g., from my phone or computer when travelling). For external connectivity and TLS management, I've got two OpenBSD VMs (one hosted by OpenBSD Amsterdam and another hosted by Hetzner) handling public-facing services like DNS, relaying traffic, and automating Let's Encrypt certificates. + +> All of this (every Linux VM to every OpenBSD box) will be connected via WireGuard tunnels, keeping everything private and secure. There will be 6 WireGuard tunnels (3 k3s nodes times two OpenBSD VMs). + +> So, when I want to access a service running in k3s, I will hit an external DNS endpoint (with the authoritative DNS servers being the OpenBSD boxes). The DNS will resolve to the master OpenBSD VM (see my KISS highly-available with OpenBSD blog post), and from there, the relayd process (with a Let's Encrypt certificate—see my Let's Encrypt with OpenBSD and Rex blog post) will accept the TCP connection and forward it through the WireGuard tunnel to a reachable node port of one of the k3s nodes, thus serving the traffic. + +```sh +> ~ curl https://f3s.foo.zone +

It works!

+ +> ~ curl https://www.f3s.foo.zone +

It works!

+ +> ~ curl https://standby.f3s.foo.zone +

It works!

+``` + + +Todo: include k9s screenshot + Other *BSD-related posts: << template::inline::rindex bsd E-Mail your comments to `paul@nospam.buetow.org` + +Note, that I've modified the hosts after I'd published this blog post. This is to ensure that there aren't any bots scarping it. => ../ Back to the main site + + +Note, that I've modified the hosts after I'd published this blog post. This is to ensure that there aren't any bots scarping it. -- cgit v1.2.3