mogenius and Punq: Developer Portal and OS Kubernetes Observability

Published: Oct 19, 2023 by Isaac Johnson

An easy way to get my attention is to read an article and give me feedback. And when that feedback comes with a link to a slick new OS Observability project, I’m even more interested.

Someone named Jan reached out just to put forward an OS project, Punq their company created and actively supports. And since I really love companies that empower their people like that, we’ll look at their commercial Kubernetes developer portal as well, mogenius

Punq

We’ll start with Punq, because I am one!

$ brew install punq
==> Fetching dependencies for mogenius/punq/punq: linux-headers@5.15
==> Fetching linux-headers@5.15
==> Downloading https://ghcr.io/v2/homebrew/core/linux-headers/5.15/manifests/5.15.135
################################################################################################################# 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/linux-headers/5.15/blobs/sha256:aee6802c39a7843bc3beb8afdbe26980508c09e
################################################################################################################# 100.0%
==> Fetching mogenius/punq/punq
==> Downloading https://github.com/mogenius/homebrew-punq/releases/download/v1.4.5/punq-v1.4.5-linux-amd64.tar.gz
==> Downloading from https://objects.githubusercontent.com/github-production-release-asset-2e65be/679598369/c1e9423f-f48
################################################################################################################# 100.0%
==> Installing punq from mogenius/punq
==> Installing dependencies for mogenius/punq/punq: linux-headers@5.15
==> Installing mogenius/punq/punq dependency: linux-headers@5.15
==> Downloading https://ghcr.io/v2/homebrew/core/linux-headers/5.15/manifests/5.15.135
Already downloaded: /home/builder/.cache/Homebrew/downloads/b2010adf4bce4c6cbd8ff3c5f1f4f47f0d82b1eadd2ad114e07fb2ffebf0b636--linux-headers@5.15-5.15.135.bottle_manifest.json
==> Pouring linux-headers@5.15--5.15.135.x86_64_linux.bottle.tar.gz
🍺  /home/linuxbrew/.linuxbrew/Cellar/linux-headers@5.15/5.15.135: 961 files, 5.7MB
==> Installing mogenius/punq/punq
🍺  /home/linuxbrew/.linuxbrew/Cellar/punq/1.4.5: 3 files, 64.2MB, built in 2 seconds
==> Running `brew cleanup punq`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
==> `brew cleanup` has not been run in the last 30 days, running now...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
Removing: /home/builder/.cache/Homebrew/bdw-gc--8.2.4... (587.7KB)
Removing: /home/builder/.cache/Homebrew/cups--2.4.6... (4.9MB)
Removing: /home/builder/.cache/Homebrew/gh--2.34.0... (10MB)
Removing: /home/builder/.cache/Homebrew/harfbuzz--8.2.0... (3.3MB)
Removing: /home/builder/.cache/Homebrew/hugo--0.118.2... (19.7MB)
Removing: /home/builder/.cache/Homebrew/isl--0.26... (2.1MB)
Removing: /home/builder/.cache/Homebrew/kdash--v0.4.2.tar.gz... (4.3MB)
Removing: /home/builder/.cache/Homebrew/kubernetes-cli--1.28.1... (14.9MB)
Removing: /home/builder/.cache/Homebrew/libnghttp2--1.56.0... (246KB)
Removing: /home/builder/.cache/Homebrew/libtiff--4.5.1... (1.8MB)
Removing: /home/builder/.cache/Homebrew/libx11--1.8.6... (2.3MB)
Removing: /home/builder/.cache/Homebrew/libxfixes--6.0.1... (33.4KB)
Removing: /home/builder/.cache/Homebrew/libxi--1.8.1... (174.6KB)
Removing: /home/builder/.cache/Homebrew/libxt--1.3.0... (578.5KB)
Removing: /home/builder/.cache/Homebrew/libyaml--0.2.5... (122.9KB)
Removing: /home/linuxbrew/.linuxbrew/Cellar/linux-headers@5.15/5.15.131... (961 files, 5.7MB)
Removing: /home/linuxbrew/.linuxbrew/Cellar/linux-headers@5.15/5.15.133... (961 files, 5.7MB)
Removing: /home/builder/.cache/Homebrew/linux-headers@5.15--5.15.131... (1.5MB)
Removing: /home/builder/.cache/Homebrew/linux-headers@5.15--5.15.133... (1.5MB)
Removing: /home/builder/.cache/Homebrew/little-cms2--2.15... (503.1KB)
Removing: /home/builder/.cache/Homebrew/opa--0.56.0... (9.3MB)
Removing: /home/builder/.cache/Homebrew/openssl@3--3.1.2... (8.8MB)
Removing: /home/builder/.cache/Homebrew/python@3.11--3.11.5... (16.7MB)
Removing: /home/builder/.cache/Homebrew/pyyaml--6.0_1... (1.7MB)
Removing: /home/builder/.cache/Homebrew/sqlite--3.43.1... (2.7MB)
Removing: /home/builder/.cache/Homebrew/vault--1.14.2... (125.9MB)
Removing: /home/builder/.cache/Homebrew/yq--4.35.1... (3.5MB)
Removing: /home/builder/.cache/Homebrew/zstd--1.5.5... (1.2MB)
Removing: /home/builder/.cache/Homebrew/libnghttp2_bottle_manifest--1.53.0... (7.5KB)
Removing: /home/builder/.cache/Homebrew/vault_bottle_manifest--1.13.2... (7.7KB)
Removing: /home/builder/.cache/Homebrew/openjdk@11_bottle_manifest--11.0.19... (24.5KB)
Removing: /home/builder/.cache/Homebrew/libyaml_bottle_manifest--0.2.5... (9.2KB)
Removing: /home/builder/.cache/Homebrew/xz_bottle_manifest--5.4.3... (7.5KB)
Removing: /home/builder/.cache/Homebrew/libxfixes_bottle_manifest--6.0.1... (9.8KB)
Removing: /home/builder/.cache/Homebrew/little-cms2_bottle_manifest--2.15... (10.1KB)
Removing: /home/builder/.cache/Homebrew/libxml2_bottle_manifest--2.11.4... (8.8KB)
Removing: /home/builder/.cache/Homebrew/python@3.11_bottle_manifest--3.11.3... (21.6KB)
Removing: /home/builder/.cache/Homebrew/sqlite_bottle_manifest--3.42.0... (8.1KB)
Removing: /home/builder/.cache/Homebrew/nettle_bottle_manifest--3.9... (8.2KB)
Removing: /home/builder/.cache/Homebrew/glib_bottle_manifest--2.76.3... (13.3KB)
Removing: /home/builder/.cache/Homebrew/yq_bottle_manifest--4.34.1... (7.3KB)
Removing: /home/builder/.cache/Homebrew/libtiff_bottle_manifest--4.5.0... (9.8KB)
Removing: /home/builder/.cache/Homebrew/openjdk--20.0.2... (192.6MB)
Removing: /home/builder/.cache/Homebrew/mpfr_bottle_manifest--4.2.0-p9... (8KB)
Removing: /home/builder/.cache/Homebrew/hugo_bottle_manifest--0.112.3... (7.3KB)
Removing: /home/builder/.cache/Homebrew/libxt_bottle_manifest--1.3.0... (11KB)
Removing: /home/builder/.cache/Homebrew/opa_bottle_manifest--0.53.0... (7.3KB)
Removing: /home/builder/.cache/Homebrew/isl_bottle_manifest--0.26... (7.6KB)
Removing: /home/builder/.cache/Homebrew/harfbuzz_bottle_manifest--7.3.0... (19.9KB)
Removing: /home/builder/.cache/Homebrew/python@3.10_bottle_manifest--3.10.11... (21.4KB)
Removing: /home/builder/.cache/Homebrew/zstd_bottle_manifest--1.5.5... (8.3KB)
Removing: /home/builder/.cache/Homebrew/pyyaml_bottle_manifest--6.0_1... (8.4KB)
Removing: /home/builder/.cache/Homebrew/gcc_bottle_manifest--13.1.0... (12.7KB)
Removing: /home/builder/.cache/Homebrew/dbus_bottle_manifest--1.14.6... (9.7KB)
Removing: /home/builder/.cache/Homebrew/alsa-lib_bottle_manifest--1.2.9... (1.9KB)
Removing: /home/builder/.cache/Homebrew/portable-ruby-2.6.10_1.x86_64_linux.bottle.tar.gz... (10.5MB)
Removing: /home/builder/.cache/Homebrew/bdw-gc_bottle_manifest--8.2.4... (7.7KB)
Removing: /home/builder/.cache/Homebrew/libxi_bottle_manifest--1.8.1... (11.1KB)
Removing: /home/builder/.cache/Homebrew/python-yq_bottle_manifest--3.2.2... (18.8KB)
Removing: /home/builder/.cache/Homebrew/linux-headers@5.15_bottle_manifest--5.15.113... (1.9KB)
Removing: /home/builder/.cache/Homebrew/freetype_bottle_manifest--2.13.0_1... (8KB)
Removing: /home/builder/.cache/Homebrew/Logs/k1s... (4KB)
Removing: /home/builder/.cache/Homebrew/Logs/popeye... (4KB)
Removing: /home/builder/.cache/Homebrew/Logs/kdash... (4KB)

