Compare commits

..

32 Commits

Author SHA1 Message Date
argoyle a62ee9efb1 refactor: migrate from ingress-nginx to Traefik v3 (#254)
## Summary

- Replace ingress-nginx 4.15.1 with Traefik v3 (Helm chart 39.0.7) as ingress controller
- Convert nginx-specific annotations to Traefik Middleware CRDs
- Update setup script selectors, namespaces, and readiness checks
- Add `.claude/settings.local.json` to `.gitignore`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed-on: #254
2026-04-15 13:05:43 +00:00
renovate 17c97b4333 chore(deps): update helm release cert-manager to v1.20.2 (#253) 2026-04-14 15:06:49 +00:00
renovate e6a410f926 chore(deps): update helm release external-secrets to v2.3.0 (#252) 2026-04-13 16:05:57 +00:00
renovate a79fb8df5a chore(deps): update helm release external-secrets to v2.3.0 (#252) 2026-04-13 16:05:54 +00:00
renovate 068537b11d chore(deps): update helm release cert-manager to v1.20.1 (#251) 2026-03-27 20:05:31 +00:00
renovate 5c3d6736dc chore(deps): update helm release external-secrets to v2.2.0 (#250) 2026-03-20 17:05:24 +00:00
renovate 62e363f01e chore(deps): update helm release ingress-nginx to v4.15.1 (#249) 2026-03-19 22:05:19 +00:00
renovate 99968b13b7 chore(deps): update helm release cert-manager to v1.20.0 (#248) 2026-03-10 16:06:09 +00:00
renovate 1de8e79a05 chore(deps): update helm release ingress-nginx to v4.15.0 (#247) 2026-03-09 21:06:11 +00:00
renovate 03bfdf847f chore(deps): update cloudamqp/lavinmq docker tag to v2.6.10 (#246) 2026-03-09 11:13:40 +00:00
renovate 9a066ac5d0 chore(deps): update helm release external-secrets to v2.1.0 (#245) 2026-03-07 18:05:18 +00:00
renovate b7f407e2d5 chore(deps): update cloudamqp/lavinmq docker tag to v2.6.9 (#244) 2026-03-03 18:08:05 +00:00
renovate f5aac44bd6 chore(deps): update postgres:18.3-alpine docker digest to 4da1a48 (#243) 2026-02-28 09:05:40 +00:00
renovate 9ff876b158 chore(deps): pin cloudamqp/lavinmq docker tag to b564dd1 (#242) 2026-02-27 14:07:24 +00:00
argoyle c93f98c93c Merge pull request 'feat(infra): replace RabbitMQ with LavinMQ' (#241) from replace-rabbitmq-with-lavinmq into main
Reviewed-on: #241
2026-02-27 13:43:44 +00:00
argoyle d89ec816a0 feat(infra): replace RabbitMQ with LavinMQ 2026-02-27 14:42:27 +01:00
renovate 5c0d102410 chore(deps): update postgres:18.3-alpine docker digest to 97e0c20 (#240) 2026-02-26 23:06:05 +00:00
renovate 34d214609d chore(deps): update postgres docker tag to v18.3 (#239) 2026-02-26 19:27:55 +00:00
renovate ed5068ae50 chore(deps): update rabbitmq:4.2.4-management docker digest to d998227 (#238) 2026-02-25 10:07:04 +00:00
renovate 5048ff2c75 chore(deps): update rabbitmq:4.2.4-management docker digest to d957c24 (#237) 2026-02-25 05:05:35 +00:00
argoyle 500f7a899b Merge pull request 'chore(deps): update helm release cert-manager to v1.19.4' (#236) from renovate/cert-manager-1.x into main
Reviewed-on: #236
2026-02-24 16:37:18 +00:00
renovate 30d9343114 chore(deps): update helm release cert-manager to v1.19.4 2026-02-24 16:08:09 +00:00
argoyle 1d3db2a586 Merge pull request 'chore(deps): update rabbitmq:4.2.4-management docker digest to ae4a462' (#235) from renovate/rabbitmq-4.2.4-management into main
Reviewed-on: #235
2026-02-21 07:55:44 +00:00
renovate 1d9202c985 chore(deps): update rabbitmq:4.2.4-management docker digest to ae4a462 2026-02-21 00:05:23 +00:00
argoyle 4708f6c4f8 Merge pull request 'chore(deps): update helm release external-secrets to v2.0.1' (#234) from renovate/external-secrets-2.x into main
Reviewed-on: #234
2026-02-20 17:09:52 +00:00
renovate 96b2c82124 chore(deps): update helm release external-secrets to v2.0.1 2026-02-20 14:18:52 +00:00
argoyle ac362db912 Merge pull request 'chore(deps): update postgres:18.2-alpine docker digest to 035b9ab' (#233) from renovate/postgres-18.2-alpine into main
Reviewed-on: #233
2026-02-19 06:33:56 +00:00
renovate 88074eac07 chore(deps): update postgres:18.2-alpine docker digest to 035b9ab 2026-02-19 02:21:07 +00:00
argoyle 57e17c6c37 Merge pull request 'chore(deps): update rabbitmq:4.2.4-management docker digest to 1b5ac1f' (#232) from renovate/rabbitmq-4.2.4-management into main
Reviewed-on: #232
2026-02-18 12:45:37 +00:00
renovate 3fde6c72da chore(deps): update rabbitmq:4.2.4-management docker digest to 1b5ac1f 2026-02-18 11:07:09 +00:00
argoyle 7196f49a7e Merge pull request 'chore(deps): update rabbitmq:4.2.4-management docker digest to f88cfa9' (#231) from renovate/rabbitmq-4.2.4-management into main
Reviewed-on: #231
2026-02-18 07:16:41 +00:00
renovate dddf77edaa chore(deps): update rabbitmq:4.2.4-management docker digest to f88cfa9 2026-02-18 02:06:06 +00:00
12 changed files with 181 additions and 193 deletions
+1
View File
@@ -1,2 +1,3 @@
data
charts
.claude/settings.local.json
+22 -4
View File
@@ -24,9 +24,9 @@ kind: Ingress
metadata:
name: frontend
annotations:
nginx.ingress.kubernetes.io/upstream-vhost: "localhost:3300"
traefik.ingress.kubernetes.io/router.middlewares: default-frontend-host@kubernetescrd
spec:
ingressClassName: nginx
ingressClassName: traefik
tls:
- hosts:
- staging-shiny.unbound.se
@@ -59,9 +59,9 @@ kind: Ingress
metadata:
name: api
annotations:
nginx.ingress.kubernetes.io/upstream-vhost: "localhost:4444"
traefik.ingress.kubernetes.io/router.middlewares: default-api-host@kubernetescrd
spec:
ingressClassName: nginx
ingressClassName: traefik
tls:
- hosts:
- staging-shiny-api.unbound.se
@@ -77,3 +77,21 @@ spec:
name: api-external
port:
number: 4444
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: frontend-host
spec:
headers:
customRequestHeaders:
Host: "localhost:3300"
---
apiVersion: traefik.io/v1alpha1
kind: Middleware
metadata:
name: api-host
spec:
headers:
customRequestHeaders:
Host: "localhost:4444"
+1 -1
View File
@@ -33,6 +33,6 @@ spec:
- key: "rds/postgres/prod-psql"
value: '{"POSTGRES_URL": "postgres://postgres:postgres@postgres:5432/postgres?sslmode=disable", "DB_HOST": "postgres", "DB_NAME": "postgres", "DB_PASSWORD": "postgres", "DB_PORT": "5432", "DB_USERNAME": "postgres"}'
- key: "mq/rabbit/prod"
value: '{"AMQP_URL": "amqp://user:password@rabbitmq:5672/"}'
value: '{"AMQP_URL": "amqp://guest:guest@lavinmq:5672/"}'
- key: "services/schemas"
value: '{"ISSUER": "auth0", "STRICT_SSL": "false"}'
+3 -3
View File
@@ -2,7 +2,7 @@ apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- postgres.yaml
- rabbitmq.yaml
- lavinmq.yaml
- namespaces.yaml
helmCharts:
- name: external-secrets
@@ -10,13 +10,13 @@ helmCharts:
includeCRDs: true
releaseName: external-secrets
repo: https://charts.external-secrets.io
version: 2.0.0
version: 2.3.0
- name: cert-manager
namespace: cert-manager
includeCRDs: true
releaseName: cert-manager
repo: https://charts.jetstack.io
version: v1.19.3
version: v1.20.2
valuesInline:
crds:
enabled: true
+100
View File
@@ -0,0 +1,100 @@
apiVersion: v1
kind: Secret
metadata:
name: lavinmq
stringData:
AMQP_URL: "amqp://guest:guest@lavinmq:5672/"
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/name: lavinmq
release: lavinmq
name: lavinmq
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: lavinmq
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:
app.kubernetes.io/name: lavinmq
spec:
containers:
- image: cloudamqp/lavinmq:2.6.10@sha256:e52866d61141b3bb61a3ae99acd7fac1c750ba86af50037864f9498c27fbd89a
imagePullPolicy: Always
livenessProbe:
tcpSocket:
port: 5672
failureThreshold: 6
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
name: lavinmq
ports:
- containerPort: 5672
name: amqp
protocol: TCP
- containerPort: 15672
name: stats
protocol: TCP
readinessProbe:
httpGet:
port: 15672
path: /api/whoami
httpHeaders:
- name: "Authorization"
value: "Basic Z3Vlc3Q6Z3Vlc3Q="
failureThreshold: 3
initialDelaySeconds: 10
periodSeconds: 5
successThreshold: 1
timeoutSeconds: 3
resources:
requests:
cpu: 100m
memory: 256Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- name: data
mountPath: /var/lib/lavinmq
volumes:
- name: data
hostPath:
path: /data/lavinmq
dnsPolicy: ClusterFirst
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: lavinmq
release: lavinmq
name: lavinmq
spec:
externalTrafficPolicy: Cluster
ports:
- name: amqp
nodePort: 5672
port: 5672
protocol: TCP
targetPort: amqp
- name: stats
nodePort: 15672
port: 15672
protocol: TCP
targetPort: stats
selector:
app.kubernetes.io/name: lavinmq
sessionAffinity: None
type: NodePort
+1 -1
View File
@@ -52,7 +52,7 @@ spec:
spec:
containers:
- name: postgres
image: postgres:18.2-alpine@sha256:88f300be8635fe8a9ed4c18a68ba497fb6df1215fd2b074895afd027bd3e1006
image: postgres:18.3-alpine@sha256:4da1a4828be12604092fa55311276f08f9224a74a62dcb4708bd7439e2a03911
args:
- -c
- shared_buffers=384MB
-166
View File
@@ -1,166 +0,0 @@
kind: ConfigMap
apiVersion: v1
metadata:
name: shared-rabbitmq
data:
RABBITMQ_SERVERS: rabbitmq
RABBITMQ_VHOST: /
RABBITMQ_USERNAME: user
---
apiVersion: v1
kind: ConfigMap
metadata:
name: rabbitmq-env-config
data:
memory.conf: |-
total_memory_available_override_value = 1GB
---
apiVersion: v1
kind: Secret
metadata:
name: rabbitmq
stringData:
AMQP_URL: "amqp://user:password@rabbitmq:5672/"
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/name: rabbitmq
release: rabbitmq
name: rabbitmq
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: rabbitmq
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
labels:
app.kubernetes.io/name: rabbitmq
spec:
securityContext:
fsGroup: 999
runAsUser: 999
runAsGroup: 999
containers:
- env:
- name: RABBITMQ_DEFAULT_USER
value: user
- name: RABBITMQ_DEFAULT_PASS
value: password
- name: RABBITMQ_NODE_PORT_NUMBER
value: "5672"
- name: RABBITMQ_NODE_TYPE
value: stats
- name: RABBITMQ_NODENAME
value: rabbit@localhost
- name: RABBITMQ_CLUSTER_NODE_NAME
- name: RABBITMQ_DEFAULT_VHOST
value: /
- name: RABBITMQ_MANAGER_PORT_NUMBER
value: "15672"
- name: RABBITMQ_DISK_FREE_LIMIT
value: '"8GiB"'
- name: RABBITMQ_CONFIG_FILES
value: /etc/rabbitmq/conf.d
image: rabbitmq:4.2.4-management@sha256:eb37f58646a901dc7727cf448cae36daaefaba79de33b5058dab79aa4c04aefb
imagePullPolicy: Always
livenessProbe:
exec:
command:
- rabbitmqctl
- status
failureThreshold: 6
initialDelaySeconds: 120
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
name: rabbitmq
ports:
- containerPort: 4369
name: epmd
protocol: TCP
- containerPort: 5672
name: amqp
protocol: TCP
- containerPort: 25672
name: dist
protocol: TCP
- containerPort: 15672
name: stats
protocol: TCP
readinessProbe:
httpGet:
port: 15672
path: /api/aliveness-test/%2F
httpHeaders:
- name: "Authorization"
value: "Basic dXNlcjpwYXNzd29yZA=="
failureThreshold: 3
initialDelaySeconds: 10
periodSeconds: 5
successThreshold: 1
timeoutSeconds: 3
resources:
requests:
cpu: 100m
memory: 256Mi
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
volumeMounts:
- name: data
mountPath: /var/lib/rabbitmq
- name: config
mountPath: /etc/rabbitmq/conf.d/20-memory.conf
subPath: memory.conf
readOnly: true
volumes:
- name: data
hostPath:
path: /data/rabbitmq
- name: config
configMap:
name: rabbitmq-env-config
dnsPolicy: ClusterFirst
restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: rabbitmq
release: rabbitmq
name: rabbitmq
spec:
externalTrafficPolicy: Cluster
ports:
- name: epmd
nodePort: 31799
port: 4369
protocol: TCP
targetPort: epmd
- name: amqp
nodePort: 5672
port: 5672
protocol: TCP
targetPort: amqp
- name: dist
nodePort: 32687
port: 25672
protocol: TCP
targetPort: dist
- name: stats
nodePort: 15672
port: 15672
protocol: TCP
targetPort: stats
selector:
app.kubernetes.io/name: rabbitmq
sessionAffinity: None
type: NodePort
-12
View File
@@ -1,12 +0,0 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespaces.yaml
helmCharts:
- name: ingress-nginx
namespace: ingress-nginx
includeCRDs: true
releaseName: ingress-nginx
repo: https://kubernetes.github.io/ingress-nginx
version: 4.14.3
valuesFile: https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/hack/manifest-templates/provider/kind/values.yaml
+12
View File
@@ -0,0 +1,12 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespaces.yaml
helmCharts:
- name: traefik
namespace: traefik
includeCRDs: true
releaseName: traefik
repo: https://traefik.github.io/charts
version: 39.0.7
valuesFile: values.yaml
+4
View File
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: traefik
+31
View File
@@ -0,0 +1,31 @@
deployment:
kind: DaemonSet
ports:
web:
hostPort: 80
websecure:
hostPort: 443
tolerations:
- key: "node-role.kubernetes.io/master"
operator: "Equal"
effect: "NoSchedule"
- key: "node-role.kubernetes.io/control-plane"
operator: "Equal"
effect: "NoSchedule"
nodeSelector:
ingress-ready: "true"
providers:
kubernetesIngress:
publishedService:
enabled: false
service:
type: ClusterIP
ingressClass:
enabled: true
isDefaultClass: true
+6 -6
View File
@@ -12,20 +12,20 @@ kubectl create secret docker-registry gitlab \
kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "gitlab"}]}'
kustomized="$(mktemp -t unboundnginx.yaml.XXXXXX)"
kustomized="$(mktemp -t unboundtraefik.yaml.XXXXXX)"
kubectl kustomize --enable-helm "k8s/nginx" >> "${kustomized}"
kubectl kustomize --enable-helm "k8s/traefik" >> "${kustomized}"
kubectl apply -f "${kustomized}" --server-side || true
printf "\nWait for pod app.kubernetes.io/component=controller to be created."
printf "\nWait for pod app.kubernetes.io/name=traefik to be created."
while :; do
sleep 2
[ -n "$(kubectl -n ingress-nginx get pod --selector=app.kubernetes.io/component=controller 2>/dev/null)" ] && printf "\n\n" && break
[ -n "$(kubectl -n traefik get pod --selector=app.kubernetes.io/name=traefik 2>/dev/null)" ] && printf "\n\n" && break
printf "."
done
echo "Wait for nginx to be available."
until [[ $(kubectl -n ingress-nginx get endpointslices -l 'kubernetes.io/service-name=ingress-nginx-controller' -o=jsonpath='{.items[*].endpoints[*].addresses[*]}') ]]; do sleep 5; done
echo "Wait for traefik to be available."
until [[ $(kubectl -n traefik get endpointslices -l 'kubernetes.io/service-name=traefik' -o=jsonpath='{.items[*].endpoints[*].addresses[*]}') ]]; do sleep 5; done
kustomized="$(mktemp -t unboundinfra.yaml.XXXXXX)"