<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Deployment on Backend Engineering Strategy Tools</title><link>https://backend-engineering-strategy-tools.github.io/site/tags/deployment/</link><description>Recent content in Deployment on Backend Engineering Strategy Tools</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Mon, 01 Jan 2024 00:00:00 +0000</lastBuildDate><atom:link href="https://backend-engineering-strategy-tools.github.io/site/tags/deployment/index.xml" rel="self" type="application/rss+xml"/><item><title>ArgoCD</title><link>https://backend-engineering-strategy-tools.github.io/site/public-notes/cicd/argo-cd/</link><pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate><guid>https://backend-engineering-strategy-tools.github.io/site/public-notes/cicd/argo-cd/</guid><description>&lt;p&gt;&lt;img alt="ArgoCD" class="gallery-image" data-flex-basis="240px" data-flex-grow="100" height="268" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://backend-engineering-strategy-tools.github.io/site/public-notes/cicd/argo-cd/argo.png" width="268"&gt;&lt;/p&gt;
&lt;p&gt;You deploy with &lt;code&gt;kubectl apply&lt;/code&gt; from your laptop. It works. Then a colleague edits a deployment directly on the cluster to fix something urgent. Now what is running no longer matches what is in Git. That is drift, and it is silent — until something breaks in production and nobody can explain why the live state differs from the last known good config.&lt;/p&gt;
&lt;p&gt;So you use ArgoCD. Git becomes the single source of truth. Every change flows through a pull request, gets reviewed, and syncs to the cluster automatically. If anyone touches a resource directly, ArgoCD detects the divergence and overrides it back. The cluster converges to Git, always.&lt;/p&gt;
&lt;p&gt;This is GitOps: the deployment pipeline is driven by Git state, not by humans running commands.&lt;/p&gt;
&lt;h2 id="ci-vs-cd"&gt;CI vs CD
&lt;/h2&gt;&lt;p&gt;A useful mental separation: CI and CD are different concerns and should be handled by different tools.&lt;/p&gt;
&lt;p&gt;&lt;img alt="CI/CD flow" class="gallery-image" data-flex-basis="426px" data-flex-grow="177" height="540" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://backend-engineering-strategy-tools.github.io/site/public-notes/cicd/argo-cd/cicd_flow.png" srcset="https://backend-engineering-strategy-tools.github.io/site/public-notes/cicd/argo-cd/cicd_flow_hu_6a2bb36163cfd265.png 800w, https://backend-engineering-strategy-tools.github.io/site/public-notes/cicd/argo-cd/cicd_flow.png 960w" width="960"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CI&lt;/strong&gt; (Continuous Integration) is about code — build, test, produce an artifact (a container image). A pipeline in GitHub Actions, Tekton, or Jenkins owns this. It ends with an image pushed to a registry.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CD&lt;/strong&gt; (Continuous Delivery) is about cluster state — take that artifact and make sure the right version is running in the right environment. ArgoCD owns this. It watches Git, not the CI pipeline.&lt;/p&gt;
&lt;p&gt;Keeping them separate means your deployment logic is not buried inside a CI pipeline that developers need to understand and maintain. ArgoCD runs in the cluster and continuously reconciles state. It is always on.&lt;/p&gt;
&lt;h2 id="applications"&gt;Applications
&lt;/h2&gt;&lt;p&gt;ArgoCD manages &lt;strong&gt;Applications&lt;/strong&gt; — a CRD that maps a Git source to a cluster destination:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;apiVersion&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;argoproj.io/v1alpha1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Application&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;my-app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;namespace&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;argocd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;spec&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;project&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;source&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;repoURL&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;https://github.com/myorg/my-app-config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;targetRevision&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;path&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;manifests/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;destination&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;server&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;https://kubernetes.default.svc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;namespace&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;my-app&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;syncPolicy&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;automated&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;prune&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;selfHeal&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;prune: true&lt;/code&gt; — resources removed from Git are deleted from the cluster.
&lt;code&gt;selfHeal: true&lt;/code&gt; — any manual change to the cluster is immediately reverted.&lt;/p&gt;
&lt;h2 id="app-of-apps"&gt;App of Apps
&lt;/h2&gt;&lt;p&gt;Managing dozens of Applications individually gets unwieldy. The &lt;strong&gt;App of Apps&lt;/strong&gt; pattern solves this: one root Application whose source is a directory of other Application manifests. ArgoCD applies the root, which creates all the child Applications, which in turn sync their own workloads. One repo, one sync, everything deployed.&lt;/p&gt;
&lt;h2 id="sync-strategies"&gt;Sync strategies
&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Strategy&lt;/th&gt;
 &lt;th&gt;Behaviour&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Automated&lt;/td&gt;
 &lt;td&gt;ArgoCD syncs on every Git change automatically&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Manual&lt;/td&gt;
 &lt;td&gt;Changes are detected and shown as OutOfSync — a human triggers the sync&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Automated sync with selfHeal is the purest GitOps posture. Manual sync is useful for production environments where you want a human approval step before changes roll out.&lt;/p&gt;
