<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Obsidian on aviadhaham.me</title><link>https://aviadhaham.me/tags/obsidian/</link><description>Recent content in Obsidian on aviadhaham.me</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>© 2024 Aviad Haham. All rights reserved.</copyright><lastBuildDate>Fri, 29 May 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://aviadhaham.me/tags/obsidian/index.xml" rel="self" type="application/rss+xml"/><item><title>Headless Obsidian Sync for an AI Vault</title><link>https://aviadhaham.me/posts/headless-obsidian-sync-ai-vault/</link><pubDate>Fri, 29 May 2026 00:00:00 +0000</pubDate><guid>https://aviadhaham.me/posts/headless-obsidian-sync-ai-vault/</guid><description>&lt;p>I wanted my agent to write into the same Obsidian vault I use on my laptop, without giving the container direct access to my desktop. The setup ended up being pretty simple:&lt;/p>
&lt;ul>
&lt;li>a host-owned vault directory on the VPS&lt;/li>
&lt;li>a headless Obsidian Sync container&lt;/li>
&lt;li>the Hermes container mounting that same vault path&lt;/li>
&lt;li>a couple of basic permission guards&lt;/li>
&lt;/ul>
&lt;p>That keeps Hermes inside the same note-taking flow I already use, while still keeping the host boundary clean.&lt;/p>
&lt;h2 id="the-storage-model">The storage model&lt;/h2>
&lt;p>Hermes mounts the host tree directly into the container:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">${HERMES_HOME_DIR}:/opt/data&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The vault lives under that tree, so anything Hermes writes to &lt;code>/opt/data/vaults&lt;/code> lands in the shared vault directory.&lt;/p>
&lt;h2 id="the-sync-bridge">The sync bridge&lt;/h2>
&lt;p>The actual sync layer is a headless Obsidian Sync container:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">services&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">obsidian-sync&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ghcr.io/belphemur/obsidian-headless-sync-docker:0.0.8@sha256:...&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">restart&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">unless-stopped&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cap_drop&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">ALL&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">cap_add&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">CHOWN&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">SETUID&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">SETGID&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">DAC_OVERRIDE&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">security_opt&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="kc">no&lt;/span>-&lt;span class="l">new-privileges:true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">environment&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">OBSIDIAN_AUTH_TOKEN&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${OBSIDIAN_AUTH_TOKEN}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">VAULT_NAME&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${VAULT_NAME}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">VAULT_PASSWORD&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${VAULT_PASSWORD:-}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">PUID&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${PUID:-1000}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">PGID&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${PGID:-1000}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">VAULT_PATH&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${VAULT_PATH:-/vault}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">DEVICE_NAME&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${DEVICE_NAME:-obsidian-docker}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">CONFLICT_STRATEGY&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">${CONFLICT_STRATEGY:-merge}&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">volumes&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">/home/hermes/vaults:/vault&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">${CONFIG_HOST_PATH:-./config}:/home/obsidian/.config&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This is the bridge to my Obsidian Sync peers. It mounts the same vault path Hermes uses, so edits move both ways:&lt;/p>
&lt;ul>
&lt;li>laptop changes sync to the VPS&lt;/li>
&lt;li>Hermes-written notes sync back to the laptop&lt;/li>
&lt;/ul>
&lt;h2 id="a-small-but-important-detail">A small but important detail&lt;/h2>
&lt;p>Before the containers start, the host directories are created with the right ownership. That avoids the usual first-run Docker problem where a root-owned directory breaks later writes.&lt;/p>
&lt;h2 id="the-security-boundary">The security boundary&lt;/h2>
&lt;p>The important part is that the agent is &lt;em>not&lt;/em> running as my admin user on the host.&lt;/p>
&lt;ul>
&lt;li>&lt;code>hermes&lt;/code> is an unprivileged host user&lt;/li>
&lt;li>vault and config dirs are owned by &lt;code>hermes&lt;/code>&lt;/li>
&lt;li>the sync container has &lt;code>no-new-privileges&lt;/code>&lt;/li>
&lt;li>capabilities are trimmed aggressively&lt;/li>
&lt;li>the mount is local to the host, not exposed over a public port&lt;/li>
&lt;/ul>
&lt;p>So the note flow stays convenient without making the vault a loose shared filesystem.&lt;/p>
&lt;h2 id="the-core-idea">The core idea&lt;/h2>
&lt;p>In practice, the architecture is:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">laptop Obsidian
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ↕ Obsidian Sync
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">headless sync container on VPS
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ↕ vault directory
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">Hermes container
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The point is simple: the agent and the human editor write into the same vault, but through a controlled host-side bridge.&lt;/p>
&lt;p>A great pattern for anyone who want an agent to work inside your notes when the agent runs remotely and you don&amp;rsquo;t share a filesystem&lt;/p></description></item><item><title>Implementing Scalable GitOps With Argo CD and ApplicationSets: A Case Study</title><link>https://aviadhaham.me/posts/implementing-gitops-with-argo-cd-and-applicationsets/</link><pubDate>Sun, 28 Apr 2024 00:00:00 +0000</pubDate><guid>https://aviadhaham.me/posts/implementing-gitops-with-argo-cd-and-applicationsets/</guid><description>&lt;blockquote>
&lt;p>&lt;em>This infrastructure was developed at &lt;a href="https://nexxen.com">Nexxen&lt;/a>, where I&amp;rsquo;m currently employed.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;p>Transitioning from the inefficient &amp;ldquo;&lt;a href="https://argo-cd.readthedocs.io/en/stable/operator-manual/cluster-bootstrapping/#app-of-apps-pattern">App of Apps&lt;/a>&amp;rdquo; model, we adopted GitOps with Argo CD and &lt;code>ApplicationSet&lt;/code>s for improved efficiency and reliability. The old system, with its hunderds of declarative Argo &lt;code>Application&lt;/code>s and frequent manual changes them, was operationally taxing, error-prone and not scalable.&lt;/p>
&lt;p>The shift to a declarative GitOps approach using &lt;code>ApplicationSet&lt;/code>s has significantly minimized manual interventions, enhancing the scalability and accuracy of our deployment processes.&lt;/p>
&lt;p>In this blog post, I&amp;rsquo;ll explore our approach to establishing a scalable and maintainable GitOps infrastructure using the Argo CD &lt;code>ApplicationSets&lt;/code> CRD.&lt;/p>
&lt;p>&lt;strong>I will delve into how we&lt;/strong>:&lt;/p>
&lt;ol>
&lt;li>Bootstrap and manage Argo CD configurations.&lt;/li>
&lt;li>Structure our &lt;code>ApplicationSet&lt;/code>s and GitOps deployments repository for scalability (utilizing the &lt;code>git&lt;/code> generator).&lt;/li>
&lt;li>Leverage &lt;code>ApplicationSet&lt;/code>s to automate deployment processes.&lt;/li>
&lt;li>Manage and scale our deployments across multiple clusters and environments.&lt;/li>
&lt;/ol>
&lt;blockquote>
&lt;p>&lt;em>I provided real examples, from two teams, Octo and Datamine2, to give you a better understanding of how we structure our deployments.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;h2 id="introduction-to-our-gitops-setup">Introduction to Our GitOps Setup&lt;/h2>
&lt;p>We divided our configurations into two repositories.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>The &lt;code>argocd-management&lt;/code> repository&lt;/strong>, accessible only to system administrators, contains sensitive Argo CD configurations.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Developers mainly use &lt;strong>the &lt;code>gitops-deployments&lt;/code> repository&lt;/strong> for deployment manifests.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>This strategy safeguards our management configurations and aligns with the principle of least privilege.&lt;/p>
&lt;/blockquote>
&lt;p>Our GitOps framework is built around two main repositories:&lt;/p>
&lt;h3 id="argocd-management-repository">&lt;code>argocd-management&lt;/code> repository:&lt;/h3>
&lt;p>Manages Argo CD&amp;rsquo;s foundational configurations, including &lt;code>AppProject&lt;/code>s and &lt;code>ApplicationSet&lt;/code>s.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Example directory structure&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">├── app-of-appprojects.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── app-of-appsets.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── appprojects
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">| ├── [more team based directories]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── octo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── appproject-infra-non-prod.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── appproject-infra-prod.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── appproject-orphans-non-prod.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── appproject-orphans-prod.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── sunflower
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── appproject-datamine2-non-prod.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── appproject-datamine2-prod.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│   └── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── appsets
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">| ├── [more team based directories]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── octo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── appset-infra-non-prod.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── appset-infra-prod.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── appset-orphans-non-prod.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── appset-orphans-prod.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── sunflower
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── appset-datamine2-non-prod.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ ├── appset-datamine2-prod.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │ └── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│   └── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── bootstrap.yml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;h3 id="gitops-deployments-repository">&lt;code>gitops-deployments&lt;/code> repository:&lt;/h3>
&lt;p>Acts as the single source of truth for all declarative deployments within our organization.&lt;/p>
&lt;blockquote>
&lt;p>This is a monorepo gitops repository that contains all the Kubernetes manifests that are used/deployed across all the company.&lt;/p>
&lt;/blockquote>
&lt;ul>
&lt;li>
&lt;p>Example directory structure&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">deployments
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── [more team based directories]
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── octo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── infra
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   ├── devlake
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   │   └── envs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   │   └── prod
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   │   ├── appset_config.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   │   ├── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   │   ├── ui_deployment_patch.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   │   └── values.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   └── vault-auth
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   └── envs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   └── prod
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   ├── appset_config.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   ├── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   └── resources.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── orphans
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── aws-search
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   ├── base
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   │   ├── deployment.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   │   ├── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   │   └── service.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   ├── envs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   │   └── prod
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   │   ├── appset_config.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   │   └── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   └── variants
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   └── prod
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   ├── deployment.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ │   └── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ └── another-app
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│    ├── base
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│    │   ├── deployment.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│    │   └── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│    └── envs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│    └── prod
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│    ├── appset_config.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│    ├── consul_configmap.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│    ├── consul_deployment.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│    └── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">└── datamine2
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── datamine-amoeba-appprd
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   ├── base
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   │   ├── deployment.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   │   ├── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   ├── envs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   │   ├── non-prod-sandbox
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   │   │   ├── appset_config.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   │   │   ├── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   │   ├── non-prod-staging
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   │   │   ├── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   │   └── prod
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   │   ├── appset_config.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   │   ├── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   └── variants
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   ├── prod
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   │   ├── env.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   │   ├── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   ├── sandbox
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   │   ├── env.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   │   ├── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   └── staging
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   ├── env.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> │   ├── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> └── datamine-amoeba-catalog
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    ├── base
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    │   ├── deployment.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    │   ├── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    ├── envs
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    │   ├── non-prod-sandbox
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    │   │   ├── appset_config.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    │   │   └── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    │   ├── non-prod-staging
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    │   │   └── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    │   └── prod
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    │   ├── appset_config.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    │   └── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    └── variants
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    ├── prod
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    │   ├── env.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    │   ├── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    ├── sandbox
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    │   ├── env.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    │   ├── kustomization.yaml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    └── staging
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    ├── env.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">    ├── kustomization.yaml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;h2 id="our-approach-to-bootstrapping-and-managing-argo-cd-configurations">Our Approach to Bootstrapping and Managing Argo CD Configurations&lt;/h2>
&lt;p>Although &lt;code>ApplicationSet&lt;/code>s offer significant reductions in time and manual errors by automating deployment processes, integrating them with Kustomize has elevated their effectiveness.&lt;/p>
&lt;p>By managing &lt;code>ApplicationSet&lt;/code>s and &lt;code>AppProject&lt;/code>s through Argo CD applications themselves (&lt;code>app-of-appsets&lt;/code> and &lt;code>app-of-appprojects&lt;/code>) we have automated even the application of these configurations to the cluster. This meta-management layer ensures that all changes are self-maintaining and self-applying, which enhances automation and reduces the need for manual oversight even further.&lt;/p>
&lt;blockquote>
&lt;p>We utlize the power of the &lt;code>Application&lt;/code> CRD to manage the &lt;code>AppProjects&lt;/code>, and the &lt;code>Application&lt;/code> factories, the &lt;code>ApplicationSets&lt;/code>!&lt;/p>
&lt;/blockquote>
&lt;p>&lt;strong>Below, I&amp;rsquo;ll explain our approach more in detail:&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>
&lt;p>We start our setup with a bootstrap operation defined in the &lt;code>bootstrap.yml&lt;/code> file, which contains all necessary configurations for initializing Argo CD.&lt;/p>
&lt;blockquote>
&lt;p>&lt;em>At the time of writing this post, it only contains an &lt;code>AppProject&lt;/code> manifest (named &lt;code>management&lt;/code>), that we use for the two root YAMLs I will mention below.&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;li>
&lt;p>In order to reconstruct our setup, &lt;strong>the only manual steps we need to perform&lt;/strong> are the following:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Apply the bootstrap configuration:&lt;/strong>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">kubectl apply -f bootstrap.yml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>&lt;strong>Set up management for AppProjects and ApplicationSets:&lt;/strong>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">kubectl apply -f app-of-appprojects.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">kubectl apply -f app-of-appsets.yml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>
&lt;p>To make changes (add, delete, or edit), simply update the &lt;code>appprojects&lt;/code> and &lt;code>appsets&lt;/code> directories using the &lt;code>kustomize&lt;/code> structure. Each change will be automatically detected by either the &lt;code>app-of-appprojects&lt;/code> or &lt;code>app-of-appsets&lt;/code> respectively.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="diagram-how-its-working-together">Diagram: How It&amp;rsquo;s Working Together&lt;/h3>
&lt;p>&lt;img src="https://aviadhaham.me/posts-images/appsets-factories-automation-diagram.png" alt="Diagram illustrating the whole operation">&lt;/p>
&lt;h2 id="understanding-our-applicationset-approach">Understanding Our ApplicationSet Approach&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Generators&lt;/strong>: Using &lt;code>generators&lt;/code>, the &lt;code>ApplicationSet&lt;/code> constructs a dynamic list of Argo CD applications to be managed. These generators use patterns and parameters defined in configuration files (like &lt;code>appset_config*.json&lt;/code> that you&amp;rsquo;ll see below) to determine which applications should exist (or be deleted).&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Scalability&lt;/strong>: This approach enables the &lt;code>ApplicationSet&lt;/code> to scale efficiently, as it can automatically adjust the number of managed applications based on the repository’s current state. New applications are created, and outdated ones are removed without manual intervention.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Considerations&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>Any directory that won&amp;rsquo;t have the &lt;code>appset_config*.json&lt;/code> file or that won&amp;rsquo;t match its appropriate &lt;code>ApplicationSet&lt;/code>, will be ignored by the &lt;code>ApplicationSet&lt;/code>.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>It&amp;rsquo;s also important to make sure that no other &lt;code>ApplicationSet&lt;/code> is targeting the same directory, as it may lead to conflicts and unexpected behavior.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h2 id="our-applicationsets-strategies">Our ApplicationSets Strategies&lt;/h2>
&lt;p>We have two main strategies for our &lt;code>ApplicationSet&lt;/code>s:&lt;/p>
&lt;h3 id="gitlab-subgroup-based-applicationsets">GitLab Subgroup-based &lt;code>ApplicationSet&lt;/code>s&lt;/h3>
&lt;p>&lt;code>ApplicationSet&lt;/code>s are primarily organized per GitLab subgroup, automatically generating Argo CD &lt;code>Application&lt;/code>s for each service or application within the subgroup.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>&amp;ldquo;Orphans&amp;rdquo; &lt;code>ApplicationSet&lt;/code>s&lt;/strong> (&lt;strong>for applications/repos that do not belong to any subgroup&lt;/strong>)
As we have many applications that do not belong to any subgroup,
we handle them as “orphans” (both in terms of &lt;code>ApplicationSet&lt;/code>s and in the &lt;code>gitops-deployments&lt;/code> repo).&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Rationale&lt;/strong>:
We encountered issues when creating an &lt;code>ApplicationSet&lt;/code> that watches the root hierarchy of the group, as it did not behave as expected. Instead, we decided to separate the &amp;ldquo;orphans&amp;rdquo; into a different directory and handle the path logic in the CI using simple bash code. For more details on how we resolved this issue, refer to the &lt;a href="#qa">Q&amp;amp;A&lt;/a> section.&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;/ul>
&lt;h3 id="prod-and-non-prod-environments">Prod and Non-Prod Environments&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>The production environments are handled by &lt;code>ApplicationSet&lt;/code>s that target directories with a &lt;code>prod&lt;/code> prefix in their paths, and non-production environments with a &lt;code>non-prod&lt;/code> prefix.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>Rationale&lt;/strong>:
By using prefixes for &lt;code>prod*&lt;/code> and &lt;code>non-prod*&lt;/code>, we can effectively manage different types of deployments in separate &lt;code>ApplicationSet&lt;/code>s. This approach also ensures that the user only needs to add these prefixes when they want the deployments to be picked up and watched by the corresponding &lt;code>ApplicationSet&lt;/code> for deployment.&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;/ul>
&lt;h3 id="examples-applicationset-manifests">Examples &lt;code>ApplicationSet&lt;/code> Manifests&lt;/h3>
&lt;p>Real example &lt;code>ApplicationSet&lt;/code>s config that we use for our own DevOps team (&amp;ldquo;Octo&amp;rdquo;):&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Infra&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">argoproj.io/v1alpha1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ApplicationSet&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">octo-infra-prod&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">argocd&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">generators&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">git&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">repoURL&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">git@git.company.com:octo/gitops-deployments.git&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">revision&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">files&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">path&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">deployments/octo/infra/**/envs/prod*/appset_config*.json&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">template&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;octo-{{path[3]}}-{{cluster.name}}-{{env}}&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">finalizers&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">resources-finalizer.argocd.argoproj.io&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">argocd&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">project&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">octo-infra-prod&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">source&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">repoURL&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">git@git.company.com:octo/gitops-deployments.git&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">targetRevision&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">path&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;{{path}}&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">destination&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">server&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;{{cluster.address}}&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;{{namespace}}&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">syncPolicy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">automated&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">selfHeal&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">prune&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">syncOptions&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">CreateNamespace=true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;li>
&lt;p>&lt;strong>Orphans&lt;/strong>:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">argoproj.io/v1alpha1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ApplicationSet&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">octo-orphans-prod&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">argocd&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">generators&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">git&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">repoURL&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">git@git.company.com:octo/gitops-deployments.git&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">revision&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">files&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">path&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">deployments/octo/orphans/**/envs/prod*/appset_config*.json&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">template&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">metadata&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;octo-{{path[3]}}-{{cluster.name}}-{{env}}&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">finalizers&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">resources-finalizer.argocd.argoproj.io&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">argocd&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">spec&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">project&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">octo-orphans-prod&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">source&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">repoURL&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">git@git.company.com:octo/gitops-deployments.git&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">targetRevision&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">main&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">path&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;{{path}}&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">destination&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">server&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;{{cluster.address}}&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="s2">&amp;#34;{{namespace}}&amp;#34;&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">syncPolicy&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">automated&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">selfHeal&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">prune&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="kc">true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">syncOptions&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="l">CreateNamespace=true&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;p>These &lt;code>ApplicationSet&lt;/code>s targets the &lt;code>orphans&lt;/code>/&lt;code>infra&lt;/code> directory within the &lt;code>octo&lt;/code> subgroup in the &lt;code>gitops-deployments&lt;/code> repo, focusing on the &lt;code>prod&lt;/code> environment.&lt;/p>
&lt;blockquote>
&lt;p>For more details about the &lt;code>appset_config*.json&lt;/code> files, refer to the &lt;a href="#qa">Q&amp;amp;A&lt;/a> section.&lt;/p>
&lt;/blockquote>
&lt;h2 id="scale-strategies-with-applicationsets">Scale Strategies with ApplicationSets&lt;/h2>
&lt;p>Our architecture leverages ApplicationSets to facilitate scalability in the following ways:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Deploying New Services&lt;/strong>: Adding a new directory in the &lt;code>gitops-deployments&lt;/code>, to a &lt;code>path&lt;/code> crawled by a specific &lt;code>ApplicationSet&lt;/code> will make the &lt;code>ApplicationSet&lt;/code> add another crawl (thanks to the globbing &lt;code>**&lt;/code> in the &lt;code>path&lt;/code>), and so, if the rest of the path is matching the regex/&lt;code>path&lt;/code> in the rest of the path, it will add your new service, including all its environments.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Deploying the Same Service to Multiple Clusters&lt;/strong>: Adding a new JSON configuration file (matching the regex &lt;code>appset_config*.json&lt;/code>) in the relevant envs directory automatically triggers the creation of a new Argo &lt;code>Application&lt;/code> tailored to the specific parameters defined within the file.&lt;/p>
&lt;blockquote>
&lt;p>This makes scaling out to additional clusters or deployment environments seamless.&lt;/p>
&lt;/blockquote>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Multi-environment Management (Prod/Non-Prod)&lt;/strong>: By defining separate paths for different environments (like &lt;code>prod&lt;/code>, &lt;code>non-prod-staging&lt;/code>, &lt;code>non-prod-sandbox&lt;/code>), &lt;code>ApplicationSet&lt;/code>s can manage deployments across multiple environments efficiently, creating distinct sets of applications for each environment.&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="example-of-environments-envs-structure">Example of Environments (&lt;code>envs&lt;/code>) Structure&lt;/h3>
&lt;p>The &lt;code>envs&lt;/code> directory structure plays a crucial role in how &lt;code>ApplicationSet&lt;/code>s manage deployments:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">envs/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── non-prod-sandbox/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── appset_config-a.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── appset_config-b.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── kustomization.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── non-prod-staging/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── appset_config-c.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">│ ├── kustomization.yml
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">├── prod/
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── appset_config-d.json
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> ├── kustomization.yml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="qa">Q&amp;amp;A&lt;/h2>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Q&lt;/strong>: How did you overcome the difference between the GitLab repositories heirarcy and the &lt;code>gitops-deployments&lt;/code> repo heirarcy?&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>A&lt;/strong>: we implemented in the CI, a logic that checks if the repository is in the “root” / group level, and then adds to its path in &lt;code>gitops-deployments&lt;/code>, the &lt;code>orphans/&lt;/code> directory, so it will hit the right path in the gitops repo.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;em>Snippet from our Gitlab CI&amp;rsquo;s &lt;code>before_script&lt;/code> logic:&lt;/em>&lt;/strong>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="o">[[&lt;/span> &lt;span class="nv">$CI_PROJECT_PATH&lt;/span> &lt;span class="o">=&lt;/span>~ ^&lt;span class="o">[&lt;/span>^/&lt;span class="o">]&lt;/span>+/&lt;span class="o">[&lt;/span>^/&lt;span class="o">]&lt;/span>+$ &lt;span class="o">]]&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="k">then&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">FULL_PROJECT_PATH&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$CI_PROJECT_NAMESPACE&lt;/span>&lt;span class="s2">/orphans/&lt;/span>&lt;span class="nv">$CI_PROJECT_NAME&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">else&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nv">FULL_PROJECT_PATH&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$CI_PROJECT_PATH&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">fi&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;hr>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Q&lt;/strong>: What are the &lt;code>appset_config*.json&lt;/code> files?&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>A&lt;/strong>: The &lt;code>appset_config*.json&lt;/code> files provide additional parameters for the &lt;code>ApplicationSet&lt;/code>; that way we can combine both the ones we get from the &lt;code>git&lt;/code> generator and the ones we define in the JSON file.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Example &lt;code>appset_config.json&lt;/code> file&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;em>taken from &lt;code>deployments/sunflower/datamine2/datamine-amoeba-appprd/envs/prod&lt;/code>, from the &lt;code>gitops-deployments&lt;/code> repo&lt;/em>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;em>Of course, you can structure your &lt;code>ApplicationSet&lt;/code> and your JSON file in any way that suits your organization&amp;rsquo;s needs.&lt;/em>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;env&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;prod&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;cluster&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;dc1-november&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;address&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;https://10.1.1.1:6443&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;dc&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;dc1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;hr>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Q&lt;/strong>: How do we integrate Helm in our deployment approach?&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>A&lt;/strong>: Our deployment approach integrates Helm, allowing us to manage Helm-based and native Kubernetes deployments seamlessly. Key integration points include:&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Enabling Helm in Kustomize:&lt;/strong> We modify the &lt;code>argocd-cm&lt;/code> ConfigMap to include the &lt;code>--enable-helm&lt;/code> flag in the Kustomize build command.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Example Kustomization Config:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kustomize.config.k8s.io/v1beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Kustomization&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">helmCharts&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">devlake&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">repo&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">https://apache.github.io/incubator-devlake-helm-chart&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">releaseName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">devlake&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">devlake&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">1.0.0&lt;/span>-&lt;span class="l">beta3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">valuesFile&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">values.yml&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;hr>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Q&lt;/strong>: How do we integrate Helm in our deployment approach?&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>A&lt;/strong>: Helm deployments work in a similar way to normal applications, where the entrypoint is the environment’s &lt;code>kustomization.yml&lt;/code> file. This file should include a &lt;code>helmCharts&lt;/code> section. Key integration points include:&lt;/p>
&lt;blockquote>
&lt;p>This enables flexibility by allowing Helm-based deployments to be patched and to create native K8s resources along the Helm releases.&lt;/p>
&lt;/blockquote>
&lt;ul>
&lt;li>
&lt;p>&lt;strong>Enabling Helm in Kustomize:&lt;/strong> We modify the &lt;code>argocd-cm&lt;/code> ConfigMap to include the &lt;code>--enable-helm&lt;/code> flag in the Kustomize build command.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Example Kustomization Config:&lt;/strong>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">apiVersion&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">kustomize.config.k8s.io/v1beta1&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">kind&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">Kustomization&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w">&lt;/span>&lt;span class="nt">helmCharts&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">name&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">devlake&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">repo&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">https://apache.github.io/incubator-devlake-helm-chart&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">releaseName&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">devlake&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">namespace&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">devlake&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">version&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="m">1.0.0&lt;/span>-&lt;span class="l">beta3&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">valuesFile&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">values.yml&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item></channel></rss>