From ee159b02ba385aebb2fbe03421cd0f603e4162d8 Mon Sep 17 00:00:00 2001 From: Viktor Barzin Date: Wed, 27 May 2026 18:37:05 +0000 Subject: [PATCH] nextcloud: disable Keel auto-upgrades MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keel bumped library/nextcloud :32.0.3-apache → :32.0.9-apache on 2026-05-26 19:42 UTC. The new image needs `occ upgrade` to migrate the DB schema, which Keel does not run, so Nextcloud landed in maintenance mode (needsDbUpgrade=true) and stayed there for ~22h — external probes saw 503, ExternalAccessDivergence kept firing. Disable Keel for this workload: - Drop the `keel.sh/enrolled=true` label from the namespace so Kyverno's `inject-keel-annotations` policy no longer matches. - Layer `keel.sh/policy=never` label + annotation onto the Helm-managed Deployment via `kubernetes_labels` / `kubernetes_annotations` (the chart at 8.8.1 doesn't expose Deployment-level commonLabels/commonAnnotations). Keel reads the annotation; the label is defense-in-depth for the Kyverno exclude rule should the namespace ever get re-enrolled. Verified: Keel logged `image no longer tracked, removing watcher` within seconds of the annotation landing, and `tg plan` is clean. Co-Authored-By: Claude Opus 4.7 --- stacks/nextcloud/main.tf | 44 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/stacks/nextcloud/main.tf b/stacks/nextcloud/main.tf index cd27572c..1fbba67a 100644 --- a/stacks/nextcloud/main.tf +++ b/stacks/nextcloud/main.tf @@ -30,7 +30,14 @@ resource "kubernetes_namespace" "nextcloud" { tier = local.tiers.edge "resource-governance/custom-limitrange" = "true" "resource-governance/custom-quota" = "true" - "keel.sh/enrolled" = "true" + # Keel disabled for nextcloud: the 2026-05-26 Keel-driven bump + # 32.0.3-apache → 32.0.9-apache left the pod in maintenance mode + # (needsDbUpgrade=true) for ~22h because Keel doesn't run + # `occ upgrade` after rolling the image. Defense-in-depth: + # (a) namespace not enrolled here, (b) workload carries the + # `keel.sh/policy=never` label + annotation below so even if the + # ns label gets re-added, Kyverno excludes this Deployment. + # "keel.sh/enrolled" = "true" } } lifecycle { @@ -39,6 +46,41 @@ resource "kubernetes_namespace" "nextcloud" { } } +# Workload-level Keel opt-out (see namespace comment above). +# Keel reads the ANNOTATION `keel.sh/policy` (it's what un-tracks the +# image watcher); the LABEL exists for the Kyverno exclude rule in +# `inject-keel-annotations` (defense-in-depth in case the namespace +# label gets re-added later). Both are set via these helper resources +# because the nextcloud chart 8.8.1 doesn't expose Deployment-level +# commonLabels / commonAnnotations. +resource "kubernetes_labels" "nextcloud_keel_optout" { + api_version = "apps/v1" + kind = "Deployment" + metadata { + name = "nextcloud" + namespace = kubernetes_namespace.nextcloud.metadata[0].name + } + labels = { + "keel.sh/policy" = "never" + } + force = true + depends_on = [helm_release.nextcloud] +} + +resource "kubernetes_annotations" "nextcloud_keel_optout" { + api_version = "apps/v1" + kind = "Deployment" + metadata { + name = "nextcloud" + namespace = kubernetes_namespace.nextcloud.metadata[0].name + } + annotations = { + "keel.sh/policy" = "never" + } + force = true + depends_on = [helm_release.nextcloud] +} + resource "kubernetes_manifest" "external_secret" { manifest = { apiVersion = "external-secrets.io/v1beta1"