Sigh. Another app wanting latest Ubuntu

$ punq install --help
punq: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.32' not found (required by punq)
punq: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.34' not found (required by punq)

I popped over to an upgraded host

builder@anna-MacBookAir:~$ brew install punq
punq 1.4.5 is already installed but outdated (so it will be upgraded).
==> Fetching mogenius/punq/punq
==> Downloading https://github.com/mogenius/homebrew-punq/releases/download/v1.4.8/punq-v1.4.8-linux-amd64.tar.gz
==> Downloading from https://objects.githubusercontent.com/github-production-release-asset-2e65be/679598369/5077d973-4e################################################################################################################ 100.0%==> Upgrading mogenius/punq/punq
  1.4.5 -> 1.4.8

🍺  /home/linuxbrew/.linuxbrew/Cellar/punq/1.4.8: 3 files, 64.3MB, built in 3 seconds
==> Running `brew cleanup punq`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
Removing: /home/linuxbrew/.linuxbrew/Cellar/punq/1.4.5... (3 files, 64.2MB)
Removing: /home/builder/.cache/Homebrew/punq--1.4.5.tar.gz... (21.2MB)
builder@anna-MacBookAir:~$ punq install --help

        This cmd installs the application permanently into you cluster.
        Please run cleanup if you want to remove it again.


Usage:

  punq install [flags]


Flags:

  -h, --help             help for install
  -i, --ingress string   Ingress hostname for operator.


Global Flags:

  -y, --config string       Use config from custom location
  -c, --context-id string   Define a context-id (default "own-context")
  -d, --debug               Enable debug information
  -s, --stage string        Use different stage environment
  -v, --version             Print version info

I’ll first setup Punq with No hostname Ingress on my test cluster

builder@anna-MacBookAir:~$ punq install
Do you really want to install punq to 'default' context? [y/n]: y
Creating punq namespace ...
Created punq namespace. ✅
Creating punq RBAC ...
Created punq RBAC. ✅
Creating punq deployment ...
Created punq deployment. ✅
Determining cluster provider ...
This cluster's provider is unknown or it might be self-managed.
Determined cluster provider: 'UNKNOWN'. ✅
Creating new punq-context secret ...
Created new punq-context secret. ✅

🚀🚀🚀 Successfully installed punq in 'default'.

Creating new punq-auth secret ...
Created new punq-users secret. ✅
{
  "id": "d2gvAz0yMoq71Cr3LuYL6",
  "email": "oliver-adams@punq.dev",
  "password": "1IxxxxxxxxxxxxxxxXK",
  "displayName": "ADMIN USER",
  "accessLevel": 2,
  "createdAt": "2023-10-17T12:54:30-05:00",
}
Creating new punq-auth secret ...
Created new punq-auth secret. ✅

That created no service or ingress, but did launch a deployment with a pod

builder@anna-MacBookAir:~$ kubectl get svc -n punq
No resources found in punq namespace.
builder@anna-MacBookAir:~$ kubectl get ingress -n punq
No resources found in punq namespace.
builder@anna-MacBookAir:~$ kubectl get rs -n punq
NAME              DESIRED   CURRENT   READY   AGE
punq-865cd6b7dc   1         1         1       91s
builder@anna-MacBookAir:~$ kubectl get deployment -n punq
NAME   READY   UP-TO-DATE   AVAILABLE   AGE
punq   1/1     1            1           95s
builder@anna-MacBookAir:~$

I’ll create a NodePort service so I can reach it internally

builder@anna-MacBookAir:~$ cat punq.svc.np.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app: punq
  name: punqsvc
  namespace: punq
spec:
  externalTrafficPolicy: Cluster
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - nodePort: 30632
    port: 8082
    protocol: TCP
    targetPort: 8082
  selector:
    app: punq
  sessionAffinity: None
  type: NodePort
builder@anna-MacBookAir:~$ kubectl apply -f punq.svc.np.yaml
service/punqsvc created
builder@anna-MacBookAir:~$ kubectl get svc -n punq
NAME      TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
punqsvc   NodePort   10.43.136.182   <none>        8082:30632/TCP   6s

That failed

/content/images/2023/10/punq-01.png

and the websocket was 404’ing in the logs

[WEBSOCK] 2023/10/17 - 17:59:42 | 404 |         589ns |       10.42.0.0 | GET      |        0 B | "/"
[WEBSOCK] 2023/10/17 - 17:59:42 | 404 |         657ns |       10.42.0.0 | GET      |        0 B | "/favicon.ico"
[WEBSOCK] 2023/10/17 - 17:59:47 | 404 |         471ns |       10.42.0.0 | GET      |        0 B | "/"
[WEBSOCK] 2023/10/17 - 17:59:51 | 404 |         862ns |       10.42.0.0 | GET      |        0 B | "/punq"
[WEBSOCK] 2023/10/17 - 18:01:06 | 404 |         692ns |       10.42.0.0 | GET      |        0 B | "/"

I realized from the logs that it served the frontend on 8081 not 8082

/content/images/2023/10/punq-02.png

I tried a port-forward

$ kubectl port-forward punq-865cd6b7dc-5swjr -n punq 8081:8081
Forwarding from 127.0.0.1:8081 -> 8081
Forwarding from [::1]:8081 -> 8081

but got a blank screen

/content/images/2023/10/punq-03.png

I changed to 8081

builder@anna-MacBookAir:~$ cat punq.svc.np.yaml
apiVersion: v1
kind: Service
metadata:
  labels:
    app: punq
  name: punqsvc
  namespace: punq
spec:
  externalTrafficPolicy: Cluster
  internalTrafficPolicy: Cluster
  ipFamilies:
  - IPv4
  ipFamilyPolicy: SingleStack
  ports:
  - nodePort: 30632
    port: 8081
    protocol: TCP
    targetPort: 8081
  selector:
    app: punq
  sessionAffinity: None
  type: NodePort
builder@anna-MacBookAir:~$ kubectl apply -f punq.svc.np.yaml
service/punqsvc configured
builder@anna-MacBookAir:~$ kubectl get svc -n punq
NAME      TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
punqsvc   NodePort   10.43.136.182   <none>        8081:30632/TCP   7m7s

