<?xml version="1.0" encoding="utf-8" standalone="yes"?><?xml-stylesheet type="text/xsl" href="https://perrotta.dev/rss.xsl"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Argocd on ¬ just serendipity 🍀</title>
    <link>https://perrotta.dev/</link>
    <description>Recent content in Argocd on ¬ just serendipity 🍀</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <managingEditor>serendipity@perrotta.dev (Thiago Perrotta)</managingEditor>
    <webMaster>serendipity@perrotta.dev (Thiago Perrotta)</webMaster>
    <copyright>© 2013 - present Thiago Perrotta ·
  a fork of [hugo ʕ•ᴥ•ʔ bear](https://github.com/janraasch/hugo-bearblog/)
</copyright>
    <lastBuildDate>Sun, 16 Aug 2026 13:35:38 +0200</lastBuildDate>
    <atom:link href="https://perrotta.dev/tags/argocd/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>ArgoCD: persistent PDB selector diff
      </title>
      <link>https://perrotta.dev/2026/05/argocd-persistent-pdb-selector-diff/</link>
      <pubDate>Fri, 22 May 2026 16:51:12 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>argocd</category>
      <category>dev</category>
      <category>kubernetes</category>
      <guid>https://perrotta.dev/2026/05/argocd-persistent-pdb-selector-diff/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://perrotta.dev/2026/05/argocd-stale-vault-secret-after-population/&#34;&gt;Previously&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Problem statement&lt;/strong&gt;: An ArgoCD application shows a persistent diff on a&#xA;&lt;code&gt;PodDisruptionBudget&lt;/code&gt; — &lt;code&gt;spec.selector.matchExpressions&lt;/code&gt; is in the rendered&#xA;manifest but missing from the live object. Sync doesn&amp;rsquo;t clear it. Hard refresh&#xA;doesn&amp;rsquo;t clear it. Syncing with replace or with server-side apply or with force&#xA;doesn&amp;rsquo;t clear it. Ugh!&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;policy/PodDisruptionBudget/default/my-super-cool-app&lt;/code&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;selector:&#xA;  matchExpressions:&#xA;    - key: job-name&#xA;      operator: DoesNotExist&#xA;  matchLabels:&#xA;    release: my-super-cool-app&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The chart was updated to add &lt;code&gt;matchExpressions&lt;/code&gt; to the PDB selector. The diff&#xA;shows up. Sync runs. Diff stays.&lt;/p&gt;&#xA;&lt;p&gt;First idea: &lt;em&gt;Kubernetes mutates PDB selectors server-side&lt;/em&gt; — no.&#xA;The PDB registry strategy in&#xA;&lt;a href=&#34;https://github.com/kubernetes/kubernetes/blob/master/pkg/registry/policy/poddisruptionbudget/strategy.go&#34;&gt;&lt;code&gt;pkg/registry/policy/poddisruptionbudget/strategy.go&lt;/code&gt;&lt;/a&gt;&#xA;only touches &lt;code&gt;Status&lt;/code&gt; and &lt;code&gt;Generation&lt;/code&gt;. No selector mutation, no admission&#xA;plugin in tree that injects this. Patterns like&#xA;&lt;code&gt;matchExpressions: [{key: job-name, operator: DoesNotExist}]&lt;/code&gt; come from chart&#xA;authors, not from K8s. This is all according to the LLM.&lt;/p&gt;&#xA;&lt;p&gt;Second idea: &lt;em&gt;PDB selectors are immutable on older K8s&lt;/em&gt; — is also wrong&#xA;here. Selector mutability landed in 1.27. The cluster is on 1.33+.&lt;/p&gt;&#xA;&lt;p&gt;The actual culprit is &lt;strong&gt;client-side &lt;code&gt;kubectl apply&lt;/code&gt; 3-way merge&lt;/strong&gt;, which is&#xA;what ArgoCD uses by default. The merge needs three inputs:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;The previous applied state, read from&#xA;&lt;code&gt;metadata.annotations.kubectl.kubernetes.io/last-applied-configuration&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;The live object.&lt;/li&gt;&#xA;&lt;li&gt;The new desired manifest.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;Check the annotation on the live PDB:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% kubectl get pdb my-super-cool-app -n default -o yaml | yq &amp;#39;.metadata.annotations.&amp;#34;kubectl.kubernetes.io/last-applied-configuration&amp;#34;&amp;#39;&#xA;{&amp;#34;apiVersion&amp;#34;:&amp;#34;policy/v1&amp;#34;,&amp;#34;kind&amp;#34;:&amp;#34;PodDisruptionBudget&amp;#34;,&amp;#34;metadata&amp;#34;:{...},&amp;#34;spec&amp;#34;:{&amp;#34;maxUnavailable&amp;#34;:1,&amp;#34;selector&amp;#34;:{&amp;#34;matchLabels&amp;#34;:{&amp;#34;release&amp;#34;:&amp;#34;my-super-cool-app&amp;#34;}}}}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;No &lt;code&gt;matchExpressions&lt;/code&gt;. So the 3-way merge sees: &lt;em&gt;the previous apply didn&amp;rsquo;t have&#xA;the field, the live object doesn&amp;rsquo;t have the field, the new manifest has the&#xA;field&lt;/em&gt;. It treats this as an addition — but the existing implementation in this&#xA;path doesn&amp;rsquo;t reliably propagate the new key into the live selector when the&#xA;parent (&lt;code&gt;spec.selector&lt;/code&gt;) is owned as an opaque value. The &lt;code&gt;managedFields&lt;/code&gt; confirm&#xA;it:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;- manager: argocd-controller&#xA;  operation: Update&#xA;  fieldsV1:&#xA;    f:spec:&#xA;      f:maxUnavailable: {}&#xA;      f:selector: {}   # opaque — no sub-field ownership&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;code&gt;f:selector: {}&lt;/code&gt; means argocd-controller owns the whole selector blob with no&#xA;sub-field tracking. New fields under &lt;code&gt;spec.selector&lt;/code&gt; get lost in the merge.&lt;/p&gt;&#xA;&lt;p&gt;The fix is to delete the live PDB and let ArgoCD recreate it on the next sync:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% kubectl delete pdb my-super-cool-app -n default&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This can alternatively be done via the ArgoCD Web UI.&lt;/p&gt;&#xA;&lt;p&gt;It is a safe operation: a PDB only gates voluntary disruptions (drains,&#xA;evictions). A brief gap doesn&amp;rsquo;t affect running pods. The recreated object gets a&#xA;fresh &lt;code&gt;last-applied-configuration&lt;/code&gt; containing &lt;code&gt;matchExpressions&lt;/code&gt;, and the diff&#xA;clears.&lt;/p&gt;&#xA;&lt;p&gt;The longer-term fix is to switch the application to server-side apply, which&#xA;tracks ownership at the field level and handles this correctly:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;syncPolicy:&#xA;  syncOptions:&#xA;    - ServerSideApply=true&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;It&amp;rsquo;s always a dilemma whether or not to use server-side apply.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: ArgoCD: persistent PDB selector diff&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/argocd/&#34;&gt;#argocd&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/kubernetes/&#34;&gt;#kubernetes&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>ArgoCD: stale Vault secret after population
      </title>
      <link>https://perrotta.dev/2026/05/argocd-stale-vault-secret-after-population/</link>
      <pubDate>Wed, 13 May 2026 12:34:36 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>argocd</category>
      <category>dev</category>
      <category>kubernetes</category>
      <guid>https://perrotta.dev/2026/05/argocd-stale-vault-secret-after-population/</guid>
      <description>&lt;p&gt;♠ &lt;strong&gt;Problem statement&lt;/strong&gt;: An ArgoCD application references a Vault secret via&#xA;&lt;code&gt;helm-secrets&lt;/code&gt; / &lt;code&gt;vals&lt;/code&gt; (e.g. &lt;code&gt;vault://kv-v2/services/foo#/apiKey&lt;/code&gt;). The&#xA;application is created &lt;em&gt;before&lt;/em&gt; the secret exists in Vault, or while the&#xA;corresponding key is blank. The key is populated later on. The application keeps&#xA;behaving as if the value is still missing — usually a &lt;code&gt;404&lt;/code&gt; from Vault, or a&#xA;&lt;code&gt;permission denied&lt;/code&gt; on the cached lookup:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;Failed to load target state: failed to generate manifest for source 1 of 2:&#xA;rpc error: code = Unknown desc = Manifest generation error (cached): failed to&#xA;execute helm template command: [...] vals error: expand&#xA;vault://kv-v2/services/foo#/apiKey: Error making API request. URL: GET&#xA;http://vault.infra-services:8200/v1/sys/internal/ui/mounts/kv-v2/services/foo&#xA;Code: 404.&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Note the &lt;code&gt;(cached)&lt;/code&gt; part of the error. The &lt;code&gt;argocd-repo-server&lt;/code&gt; caches the&#xA;result of manifest generation, &lt;em&gt;including&lt;/em&gt; failed &lt;code&gt;vals&lt;/code&gt; / &lt;code&gt;helm-secrets&lt;/code&gt;&#xA;lookups. A normal sync or refresh happily reuses the cached (stale) failure and&#xA;never re-resolves the Vault reference. So the freshly-populated secret goes&#xA;unnoticed. A blank to non-blank update counts as well, besides outright&#xA;token rotations.&lt;/p&gt;&#xA;&lt;p&gt;The fix is to perform a &lt;strong&gt;Hard Refresh&lt;/strong&gt; on the application — that&amp;rsquo;s what busts&#xA;the manifest cache and forces a fresh Vault lookup:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;argocd app get &amp;lt;app&amp;gt; --hard-refresh&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Or, in the web UI: open the application → &lt;code&gt;REFRESH ▾&lt;/code&gt; dropdown → &lt;code&gt;HARD REFRESH&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;If a hard refresh alone doesn&amp;rsquo;t pick up the new value, restart the argocd repo&#xA;server:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl rollout restart deployment -n argocd argocd-repo-server&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;A regular refresh won&amp;rsquo;t do. The cache key for the failed lookup outlives the&#xA;refresh.&lt;/p&gt;&#xA;&lt;p&gt;By default, the application cache lasts for &lt;strong&gt;24h&lt;/strong&gt; (though it can be changed&#xA;via helm values); hence, another way to resolve the issue is to simply sit out&#xA;on it and wait.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: ArgoCD: stale Vault secret after population&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/argocd/&#34;&gt;#argocd&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/kubernetes/&#34;&gt;#kubernetes&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>ArgoCD: sync stuck in terminating
      </title>
      <link>https://perrotta.dev/2026/05/argocd-sync-stuck-in-terminating/</link>
      <pubDate>Tue, 05 May 2026 13:51:10 -0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>argocd</category>
      <category>dev</category>
      <category>kubernetes</category>
      <guid>https://perrotta.dev/2026/05/argocd-sync-stuck-in-terminating/</guid>
      <description>&lt;p&gt;♠ &lt;strong&gt;Problem statement&lt;/strong&gt;: An ArgoCD application&amp;rsquo;s sync operation is stuck in&#xA;&lt;code&gt;Terminating&lt;/code&gt; for hours. The web UI shows &lt;em&gt;operation is terminating due to&#xA;timeout&lt;/em&gt;. A PreSync hook resource keeps appearing as &lt;code&gt;Running&lt;/code&gt; even though&#xA;the underlying &lt;code&gt;Job&lt;/code&gt; already completed in the cluster.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% kubectl get application &amp;lt;app&amp;gt; -n argocd -o yaml | yq &amp;#39;.status.operationState.phase&amp;#39;&#xA;Terminating&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The application controller is stuck in a busy loop:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;&amp;#34;Resuming in-progress operation. phase: Terminating, message: operation is terminating due to timeout&amp;#34;&#xA;&amp;#34;No operation updates necessary to &amp;#39;&amp;lt;ns&amp;gt;/&amp;lt;app&amp;gt;&amp;#39;. Skipping patch&amp;#34;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;In my case this followed a transient &lt;code&gt;ImagePullBackOff&lt;/code&gt; on a PreSync hook job:&#xA;the image was being mirrored to a regional ECR, the first hook attempt failed,&#xA;and by the time the image landed and the retry succeeded, the parent operation&#xA;had already moved into &lt;code&gt;Terminating&lt;/code&gt; and never recovered.&lt;/p&gt;&#xA;&lt;p&gt;The instinct is to clear the operation:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl patch application &amp;lt;app&amp;gt; -n argocd --type merge -p &amp;#39;{&amp;#34;operation&amp;#34;: null}&amp;#39;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;It&amp;rsquo;s a no-op. The wedge doesn&amp;rsquo;t live in &lt;code&gt;spec.operation&lt;/code&gt; (the request) — it&#xA;lives in &lt;code&gt;status.operationState&lt;/code&gt; (the controller&amp;rsquo;s bookkeeping). And &lt;code&gt;status&lt;/code&gt;&#xA;is owned by the controller, so a regular &lt;code&gt;--type merge&lt;/code&gt; patch won&amp;rsquo;t touch it.&lt;/p&gt;&#xA;&lt;p&gt;We need the &lt;code&gt;status&lt;/code&gt; subresource:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl patch application &amp;lt;app&amp;gt; -n argocd --type merge \&#xA;  -p &amp;#39;{&amp;#34;operation&amp;#34;: null}&amp;#39;&#xA;kubectl patch application &amp;lt;app&amp;gt; -n argocd --subresource status --type merge \&#xA;  -p &amp;#39;{&amp;#34;status&amp;#34;:{&amp;#34;operationState&amp;#34;:null}}&amp;#39;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Both patches together. Neither touches cluster resources — they only modify&#xA;ArgoCD&amp;rsquo;s view of the operation. After that, re-trigger the sync from the UI&#xA;and the application reconciles cleanly.&lt;/p&gt;&#xA;&lt;p&gt;Restarting &lt;code&gt;argocd-application-controller&lt;/code&gt; does &lt;em&gt;not&lt;/em&gt; help: the stuck state&#xA;sits in etcd, and the freshly-elected leader picks it up on startup and resumes&#xA;the same loop.&lt;/p&gt;&#xA;&lt;p&gt;One caveat: verify the underlying hook resource has actually finished before&#xA;clearing. &lt;code&gt;kubectl describe job -n argocd &amp;lt;hook-job&amp;gt;&lt;/code&gt; should show&#xA;&lt;code&gt;1 Succeeded&lt;/code&gt;. Otherwise we&amp;rsquo;ll lose in-flight progress.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: ArgoCD: sync stuck in terminating&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/argocd/&#34;&gt;#argocd&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/kubernetes/&#34;&gt;#kubernetes&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>ArgoCD: git index.lock issue
      </title>
      <link>https://perrotta.dev/2025/08/argocd-git-index.lock-issue/</link>
      <pubDate>Sat, 23 Aug 2025 12:39:14 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>argocd</category>
      <category>dev</category>
      <category>git</category>
      <category>kubernetes</category>
      <guid>https://perrotta.dev/2025/08/argocd-git-index.lock-issue/</guid>
      <description>&lt;p&gt;♠ &lt;strong&gt;Problem statement&lt;/strong&gt;: Every ArgoCD application is stuck in &lt;em&gt;Unknown&lt;/em&gt; state,&#xA;with the following error:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;Failed to load target state: failed to generate manifest for source 1 of 2:&#xA;rpc error: code = Unknown desc = failed to initialize repository resources: rpc&#xA;error: code = Internal desc = Failed to checkout FETCH_HEAD: failed to checkout&#xA;FETCH_HEAD: `git checkout --force FETCH_HEAD` failed exit status 128: fatal:&#xA;Unable to create &amp;#39;&amp;lt;path to cached source&amp;gt;/.git/index.lock&amp;#39;: File exists. Another&#xA;git process seems to be running in this repository, e.g. an editor opened by&#xA;&amp;#39;git commit&amp;#39;. Please make sure all processes are terminated then try again. If&#xA;it still fails, a git process may have crashed in this repository earlier:&#xA;remove the file manually to continue.&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;It is a lock contention race condition issue within the ArgoCD repo server&#xA;component, with the git &lt;code&gt;index.lock&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The easiest way to address it is to restart the repo server:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl rollout restart deploy -n argocd argocd-repo-server&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Afterwards, refresh all applications in the cluster via the web UI:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;click Applications on the left-side nav bar&lt;/li&gt;&#xA;&lt;li&gt;click Refresh apps at the top&lt;/li&gt;&#xA;&lt;li&gt;select ALL applications, set refresh type to NORMAL&lt;/li&gt;&#xA;&lt;li&gt;click refresh&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: ArgoCD: git index.lock issue&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/argocd/&#34;&gt;#argocd&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/git/&#34;&gt;#git&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/kubernetes/&#34;&gt;#kubernetes&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>ArgoCD: app version notifications
      </title>
      <link>https://perrotta.dev/2025/08/argocd-app-version-notifications/</link>
      <pubDate>Tue, 12 Aug 2025 12:07:20 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>argocd</category>
      <category>dev</category>
      <category>kubernetes</category>
      <guid>https://perrotta.dev/2025/08/argocd-app-version-notifications/</guid>
      <description>&lt;p&gt;♠ &lt;strong&gt;Problem statement&lt;/strong&gt;: when using &lt;a href=&#34;https://argo-cd.readthedocs.io/en/stable/operator-manual/notifications/&#34;&gt;ArgoCD&#xA;notifications&lt;/a&gt;,&#xA;starting off from their&#xA;&lt;a href=&#34;https://argo-cd.readthedocs.io/en/stable/operator-manual/notifications/catalog/&#34;&gt;catalog&lt;/a&gt;,&#xA;print the app chart version in addition to existing information.&lt;/p&gt;&#xA;&lt;p&gt;More specifically, currently, a Slack notification message from Argo looks like&#xA;the following:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;Cluster 37: Application heart-of-gold is unhealthy.&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;We want to improve it to:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;Cluster 37: Application heart-of-gold (~1.18.3) is unhealthy.&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The following diff (under a &lt;code&gt;template&lt;/code&gt; block) accomplishes that:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-diff&#34;&gt;-          {{if eq .serviceType &amp;#34;slack&amp;#34;}}:interrobang:{{end}} Cluster &amp;lt;{{.context.argocdUrl}}|*{{.context.clusterId}}*&amp;gt;: Application &amp;lt;{{.context.argocdUrl}}/applications/{{.app.metadata.name}}|`{{.app.metadata.name}}`&amp;gt; _sync_ by {{.app.status.operationState.operation.initiatedBy.username | default &amp;#34;_automation_&amp;#34; }} is _unknown_.&#xA;&amp;#43;          {{if eq .serviceType &amp;#34;slack&amp;#34;}}:interrobang:{{end}} Cluster &amp;lt;{{.context.argocdUrl}}|*{{.context.clusterId}}*&amp;gt;: Application &amp;lt;{{.context.argocdUrl}}/applications/{{.app.metadata.name}}|`{{.app.metadata.name}}`&amp;gt;{{if .app.spec.source.targetRevision}} ({{.app.spec.source.targetRevision}}){{else}}{{range .app.spec.sources}}{{if .targetRevision}} ({{.targetRevision}}){{break}}{{end}}{{end}}{{end}} _sync_ by {{.app.status.operationState.operation.initiatedBy.username | default &amp;#34;_automation_&amp;#34; }} is _unknown_.&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Diving into it with pretty-printing&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2025/08/argocd-app-version-notifications/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-go-template&#34;&gt;{{if .app.spec.source.targetRevision}}&#xA;  ({{.app.spec.source.targetRevision}})&#xA;{{else}}&#xA;  {{range .app.spec.sources}}&#xA;    {{if .targetRevision}}&#xA;      ({{.targetRevision}})&#xA;      {{break}}&#xA;    {{end}}&#xA;  {{end}}&#xA;{{end}}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;If there&amp;rsquo;s a single source in the helm chart, we extract its &lt;code&gt;targetRevision&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Otherwise, when using a &lt;a href=&#34;https://argo-cd.readthedocs.io/en/latest/user-guide/multiple_sources/&#34;&gt;multi-source&#xA;app&lt;/a&gt;, we&#xA;extract the first available &lt;code&gt;targetRevision&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;These are&#xA;&lt;a href=&#34;https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/GoTemplate/&#34;&gt;golang&lt;/a&gt;&#xA;&lt;a href=&#34;https://pkg.go.dev/text/template&#34;&gt;templates&lt;/a&gt;.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2025/08/argocd-app-version-notifications/#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: ArgoCD: app version notifications&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/argocd/&#34;&gt;#argocd&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/kubernetes/&#34;&gt;#kubernetes&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>ArgoCD: recovery when traefik is broken
      </title>
      <link>https://perrotta.dev/2025/08/argocd-recovery-when-traefik-is-broken/</link>
      <pubDate>Sat, 09 Aug 2025 15:24:53 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>argocd</category>
      <category>dev</category>
      <category>kubernetes</category>
      <guid>https://perrotta.dev/2025/08/argocd-recovery-when-traefik-is-broken/</guid>
      <description>&lt;p&gt;♠ It&amp;rsquo;s Friday. The best day to push to prod™.&#xA;An internal scheduled upgrade for &lt;code&gt;traefik&lt;/code&gt; goes awry.&#xA;Internal services are no longer accessible.&#xA;HTTP requests won&amp;rsquo;t be properly routed.&lt;/p&gt;&#xA;&lt;p&gt;The most sensible SRE / DevOps will simply roll it back. Roll back first,&#xA;investigate later: it&amp;rsquo;s crucial to minimize downtime.&lt;/p&gt;&#xA;&lt;p&gt;How do we roll back?&#xA;We&amp;rsquo;re using GitOps, the most sensible approach is to make a new git commit by&#xA;submitting a pull request.&#xA;However, this is an emergency situation. Can we roll back faster?&lt;/p&gt;&#xA;&lt;p&gt;Sure, let&amp;rsquo;s make temporary changes directly in the cluster.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;traefik&lt;/code&gt; app is managed with ArgoCD. Let&amp;rsquo;s log in to the ArgoCD web UI and&#xA;roll back to the previous version.&lt;/p&gt;&#xA;&lt;p&gt;Oh, wait. We can&amp;rsquo;t. The ArgoCD web UI isn&amp;rsquo;t accessible, because traefik is&#xA;broken. &lt;em&gt;Sighs&lt;/em&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s use the ArgoCD CLI then.&lt;/p&gt;&#xA;&lt;p&gt;Aaaah, no. The ArgoCD CLI is really a REST client for the ArgoCD API. HTTP(S) is&#xA;not accessible, so the CLI won&amp;rsquo;t work either.&lt;/p&gt;&#xA;&lt;p&gt;What&amp;rsquo;s next? A plain &lt;code&gt;helm&lt;/code&gt; upgrade should work. But &lt;code&gt;helm&lt;/code&gt; is picky and will&#xA;refuse to touch manifests it doesn&amp;rsquo;t own. The manifests are managed by Argo.&#xA;&lt;code&gt;helm&lt;/code&gt; won&amp;rsquo;t budge. Oh gosh.&lt;/p&gt;&#xA;&lt;p&gt;Last option: the ArgoCD controllers are still running. We don&amp;rsquo;t need the ArgoCD&#xA;HTTPS API to communicate with them. Let&amp;rsquo;s simply edit the k8s manifests&#xA;directly.&lt;/p&gt;&#xA;&lt;p&gt;First we patch the root app (app-of-apps pattern):&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl edit app -n argocd root&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;We remove the &lt;code&gt;automated&lt;/code&gt; block, to effectively pause auto sync, otherwise our&#xA;subsequent changes to traefik would be immediately reverted:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;spec:&#xA;#  automated:&#xA;#    prune: [..]&#xA;#    selfHeal: [...]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;You can comment or delete the &lt;code&gt;automated:&lt;/code&gt; block, either is fine.&lt;/p&gt;&#xA;&lt;p&gt;Next, we need to remove traefik from all application project (app project) sync&#xA;windows, so that changes to it will be immediately applied:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl edit appproject -n argocd cluster&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The traefik entry got removed from all sync windows.&lt;/p&gt;&#xA;&lt;p&gt;Now, finally, let&amp;rsquo;s instruct Argo to roll traefik back.&lt;/p&gt;&#xA;&lt;p&gt;The broken version is 2.5.1, the previous working version was 2.4.1.&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl edit app -n argocd traefik&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Update &lt;code&gt;targetRevision: 2.4.1&lt;/code&gt; under the &lt;code&gt;helm&lt;/code&gt; block.&lt;/p&gt;&#xA;&lt;p&gt;Wait a few seconds. Observe traefik pods as they are rolling restarted:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl get deploy -n kube-system traefik -w&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Finally, all services are once again accessible!&lt;/p&gt;&#xA;&lt;p&gt;From this point on, we can go back to &lt;code&gt;git&lt;/code&gt; and do a proper pull request revert&#xA;to reconcile the codebase with the live cluster state.&lt;/p&gt;&#xA;&lt;p&gt;This was an interesting exercise. I&amp;rsquo;m quite familiar with ArgoCD and GitOps at&#xA;this point, and I instinctively knew what to do in this situation, without&#xA;needing to consult the official documentation or even an LLM. I wouldn&amp;rsquo;t have&#xA;minded doing either of these if needed, but the point is that it feels good to&#xA;be well familiar with how a system works and how to apply your knowledge to fix&#xA;day-to-day problems.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: ArgoCD: recovery when traefik is broken&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/argocd/&#34;&gt;#argocd&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/kubernetes/&#34;&gt;#kubernetes&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>ArgoCD: all applications stuck on refresh
      </title>
      <link>https://perrotta.dev/2025/08/argocd-all-applications-stuck-on-refresh/</link>
      <pubDate>Fri, 01 Aug 2025 14:30:58 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>argocd</category>
      <category>dev</category>
      <category>kubernetes</category>
      <guid>https://perrotta.dev/2025/08/argocd-all-applications-stuck-on-refresh/</guid>
      <description>&lt;p&gt;♠ The problem is very likely the Application Controller.&lt;/p&gt;&#xA;&lt;p&gt;You can restart it:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl rollout restart sts -n argocd argocd-application-controller&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Or inspect its logs:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;kubectl logs -n argocd argocd-application-controller-0 --tail=100 | less&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;While we&amp;rsquo;re here, make sure there is at least one replica running:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;% kubectl get sts -n argocd argocd-application-controller&#xA;NAME                            READY   AGE&#xA;argocd-application-controller   1/1     415d&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/argoproj/argo-cd/issues/11831&#34;&gt;Upstream issue&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: ArgoCD: all applications stuck on refresh&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/argocd/&#34;&gt;#argocd&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/kubernetes/&#34;&gt;#kubernetes&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>ArgoCD: deployment spec.selector: field is immutable
      </title>
      <link>https://perrotta.dev/2025/06/argocd-deployment-spec.selector-field-is-immutable/</link>
      <pubDate>Mon, 30 Jun 2025 13:04:51 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>argocd</category>
      <category>dev</category>
      <category>kubernetes</category>
      <guid>https://perrotta.dev/2025/06/argocd-deployment-spec.selector-field-is-immutable/</guid>
      <description>&lt;p&gt;♠ When using &lt;a href=&#34;https://argo-cd.readthedocs.io/en/stable/&#34;&gt;ArgoCD&lt;/a&gt; to manage an app,&#xA;the Deployment manifest needs to undergo significant changes, updating its&#xA;selector labels. When trying to sync the argocd app, we get the following error:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;one or more objects failed to apply, reason: error when patching &amp;#34;/dev/shm/3469418025&amp;#34;: Deployment.apps &amp;#34;myapp&amp;#34; is invalid: spec.selector: Invalid value: v1.LabelSelector{MatchLabels:v1.LabelSelectorRequirement(nil)}: field is immutable. Retrying attempt #2 at 11:02AM.&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This error doesn&amp;rsquo;t come directly from Argo, it is from &lt;code&gt;kubectl apply&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;There are two ways to address it:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Sync the argo app with the&#xA;&lt;a href=&#34;https://argo-cd.readthedocs.io/en/latest/user-guide/sync-options/#force-sync&#34;&gt;&amp;ldquo;force&amp;rdquo;&lt;/a&gt;&#xA;option enabled&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Run &lt;code&gt;kubectl apply&lt;/code&gt; with &lt;code&gt;--force&lt;/code&gt; (which is ultimately what the&#xA;aforementioned option maps to).&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;In action (&lt;code&gt;-w&lt;/code&gt; is short for &lt;code&gt;--watch&lt;/code&gt;):&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;% kubectl get endpoints -w&#xA;NAME         ENDPOINTS         AGE&#xA;myapp        &amp;lt;none&amp;gt;            5y44d&#xA;myapp                          5y44d&#xA;myapp        10.1.13.40:8080   5y44d&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: ArgoCD: deployment spec.selector: field is immutable&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/argocd/&#34;&gt;#argocd&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/kubernetes/&#34;&gt;#kubernetes&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>Helm repository with a trailing slash
      </title>
      <link>https://perrotta.dev/2025/06/helm-repository-with-a-trailing-slash/</link>
      <pubDate>Tue, 24 Jun 2025 11:32:50 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>argocd</category>
      <category>dev</category>
      <category>kubernetes</category>
      <category>pre-commit</category>
      <guid>https://perrotta.dev/2025/06/helm-repository-with-a-trailing-slash/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://github.com/argoproj/argo-cd/issues/9857&#34;&gt;A repository URL with a trailing slash, and the same URL without a trailing&#xA;slash, are treated as different&#xA;repos&lt;/a&gt;. We found this out the&#xA;hard way:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;Failed to load target state: failed to generate manifest for source 1 of 2: rpc error: code = Unknown desc = error building helm chart dependencies: failed to add helm repository https://chartmuseum.{corp intranet}/orgs/{corp}/: failed to add repository: failed to get command args to log: `helm repo add https:--chartmuseum.{corp intranet}-orgs-{corp}- https://chartmuseum.{corp intranet}/orgs/{corp}/` failed exit status 1: Error: looks like &amp;#34;https://chartmuseum.{corp intranet}/orgs/{corp}/&amp;#34; is not a valid chart repository or cannot be reached: failed to fetch https://chartmuseum.{corp intranet}/orgs/{corp}/index.yaml : 401 Unauthorized&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Let&amp;rsquo;s put aside the fact the error message REALLY likes to repeat the repo name.&lt;/p&gt;&#xA;&lt;p&gt;This is a repository that we&amp;rsquo;ve already configured, with proper authentication&#xA;credentials. Why would it start to fail now, all of a sudden?&lt;/p&gt;&#xA;&lt;p&gt;You already got spoiled in the post title. Given &lt;code&gt;Chart.yaml&lt;/code&gt;:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: v2&#xA;name: corp-postgres-operator&#xA;description: Corp Postgres Operator&#xA;type: application&#xA;version: 1.1.13&#xA;&#xA;dependencies:&#xA;  - name: postgres-operator&#xA;    repository: https://chartmuseum.{corp intranet}/orgs/archive&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;And also:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: v2&#xA;name: corp-postgres-operator&#xA;description: Corp Postgres Operator&#xA;type: application&#xA;version: 1.1.13&#xA;&#xA;dependencies:&#xA;  - name: postgres-operator&#xA;    repository: https://chartmuseum.{corp intranet}/orgs/archive/&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;These two dependencies end up being treated differently by Argo, even though&#xA;they are effectively the same. It&amp;rsquo;s an upstream bug.&lt;/p&gt;&#xA;&lt;p&gt;To work around it, I decided to simply remove all trailing slashes from&#xA;helm repository dependencies. Canonicalize everything!&lt;/p&gt;&#xA;&lt;p&gt;A git &lt;a href=&#34;https://pre-commit.com&#34;&gt;pre-commit.com hook&lt;/a&gt; is a good mechanism to do so:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;repos:&#xA;  repo: local&#xA;  hooks:&#xA;    - id: helm-repo-trailing-slash&#xA;      name: Helm repositories must not contain trailing slashes in Chart.yaml&#xA;      files: Chart.yaml$&#xA;      language: pygrep&#xA;      entry: &amp;#39;\s*repository: [\w:/.]&amp;#43;/$&amp;#39;&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Run &lt;code&gt;pre-commit run -a helm-repo-trailing-slash&lt;/code&gt;, fix all violations, and then&#xA;never think about this again.&lt;/p&gt;&#xA;&lt;p&gt;Should the upstream bug ever be fixed, we can remove this workaround.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: Helm repository with a trailing slash&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/argocd/&#34;&gt;#argocd&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/kubernetes/&#34;&gt;#kubernetes&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/pre-commit/&#34;&gt;#pre-commit&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>★ ArgoCD: every application in unknown state
      </title>
      <link>https://perrotta.dev/2025/06/argocd-every-application-in-unknown-state/</link>
      <pubDate>Fri, 13 Jun 2025 22:34:33 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>argocd</category>
      <category>bestof</category>
      <category>dev</category>
      <category>kubernetes</category>
      <guid>https://perrotta.dev/2025/06/argocd-every-application-in-unknown-state/</guid>
      <description>&lt;p&gt;♠ &lt;strong&gt;Symptom&lt;/strong&gt;: Every single application in the Kubernetes cluster that is managed&#xA;by Argo is in &lt;code&gt;Unknown&lt;/code&gt; sync status. A disaster! 😱&lt;/p&gt;&#xA;&lt;p&gt;This has only happened in one of our clusters. More specifically, in an&#xA;&lt;a href=&#34;https://learn.microsoft.com/en-us/azure/aks/core-aks-concepts&#34;&gt;AKS&lt;/a&gt; cluster&#xA;(from Microsoft Azure).&lt;/p&gt;&#xA;&lt;p&gt;An observed effect:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% kubectl get --raw=&amp;#39;/openapi/v2&amp;#39; | head -c 200&#xA;Error from server (ServiceUnavailable): the server is currently unable to handle the request&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Aha! The Kubernetes OpenAPI server is not responding properly.&#xA;That explains why Argo is having so much trouble to figure out the state of affairs in&#xA;the cluster.&lt;/p&gt;&#xA;&lt;p&gt;It was quite difficult to troubleshoot this issue. There are barely any&#xA;resources about it in the open web. We filed an Azure Support ticket, but it was&#xA;completely useless. They offered to restart&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;https://perrotta.dev/2025/06/argocd-every-application-in-unknown-state/#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; the OpenAPI server, but that&#xA;didn&amp;rsquo;t help (of course it wouldn&amp;rsquo;t!).&lt;/p&gt;&#xA;&lt;p&gt;Because this is a managed Kubernetes cluster, we have limited access to it,&#xA;which includes lack of access to raw logs. The Azure portal doesn&amp;rsquo;t make it easy&#xA;but, after digging quite deep into it, eventually we found this error message in&#xA;the logs:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt; {&amp;#34;pod&amp;#34;:&amp;#34;kube-apiserver-7785d59f4f-scqmp&amp;#34;,&amp;#34;stream&amp;#34;:&amp;#34;stderr&amp;#34;,&amp;#34;containerID&amp;#34;:&amp;#34;925345f6501626aa6cd40dd187d5cf57837389eec9cb39b2292fb9ae3f66242f&amp;#34;,&amp;#34;log&amp;#34;:&amp;#34;E0512 12:01:36.876768       1 handler.go:160] Error in OpenAPI handler: failed to build merge specs: unable to merge: duplicated path \/apis\/reports.kyverno.io\/v1\/clusterephemeralreports\n&amp;#34;}&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;That was the first clue! Now we know it&amp;rsquo;s related to&#xA;&lt;a href=&#34;https://kyverno.io/&#34;&gt;Kyverno&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;That error eventually led us to&#xA;&lt;a href=&#34;https://github.com/kubernetes/kubernetes/issues/122668#issuecomment-2531243040&#34;&gt;this&lt;/a&gt;&#xA;issue in Kubernetes:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;We have the same issue here, actually also triggered by installing the kyverno&#xA;reports-server with both apiservices (different groups served by the same&#xA;api-server).&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Aha!&lt;/p&gt;&#xA;&lt;p&gt;Deleting the duplicate CRDs installed by &lt;a href=&#34;https://github.com/kyverno/reports-server&#34;&gt;kyverno reports&#xA;server&lt;/a&gt; has immediately resolved the&#xA;OpenAPI server unresponsiveness. It wasn&amp;rsquo;t even necessary to restart it:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% kubectl delete crd ephemeralreports.reports.kyverno.io clusterephemeralreports.reports.kyverno.io clusterpolicyreports.wgpolicyk8s.io policyreports.wgpolicyk8s.io&#xA;customresourcedefinition.apiextensions.k8s.io &amp;#34;ephemeralreports.reports.kyverno.io&amp;#34; deleted&#xA;customresourcedefinition.apiextensions.k8s.io &amp;#34;clusterephemeralreports.reports.kyverno.io&amp;#34; deleted&#xA;customresourcedefinition.apiextensions.k8s.io &amp;#34;clusterpolicyreports.wgpolicyk8s.io&amp;#34; deleted&#xA;customresourcedefinition.apiextensions.k8s.io &amp;#34;policyreports.wgpolicyk8s.io&amp;#34; deleted&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;And now:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;$ kubectl get --raw=&amp;#39;/openapi/v2&amp;#39; | head -c 200&#xA;{&amp;#34;swagger&amp;#34;:&amp;#34;2.0&amp;#34;,&amp;#34;info&amp;#34;:{&amp;#34;title&amp;#34;:&amp;#34;Kubernetes&amp;#34;,&amp;#34;version&amp;#34;:&amp;#34;v1.30.11&amp;#34;},&amp;#34;paths&amp;#34;:{&amp;#34;/.well-known/openid-configuration/&amp;#34;:{&amp;#34;get&amp;#34;:{&amp;#34;description&amp;#34;:&amp;#34;get service account issuer OpenID configuration, also known as&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;That was a tricky one! Interestingly: it has only occurred in AKS.&#xA;&lt;a href=&#34;https://aws.amazon.com/eks/&#34;&gt;EKS&lt;/a&gt; was fine.&lt;/p&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://en.wikiquote.org/wiki/The_IT_Crowd&#34;&gt;Hello, IT. Have you tried turning it off and on&#xA;again?&lt;/a&gt;.&amp;#160;&lt;a href=&#34;https://perrotta.dev/2025/06/argocd-every-application-in-unknown-state/#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: ArgoCD: every application in unknown state&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/argocd/&#34;&gt;#argocd&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/bestof/&#34;&gt;#bestof&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/kubernetes/&#34;&gt;#kubernetes&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>★ ArgoCD: custom health check for StatefulSet (OnDelete)
      </title>
      <link>https://perrotta.dev/2025/06/argocd-custom-health-check-for-statefulset-ondelete/</link>
      <pubDate>Fri, 13 Jun 2025 21:40:01 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>argocd</category>
      <category>bestof</category>
      <category>dev</category>
      <category>kubernetes</category>
      <guid>https://perrotta.dev/2025/06/argocd-custom-health-check-for-statefulset-ondelete/</guid>
      <description>&lt;p&gt;♠ It turns out the&#xA;&lt;a href=&#34;https://github.com/argoproj/gitops-engine/blob/master/pkg/health/health_statefulset.go&#34;&gt;built-in&lt;/a&gt;&#xA;health check for&#xA;&lt;a href=&#34;https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/&#34;&gt;StatefulSets&lt;/a&gt;&#xA;in ArgoCD is not comprehensive enough.&lt;/p&gt;&#xA;&lt;p&gt;It covers&#xA;&lt;a href=&#34;https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#update-strategies&#34;&gt;&lt;code&gt;RollingUpdate&lt;/code&gt;&lt;/a&gt;&#xA;well enough, but &lt;code&gt;OnDelete&lt;/code&gt; is incomplete.&lt;/p&gt;&#xA;&lt;p&gt;More specifically:&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Observed&lt;/strong&gt;: whenever you push an update to an STS whose &lt;code&gt;.spec.updateStrategy&lt;/code&gt;&#xA;is &lt;code&gt;OnDelete&lt;/code&gt;, its health status stays as &lt;code&gt;Healthy&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Expected&lt;/strong&gt;: there should be an indication that the STS pods are not&#xA;up-to-date, and hence need to be restarted to incorporate the latest changes.&lt;/p&gt;&#xA;&lt;p&gt;There is &lt;a href=&#34;https://github.com/argoproj/argo-cd/issues/6527&#34;&gt;an open bug&lt;/a&gt;:&#xA;&lt;code&gt;Statefulset healthcheck does not work #6527&lt;/code&gt; for it.&lt;/p&gt;&#xA;&lt;p&gt;I managed to work around it by defining my own health check. This is an use case&#xA;where Gen AI is helpful, though it does not shine. I could not have Gen AI&#xA;produce a fully working health check for this scenario. Instead, I used it to&#xA;bootstrap a basic example, then had to tweak it until it worked. This has been&#xA;tested multiple times, I am reasonably confident it works well (some edge cases&#xA;could be missing though).&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-lua&#34;&gt;health_status = {}&#xA;&#xA;if obj.status == nil then&#xA;  health_status.status = &amp;#34;Progressing&amp;#34;&#xA;  health_status.message = &amp;#34;Waiting for status to be reported&amp;#34;&#xA;  return health_status&#xA;end&#xA;&#xA;local strategy = obj.spec.updateStrategy and obj.spec.updateStrategy.type or &amp;#34;RollingUpdate&amp;#34;&#xA;local spec_replicas = obj.spec.replicas or 1&#xA;local ready_replicas = obj.status.readyReplicas or 0&#xA;local updated_replicas = obj.status.updatedReplicas or 0&#xA;local status_replicas = obj.status.replicas or 0&#xA;local current_revision = obj.status.currentRevision or &amp;#34;&amp;#34;&#xA;local update_revision = obj.status.updateRevision or &amp;#34;&amp;#34;&#xA;&#xA;if strategy == &amp;#34;OnDelete&amp;#34; then&#xA;  if ready_replicas == status_replicas and updated_replicas == spec_replicas then&#xA;    health_status.status = &amp;#34;Healthy&amp;#34;&#xA;    health_status.message = &amp;#34;All replicas are ready and updated (OnDelete strategy)&amp;#34;&#xA;  elseif updated_replicas == 0 then&#xA;    health_status.status = &amp;#34;Degraded&amp;#34;&#xA;    health_status.message = &amp;#34;No replicas have been updated (OnDelete strategy): 0/&amp;#34; .. spec_replicas .. &amp;#34; updated. Still running an old revision!&amp;#34;&#xA;  else&#xA;    health_status.status = &amp;#34;Progressing&amp;#34;&#xA;    health_status.message = &amp;#34;Progressing (OnDelete): &amp;#34; .. ready_replicas .. &amp;#34;/&amp;#34; .. status_replicas .. &amp;#34; ready, &amp;#34; .. updated_replicas .. &amp;#34;/&amp;#34; .. spec_replicas .. &amp;#34; updated&amp;#34;&#xA;  end&#xA;else&#xA;  if ready_replicas == status_replicas and updated_replicas == spec_replicas then&#xA;    if current_revision ~= update_revision then&#xA;      health_status.status = &amp;#34;Progressing&amp;#34;&#xA;      health_status.message = &amp;#34;Waiting for rollout to complete: revision mismatch (&amp;#34; .. current_revision .. &amp;#34; ≠ &amp;#34; .. update_revision .. &amp;#34;)&amp;#34;&#xA;    else&#xA;      health_status.status = &amp;#34;Healthy&amp;#34;&#xA;      health_status.message = &amp;#34;All replicas updated, ready, and revisions match&amp;#34;&#xA;    end&#xA;  else&#xA;    health_status.status = &amp;#34;Progressing&amp;#34;&#xA;    health_status.message = &amp;#34;RollingUpdate progressing: &amp;#34; .. ready_replicas .. &amp;#34;/&amp;#34; .. status_replicas .. &amp;#34; ready, &amp;#34; .. updated_replicas .. &amp;#34;/&amp;#34; .. spec_replicas .. &amp;#34; updated&amp;#34;&#xA;  end&#xA;end&#xA;return health_status&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;It is necessary to distinguish between &lt;code&gt;OnDelete&lt;/code&gt; and &lt;code&gt;RollingUpdate&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;&lt;code&gt;OnDelete&lt;/code&gt; should not use &lt;code&gt;currentRevision&lt;/code&gt; / &lt;code&gt;update_revision&lt;/code&gt;, as these values&#xA;don&amp;rsquo;t mean anything for that update strategy. This can be observed&#xA;&lt;a href=&#34;https://github.com/argoproj/gitops-engine/blob/f8f1b61ba3fd5fcb647563db3106977e1364de31/pkg/health/health_statefulset.go#L63&#34;&gt;upstream&lt;/a&gt;&#xA;as well.&lt;/p&gt;&#xA;&lt;p&gt;It is easy to write / tweak the health check when you look at the live STS&#xA;resource / manifest in the cluster. &lt;code&gt;obj&lt;/code&gt; refers to the STS manifest (&lt;code&gt;kubectl get sts -o yaml&lt;/code&gt;). The most relevant field is &lt;code&gt;status:&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;If you deploy ArgoCD via its helm chart, add that check for &lt;code&gt;argocd-cm&lt;/code&gt;. The&#xA;&lt;code&gt;values.yaml&lt;/code&gt; file:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;argo-cd:&#xA;  configs:&#xA;    cm:&#xA;      resource.customizations.health.apps_StatefulSet: |&#xA;        health_status = {}&#xA;        [...]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;This custom health check was partly inspired by a Prometheus alert we have:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;alert: StatefulSetUpdateNotRolledOut&#xA;expr: max without (revision) (kube_statefulset_status_current_revision unless kube_statefulset_status_update_revision) * (kube_statefulset_replicas != kube_statefulset_status_replicas_updated)&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;How long will it take until LLMs &lt;del&gt;steal&lt;/del&gt; adopt this novel solution from me?&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: ArgoCD: custom health check for StatefulSet (OnDelete)&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/argocd/&#34;&gt;#argocd&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/bestof/&#34;&gt;#bestof&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/kubernetes/&#34;&gt;#kubernetes&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>ArgoCD: application stuck in unknown
      </title>
      <link>https://perrotta.dev/2025/06/argocd-application-stuck-in-unknown/</link>
      <pubDate>Thu, 12 Jun 2025 11:51:32 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>argocd</category>
      <category>dev</category>
      <category>kubernetes</category>
      <guid>https://perrotta.dev/2025/06/argocd-application-stuck-in-unknown/</guid>
      <description>&lt;p&gt;♠ &lt;strong&gt;Problem statement&lt;/strong&gt;: An application in ArgoCD that was previously running&#xA;smoothly has suddenly started to fail. Its status has changed to &amp;ldquo;Unknown&amp;rdquo;.&#xA;The &amp;ldquo;Refresh&amp;rdquo; button is grayed out in the Argo web UI.&lt;/p&gt;&#xA;&lt;p&gt;I found the following works in this scenario, which is typically a transient&#xA;issue:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;restart the argo server&lt;/li&gt;&#xA;&lt;li&gt;restart the argo repo server&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;In terms of commands:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% kubectl rollout restart deployment argocd-server -n argocd&#xA;% kubectl rollout restart deployment argocd-repo-server -n argocd&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: ArgoCD: application stuck in unknown&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/argocd/&#34;&gt;#argocd&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/kubernetes/&#34;&gt;#kubernetes&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>ArgoCD: upgrade to v3, remove helm labels
      </title>
      <link>https://perrotta.dev/2025/06/argocd-upgrade-to-v3-remove-helm-labels/</link>
      <pubDate>Mon, 02 Jun 2025 13:03:24 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>argocd</category>
      <category>dev</category>
      <category>kubernetes</category>
      <guid>https://perrotta.dev/2025/06/argocd-upgrade-to-v3-remove-helm-labels/</guid>
      <description>&lt;p&gt;♠ I am leading the effort to upgrade ArgoCD to its &lt;a href=&#34;https://blog.argoproj.io/announcing-argo-cd-v3-small-but-mighty-df05c0b39ad6&#34;&gt;newest major version&#xA;(v3)&lt;/a&gt;&#xA;across our fleet.&lt;/p&gt;&#xA;&lt;p&gt;One of its &lt;a href=&#34;https://argo-cd.readthedocs.io/en/stable/operator-manual/upgrading/2.14-3.0/&#34;&gt;breaking&#xA;changes&lt;/a&gt;&#xA;is the removal of helm labels from argo applications, like such:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;metadata:&#xA;# [...]&#xA;  labels:&#xA;    app.kubernetes.io/managed-by: Helm&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Applying a normal sync does not get rid of the label.&lt;/p&gt;&#xA;&lt;p&gt;I found out that doing an one-off &lt;a href=&#34;https://argo-cd.readthedocs.io/en/latest/user-guide/sync-options/#server-side-apply&#34;&gt;server-side apply&#xA;sync&lt;/a&gt;&#xA;addresses the label removal, and it is safe to do (incurs no downtime):&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;However, there are some cases where you want to use &lt;code&gt;kubectl apply --server-side&lt;/code&gt; over &lt;code&gt;kubectl apply&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;p&gt;[&amp;hellip;]&lt;/p&gt;&#xA;&lt;p&gt;Patching of existing resources on the cluster that are not fully managed by&#xA;Argo CD.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;There&amp;rsquo;s no need to make the server-side apply a permanent config, i.e.:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: argoproj.io/v1alpha1&#xA;kind: Application&#xA;spec:&#xA;  syncPolicy:&#xA;    syncOptions:&#xA;    - ServerSideApply=true&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;&amp;hellip;though there&amp;rsquo;s no harm either in doing so.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: ArgoCD: upgrade to v3, remove helm labels&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/argocd/&#34;&gt;#argocd&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/kubernetes/&#34;&gt;#kubernetes&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>ArgoCD: vertical-pod-autoscaler sync loop
      </title>
      <link>https://perrotta.dev/2025/02/argocd-vertical-pod-autoscaler-sync-loop/</link>
      <pubDate>Thu, 13 Feb 2025 13:17:36 +0100</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>argocd</category>
      <category>dev</category>
      <category>kubernetes</category>
      <guid>https://perrotta.dev/2025/02/argocd-vertical-pod-autoscaler-sync-loop/</guid>
      <description>&lt;p&gt;♠ We&amp;rsquo;ve had a long time issue wherein our&#xA;&lt;a href=&#34;https://artifacthub.io/packages/helm/cowboysysop/vertical-pod-autoscaler&#34;&gt;vertical-pod-autoscaler&lt;/a&gt;&#xA;(VPA) ArgoCD application, deployed via its helm chart, got stuck in a sync loop.&lt;/p&gt;&#xA;&lt;p&gt;More specifically: the helm chart automatically generates a self-signed&#xA;certificate via the&#xA;&lt;a href=&#34;https://helm.sh/docs/chart_template_guide/function_list/#genca&#34;&gt;GenCA&lt;/a&gt; helm&#xA;function upon every change to our gitops repository. It turns out&#xA;&lt;a href=&#34;https://github.com/cowboysysop/charts/blob/9527602f8f2ea59f51cd3a7d3380810ba60c39fc/charts/vertical-pod-autoscaler/README.md?plain=1#L236&#34;&gt;this&lt;/a&gt;&#xA;is documented and we can see its corresponding manifest&#xA;&lt;a href=&#34;https://github.com/cowboysysop/charts/blob/9527602f8f2ea59f51cd3a7d3380810ba60c39fc/charts/vertical-pod-autoscaler/templates/admission-controller/tls-secret.yaml#L3C1-L3C91&#34;&gt;in the chart template&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;So that&amp;rsquo;s where the sync loop was coming from! ArgoCD was constantly reporting&#xA;(and resolving) a diff in the admission controller secret.&lt;/p&gt;&#xA;&lt;p&gt;The manifest:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-yaml&#34;&gt;apiVersion: v1&#xA;data:&#xA;  ca.crt: &amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&#xA;  tls.crt: &amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&#xA;  tls.key: &amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&amp;#43;&#xA;kind: Secret&#xA;metadata:&#xA;[...]&#xA;  name: vertical-pod-autoscaler-admission-controller-tls&#xA;  namespace: kube-system&#xA;[...]&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;The problematic are all the ones under &lt;code&gt;data:&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I confirmed that was indeed the case in the &lt;a href=&#34;https://cloud-native.slack.com/archives/C01TSERG0KZ/p1739442822542539&#34;&gt;CNCF&#xA;Slack&lt;/a&gt;&#xA;&lt;code&gt;#argo-cd&lt;/code&gt;. Thanks Tim!&lt;/p&gt;&#xA;&lt;p&gt;How to address it?&lt;/p&gt;&#xA;&lt;p&gt;We leverage&#xA;&lt;a href=&#34;https://argo-cd.readthedocs.io/en/stable/user-guide/diffing/&#34;&gt;&lt;code&gt;ignoreDifferences&lt;/code&gt;&lt;/a&gt;&#xA;(c.f. &lt;a href=&#34;https://stackoverflow.com/questions/77510338/argocd-show-as-out-of-sync-on-every-push-for-auto-generate-certs-password&#34;&gt;Stack&#xA;Overflow&lt;/a&gt;)&#xA;in the ArgoCD app manifest:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;% git diff HEAD~2..HEAD&#xA;diff --git apps/base/vertical-pod-autoscaler/vertical-pod-autoscaler.yaml apps/base/vertical-pod-autoscaler/vertical-pod-autoscaler.yaml&#xA;index 92bfbcc..90d8435 100644&#xA;--- apps/base/vertical-pod-autoscaler/vertical-pod-autoscaler.yaml&#xA;&amp;#43;&amp;#43;&amp;#43; apps/base/vertical-pod-autoscaler/vertical-pod-autoscaler.yaml&#xA;@@ -34,3 &amp;#43;34,15 @@ spec:&#xA;         maxDuration: 1m&#xA;     syncOptions:&#xA;       - CreateNamespace=true&#xA;&amp;#43;      - RespectIgnoreDifferences=true&#xA;&amp;#43;  ignoreDifferences:&#xA;&amp;#43;    - group: &amp;#34;&amp;#34;&#xA;&amp;#43;      kind: Secret&#xA;&amp;#43;      name: vertical-pod-autoscaler-admission-controller-tls&#xA;&amp;#43;      jsonPointers:&#xA;&amp;#43;        - /data&#xA;&amp;#43;    - group: apps&#xA;&amp;#43;      kind: Deployment&#xA;&amp;#43;      name: vertical-pod-autoscaler-admission-controller&#xA;&amp;#43;      jsonPointers:&#xA;&amp;#43;        - /spec/template/metadata/annotations/checksum~1tls-secret&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;In &lt;a href=&#34;https://www.rfc-editor.org/rfc/rfc6901&#34;&gt;JSON Pointers&lt;/a&gt; (RFC 6901), one&#xA;escapes the slash character with a &lt;code&gt;~1&lt;/code&gt; (c.f. section 3 in the spec):&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;Because the characters &amp;#39;~&amp;#39; (%x7E) and &amp;#39;/&amp;#39; (%x2F) have special meanings in&#xA;JSON Pointer, &amp;#39;~&amp;#39; needs to be encoded as &amp;#39;~0&amp;#39; and &amp;#39;/&amp;#39; needs to be encoded as&#xA;&amp;#39;~1&amp;#39; when these characters appear in a reference token.&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;Problem resolved!&lt;/p&gt;&#xA;&lt;p&gt;In general all helm charts that generate self-signed certificates (with &lt;code&gt;genCA&lt;/code&gt;)&#xA;may experience this sync loop when used with a CD framework such as Argo.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: ArgoCD: vertical-pod-autoscaler sync loop&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/argocd/&#34;&gt;#argocd&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/kubernetes/&#34;&gt;#kubernetes&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>ArgoCD: cache: key is missing
      </title>
      <link>https://perrotta.dev/2025/01/argocd-cache-key-is-missing/</link>
      <pubDate>Thu, 09 Jan 2025 20:20:03 -0300</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>argocd</category>
      <category>dev</category>
      <category>kubernetes</category>
      <guid>https://perrotta.dev/2025/01/argocd-cache-key-is-missing/</guid>
      <description>&lt;p&gt;♠ If you experience the title error message in ArgoCD (e.g. via its web UI and/or&#xA;in pod logs), it&amp;rsquo;s related to&#xA;&lt;a href=&#34;https://github.com/argoproj/argo-cd/issues/5068&#34;&gt;argo-cd#5068&lt;/a&gt;. The full error&#xA;message is:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;Unable to load data: cache: key is missing&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;As I&#xA;&lt;a href=&#34;https://github.com/argoproj/argo-cd/issues/5068#issuecomment-2580878251&#34;&gt;commented&lt;/a&gt;&#xA;in the bug, here&amp;rsquo;s how to fix it:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;The following workaround sufficed for me: &lt;code&gt;kubectl delete pod -n argocd argocd-application-controller-0&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Initially I ran &lt;code&gt;kubectl rollout restart deployment -n argocd argocd-application-controller&lt;/code&gt; but it didn&amp;rsquo;t work.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;In my experience, this error only happens once, ephemerally, during ArgoCD&#xA;bootstrapping. Once fixed it does not reoccur.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Update(2025-06-06)&lt;/strong&gt;: This error reoccurs intermittently 🤷.&lt;/p&gt;&#xA;&lt;p&gt;Another potential workaround is to disable redis / caching altogether, as ArgoCD&#xA;can fully operate without it, but I wouldn&amp;rsquo;t recommend that.&lt;/p&gt;&#xA;&lt;p&gt;See also: &lt;a href=&#34;https://github.com/argoproj/argo-cd/issues/18503&#34;&gt;#18503&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: ArgoCD: cache: key is missing&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/argocd/&#34;&gt;#argocd&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/kubernetes/&#34;&gt;#kubernetes&lt;/a&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>New APKBUILD: argocd
      </title>
      <link>https://perrotta.dev/2024/10/new-apkbuild-argocd/</link>
      <pubDate>Wed, 09 Oct 2024 23:03:32 +0200</pubDate><author>serendipity@perrotta.dev (Thiago Perrotta)</author>
      <category>alpine-linux</category>
      <category>argocd</category>
      <category>dev</category>
      <category>kubernetes</category>
      <guid>https://perrotta.dev/2024/10/new-apkbuild-argocd/</guid>
      <description>&lt;p&gt;♠ &lt;a href=&#34;https://argo-cd.readthedocs.io/en/stable/&#34;&gt;ArgoCD&lt;/a&gt; is a widely used GitOps&#xA;software for Kubernetes Continuous Delivery (see&#xA;&lt;a href=&#34;https://github.com/argoproj/argo-cd/blob/master/USERS.md&#34;&gt;USERS.md&lt;/a&gt;).&lt;/p&gt;&#xA;&lt;p&gt;I am quite surprised no one bothered to create an Alpine Linux package for it.&lt;/p&gt;&#xA;&lt;p&gt;Until&amp;hellip;&lt;a href=&#34;https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/73305&#34;&gt;now&lt;/a&gt;,&#xA;by yours truly.&lt;/p&gt;&#xA;&lt;p&gt;This &lt;code&gt;APKBUILD&lt;/code&gt; took a bit longer to create than the usual.&#xA;There were a couple of issues with &lt;code&gt;-buildmode=pie&lt;/code&gt;, addressed with&#xA;&lt;code&gt;export CGO_ENABLED=1&lt;/code&gt; (via &lt;code&gt;make CGO_FLAG=1&lt;/code&gt;).&lt;/p&gt;&#xA;&lt;p&gt;Also, not every architecture is compatible with it. The following error message&#xA;appears in ARM builds:&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-plaintext&#34;&gt;cannot use math.MaxInt64 (untyped int constant 9223372036854775807) as int value in argument to env.ParseNumFromEnv (overflows)&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;Anyway, once it is merged upstream, enjoy!&lt;/p&gt;&#xA;&#xA;&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;% doas apk add argocd&lt;/code&gt;&lt;/pre&gt;&#xA;&lt;p&gt;— § —&lt;/p&gt;&lt;p&gt;Reply via &lt;a href=&#34;mailto:serendipity@perrotta.dev?subject=Reply to: New APKBUILD: argocd&#34;&gt;email&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href=&#34;https://perrotta.dev/tags/alpine-linux/&#34;&gt;#alpine-linux&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/argocd/&#34;&gt;#argocd&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/dev/&#34;&gt;#dev&lt;/a&gt; &lt;a href=&#34;https://perrotta.dev/tags/kubernetes/&#34;&gt;#kubernetes&lt;/a&gt;&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
