Compare commits

...
11 Commits
Author SHA1 Message Date
Jeffrey f53e8f5b00 jellyfin: upgrade to 12.0
All five installed plugins have 12.0.0.0 targetAbi builds available. The
archived 9p4 SSO Authentication plugin has been removed, since it has no
v12 build and is being replaced by an OIDC plugin later.

Plugins must be updated from the Jellyfin dashboard after the rollout;
the container upgrade does not touch /config/plugins.
2026-09-13 12:56:38 +02:00
Jeffrey 30f9c63c9b authentik: spell out API-defaulted fields on the LDAP route and listeners
The API server defaults group on allowedRoutes.kinds and certificateRefs,
and group, kind and weight on the TCPRoute backendRefs. Omitting them left
both ArgoCD apps permanently OutOfSync against the live objects. Matches
what authentik-httproute.yaml already does.
2026-09-13 11:39:35 +02:00
Jeffrey c1287fa343 authentik: serve LDAP via an outpost behind the internal gateway
Adds the LDAP outpost deployment and routes ports 389 and 636 on
gateway-internal to it. 636 is a TLS listener in Terminate mode so
cert-manager renews the LDAPS certificate automatically, and both
listeners forward to the outpost's plaintext 3389.

allowedRoutes.kinds is set explicitly on both listeners: a TCP listener
permits no route kinds by default and a TLS listener defaults to
TLSRoute, so the TCPRoute would not attach otherwise.
2026-09-13 11:24:23 +02:00
Jeffrey 7ee7db2346 minio-aistor: restore the backend traffic policy to its pre-4207459 state
Swept into d5e0731 by the same stray `git add -u`. Unlike argocd-install
this one is synced, so it went live; reverting here rolls the cluster back
to connectionIdleTimeout 3600s with no retry block.

The content is still reachable at d5e0731 if it is wanted back.
2026-08-29 19:08:17 +02:00
Jeffrey 1593166803 argocd: restore argocd-install.yaml to its pre-4207459 state
It was swept into d5e0731 by a stray `git add -u` while amending an
unrelated commit. Nothing syncs infra/argocd, so the cluster was never
affected, but the file did not belong in that change.

The content is still reachable at d5e0731 if it is wanted back.
2026-08-29 19:07:16 +02:00
Jeffrey 42074599e9 gitea-runner: add the missing Application manifest
The Application was created with kubectl and never committed, so its chart
version, release config and values path lived only on the cluster. That made
the values-path fix a live patch: recreating the app would have restored the
old $values/gitea/runner/values.yaml and broken helm template again.

Both sources are public, so this sits alongside the other Helm-based apps
here rather than in the private repo.
2026-08-29 18:56:36 +02:00
Jeffrey a775c8b837 victoria-metrics: pin back to chart 0.77.0 after a failed 0.91.2 upgrade
The 0.91.2 bump had been sitting in Git unapplied because the app could not
generate manifests. Once the values path was fixed it applied, and Grafana
crash-looped on "Datasource provisioning error: data source not found".
Rolled back; Grafana and all 35 VMRules are healthy again on 0.77.0.

0.91.2 also moves the default dashboards and rules out of the Helm render
into a runtime sync-job, so upgrading needs a values migration and a
verified datasource config rather than a version bump.
2026-08-29 18:39:49 +02:00
Jeffrey 02c43d8b85 victoria-metrics: point the values ref at applications/
$values resolves to the repo root, so $values/victoria-metrics/values.yaml
never existed once the manifests moved under applications/. helm template
failed on every reconcile, leaving the app permanently sync status Unknown.

gitea-runner had the same broken path but has no manifest in this repo, so
it was patched on the cluster only.
2026-08-29 18:18:27 +02:00
Jeffrey d5e073131d infisical: ignore every volumeClaimTemplate field the api server injects
The earlier rule covered creationTimestamp, volumeMode and status but missed
apiVersion and kind, which the API server also injects into
volumeClaimTemplates. Those two alone kept both StatefulSets permanently
OutOfSync: a sync would apply successfully and report Synced, then the very
next comparison flagged them again.
2026-08-29 18:16:25 +02:00
Jeffrey 8fa2cb558e infisical: ignore the volumeClaimTemplate fields argocd cannot reconcile
A StatefulSet's volumeClaimTemplates are immutable, and the API server
injects creationTimestamp, volumeMode and a status block that are not in
the manifest. ArgoCD diffed those and reported OutOfSync permanently,
since no sync could ever resolve them.