I can see the Punq icon in Firefox this time, but no page

/content/images/2023/10/punq-04.png

I have a feeling I need to have 8081 and 8082 both available. I tried port-forwarding on both 8081 and 8082 but still no luck.

I really hate having to test on production.

I reloaded the cluster and also tried with Istio installed

builder@LuiGi17:~/Workspaces/jekyll-blog$ kubectl get nodes
NAME                  STATUS   ROLES                  AGE   VERSION
isaac-macbookpro      Ready    <none>                 19m   v1.27.6+k3s1
builder-macbookpro2   Ready    <none>                 19m   v1.27.6+k3s1
anna-macbookair       Ready    control-plane,master   20m   v1.27.6+k3s1

builder@LuiGi17:~/Workspaces/jekyll-blog$ kubectl get svc --all-namespaces
NAMESPACE       NAME                   TYPE           CLUSTER-IP      EXTERNAL-IP
PORT(S)                                      AGE
default         kubernetes             ClusterIP      10.43.0.1       <none>
443/TCP                                      16m
kube-system     kube-dns               ClusterIP      10.43.0.10      <none>
53/UDP,53/TCP,9153/TCP                       16m
kube-system     metrics-server         ClusterIP      10.43.101.37    <none>
443/TCP                                      16m
istio-system    istiod                 ClusterIP      10.43.50.236    <none>
15010/TCP,15012/TCP,443/TCP,15014/TCP        14m
istio-ingress   istio-ingress          LoadBalancer   10.43.126.109   192.168.1.13,192.168.1.159,192.168.1.206   15021:30288/TCP,80:32338/TCP,443:31219/TCP   13m
cert-manager    cert-manager-webhook   ClusterIP      10.43.116.108   <none>
443/TCP                                      13m
cert-manager    cert-manager           ClusterIP      10.43.144.161   <none>
9402/TCP                                     13m
builder@LuiGi17:~/Workspaces/jekyll-blog$ punq install -i punqdemo.freshbrewed.science
Do you really want to install punq to 'mac81' context? [y/n]: y
Creating punq namespace ...
Created punq namespace. ✅
Creating punq RBAC ...
Created punq RBAC. ✅
Creating punq deployment ...
Created punq deployment. ✅
Determining cluster provider ...
This cluster's provider is unknown or it might be self-managed.
Determined cluster provider: 'UNKNOWN'. ✅
Creating new punq-context secret ...
Created new punq-context secret. ✅
Creating punq service ...
Created punq service. ✅
Deleting punq RBAC ...
Deleted punq RBAC. ✅
Deleting punq deployment ...
Deleted punq deployment. ✅
Deleting punq/punq-contexts secret ...
Deleted punq/punq-contexts secret. ✅
Deleting punq/punq-users secret ...
Deleted punq/punq-users secret. ✅
Deleting punq-service service ...
Deleted punq-service service. ✅
Deleting punq-ingress ingress ...
Deleted punq-ingress ingress. ✅

🚀🚀🚀 Successfully uninstalled punq from 'mac81'.

Error: No ingress controller found.
We recomend installing TRAEFIK:
  helm repo add traefik https://traefik.github.io/charts
  helm install traefik traefik/traefik
After installing TRAEFIK, you can retry installing punq.

I launched again with Traefik and it worked this time

builder@LuiGi17:~/Workspaces/jekyll-blog$ kubectl get nodes
NAME                  STATUS   ROLES                  AGE     VERSION
anna-macbookair       Ready    control-plane,master   5m34s   v1.27.6+k3s1
builder-macbookpro2   Ready    <none>                 4m42s   v1.27.6+k3s1
isaac-macbookpro      Ready    <none>                 4m47s   v1.27.6+k3s1
builder@LuiGi17:~/Workspaces/jekyll-blog$ kubectl get svc --all-namespaces
NAMESPACE     NAME             TYPE           CLUSTER-IP      EXTERNAL-IP                                PORT(S)                      AGE
default       kubernetes       ClusterIP      10.43.0.1       <none>                                     443/TCP                      5m42s
kube-system   kube-dns         ClusterIP      10.43.0.10      <none>                                     53/UDP,53/TCP,9153/TCP       5m39s
kube-system   metrics-server   ClusterIP      10.43.12.115    <none>                                     443/TCP                      5m38s
kube-system   traefik          LoadBalancer   10.43.161.247   192.168.1.13,192.168.1.159,192.168.1.206   80:32442/TCP,443:32292/TCP   5m11s
builder@LuiGi17:~/Workspaces/jekyll-blog$ punq install -i punqdemo.freshbrewed.science
Do you really want to install punq to 'mac81' context? [y/n]: y
Creating punq namespace ...
Created punq namespace. ✅
Creating punq RBAC ...
Created punq RBAC. ✅
Creating punq deployment ...
Created punq deployment. ✅
Determining cluster provider ...
This cluster's provider is unknown or it might be self-managed.
Determined cluster provider: 'UNKNOWN'. ✅
Creating new punq-context secret ...
Created new punq-context secret. ✅
Creating punq service ...
Created punq service. ✅
Creating TRAEFIK punq ingress (punqdemo.freshbrewed.science) ...
Created TRAEFIK punq ingress (punqdemo.freshbrewed.science). ✅
Creating TRAEFIK middleware (punqdemo.freshbrewed.science) ...
Created TRAEFIK middleware (punqdemo.freshbrewed.science). ✅

🚀🚀🚀 Successfully installed punq in 'mac81'.

Creating new punq-auth secret ...
Created new punq-users secret. ✅
{
  "id": "s4CU4jDaCZS3KK0DCnaAb",
  "email": "william-perry@punq.dev",
  "password": "xxxxxxxxxx",
  "displayName": "ADMIN USER",
  "accessLevel": 2,
  "createdAt": "2023-10-18T20:29:58-05:00",
}
Creating new punq-auth secret ...
Created new punq-auth secret. ✅

I forwarded a different port to this cluster and found it worked suprisingly well

/content/images/2023/10/punq-55.png

I added a context to solve the IP

/content/images/2023/10/punq-56.png

I can now import it

/content/images/2023/10/punq-57.png

I can now view it under the default context

/content/images/2023/10/punq-58.png

I can add a user, but it doesn’t accept the access level numerically

