ArgoCD / GitOps
This guide covers deploying Astromesh across multiple environments using ArgoCD and GitOps principles. Push configuration changes to Git, and ArgoCD automatically syncs them to your Kubernetes clusters.
What and Why
Section titled “What and Why”GitOps is an operational model where the desired state of your infrastructure is stored in Git. Instead of running helm install or kubectl apply manually, you:
- Commit configuration changes to a Git repository
- ArgoCD detects the change
- ArgoCD syncs the Kubernetes cluster to match the desired state
- Rolling updates happen automatically
This provides:
- Audit trail — every change is a Git commit with author, timestamp, and diff
- Reproducibility — any environment can be recreated from the Git state
- Rollback — revert a Git commit to roll back a deployment
- Multi-environment consistency — dev, staging, and prod all deploy from the same chart with different values
Prerequisites
Section titled “Prerequisites”| Requirement | Version | Check command |
|---|---|---|
| Kubernetes | 1.26+ | kubectl version |
| ArgoCD | 2.8+ | argocd version |
| Helm | 3.12+ | helm version |
| Git repo | accessible from ArgoCD | — |
Verify ArgoCD is installed
Section titled “Verify ArgoCD is installed”kubectl get pods -n argocdExpected output:
NAME READY STATUS RESTARTS AGEargocd-application-controller-0 1/1 Running 0 2dargocd-applicationset-controller-7b74965f7-x2k4m 1/1 Running 0 2dargocd-dex-server-6dcf645b6b-abc12 1/1 Running 0 2dargocd-notifications-controller-5c4d48f9b-def34 1/1 Running 0 2dargocd-redis-6976fc7dfc-ghi56 1/1 Running 0 2dargocd-repo-server-7c4f568f7-jkl78 1/1 Running 0 2dargocd-server-7bc7684f8d-mno90 1/1 Running 0 2dIf ArgoCD is not installed, install it:
kubectl create namespace argocdkubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yamlVerify ArgoCD can access the repository
Section titled “Verify ArgoCD can access the repository”ArgoCD needs read access to your Git repository. For private repos, add credentials:
argocd repo add https://github.com/monaccode/astromesh.git \ --username git \ --password ghp_your_tokenExpected output:
Repository 'https://github.com/monaccode/astromesh.git' addedStep-by-step Setup
Section titled “Step-by-step Setup”1. Review the ApplicationSet
Section titled “1. Review the ApplicationSet”The Astromesh repository includes an ArgoCD ApplicationSet at deploy/gitops/argocd/applicationset.yaml:
apiVersion: argoproj.io/v1alpha1kind: ApplicationSetmetadata: name: astromesh namespace: argocdspec: generators: - list: elements: - env: dev namespace: astromesh-dev valuesFile: values-dev.yaml - env: staging namespace: astromesh-staging valuesFile: values-staging.yaml - env: prod namespace: astromesh-prod valuesFile: values-prod.yaml template: metadata: name: astromesh-{{env}} spec: project: default source: repoURL: https://github.com/monaccode/astromesh.git targetRevision: HEAD path: deploy/helm/astromesh helm: valueFiles: - "{{valuesFile}}" destination: server: https://kubernetes.default.svc namespace: "{{namespace}}" syncPolicy: automated: prune: true selfHeal: true syncOptions: - CreateNamespace=trueThis creates one ArgoCD Application per environment, each deploying the same Helm chart with different values files.
2. Deploy the ApplicationSet
Section titled “2. Deploy the ApplicationSet”kubectl apply -f deploy/gitops/argocd/applicationset.yamlExpected output:
applicationset.argoproj.io/astromesh created3. Verify the Applications
Section titled “3. Verify the Applications”argocd app listExpected output:
NAME CLUSTER NAMESPACE PROJECT STATUS HEALTH SYNCPOLICY CONDITIONSastromesh-dev https://kubernetes.default.svc astromesh-dev default Synced Healthy Auto-Prune <none>astromesh-staging https://kubernetes.default.svc astromesh-staging default Synced Healthy Auto-Prune <none>astromesh-prod https://kubernetes.default.svc astromesh-prod default Synced Healthy Auto-Prune <none>All three environments show Synced and Healthy.
4. Check pods in each namespace
Section titled “4. Check pods in each namespace”kubectl get pods -n astromesh-devExpected output:
NAME READY STATUS RESTARTS AGEastromesh-5d8f9c7b6-x2k4m 1/1 Running 0 2mastromesh-postgresql-0 1/1 Running 0 2mastromesh-redis-master-0 1/1 Running 0 2mkubectl get pods -n astromesh-prodExpected output:
NAME READY STATUS RESTARTS AGEastromesh-5d8f9c7b6-a1b2c 1/1 Running 0 2mastromesh-5d8f9c7b6-d3e4f 1/1 Running 0 2mastromesh-5d8f9c7b6-g5h6i 1/1 Running 0 2mastromesh-vllm-7f8g9h0i-j1k2l 1/1 Running 0 2mastromesh-tei-embeddings-m3n4o-p5q6r 1/1 Running 0 2mastromesh-tei-reranker-s7t8u-v9w0x 1/1 Running 0 2mProduction has 3 Astromesh replicas, vLLM, and two TEI instances as defined in values-prod.yaml.
Configuration
Section titled “Configuration”Environments
Section titled “Environments”The ApplicationSet uses a list generator to create one Application per environment:
| Environment | Namespace | Values File | Auto-sync | Description |
|---|---|---|---|---|
| dev | astromesh-dev | values-dev.yaml | Yes | Development with all subcharts, no GPU limits |
| staging | astromesh-staging | values-staging.yaml | Yes | Pre-production validation |
| prod | astromesh-prod | values-prod.yaml | Yes | Production with external DBs, GPU, TLS |
Sync Policy
Section titled “Sync Policy”syncPolicy: automated: prune: true # Delete resources removed from Git selfHeal: true # Revert manual cluster changes to match Git syncOptions: - CreateNamespace=true # Create namespace if it doesn't existprune: true— if you remove a resource from your Helm chart, ArgoCD deletes it from the clusterselfHeal: true— if someone manually edits a resource in the cluster, ArgoCD reverts it to match Git
Workflow
Section titled “Workflow”The GitOps workflow for making changes:
1. Edit configuration in Git
Section titled “1. Edit configuration in Git”For example, to scale production to 5 replicas, edit deploy/helm/astromesh/values-prod.yaml:
replicaCount: 52. Commit and push
Section titled “2. Commit and push”git add deploy/helm/astromesh/values-prod.yamlgit commit -m "feat: scale production to 5 replicas"git push origin main3. ArgoCD detects the change
Section titled “3. ArgoCD detects the change”ArgoCD polls the repository (default every 3 minutes) or receives a webhook notification. It detects the diff between the desired state (Git) and the live state (cluster).
4. ArgoCD syncs
Section titled “4. ArgoCD syncs”Because automated.selfHeal: true is set, ArgoCD automatically syncs:
argocd app get astromesh-prodExpected output:
Name: astromesh-prodServer: https://kubernetes.default.svcNamespace: astromesh-prodRepo: https://github.com/monaccode/astromesh.gitPath: deploy/helm/astromeshTarget: HEADStatus: SyncedHealth: Progressing5. Rolling update completes
Section titled “5. Rolling update completes”kubectl get pods -n astromesh-prodExpected output:
NAME READY STATUS RESTARTS AGEastromesh-5d8f9c7b6-a1b2c 1/1 Running 0 10mastromesh-5d8f9c7b6-d3e4f 1/1 Running 0 10mastromesh-5d8f9c7b6-g5h6i 1/1 Running 0 10mastromesh-5d8f9c7b6-j7k8l 1/1 Running 0 30sastromesh-5d8f9c7b6-m9n0o 1/1 Running 0 30sFive replicas running.
Customizing the ApplicationSet
Section titled “Customizing the ApplicationSet”Change repository URL
Section titled “Change repository URL”Edit deploy/gitops/argocd/applicationset.yaml:
source: repoURL: https://github.com/your-org/your-repo.gitChange target branch
Section titled “Change target branch”To deploy from a specific branch instead of HEAD:
source: targetRevision: mainOr use a tag:
source: targetRevision: v0.10.0Deploy to a different cluster
Section titled “Deploy to a different cluster”destination: server: https://remote-cluster-api.example.com namespace: "{{namespace}}"Disable auto-sync for production
Section titled “Disable auto-sync for production”For manual approval before production deployments:
generators: - list: elements: - env: dev namespace: astromesh-dev valuesFile: values-dev.yaml - env: staging namespace: astromesh-staging valuesFile: values-staging.yaml - env: prod namespace: astromesh-prod valuesFile: values-prod.yamlThen override sync policy per-environment by creating separate ApplicationSets or using a matrix generator with sync policy conditions. For simpler control, disable auto-sync on prod after creation:
argocd app set astromesh-prod --sync-policy noneAdding New Environments
Section titled “Adding New Environments”To add a new environment (e.g., qa):
1. Create a values file
Section titled “1. Create a values file”cp deploy/helm/astromesh/values-staging.yaml deploy/helm/astromesh/values-qa.yamlEdit values-qa.yaml with QA-specific settings.
2. Add to the ApplicationSet
Section titled “2. Add to the ApplicationSet”Edit deploy/gitops/argocd/applicationset.yaml, add to the elements list:
generators: - list: elements: - env: dev namespace: astromesh-dev valuesFile: values-dev.yaml - env: qa namespace: astromesh-qa valuesFile: values-qa.yaml - env: staging namespace: astromesh-staging valuesFile: values-staging.yaml - env: prod namespace: astromesh-prod valuesFile: values-prod.yaml3. Commit and apply
Section titled “3. Commit and apply”git add deploy/git commit -m "feat: add QA environment"git push origin mainkubectl apply -f deploy/gitops/argocd/applicationset.yamlArgoCD creates the new astromesh-qa Application and syncs it.
Promotion Workflow
Section titled “Promotion Workflow”Promote changes from dev to staging to production:
1. Make changes in dev values
Section titled “1. Make changes in dev values”Edit deploy/helm/astromesh/values-dev.yaml:
config: agents: new-agent.agent.yaml: | apiVersion: astromesh/v1 kind: Agent metadata: name: new-agent spec: identity: display_name: "New Agent" model: primary: provider: ollama model: llama3.1:8b orchestration: pattern: reactCommit, push, and verify in dev.
2. Promote to staging
Section titled “2. Promote to staging”Copy the agent definition to values-staging.yaml:
# Copy the new agent config sectiongit diff values-dev.yaml # Review what was added# Apply the same change to values-staging.yamlCommit and push. ArgoCD syncs staging.
3. Promote to production
Section titled “3. Promote to production”After validating in staging, apply the same change to values-prod.yaml. Commit and push.
Each promotion is a Git commit, providing a clear audit trail of what changed and when.
Rollback
Section titled “Rollback”Using ArgoCD
Section titled “Using ArgoCD”Roll back to a previous sync:
argocd app history astromesh-prodExpected output:
ID DATE REVISION2 2026-03-09 11:30:00 +0000 UTC abc12341 2026-03-09 10:00:00 +0000 UTC def5678argocd app rollback astromesh-prod 1Expected output:
TIMESTAMP GROUP/KIND NAMESPACE NAME STATUS HEALTH2026-03-09T10:00:00+00:00 apps/Deployment astromesh-prod astromesh Synced HealthyUsing Git
Section titled “Using Git”Revert the commit that introduced the problem:
git revert abc1234git push origin mainArgoCD detects the revert and syncs the cluster back to the previous state.
Common Operations
Section titled “Common Operations”View sync status
Section titled “View sync status”# All environmentsargocd app list
# Specific environmentargocd app get astromesh-prodManual sync
Section titled “Manual sync”If auto-sync is disabled or you want to trigger immediately:
argocd app sync astromesh-prodExpected output:
TIMESTAMP GROUP/KIND NAMESPACE NAME STATUS HEALTH2026-03-09T11:00:00+00:00 /Service astromesh-prod astromesh Synced Healthy2026-03-09T11:00:00+00:00 apps/Deployment astromesh-prod astromesh Synced Healthy
Message: successfully synced (all tasks run)View diff before sync
Section titled “View diff before sync”argocd app diff astromesh-prodAccess ArgoCD UI
Section titled “Access ArgoCD UI”kubectl port-forward svc/argocd-server 8080:443 -n argocdOpen https://localhost:8080. Get the initial admin password:
argocd admin initial-password -n argocdTroubleshooting
Section titled “Troubleshooting”Sync failed
Section titled “Sync failed”argocd app get astromesh-prodIf status shows OutOfSync or SyncFailed:
argocd app sync astromesh-prod --retry-limit 3Check the sync details:
argocd app get astromesh-prod --show-operationCommon causes:
- Helm template error: invalid YAML in values file. Test locally:
helm template astromesh ./deploy/helm/astromesh -f deploy/helm/astromesh/values-prod.yaml-
Resource conflict: another controller manages the same resource. Check annotations.
-
Dependency not downloaded: Helm chart dependencies need to be in the
charts/directory or resolvable by ArgoCD.
Secret issues
Section titled “Secret issues”ArgoCD stores manifests in Git, which means secrets should not be committed in plain text. Use one of these approaches:
- External Secrets Operator — secrets synced from AWS/GCP/Vault (see Helm guide)
- Sealed Secrets — encrypted in Git, decrypted in cluster
- existingSecret — create secrets out-of-band, reference by name in values
Do not put API keys or passwords in values files that are committed to Git.
Configuration drift
Section titled “Configuration drift”If someone manually changes a resource in the cluster, ArgoCD detects drift and shows OutOfSync. With selfHeal: true, it automatically reverts the change.
To check for drift:
argocd app diff astromesh-prodArgoCD cannot reach the repository
Section titled “ArgoCD cannot reach the repository”rpc error: code = Unknown desc = authentication requiredAdd or update repository credentials:
argocd repo add https://github.com/monaccode/astromesh.git \ --username git \ --password ghp_new_tokenApplication stuck in “Progressing”
Section titled “Application stuck in “Progressing””Check pod status:
kubectl get pods -n astromesh-prodkubectl describe pod <pod-name> -n astromesh-prodCommon causes:
- Image pull errors (wrong tag or registry auth)
- Insufficient resources (CPU/memory limits too low)
- Failed health checks (readiness probe failing)
Webhook setup (faster sync)
Section titled “Webhook setup (faster sync)”By default, ArgoCD polls every 3 minutes. For faster sync, configure a GitHub webhook:
- In the ArgoCD UI, go to Settings > Repositories
- Note the webhook URL:
https://argocd.example.com/api/webhook - In GitHub, go to your repo Settings > Webhooks > Add webhook
- Set the Payload URL to the ArgoCD webhook endpoint
- Set Content type to
application/json - Select “Just the push event”
Now ArgoCD syncs within seconds of a push.