ArgoCD Setup
GitOps deployment with ArgoCD and SOPS
ArgoCD handles GitOps deployments, automatically syncing Kubernetes manifests from Git.
Installation
kubectl create namespace argocd
kubectl apply -k infrastructure/kubernetes/argocdAccess the UI
# Port forward
kubectl port-forward svc/argocd-server -n argocd 8080:443
# Get admin password
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -dVisit https://localhost:8080 with username admin.
After first login, change the admin password and delete the initial secret:
kubectl delete secret argocd-initial-admin-secret -n argocdSOPS Integration
ArgoCD decrypts SOPS-encrypted secrets using an age key during deployment.
Configure the Age Key
Required: The age private key must be created manually as a secret in ArgoCD namespace. This is a one-time setup step.
# Create secret from age key file
kubectl create secret generic sops-age-key \
--namespace argocd \
--from-file=keys.txt=~/.config/sops/age/keys.txt
# The repo-server will automatically restart with KSOPS supportThe ArgoCD repo-server is patched to:
- Install KSOPS plugin (init container)
- Mount the age key at
/sops/age/keys.txt - Set
SOPS_AGE_KEY_FILEenvironment variable - Enable
--enable-alpha-plugins --enable-execfor kustomize
Verify the setup:
# Check if age key is mounted
kubectl -n argocd exec deployment/argocd-repo-server -- ls -la /sops/age/
# Check if KSOPS is available
kubectl -n argocd exec deployment/argocd-repo-server -- which ksopsApplication Configuration
Our application is defined in infrastructure/kubernetes/argocd/applications/lcmd-app-prod.yaml:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: lcmd-app
namespace: argocd
spec:
source:
repoURL: git@github.com:lcmd-epfl/db.git
targetRevision: main
path: infrastructure/kubernetes/app/overlays/prod
destination:
server: https://kubernetes.default.svc
namespace: prod
syncPolicy:
automated:
prune: true # Remove deleted resources
selfHeal: true # Revert manual changesImage Updater
ArgoCD doesn't poll container registries on its own. ArgoCD Image Updater is installed alongside it and handles tag promotion: every 2 minutes it scans ghcr.io for main-* tags newer than the current lcmd-app spec, then rewrites spec.source.kustomize.images in place. ArgoCD's automated sync reconciles.
The full operator runbook — pull-secret rotation, kubeseal steps, CRD config — lives in infrastructure/kubernetes/argocd/image-updater/README.md. See CI/CD for the end-to-end merge-to-prod flow.
Monitoring
# Check sync status
kubectl -n argocd get applications
# View application details
kubectl -n argocd describe application lcmd-app
# Check logs
kubectl -n argocd logs -l app.kubernetes.io/name=argocd-application-controllerTroubleshooting
Secrets not decrypting:
# Check if age key is mounted
kubectl -n argocd exec deployment/argocd-repo-server -- ls /sops/age/
# Check repo-server logs
kubectl -n argocd logs deployment/argocd-repo-serverSync failing:
# Force refresh
kubectl -n argocd patch application lcmd-app --type merge -p '{"metadata":{"annotations":{"argocd.argoproj.io/refresh":"hard"}}}'