builder@LuiGi17:~/Workspaces/jekyll-blog$ punq user add --context-id "default" --accesslevel 2 -j "Isaac Johnson" -e "isaac@freshbrewed.science" -p "xxxxxxxxx"
Current context: 'default'
User added succesfully ✅.
{
  "password": "xxxxxxxxx",
  "displayName": "Isaac Johnson",
  "accessLevel": 0,
  "email": "isaac@freshbrewed.science",
}
builder@LuiGi17:~/Workspaces/jekyll-blog$ punq user list -c default
Current context: 'default'
+---+-----------------------+---------------+---------------------------+-------------+---------+
| # | ID                    | DISPLAYNAME   | EMAIL                     | ACCESSLEVEL | CREATED |
+---+-----------------------+---------------+---------------------------+-------------+---------+
| 1 | s4CU4jDaCZS3KK0DCnaAb | ADMIN USER    | william-perry@punq.dev    |           2 | 56m     |
| 2 | M7eD8iMg1AHh4XAZKRXbr | Isaac Johnson | isaac@freshbrewed.science |           0 | 13s     |
+---+-----------------------+---------------+---------------------------+-------------+---------+
builder@LuiGi17:~/Workspaces/jekyll-blog$ punq user update -u M7eD8iMg1AHh4XAZKRXbr -a 2
Current context: 'own-context'
User updated succesfully ✅.
builder@LuiGi17:~/Workspaces/jekyll-blog$ punq user list -c default
Current context: 'default'
+---+-----------------------+---------------+---------------------------+-------------+---------+
| # | ID                    | DISPLAYNAME   | EMAIL                     | ACCESSLEVEL | CREATED |
+---+-----------------------+---------------+---------------------------+-------------+---------+
| 1 | M7eD8iMg1AHh4XAZKRXbr | Isaac Johnson | isaac@freshbrewed.science |           0 | 68s     |
| 2 | s4CU4jDaCZS3KK0DCnaAb | ADMIN USER    | william-perry@punq.dev    |           2 | 57m     |
+---+-----------------------+---------------+---------------------------+-------------+---------+
builder@LuiGi17:~/Workspaces/jekyll-blog$ punq user update -u M7eD8iMg1AHh4XAZKRXbr -a 2 -c default
Current context: 'default'
User updated succesfully ✅.
builder@LuiGi17:~/Workspaces/jekyll-blog$ punq user list -c default
Current context: 'default'
+---+-----------------------+---------------+---------------------------+-------------+---------+
| # | ID                    | DISPLAYNAME   | EMAIL                     | ACCESSLEVEL | CREATED |
+---+-----------------------+---------------+---------------------------+-------------+---------+
| 1 | M7eD8iMg1AHh4XAZKRXbr | Isaac Johnson | isaac@freshbrewed.science |           0 | 77s     |
| 2 | s4CU4jDaCZS3KK0DCnaAb | ADMIN USER    | william-perry@punq.dev    |           2 | 57m     |
+---+-----------------------+---------------+---------------------------+-------------+---------+
builder@LuiGi17:~/Workspaces/jekyll-blog$ punq user update -u M7eD8iMg1AHh4XAZKRXbr --accesslevel "2" -c default
Current context: 'default'
User updated succesfully ✅.
builder@LuiGi17:~/Workspaces/jekyll-blog$ punq user list -c default
Current context: 'default'
+---+-----------------------+---------------+---------------------------+-------------+---------+
| # | ID                    | DISPLAYNAME   | EMAIL                     | ACCESSLEVEL | CREATED |
+---+-----------------------+---------------+---------------------------+-------------+---------+
| 1 | M7eD8iMg1AHh4XAZKRXbr | Isaac Johnson | isaac@freshbrewed.science |           0 | 97s     |
| 2 | s4CU4jDaCZS3KK0DCnaAb | ADMIN USER    | william-perry@punq.dev    |           2 | 57m     |
+---+-----------------------+---------------+---------------------------+-------------+---------+

I searched the codebase and figured out the keywords that are actually used:

level number name
0 READER
1 USER
2 ADMIN

Knowing that, I was able to test

builder@LuiGi17:~/Workspaces/jekyll-blog$ punq user update -u M7eD8iMg1AHh4XAZKRXbr --accesslevel READER -c default
Current context: 'default'
User updated succesfully ✅.
builder@LuiGi17:~/Workspaces/jekyll-blog$ punq user list -c default
Current context: 'default'
+---+-----------------------+---------------+---------------------------+-------------+---------+
| # | ID                    | DISPLAYNAME   | EMAIL                     | ACCESSLEVEL | CREATED |
+---+-----------------------+---------------+---------------------------+-------------+---------+
| 1 | M7eD8iMg1AHh4XAZKRXbr | Isaac Johnson | isaac@freshbrewed.science |           0 | 5m38s   |
| 2 | s4CU4jDaCZS3KK0DCnaAb | ADMIN USER    | william-perry@punq.dev    |           2 | 61m     |
+---+-----------------------+---------------+---------------------------+-------------+---------+
builder@LuiGi17:~/Workspaces/jekyll-blog$ punq user update -u M7eD8iMg1AHh4XAZKRXbr --accesslevel ADMIN -c default
Current context: 'default'
User updated succesfully ✅.
builder@LuiGi17:~/Workspaces/jekyll-blog$ punq user list -c default
Current context: 'default'
+---+-----------------------+---------------+---------------------------+-------------+---------+
| # | ID                    | DISPLAYNAME   | EMAIL                     | ACCESSLEVEL | CREATED |
+---+-----------------------+---------------+---------------------------+-------------+---------+
| 1 | M7eD8iMg1AHh4XAZKRXbr | Isaac Johnson | isaac@freshbrewed.science |           2 | 5m50s   |
| 2 | s4CU4jDaCZS3KK0DCnaAb | ADMIN USER    | william-perry@punq.dev    |           2 | 62m     |
+---+-----------------------+---------------+---------------------------+-------------+---------+
builder@LuiGi17:~/Workspaces/jekyll-blog$ punq user update -u M7eD8iMg1AHh4XAZKRXbr --accesslevel USER -c default
Current context: 'default'
User updated succesfully ✅.
builder@LuiGi17:~/Workspaces/jekyll-blog$ punq user list -c default
Current context: 'default'
+---+-----------------------+---------------+---------------------------+-------------+---------+
| # | ID                    | DISPLAYNAME   | EMAIL                     | ACCESSLEVEL | CREATED |
+---+-----------------------+---------------+---------------------------+-------------+---------+
| 1 | M7eD8iMg1AHh4XAZKRXbr | Isaac Johnson | isaac@freshbrewed.science |           1 | 6m41s   |
| 2 | s4CU4jDaCZS3KK0DCnaAb | ADMIN USER    | william-perry@punq.dev    |           2 | 62m     |
+---+-----------------------+---------------+---------------------------+-------------+---------+

Prod

I guess we have to ‘do it live’

I’ll create a quick A Record

$ cat r53-punq.json
{
    "Comment": "CREATE punq fb.s A record ",
    "Changes": [
      {
        "Action": "CREATE",
        "ResourceRecordSet": {
          "Name": "punq.freshbrewed.science",
          "Type": "A",
          "TTL": 300,
          "ResourceRecords": [
            {
              "Value": "75.73.224.240"
            }
          ]
        }
      }
    ]
  }
$ aws route53 change-resource-record-sets --hosted-zone-id Z39E8QFU0F9PZP --change-batch file://r53-punq.json
{
    "ChangeInfo": {
        "Id": "/change/C08531302O6CR0DJBWD6J",
        "Status": "PENDING",
        "SubmittedAt": "2023-10-17T18:14:29.743Z",
        "Comment": "CREATE punq fb.s A record "
    }
}

I installed without issue, though it didn’t know what kind of cluster I had

$ punq install -i punq.freshbrewed.science
Do you really want to install punq to 'mac77' context? [y/n]: y
Creating punq namespace ...
Created punq namespace. ✅
Creating punq RBAC ...
Created punq RBAC. ✅
Creating punq deployment ...
Created punq deployment. ✅
Determining cluster provider ...
This cluster's provider is unknown or it might be self-managed.
Determined cluster provider: 'UNKNOWN'. ✅
Creating new punq-context secret ...
Created new punq-context secret. ✅
Creating punq service ...
Created punq service. ✅

🚀🚀🚀 Successfully installed punq in 'mac77'.

Creating new punq-auth secret ...
Created new punq-users secret. ✅
{
  "email": "michael-kelly@punq.dev",
  "password": "exxxxxxxxxxxxxD",
  "displayName": "ADMIN USER",
  "accessLevel": 2,
  "createdAt": "2023-10-17T13:36:32-05:00",
  "id": "sCYwdeuz9HpRXOG15sYie",
}
Creating new punq-auth secret ...
Created new punq-auth secret. ✅

While no ingress was created, I did see a service

$ kubectl get svc -n punq
NAME           TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                      AGE
punq-service   ClusterIP   10.43.0.8    <none>        8080/TCP,8081/TCP,8082/TCP   19m