&lt;h2 id="rollback"&gt;Rollback
&lt;/h2&gt;&lt;p&gt;Because every state the cluster has ever been in corresponds to a Git commit, rollback is a &lt;code&gt;git revert&lt;/code&gt; — or clicking &amp;ldquo;Sync to previous revision&amp;rdquo; in the ArgoCD UI. No special tooling, no runbooks, just Git history.&lt;/p&gt;
&lt;h2 id="repo-structure"&gt;Repo structure
&lt;/h2&gt;&lt;p&gt;A layout that works well in practice separates ArgoCD&amp;rsquo;s own installation from the workloads it manages:&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;cluster/&amp;lt;cluster&amp;gt;/
 cfg/argo-cd/ # ArgoCD install only — CRDs and Helm values
 app-of-apps/ # Root Application, Projects, app definitions
 overlay/&amp;lt;app&amp;gt;/ # Per-cluster Kustomize patches, secret/config overrides

external/ # Reusable base manifests shared across clusters
internal/ # Internal app base manifests
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The key separations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;ArgoCD install is isolated&lt;/strong&gt; in &lt;code&gt;cfg/argo-cd&lt;/code&gt; to avoid recursive install loops and make upgrades predictable. ArgoCD is not managing its own installation yet at this point — that comes later.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;App-of-Apps lives separately&lt;/strong&gt; from the install. Once ArgoCD is running, applying &lt;code&gt;app-of-apps/&lt;/code&gt; bootstraps the entire cluster in one step.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Base vs overlay&lt;/strong&gt; — &lt;code&gt;external/&lt;/code&gt; and &lt;code&gt;internal/&lt;/code&gt; define &lt;em&gt;what an app is&lt;/em&gt;. The cluster overlay defines &lt;em&gt;how it runs in this environment&lt;/em&gt;. Cluster-specific concerns (resource limits, replica counts, secret refs) stay in the cluster directory and never bleed into the base.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="bootstrapping-a-cluster"&gt;Bootstrapping a cluster
&lt;/h2&gt;&lt;p&gt;There is a chicken-and-egg problem: ArgoCD manages everything, but something has to install ArgoCD first. The two-step bootstrap solves it cleanly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1 — Install ArgoCD manually (once):&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm repo add argo https://argoproj.github.io/argo-helm
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm repo update
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;helm install argocd argo/argo-cd &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -n argo-cd --create-namespace &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -f cluster/staging/cfg/argo-cd/values.yaml
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;Step 2 — Apply the App-of-Apps root:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kubectl apply -k cluster/&amp;lt;cluster&amp;gt;/app-of-apps/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;From this point ArgoCD reconciles the entire cluster. Every subsequent change goes through Git — you never run &lt;code&gt;helm install&lt;/code&gt; or &lt;code&gt;kubectl apply&lt;/code&gt; for workloads again.&lt;/p&gt;
&lt;h2 id="self-management"&gt;Self-management
&lt;/h2&gt;&lt;p&gt;The final step is making ArgoCD manage its own upgrades. Create an Application that points at &lt;code&gt;cluster/&amp;lt;cluster&amp;gt;/cfg/argo-cd&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;apiVersion&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;argoproj.io/v1alpha1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;kind&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;Application&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;metadata&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;name&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;argocd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;namespace&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;argocd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;spec&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;project&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;default&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;source&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;repoURL&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;https://github.com/myorg/cluster-config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;targetRevision&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;main&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;path&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;cluster/staging/cfg/argo-cd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;destination&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;server&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;https://kubernetes.default.svc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;namespace&lt;/span&gt;: &lt;span style="color:#ae81ff"&gt;argocd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;syncPolicy&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;automated&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;prune&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt; &lt;span style="color:#75715e"&gt;# be cautious pruning ArgoCD&amp;#39;s own resources&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;selfHeal&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now ArgoCD upgrades itself when you update the Helm values in Git. No more manual &lt;code&gt;helm upgrade&lt;/code&gt; — the cluster is fully self-managing. Changes to ArgoCD config go through the same PR review process as everything else.&lt;/p&gt;
&lt;h2 id="resources"&gt;Resources
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://argo-cd.readthedocs.io/" target="_blank" rel="noopener"
 &gt;ArgoCD documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://opengitops.dev/" target="_blank" rel="noopener"
 &gt;GitOps principles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://argo-cd.readthedocs.io/en/stable/user-guide/best_practices/" target="_blank" rel="noopener"
 &gt;ArgoCD best practices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>