ArgoCD — GitOps Continuous Delivery

Overview

LuckyPlans uses ArgoCD for pull-based GitOps continuous delivery. ArgoCD watches the Git repository for changes to Helm values files and automatically synchronizes deployments to the target Kubernetes clusters.

GitOps Flow

Developer pushes code to main


CI workflow (lint, test, build)


Docker Build & Push (ghcr.io/takeshi-su57/<service>:sha-<hash>)


Update Tags workflow commits new image tags to values files [skip ci]


ArgoCD detects change in Git → auto-syncs


Post-sync hook runs smoke tests (health, web, GraphQL)

Architecture

Components

ComponentLocationPurpose
ArgoCD Helm valuesinfrastructure/argocd/values-base.yaml, values-prod.yamlArgoCD server configuration
Application manifestinfrastructure/argocd/apps/luckyplans-prod.yamlArgoCD Application resource for prod
Install scriptinfrastructure/scripts/install-argocd.shOne-time ArgoCD installation on prod cluster
Smoke test hookinfrastructure/helm/luckyplans/templates/smoke-test-job.yamlPost-sync verification
Tag update workflow.github/workflows/update-tags.ymlCI commits image tags to values files

Environment Strategy

ArgoCD is used only for prod. Local development uses direct Helm (pnpm deploy:local).

EnvironmentCD MethodImage UpdateApproval
LocalDirect HelmManual (k3d import)None
ProdArgoCD (auto-sync)CI updates valuesAutomatic

Installation

Prerequisites

  • k3d cluster running with Traefik ingress
  • Helm 3.x installed
  • kubectl configured for the target cluster
  • GitHub personal access token (PAT) with repo read access
  • CD push token (required with branch protection): Fine-grained PAT with Contents: read+write scope stored as the CD_PUSH_TOKEN repository secret

Install ArgoCD

./infrastructure/scripts/install-argocd.sh --github-token ghp_xxx

The script:

  1. Adds the ArgoCD Helm repo
  2. Installs ArgoCD into the argocd namespace with base + prod values
  3. Waits for ArgoCD server, repo server, and application controller to be ready
  4. Prints the initial admin password
  5. Applies the Traefik HTTPS redirect middleware for the ArgoCD UI
  6. Applies the luckyplans-prod Application manifest
  7. Prints the ArgoCD UI access URL

Accessing ArgoCD UI

URL: https://luckyplans.xyz/argocd 

Initial login:

  • Username: admin
  • Password: retrieve with:
    kubectl -n argocd get secret argocd-initial-admin-secret \
      -o jsonpath='{.data.password}' | base64 -d

Operations

Check Sync Status

argocd app get luckyplans-prod --server <argocd-url> --grpc-web

Rollback

Option 1: Git revert (recommended)

git log --oneline -5
git revert <commit-sha>
git push origin main

Option 2: ArgoCD UI rollback (temporary — auto-sync overrides immediately)

  1. Open the Application in ArgoCD UI
  2. Click History and Rollback
  3. Select a previous revision → Rollback

Smoke Tests

Smoke tests run automatically as ArgoCD post-sync hooks. They verify:

  1. API Gateway health (/health returns {"status":"ok"})
  2. Web frontend (HTTP 200 on /)
  3. GraphQL endpoint ({ health } query returns expected response)
kubectl -n luckyplans logs job/smoke-test

Secret Management

Secrets (JWT_SECRET, DB_PASSWORD) are not stored in Git. They use Helm’s lookup function to preserve existing values from the cluster across ArgoCD syncs.

First-time setup:

kubectl -n luckyplans create secret generic luckyplans-secrets \
  --from-literal=JWT_SECRET="$(openssl rand -base64 48)" \
  --from-literal=DB_PASSWORD="your-db-password"

Troubleshooting

Application stuck in “Progressing”

kubectl -n luckyplans get pods
kubectl -n luckyplans describe pod <pod-name>

Application shows “OutOfSync” after sync

Handled by ignoreDifferences + RespectIgnoreDifferences=true in the Application manifests — tells ArgoCD to skip diffing the Secret resource since Helm’s lookup function renders a different value each time in the repo server.

CI tag update commit conflicts

The update-tags workflow uses a concurrency group to prevent races. If a conflict occurs, re-run the workflow manually.

update-tags workflow fails to push to main

Create a fine-grained PAT with Contents: read+write scope and store it as the CD_PUSH_TOKEN repository secret.