I’m guessing the issue is that Punq couldn’t determine the Ingress controller

$ punq system ingress-controller-type
unknown ingress controller: nginx.org/ingress-controller
Ingress Controller Type: UNKNOWN

I made my own Ingress definition. I ended up trying 8081, 8080 and 8082

$ cat punq.ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    ingress.kubernetes.io/proxy-body-size: "0"
    ingress.kubernetes.io/ssl-redirect: "true"
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/proxy-body-size: "0"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.org/client-max-body-size: "0"
    nginx.org/proxy-connect-timeout: "600"
    nginx.org/proxy-read-timeout: "600"
  labels:
    app.kubernetes.io/name: punq
  name: punq
  namespace: punq
spec:
  rules:
  - host: punq.freshbrewed.science
    http:
      paths:
      - backend:
          service:
            name: punq-service
            port:
              number: 8081
        path: /
        pathType: ImplementationSpecific
  tls:
  - hosts:
    - punq.freshbrewed.science
    secretName: punq-tls

System Info

$ punq system info
Current context: 'own-context'
Config
Version:                  2

Frontend
Host:                     127.0.0.1
Port:                     8081

Backend
Host:                     127.0.0.1
Port:                     8080

KUBERNETES
ClusterName:              your-cluster-name
OwnNamespace:             punq
RunInCluster:             false

MISC
Stage:                    prod
Debug:                    false
CheckForUpdates:          86400
IgnoreNamespaces:         kube-system

Config:                   /home/builder/.punq/config.yaml

I will admit I circle back to this later trying many permutations of the ingress definition matching what I found after doing the AKS demo (next section).

$ cat punq.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    ingress.kubernetes.io/proxy-body-size: "0"
    ingress.kubernetes.io/ssl-redirect: "true"
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/configuration-snippet: |
      proxy_http_version 1.1;
      proxy_set_header Upgrade "websocket";
      proxy_set_header Connection "Upgrade";
    nginx.ingress.kubernetes.io/proxy-body-size: "0"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.org/client-max-body-size: "0"
    nginx.org/proxy-connect-timeout: "600"
    nginx.org/proxy-read-timeout: "600"
  labels:
    app.kubernetes.io/name: punq
  name: punq
  namespace: punq
spec:
  rules:
  - host: punq.freshbrewed.science
    http:
      paths:
      - backend:
          service:
            name: punq-service
            port:
              number: 8080
        path: /backend/
        pathType: Prefix
      - backend:
          service:
            name: punq-service
            port:
              number: 8082
        path: /websocket/
        pathType: Prefix
      - backend:
          service:
            name: punq-service
            port:
              number: 8081
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - punq.freshbrewed.science
    secretName: punq-tls

$ kubectl apply -f punq.yaml
ingress.networking.k8s.io/punq created

and

$ kubectl get ingress punq -n punq -o yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
    field.cattle.io/publicEndpoints: '[{"addresses":["192.168.1.215","192.168.1.36","192.168.1.57","192.168.1.78"],"port":443,"protocol":"HTTPS","serviceName":"punq:punq-service","ingressName":"punq:punq","hostname":"punq.freshbrewed.science","path":"/backend/","allNodes":false},{"addresses":["192.168.1.215","192.168.1.36","192.168.1.57","192.168.1.78"],"port":443,"protocol":"HTTPS","serviceName":"punq:punq-service","ingressName":"punq:punq","hostname":"punq.freshbrewed.science","path":"/websocket/","allNodes":false},{"addresses":["192.168.1.215","192.168.1.36","192.168.1.57","192.168.1.78"],"port":443,"protocol":"HTTPS","serviceName":"punq:punq-service","ingressName":"punq:punq","hostname":"punq.freshbrewed.science","path":"/","allNodes":false}]'
    ingress.kubernetes.io/ssl-redirect: "true"
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"networking.k8s.io/v1","kind":"Ingress","metadata":{"annotations":{"cert-manager.io/cluster-issuer":"letsencrypt-prod","ingress.kubernetes.io/proxy-body-size":"0","ingress.kubernetes.io/ssl-redirect":"true","kubernetes.io/ingress.class":"nginx","nginx.ingress.kubernetes.io/configuration-snippet":"proxy_http_version 1.1;\nproxy_set_header Upgrade \"websocket\";\nproxy_set_header Connection \"Upgrade\";\n","nginx.ingress.kubernetes.io/proxy-body-size":"0","nginx.ingress.kubernetes.io/proxy-read-timeout":"3600","nginx.ingress.kubernetes.io/proxy-send-timeout":"3600","nginx.ingress.kubernetes.io/ssl-redirect":"true","nginx.org/client-max-body-size":"0","nginx.org/proxy-connect-timeout":"600","nginx.org/proxy-read-timeout":"600"},"labels":{"app.kubernetes.io/name":"punq"},"name":"punq","namespace":"punq"},"spec":{"rules":[{"host":"punq.freshbrewed.science","http":{"paths":[{"backend":{"service":{"name":"punq-service","port":{"number":8080}}},"path":"/backend/","pathType":"Prefix"},{"backend":{"service":{"name":"punq-service","port":{"number":8082}}},"path":"/websocket/","pathType":"Prefix"},{"backend":{"service":{"name":"punq-service","port":{"number":8081}}},"path":"/","pathType":"Prefix"}]}}],"tls":[{"hosts":["punq.freshbrewed.science"],"secretName":"punq-tls"}]}}
    kubernetes.io/ingress.class: nginx
    nginx.ingress.kubernetes.io/configuration-snippet: |
      proxy_http_version 1.1;
      proxy_set_header Upgrade "websocket";
      proxy_set_header Connection "Upgrade";
    nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
    nginx.org/proxy-connect-timeout: "3600"
    nginx.org/proxy-read-timeout: "3600"
  creationTimestamp: "2023-10-18T23:52:49Z"
  generation: 1
  labels:
    app.kubernetes.io/name: punq
  name: punq
  namespace: punq
  resourceVersion: "247734579"
  uid: 7d757b0e-ea2c-4ac5-a7af-68ab2dad7e15
spec:
  rules:
  - host: punq.freshbrewed.science
    http:
      paths:
      - backend:
          service:
            name: punq-service
            port:
              number: 8080
        path: /backend/
        pathType: Prefix
      - backend:
          service:
            name: punq-service
            port:
              number: 8082
        path: /websocket/
        pathType: Prefix
      - backend:
          service:
            name: punq-service
            port:
              number: 8081
        path: /
        pathType: Prefix
  tls:
  - hosts:
    - punq.freshbrewed.science
    secretName: punq-tls
status:
  loadBalancer:
    ingress:
    - ip: 192.168.1.215
    - ip: 192.168.1.36
    - ip: 192.168.1.57
    - ip: 192.168.1.78

I also tried a port-forward for all the ports listed in the service definition, but that didn’t work too well either

$ kubectl port-forward svc/punq-service -n punq 8080:8080 8081:8081 8082:
8082
Forwarding from 127.0.0.1:8080 -> 8080
Forwarding from [::1]:8080 -> 8080
Forwarding from 127.0.0.1:8081 -> 8081
Forwarding from [::1]:8081 -> 8081
Forwarding from 127.0.0.1:8082 -> 8082
Forwarding from [::1]:8082 -> 8082

/content/images/2023/10/punq-54.png

I know that Nginx as an ingress controller has nuances with websockets. So plenty of times I’ve found systems that depend on websockets (websockets do not return 2xx, rather 101 and nginx is at the end of the day a form of a webserver) tend to not work so well with my Nginx Ingress controller.

I once tried living with Traefik, which is fine, but has other limitations. For instance, I find Nginx handles very large payloads (which happens with a CR) and includes some basic auth features.

AKS and MacOS