infisical-postgres and infisical-valkey are the only StatefulSets here
using volumeClaimTemplates, which is why this app alone was affected.
2026-08-29 18:00:35 +02:00
Jeffrey 7a937dae07 gitea: drop the orphaned runner pvc that could never bind
gitea-runner-pvc referenced volumeName gitea-runner-data, but neither that
PV nor a Longhorn volume of that name exists, so it sat Pending since May.
ArgoCD treats a Pending PVC as Progressing and rolled that up to the whole
app, which is why gitea never reported Healthy.

Nothing mounted it. The runner uses the PVC the gitea/actions chart
generates from its own volumeClaimTemplate.
2026-08-29 18:00:28 +02:00
12 changed files with 223 additions and 16 deletions
@@ -0,0 +1,46 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: authentik-ldap
namespace: authentik
spec:
replicas: 1
selector:
matchLabels:
app: authentik-ldap
template:
metadata:
labels:
app: authentik-ldap
spec:
containers:
- name: ldap
image: ghcr.io/goauthentik/ldap:2026.8.0
ports:
- containerPort: 3389
name: ldap
- containerPort: 6636
name: ldaps
- containerPort: 9300
name: metrics
envFrom:
- secretRef:
name: authentik-ldap-secrets
livenessProbe:
httpGet:
path: /outpost.goauthentik.io/ping
port: 9300
initialDelaySeconds: 10
periodSeconds: 30
readinessProbe:
httpGet:
path: /outpost.goauthentik.io/ping
port: 9300
initialDelaySeconds: 5
periodSeconds: 10
resources:
requests:
cpu: 50m
memory: 128Mi
limits:
memory: 256Mi
@@ -0,0 +1,24 @@
apiVersion: secrets.infisical.com/v1alpha1
kind: InfisicalSecret
metadata:
name: authentik-ldap-secrets
namespace: infisical
spec:
hostAPI: https://infisical.jsme.be
resyncInterval: 30
authentication:
kubernetesAuth:
identityId: "5458def7-7c63-40d2-95da-41c614d0933a"
serviceAccountRef:
name: infisical-auth
namespace: infisical
autoCreateServiceAccountToken: true
secretsScope:
projectSlug: "kubernetes"
envSlug: "prod"
secretsPath: "/authentik/authentik-ldap"
recursive: false
managedSecretReference:
secretName: authentik-ldap-secrets
secretNamespace: authentik
secretType: Opaque
+15
View File
@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: authentik-ldap
namespace: authentik
spec:
selector:
app: authentik-ldap
ports:
- name: ldap
port: 3389
targetPort: 3389
- name: metrics
port: 9300
targetPort: 9300
+25
View File
@@ -0,0 +1,25 @@
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: TCPRoute
metadata:
name: authentik-ldap
namespace: authentik
spec:
parentRefs:
- group: gateway.networking.k8s.io
kind: Gateway
name: gateway-internal
namespace: envoy-gateway
sectionName: authentik-ldap
- group: gateway.networking.k8s.io
kind: Gateway
name: gateway-internal
namespace: envoy-gateway
sectionName: authentik-ldaps
rules:
# The gateway terminates TLS on 636, so both listeners hit the plaintext port
- backendRefs:
- name: authentik-ldap
port: 3389
kind: Service
group: ""
weight: 1
@@ -1,13 +0,0 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: gitea-runner-pvc
namespace: gitea
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn-static
volumeName: gitea-runner-data
resources:
requests:
storage: 20Gi
@@ -20,7 +20,7 @@ spec:
gpu: "true"
containers:
- name: jellyfin
image: jellyfin/jellyfin:10.11.11
image: jellyfin/jellyfin:12.0
ports:
- containerPort: 8096
resources:
@@ -0,0 +1,28 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: gitea-runner
namespace: argocd
spec:
project: default
sources:
# The act_runner chart itself. Values live in this repo, pulled in via the
# $values ref below.
- repoURL: https://dl.gitea.com/charts/
chart: actions
targetRevision: 0.1.0
helm:
# $values resolves to the ref source's repo root, so this path is
# relative to the repository, not to the chart.
valueFiles:
- $values/applications/gitea/runner/values.yaml
- repoURL: https://gitea.jsme.be/Jeffrey/Kubernetes-Manifests.git
targetRevision: main
ref: values
destination:
server: https://kubernetes.default.svc
namespace: gitea
syncPolicy:
automated:
prune: true
selfHeal: true
@@ -17,6 +17,21 @@ spec:
destination:
server: https://kubernetes.default.svc
namespace: infisical
# A StatefulSet's volumeClaimTemplates are immutable, and the API server
# injects fields into them that are not in the manifest: apiVersion, kind,
# metadata.creationTimestamp, spec.volumeMode and a status block. ArgoCD
# diffs those and reports OutOfSync forever, since no sync can resolve them.
# infisical-postgres and infisical-valkey are the only StatefulSets here
# using volumeClaimTemplates, which is why this app alone was affected.
ignoreDifferences:
- group: apps
kind: StatefulSet
jqPathExpressions:
- '.spec.volumeClaimTemplates[]?.apiVersion'
- '.spec.volumeClaimTemplates[]?.kind'
- '.spec.volumeClaimTemplates[]?.metadata.creationTimestamp'
- '.spec.volumeClaimTemplates[]?.spec.volumeMode'
- '.spec.volumeClaimTemplates[]?.status'
syncPolicy:
automated:
prune: true
@@ -8,12 +8,18 @@ spec:
sources:
- repoURL: https://victoriametrics.github.io/helm-charts/
chart: victoria-metrics-k8s-stack
targetRevision: 0.91.2
# Pinned at 0.77.0. 0.91.2 was tried on 2026-08-29 and rolled back:
# Grafana crash-looped on "Datasource provisioning error: data source
# not found". The chart also moves dashboards and the 35 default VMRules
# out of the Helm render and into a runtime sync-job, so the upgrade
# needs a values migration and a verified datasource config, not a
# version bump.
targetRevision: 0.77.0
helm:
# Release name kept short to avoid label length >63 chars on alertmanager StatefulSet pods
releaseName: vm
valueFiles:
- $values/victoria-metrics/values.yaml
- $values/applications/victoria-metrics/values.yaml
- repoURL: https://gitea.jsme.be/Jeffrey/Kubernetes-Manifests.git
targetRevision: HEAD
ref: values
@@ -0,0 +1,14 @@
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: authentik-ldap-tls
namespace: envoy-gateway
spec:
secretName: authentik-ldap-tls
privateKey:
rotationPolicy: Always
issuerRef:
name: azure-dns
kind: ClusterIssuer
dnsNames:
- ldap.jsme.be
@@ -0,0 +1,40 @@
# TCP listeners for the authentik LDAP outpost. kinds must be set explicitly:
# TCP allows nothing by default and TLS defaults to TLSRoute.
- op: add
path: /spec/listeners/-
value:
name: authentik-ldap
protocol: TCP
port: 389
allowedRoutes:
kinds:
- group: gateway.networking.k8s.io
kind: TCPRoute
namespaces:
from: Selector
selector:
matchLabels:
kubernetes.io/metadata.name: authentik
- op: add
path: /spec/listeners/-
value:
name: authentik-ldaps
protocol: TLS
port: 636
# No hostname: LDAP clients cannot be relied on to send SNI
tls:
mode: Terminate
certificateRefs:
- group: ""
kind: Secret
name: authentik-ldap-tls
namespace: envoy-gateway
allowedRoutes:
kinds:
- group: gateway.networking.k8s.io
kind: TCPRoute
namespaces:
from: Selector
selector:
matchLabels:
kubernetes.io/metadata.name: authentik
+7
View File
@@ -23,6 +23,7 @@ resources:
# Certificates
- authentik/authentik-certificate.yaml
- authentik/authentik-ldap-certificate.yaml
- argocd/argocd-certificate.yaml
- bentopdf/bentopdf-certificate.yaml
- gitea/gitea-certificate.yaml
@@ -70,6 +71,12 @@ patches:
kind: Gateway
name: gateway-internal
path: authentik/authentik-gateway-patch.yaml
- target:
group: gateway.networking.k8s.io
version: v1
kind: Gateway
name: gateway-internal
path: authentik/authentik-ldap-gateway-patch.yaml
- target:
group: gateway.networking.k8s.io
version: v1