I decided to pivot and create a quick AKS cluster which is a proper k8s.

$ az group create --name mogenius --location centralus

$ az ad sp create-for-rbac -n idjaksupg01sp --skip-assignment --output json > my_sp.json

$ export SP_PASS=`cat my_sp.json | jq -r .password`
$ export SP_ID=`cat my_sp.json | jq -r .appId`

$ az aks create --resource-group mogenius --name idjaksmogenius --location centralus --node-count 3 --enable-cluster-autoscaler --min-count 2 --max-count 4 --generate-ssh-keys --network-plugin azure --network-policy azure --service-principal $SP_ID --client-secret $SP_PASS

I can now see it running

$ az aks list -o table
Name            Location    ResourceGroup    KubernetesVersion    CurrentKubernetesVersion    ProvisioningState    Fqdn
--------------  ----------  ---------------  -------------------  --------------------------  -------------------  -----------------------------------------------------------
idjaksmogenius  centralus   mogenius         1.26.6               1.26.6                      Succeeded            idjaksmoge-mogenius-8defc6-r99v9s2n.hcp.centralus.azmk8s.io

I’ll now login

$ az aks get-credentials -n idjaksmogenius -g mogenius --admin
Merged "idjaksmogenius-admin" as current context in /Users/isaac.johnson/.kube/config

My first attempt to install the homebrew formula failed as it wanted XCode updated

$ brew install punq
==> Fetching mogenius/punq/punq
==> Downloading https://github.com/mogenius/homebrew-punq/releases/download/v1.4.8/punq-v1.4.8-darwin-amd64.tar.gz
==> Downloading from https://objects.githubusercontent.com/github-production-release-asset-2e65be/679598369/b99cfab7-b8c5-45cf-a280-34364e3b5139?X-Amz
############################################################################################################################################### 100.0%
==> Installing punq from mogenius/punq
Error: Your Command Line Tools are too outdated.
Update them from Software Update in System Settings.

If that doesn't show you any updates, run:
  sudo rm -rf /Library/Developer/CommandLineTools
  sudo xcode-select --install

Alternatively, manually download them from:
  https://developer.apple.com/download/all/.
You should download the Command Line Tools for Xcode 15.0.

This was actually already slated to go. I generally stall on XCode updates because it always screws with my shell (leave bash alone dammit).

/content/images/2023/10/punq-47.png

The second run worked

$ brew install punq
==> Downloading https://formulae.brew.sh/api/formula.jws.json
############################################################################################################################################### 100.0%
==> Downloading https://formulae.brew.sh/api/cask.jws.json
############################################################################################################################################### 100.0%
==> Fetching mogenius/punq/punq
==> Downloading https://github.com/mogenius/homebrew-punq/releases/download/v1.4.8/punq-v1.4.8-darwin-amd64.tar.gz
Already downloaded: /Users/isaac.johnson/Library/Caches/Homebrew/downloads/9d7f2b5864e85cc823f38bd8c4384ab307bfb27b4bdb799115857bf5c65afd71--punq-v1.4.8-darwin-amd64.tar.gz
==> Installing punq from mogenius/punq
🍺  /usr/local/Cellar/punq/1.4.8: 3 files, 69.7MB, built in 6 seconds
==> Running `brew cleanup punq`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
==> `brew cleanup` has not been run in the last 30 days, running now...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/ansible--8.4.0... (53.1MB)
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/azure-cli--2.52.0_1... (47.5MB)
Removing: /usr/local/Cellar/brotli/1.0.9... (25 files, 2.3MB)
Removing: /usr/local/Cellar/ca-certificates/2023-01-10... (3 files, 216.9KB)
Removing: /usr/local/Cellar/ca-certificates/2023-05-30... (3 files, 216.2KB)
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/cffi--1.15.1... (166.8KB)
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/curl--8.3.0... (1.3MB)
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/freetds--1.3.20... (2.7MB)
Removing: /usr/local/Cellar/freetype/2.13.0_1... (67 files, 2.4MB)
Removing: /usr/local/Cellar/glib/2.76.1... (455 files, 21MB)
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/harfbuzz--8.2.0... (2.5MB)
Removing: /usr/local/Cellar/highway/1.0.4... (65 files, 4.0MB)
Removing: /usr/local/Cellar/jpeg-turbo/2.1.5.1... (44 files, 3.8MB)
Removing: /usr/local/Cellar/krb5/1.21... (162 files, 4.9MB)
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/libnghttp2--1.56.0... (213.6KB)
Removing: /usr/local/Cellar/libpq/15.3... (2,369 files, 28MB)
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/libtiff--4.5.1... (1.7MB)
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/libx11--1.8.6... (2.2MB)
Removing: /usr/local/Cellar/libxcb/1.15_1... (2,461 files, 6.9MB)
Removing: /usr/local/Cellar/libzip/1.9.2... (145 files, 779.4KB)
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/openexr--3.2.0... (1.9MB)
Removing: /usr/local/Cellar/openldap/2.6.4... (83 files, 6.6MB)
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/openssl@3--3.1.2... (7.9MB)
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/php--8.2.10... (19.9MB)
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/python-packaging--23.1... (129.5KB)
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/python-pytz--2023.3.post1... (822.9KB)
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/python@3.11--3.11.5... (14.8MB)
Removing: /usr/local/Cellar/pyyaml/6.0_1... (91 files, 1.9MB)
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/sqlite--3.43.1... (2.2MB)
Removing: /usr/local/Cellar/unixodbc/2.3.11... (48 files, 2.1MB)
Removing: /usr/local/Cellar/webp/1.3.0... (63 files, 2.5MB)
Removing: /usr/local/Cellar/webp/1.3.0_1... (63 files, 2.5MB)
Removing: /usr/local/Cellar/xorgproto/2022.2... (268 files, 3.9MB)
Removing: /usr/local/Cellar/xz/5.4.2... (162 files, 2.5MB)
Removing: /usr/local/Cellar/xz/5.4.3... (162 files, 2.5MB)
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/yq--4.35.1... (3.6MB)
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/krew_bottle_manifest--0.4.3... (8.5KB)
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/nvm_bottle_manifest--0.39.3... (1.7KB)
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/kubernetes-cli_bottle_manifest--1.27.2... (7.3KB)
Removing: /Users/isaac.johnson/Library/Caches/Homebrew/Cask/wkhtmltopdf--0.12.6-2.pkg... (48.8MB)
Pruned 0 symbolic links and 41 directories from /usr/local

The first time through, Punq recognized I needed an ingress controller

$ punq install -i punqaks.freshbrewed.science
Do you really want to install punq to 'idjaksmogenius-admin' context? [y/n]: y
Creating punq namespace ...
Created punq namespace. ✅
Creating punq RBAC ...
Created punq RBAC. ✅
Creating punq deployment ...
Created punq deployment. ✅
Determining cluster provider ...
Determined cluster provider: 'AKS'. ✅
Creating new punq-context secret ...
Created new punq-context secret. ✅
Creating punq service ...
Created punq service. ✅
Deleting punq RBAC ...
Deleted punq RBAC. ✅
Deleting punq deployment ...
Deleted punq deployment. ✅
Deleting punq/punq-contexts secret ...
Deleted punq/punq-contexts secret. ✅
Deleting punq/punq-users secret ...
Deleted punq/punq-users secret. ✅
Deleting punq-service service ...
Deleted punq-service service. ✅
Deleting punq-ingress ingress ...
Deleted punq-ingress ingress. ✅

🚀🚀🚀 Successfully uninstalled punq from 'idjaksmogenius-admin'.

Error: No ingress controller found.
We recomend installing TRAEFIK:
  helm repo add traefik https://traefik.github.io/charts
  helm install traefik traefik/traefik
After installing TRAEFIK, you can retry installing punq.

Once I upgraded my helm to a sufficiently new enough version (3.9 or higher) then I could add traeffik

$ helm install traefik traefik/traefik
NAME: traefik
LAST DEPLOYED: Wed Oct 18 14:59:29 2023
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Traefik Proxy v2.10.4 has been deployed successfully on default namespace !

This time it worked

$ punq install -i punqaks.freshbrewed.science
Do you really want to install punq to 'idjaksmogenius-admin' context? [y/n]: y
Creating punq namespace ...
Created punq namespace. ✅
Creating punq RBAC ...
Created punq RBAC. ✅
Creating punq deployment ...
Created punq deployment. ✅
Determining cluster provider ...
Determined cluster provider: 'AKS'. ✅
Creating new punq-context secret ...
Created new punq-context secret. ✅
Creating punq service ...
Created punq service. ✅
Creating TRAEFIK punq ingress (punqaks.freshbrewed.science) ...
Created TRAEFIK punq ingress (punqaks.freshbrewed.science). ✅
Creating TRAEFIK middleware (punqaks.freshbrewed.science) ...
Created TRAEFIK middleware (punqaks.freshbrewed.science). ✅

🚀🚀🚀 Successfully installed punq in 'idjaksmogenius-admin'.

Creating new punq-auth secret ...
Created new punq-users secret. ✅
{
  "id": "WWjuFslSjm1Wo7LQyC0go",
  "email": "hannah-cohen@punq.dev",
  "password": "xxxxxxxxx",
  "displayName": "ADMIN USER",
  "accessLevel": 2,
  "createdAt": "2023-10-18T15:00:32-05:00",
}
Creating new punq-auth secret ...
Created new punq-auth secret. ✅

I can now see the Ingress and external IP I’ll need to use for an A Record

$ kubectl get svc traefik
NAME      TYPE           CLUSTER-IP    EXTERNAL-IP      PORT(S)                      AGE
traefik   LoadBalancer   10.0.205.87   52.158.174.233   80:30575/TCP,443:30160/TCP   109s

$ kubectl get ingress --all-namespaces
NAMESPACE   NAME           CLASS     HOSTS                         ADDRESS   PORTS   AGE
punq        punq-ingress   traefik   punqaks.freshbrewed.science             80      52s

I’ll make a quick A record

/content/images/2023/10/punq-48.png

I can see it show up, but without a proper cert. This makes sense as we have no clusterissuer so I would be unsure how it would have gotten a signed TLS if it did work.

/content/images/2023/10/punq-49.png

The ingress:

$ kubectl get ingress punq-ingress -n punq -o yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
    traefik.ingress.kubernetes.io/router.middlewares: punq-mw-backend@kubernetescrd
  creationTimestamp: "2023-10-18T20:00:31Z"
  generation: 1
  name: punq-ingress
  namespace: punq
  resourceVersion: "7104"
  uid: 30fea16f-adf5-4fea-af2c-774ee406ebcc
spec:
  ingressClassName: traefik
  rules:
  - host: punqaks.freshbrewed.science
    http:
      paths:
      - backend:
          service:
            name: punq-service
            port:
              number: 8080
        path: /backend/
        pathType: Prefix
      - backend:
          service:
            name: punq-service
            port:
              number: 8082
        path: /websocket/
        pathType: Prefix
      - backend:
          service:
            name: punq-service
            port:
              number: 8081
        path: /
        pathType: Prefix
status:
  loadBalancer: {}

I’ll login with the setup credentials Punq gave me

/content/images/2023/10/punq-50.png

I can get a shell into a pod which is a pretty handy feature

/content/images/2023/10/punq-51.png

I can view the describe output and YAML but not edit them

/content/images/2023/10/punq-52.png

I know many people like dark mode, but I rather liked the UI in light

/content/images/2023/10/punq-53.png

Lastly, from lessons learned in recent months, we can clean up the cluster when done

$ az aks delete -n idjaksmogenius -g mogenius 
Are you sure you want to perform this operation? (y/n): y
 \ Running ..


$ az group delete -n mogenius
Are you sure you want to perform this operation? (y/n): y
 \ Running ..

mogenius

We can signup on mogenius

/content/images/2023/10/punq-05.png

I can now create organizations

/content/images/2023/10/punq-06.png

I’ll create a PK Org

/content/images/2023/10/punq-07.png

I now have a 2-week free trial listed (Note: While the UI did not indicate the other address fields were required, once you enter some, you have to enter the rest)

/content/images/2023/10/punq-08.png

I think I’m in my Organization, though there is no UI element to indicate as such

/content/images/2023/10/punq-09.png

Next, I’ll add a cluster and indicate my primary

/content/images/2023/10/punq-10.png

I decided to add my second cluster as I don’t know what this will do exactly and realized the trial gives you a 1 cluster limit

/content/images/2023/10/punq-11.png

My first attempt to install to my v1.26 k3s cluster failed due to an existing metrics server

builder@anna-MacBookAir:~$ kubectl create namespace mogenius
helm repo add mogenius https://helm.mogenius.com/public
helm repo update
helm install mogenius mogenius/mogenius-platform -n mogenius \
--set namespace="mogenius" \
--set global.cluster_name="myprimaryprod" \
--set global.api_key="mo_13e3ac31-44d6-49f3-aedb-fb4db89a3bb5_kxxseebzgo8u6u2k62gq" \
--set global.namespace="mogenius" \
--set global.cluster_provider="K3S" \
--set k8smanager.enabled=true \
--set metrics.enabled=true \
--set traffic-collector.enabled=true \
--set pod-stats-collector.enabled=true \
--set ingress-nginx.enabled=false
namespace/mogenius created
WARNING: Kubernetes configuration file is group-readable. This is insecure. Location: /home/builder/.kube/config
WARNING: Kubernetes configuration file is world-readable. This is insecure. Location: /home/builder/.kube/config
"mogenius" has been added to your repositories
WARNING: Kubernetes configuration file is group-readable. This is insecure. Location: /home/builder/.kube/config
WARNING: Kubernetes configuration file is world-readable. This is insecure. Location: /home/builder/.kube/config
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "nfs" chart repository
...Successfully got an update from the "teletrace" chart repository
...Successfully got an update from the "akomljen-charts" chart repository
...Successfully got an update from the "open-telemetry" chart repository
...Successfully got an update from the "mogenius" chart repository
Update Complete. ⎈Happy Helming!⎈
WARNING: Kubernetes configuration file is group-readable. This is insecure. Location: /home/builder/.kube/config
WARNING: Kubernetes configuration file is world-readable. This is insecure. Location: /home/builder/.kube/config
Error: INSTALLATION FAILED: Unable to continue with install: ServiceAccount "metrics-server" in namespace "kube-system" exists and cannot be imported into the current release: invalid ownership metadata; label validation error: missing key "app.kubernetes.io/managed-by": must be set to "Helm"; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "mogenius"; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "mogenius"

Without Metrics Server, it worked

kubectl create namespace mogenius
helm repo add mogenius https://helm.mogenius.com/public
helm repo update
helm install mogenius mogenius/mogenius-platform -n mogenius \
--set namespace="mogenius" \
--set global.cluster_name="myprimaryprod" \
--set global.api_key="mo_13e3ac31-44d6-49f3-aedb-fb4db89a3bb5_kxxseebzgo8u6u2k62gq" \
--set global.namespace="mogenius" \
--set global.cluster_provider="K3S" \
--set k8smanager.enabled=true \
--set metrics.enabled=false \
--set traffic-collector.enabled=true \
--set pod-stats-collector.enabled=true \
--set ingress-nginx.enabled=false


NAME: mogenius
LAST DEPLOYED: Tue Oct 17 16:39:51 2023
NAMESPACE: mogenius
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Thank you for installing mogenius-platform.

Your release is named mogenius.

Check your installation:

#> kubectl get deploy -n mogenius
#> kubectl get pods -n mogenius

Make sure that the ClusterIssuer is installed in your cluster:

#> kubectl get clusterissuer

If the ClusterIssuer is not installed yet, execute the following command:

#> helm install mogenius-issuer mogenius/mogenius-cluster-issuer --set global.clusterissuermail="yourmailaddr@company.com"

For the DNS configuration for the load balancer host, you can read the IP from the ingress service configuration with the following command:

#> kubectl get services \
   --namespace mogenius \
   mogenius-ingress-nginx-controller \
   --output jsonpath='{.status.loadBalancer.ingress[0].ip}'

I then saw a notice it connected in the Web UI

/content/images/2023/10/punq-12.png

Clicking the connected cluster I could see general details

/content/images/2023/10/punq-13.png

I could see all sorts of things under workloads like namespaces

/content/images/2023/10/punq-14.png

Pretty much anything in the cluster I could view, the list was too long to show

/content/images/2023/10/punq-15.png

Anything I could view, I could also edit such as secrets

/content/images/2023/10/punq-16.png

I particularly liked the details shown in the service

/content/images/2023/10/punq-17.png

While YAML always worked, the describe only did sometimes. Here is a blank describe on a PVC

/content/images/2023/10/punq-18.png

Projects

Let’s create our first project

/content/images/2023/10/punq-19.png

This opened up a world of options

/content/images/2023/10/punq-20.png

Let’s try firing up a service using an ubuntu container

/content/images/2023/10/punq-21.png

We can then watch it launch the deployment with the pod

/content/images/2023/10/punq-22.png

It crashed

/content/images/2023/10/punq-23.png

But I’m pretty sure its because Ubuntu needs an entrypoint/command to hold it live.

Let’s change that

/content/images/2023/10/punq-24.png

Once I fixed those settings (it does want them in brackets)

/content/images/2023/10/punq-25.png

It stayed up

builder@anna-MacBookAir:~$ kubectl get pods -n myfirstproject-prod-by1sfd
NAME                              READY   STATUS    RESTARTS   AGE
myfirstservice-7944bf8f55-tswdr   1/1     Running   0          69s

If there were logs, we could view them now

/content/images/2023/10/punq-26.png

One feature that didn’t seem to work was ‘Scan Vulnerabilities’

I tried a few times clicking “Scan Vulnerabilities”

/content/images/2023/10/punq-28.png

which would kill the pod

/content/images/2023/10/punq-27.png

But each time, coming back to the page, just showed the same page:

/content/images/2023/10/punq-29.png

I tried to add an app, but I was dismayed in the limited set of CRs available (where is Harbor? Or just enter my own with Docker v1 login?) - Update: I can use any - see “Custom CR” section below

/content/images/2023/10/punq-31.png

The second, is it tried to push the container image to ‘docker.io/library/myfirstproject-prod-by1sfd-mydocusaurus3’ and it’s required for user spaces to always be in your username, ie. docker.io/library/idjohnson/whatever

/content/images/2023/10/punq-30.png

Actually, that was my mistake. One needs to put in their path on the Registry-Path and I had left it default

/content/images/2023/10/punq-32.png

Once I corrected, I tried a rebuild

/content/images/2023/10/punq-33.png

Not sure what happened, but it stopped after the clone

/content/images/2023/10/punq-34.png

I decided to try fresh again with a Docusaurus deploy

I’m not sure what the issue is.

I snagged the deployment yaml, removed the pause and deploymentprogression time limit and tried applying a “7b”

$ cat t.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  generation: 1
  labels:
    mo-service-name: mydocusaurus7b
  name: mydocusaurus7b
  namespace: myfirstproject-prod-by1sfd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mydocusaurus7b
      ns: myfirstproject-prod-by1sfd
  strategy:
    type: Recreate
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: mydocusaurus7b
        ns: myfirstproject-prod-by1sfd
    spec:
      containers:
      - image: ghcr.io/mogenius/mo-default-backend:latest
        imagePullPolicy: Always
        name: mydocusaurus7
        ports:
        - containerPort: 3000
          protocol: TCP
        resources:
          limits:
            cpu: 200m
            ephemeral-storage: 100Mi
            memory: 256Mi
          requests:
            cpu: 1m
            ephemeral-storage: 100Mi
            memory: 1Mi
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      imagePullSecrets:
      - name: container-secret-myfirstproject-prod-by1sfd
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30

$ kubectl apply -f t.yaml
deployment.apps/mydocusaurus7b created

Whatever the issue, both 7 and 7b now showup

builder@DESKTOP-QADGF36:~/glibc/build$ kubectl get rs -n myfirstproject-prod-by1sfd
NAME                        DESIRED   CURRENT   READY   AGE
myfirstservice-f7d4cfff9    1         1         1       70m
myfirstservice-57f4db55c8   0         0         0       72m
mydocusaurus7b-689b57896f   1         1         1       65s
mydocusaurus7-5c5c95dbf6    1         1         0       17s

We can actually see a full CI/CD flow in updating the repo then seeing it fully build and deploy a changed container:

If we look at the mogenius namespace, we can see the pods I got out of the box with our deployment. Note, I turned a lot of features like Metrics and Cluster issuer off.

/content/images/2023/10/punq-37.png

We can see some of the logs of the pods and that my Certificates are stuck because my demo cluster lacks a clusterissuer

It would seem that it really wants a cluster issuer named “letsencrypt-cluster-issuer” and that is not a setting I can change in the Cluster settings.

My primary cluster uses

$ kubectl get clusterissuer
NAME                   READY   AGE
letsencrypt-staging    True    449d
letsencrypt-prod-old   True    449d
letsencrypt-prod       True    449d

So if I onboarded mogenius to my main, I might have to duplicate letsencrypt-prod

Custom CR

With a followup email from Jan, I got details on the CR drop down. It was a pick list of suggestions, but one can just type in their own URL if they desire.

Let’s use our Harbor CR in this case.

First, in Harbor, I’ll create a new user:

/content/images/2023/10/punq-38.png

and add to my private project

/content/images/2023/10/punq-39.png

I then set it in the cluster settings of mogenius

/content/images/2023/10/punq-40.png

And added an app

/content/images/2023/10/punq-41.png

mogenius then kicked in a build

/content/images/2023/10/punq-42.png

when the build was wrapping, I saw the new container show up in Harbor

/content/images/2023/10/punq-43.png

And using logs, could verify it was that mogenius user I had just created that uploaded it

/content/images/2023/10/punq-45.png

I can now pull details and scan for Vulnerabilities in Harbor

/content/images/2023/10/punq-44.png

Partial results:

/content/images/2023/10/punq-46.png

Summary

As we saw, Punq works great with Traefik on-prem but not as well with Istio or Nginx. I imagine if a Docker Compose version comes out, I could move to using that. I think Punq has a lot of promise and until I respin my secondary cluster, I’ll continue to experiment with it.

mogenius will release pricing soon, but it will likely be starting around US$1000/mo for the Professional plan and starting around US$2600/mo for Enterprise.

The official prices should come out in the coming weeks and might be slightly different (I converted from Euros so it’s loose numbers).

Punq mogenius

Have something to add? Feedback? You can use the feedback form

Isaac Johnson

Isaac Johnson

Cloud Solutions Architect

Isaac is a CSA and DevOps engineer who focuses on cloud migrations and devops processes. He also is a dad to three wonderful daughters (hence the references to Princess King sprinkled throughout the blog).

Theme built by C.S. Rhymes