Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

GitOps with ArgoCD: Declarative Kubernetes Deployments

By Kokil Thapa | Last reviewed: August 2026

Managing Kubernetes manifests manually or through imperative CI scripts creates drift between your repository and actual cluster state. GitOps with ArgoCD: Declarative Kubernetes Deployments solves this by making Git the single source of truth and having a controller continuously reconcile the live environment against it. This approach eliminates configuration drift and provides an auditable history of every infrastructure change.

For developers accustomed to traditional deployment methods, shifting to a pull-based model requires understanding new primitives. If you are exploring modern backend architectures or moving beyond standard Laravel development workflows, adopting GitOps provides the operational maturity needed for scalable systems. The following sections break down the architecture, installation, and operational patterns required to run ArgoCD in production.

How does GitOps with ArgoCD differ from traditional CI/CD?

Traditional CI/CD pipelines typically use a push-based model where the CI server authenticates directly to the Kubernetes API and applies changes after a successful build. This grants the CI system broad write permissions to your cluster and makes the pipeline execution log the only record of what was deployed. If someone manually edits a resource via kubectl, the cluster diverges from Git silently until the next pipeline run overwrites it.

GitOps with ArgoCD inverts this flow using a pull-based architecture. A controller running inside the cluster polls the Git repository (or receives webhooks) and compares the desired state in Git against the live state in Kubernetes. When a difference is detected, the controller applies the necessary changes to reconcile the two states. The CI system only pushes artifacts to a registry and updates manifest versions in Git; it never touches the cluster API directly.

Traditional Push ModelCI ServerK8s ClusterDirect Apply⚠️ Manual kubectl causes silent drift⚠️ CI credentials have cluster admin accessGitOps Pull Model (ArgoCD)Git RepoArgoCD ControllerK8s ClusterPoll / WebhookReconcile✅ Drift auto-detected and corrected✅ Cluster credentials stay internal
Push-based CI/CD grants external access and allows drift, while GitOps with ArgoCD keeps credentials internal and continuously reconciles state.

This distinction matters operationally. With GitOps, the cluster becomes self-healing at the configuration level. Unauthorized manual changes are either reverted automatically or flagged as out-of-sync, depending on your policy. The security boundary also improves because no external system needs long-lived cluster credentials; only the in-cluster controller has write access.

How do you install and configure ArgoCD on Kubernetes?

ArgoCD v2.13+ (stable as of 2026) installs cleanly via Helm or plain manifests. For production environments, I recommend the Helm chart because it simplifies upgrades and configuration management. The following steps assume a Kubernetes 1.29+ cluster with kubectl configured.

Create the namespace and install via Helm

<!-- Add the ArgoCD Helm repository -->
helm repo add argo https://argoproj.github.io/argo-helm
helm repo update

<!-- Create dedicated namespace -->
kubectl create namespace argocd

<!-- Install ArgoCD with production-safe defaults -->
helm install argocd argo/argo-cd \
  --namespace argocd \
  --set server.extraArgs[0]=--insecure \
  --set configs.params."server\.disable\.auth"=false \
  --version 7.7.x \
  --wait

The --insecure flag on the server component assumes you will terminate TLS at an ingress controller (Nginx, Traefik, or cloud load balancer) rather than within the ArgoCD pod itself. This is the standard pattern when running behind a reverse proxy with certificates managed externally via cert-manager or cloud provider integration.

Retrieve initial admin credentials

<!-- Get the auto-generated admin password -->
kubectl -n argocd get secret argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 -d

Log in to the UI at your configured domain or port-forward locally with kubectl port-forward svc/argocd-server -n argocd 8080:443. Change the default password immediately. For team environments, configure SSO (OIDC/LDAP) early rather than sharing the admin account. ArgoCD supports Dex integration out of the box for identity federation.

Register your Git repository

You can register repositories via the UI, CLI, or declaratively via an Application manifest. Declarative registration is preferred for GitOps consistency:

apiVersion: v1
kind: Secret
metadata:
  name: app-repo
  namespace: argocd
  labels:
    argocd.argoproj.io/secret-type: repository
stringData:
  url: https://github.com/your-org/k8s-manifests.git
  type: git
  # For private repos, use SSH key or token
  # sshPrivateKey: |
  #   -----BEGIN OPENSSH PRIVATE KEY-----
  #   ...

Store this secret in your bootstrap repository or manage it via External Secrets Operator if you want to avoid committing credentials. The repository registration tells ArgoCD where to find your desired state definitions.

What is the correct Application manifest structure for declarative sync?

The Application CRD is the core primitive in GitOps with ArgoCD. It defines what to sync, from where, and to which destination cluster/namespace. Getting this manifest right prevents most operational headaches.

Source (Git)repoURLtargetRevisionpath / chartvaluesFiles / paramsApplication CRDspec.sourcespec.destinationspec.syncPolicyspec.projectstatus.health / syncDestination (K8s)server / namenamespaceLive Resources
ArgoCD Application manifest maps Git source fields through the CRD specification to the target Kubernetes destination.
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: legal-tech-portal
  namespace: argocd
spec:
  project: default
  
  source:
    repoURL: https://github.com/your-org/k8s-manifests.git
    targetRevision: HEAD
    path: apps/legal-portal/prod
    
  destination:
    server: https://kubernetes.default.svc
    namespace: legal-tech-prod
    
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
      - PrunePropagationPolicy=foreground
    retry:
      limit: 5
      backoff:
        duration: 5s
        factor: 2
        maxDuration: 3m

Key fields deserve explanation:

  • automated.prune: Removes resources from the cluster that no longer exist in Git. Without this, deleted manifests leave orphaned objects behind indefinitely.
  • automated.selfHeal: Reverts manual changes made directly to the cluster. Disable this during active debugging sessions, but enable it for production stability.
  • syncOptions.CreateNamespace: Auto-creates the target namespace if missing. Convenient but consider managing namespaces explicitly via manifests for better auditability.
  • retry.backoff: Prevents hammering the API server during transient failures. Exponential backoff handles network blips gracefully.

Commit this manifest to your GitOps repository (not the application repo). ArgoCD watches its own namespace for Application CRDs, so pushing this file triggers automatic registration and sync.

How do you handle secrets and multi-environment configurations safely?

Storing plaintext secrets in Git defeats the purpose of version control. In practice, I use one of three patterns depending on client infrastructure maturity and compliance requirements.

ApproachBest ForComplexityTrade-offs
Sealed SecretsSmall teams, pure GitOpsLowEncrypted blobs in Git; rotation requires re-sealing
External Secrets OperatorAWS/GCP/Azure native shopsMediumPulls from cloud secret managers at runtime; adds operator dependency
SOPS + Age/GPGMulti-cloud, offline-capableMediumDecrypts in-cluster; key management overhead
Vault Agent InjectorEnterprise, dynamic secretsHighFull Vault operational burden; powerful but complex

For most Nepal-based clients and mid-sized projects, External Secrets Operator with AWS Secrets Manager or GCP Secret Manager strikes the right balance. You store a reference in Git, not the secret itself:

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-credentials
  namespace: legal-tech-prod
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: aws-secrets-manager
    kind: ClusterSecretStore
  target:
    name: db-credentials
    creationPolicy: Owner
  data:
    - secretKey: DB_PASSWORD
      remoteRef:
        key: prod/legal-portal/db-password
    - secretKey: DB_USERNAME
      remoteRef:
        key: prod/legal-portal/db-username

For multi-environment setups (dev/staging/prod), use Kustomize overlays or Helm value files per environment. Keep the base manifests identical and override only what differs. This prevents copy-paste drift between environments — a common failure mode I've seen repeatedly on client projects where staging and production gradually diverge until deployments break unexpectedly.

What monitoring and troubleshooting patterns work in production?

ArgoCD exposes Prometheus metrics at /metrics on the server and application controller pods. Alert on these signals before users notice problems:

  • argocd_app_sync_total{phase="Failed"}: Sync failures indicate broken manifests, failed hooks, or resource quota exhaustion.
  • argocd_app_health_status{health_status="Degraded"}: Pods crashing, readiness probes failing, or insufficient resources.
  • argocd_app_reconcile_duration_seconds: Spikes suggest large diffs, slow API server responses, or webhook processing bottlenecks.
Sync Failed / DegradedCheck Application Events & ConditionsManifest Validation ErrorResource Quota / RBAC DenyHealth Check FailingFix YAML/Helm syntaxValidate locally first:helm template / kustomize buildCheck ResourceQuota, LimitRangeVerify ServiceAccount permissionskubectl auth can-i --listInspect pod logs & eventsCheck liveness/readiness probesVerify image pull & configmapsAfter fix: commit to Git → auto-sync resolves issue
Troubleshooting decision tree for ArgoCD sync failures: validate manifests, check quotas/RBAC, then inspect pod health before committing fixes.

A common gotcha: ArgoCD caches Git state aggressively. If you force-push or rewrite history (don't do this on deployment branches), the controller may serve stale manifests. Use immutable tags or commit SHAs for targetRevision in production applications. Branch names like main are fine for development but introduce race conditions under high-frequency commits.

When debugging sync loops, check the Application controller logs first:

kubectl logs -n argocd deploy/argocd-application-controller \
  --tail=200 | grep "legal-tech-portal"

Most issues trace back to three root causes: invalid YAML/Helm output, insufficient RBAC for the service account ArgoCD uses, or resource quota exhaustion in the target namespace. Validate manifests locally with helm template or kustomize build before pushing to catch syntax errors without triggering a sync cycle.

Implementing GitOps with ArgoCD for Production Reliability

Adopting GitOps with ArgoCD transforms Kubernetes operations from fragile imperative scripts into a deterministic, auditable system. Start with a single non-production application to build muscle memory around the reconciliation loop, sync policies, and secret management patterns before rolling out to critical workloads. Measure success by reduced deployment failures and faster incident recovery, not by tool adoption alone.

If your team needs guidance implementing declarative deployments or integrating ArgoCD with existing Laravel or PHP-based microservices on Kubernetes, reach out to discuss your infrastructure requirements. For teams evaluating whether Kubernetes is appropriate versus simpler deployment targets, review cloud hosting options in Nepal to match infrastructure complexity to actual business needs. Teams managing multiple services should also explore CI/CD pipeline setup strategies that complement GitOps workflows effectively.

Frequently Asked Questions

ArgoCD is a declarative, continuous delivery tool for Kubernetes that uses Git as the single source of truth. It automatically synchronizes cluster state with repository definitions, ensuring infrastructure matches code without manual kubectl commands or imperative scripts.

Jenkins and GitLab CI are push-based systems that execute deployment scripts externally. ArgoCD runs inside the cluster and continuously pulls desired state from Git, automatically correcting drift. This pull model provides superior security, auditability, and self-healing capabilities compared to traditional push pipelines.

Yes, ArgoCD is 100% open-source under Apache 2.0 license. Production costs involve only underlying compute resources, typically requiring 500MB RAM and 0.5 CPU cores minimum. For Nepal teams, this eliminates licensing fees unlike enterprise alternatives costing thousands of USD annually.

Separate application manifests from ArgoCD configuration using an apps/ folder for Application CRDs and a services/ folder for Helm charts or Kustomize overlays. In my experience managing multi-environment deployments, this separation prevents circular dependencies and simplifies RBAC policies when scaling beyond three microservices across staging and production clusters.

Never commit plaintext secrets to Git. Use Sealed Secrets, External Secrets Operator, or Vault integration to inject sensitive data at sync time. On legal-tech portals handling client documents, I implement External Secrets Operator fetching from AWS Secrets Manager, keeping encryption keys outside Git while maintaining full declarative reproducibility and audit trails.

Yes, ArgoCD supports multi-cluster management through ApplicationSets and external cluster registration. You define cluster credentials once via CLI or UI, then reference them in Application manifests. For projects spanning development, staging, and production clusters, this eliminates duplicate configurations and enables consistent policy enforcement across all environments from a single control plane.

ArgoCD detects drift within three minutes by default and marks applications OutOfSync. With auto-sync enabled, it immediately reconciles differences by applying Git-defined state. Without auto-sync, operators manually trigger syncs after review. In production systems, I enable auto-sync for non-critical configs but require manual approval for database migrations and core service updates.

Define resource health assessments using custom Lua scripts in ConfigMaps and order deployments via sync-wave annotations. Database migrations get wave 0, backend services wave 1, ingress controllers wave 2. On eCommerce platforms, this sequencing prevents frontend exposure before backend readiness, reducing failed deployments during peak traffic periods like Dashain sales events.

Yes, ArgoCD renders Helm, Kustomize, Jsonnet, and plain YAML without external plugins. Specify source type in Application specs or let auto-detection handle it. For complex parameterization, use Helm values files per environment. I prefer Kustomize overlays for environment-specific patches on Laravel applications, avoiding template duplication while maintaining base chart reusability across dev and prod.

Check Application status via argocd app get command or UI dashboard for detailed error messages. Common issues include invalid YAML syntax, missing CRDs, insufficient RBAC permissions, or resource quota exhaustion. Review controller logs with kubectl logs -n argocd deployment/argocd-application-controller. In practice, most sync failures stem from namespace mismatches or unregistered custom resources rather than ArgoCD bugs themselves.

Implement project-scoped RBAC limiting teams to specific namespaces, repositories, and operations. Define AppProjects grouping related applications, then bind OIDC groups or local users to roles like developer (sync-only) or admin (full access). On multi-tenant platforms serving law firms, this isolation prevents accidental cross-project modifications while enabling self-service deployments within bounded contexts.

Upgrade via Helm chart bump or manifest replacement, always backing up etcd and testing in staging first. ArgoCD maintains backward compatibility within major versions. Disable auto-sync during upgrade windows to prevent reconciliation storms. After upgrading, verify controller health and re-enable syncs incrementally. Downtime is rare but plan maintenance windows during low-traffic periods for safety.

Yes, CI systems build container images, update image tags in Git repositories, then ArgoCD detects changes and deploys automatically. This decouples build from deploy, enabling independent scaling and rollback. Configure webhooks for instant detection instead of polling. On grocery delivery platforms, this pattern reduced deployment latency from fifteen minutes to under sixty seconds while preserving Git auditability.

Enable Prometheus metrics endpoint and import official Grafana dashboards tracking sync duration, failure rates, and resource utilization. Configure alerts for consecutive sync failures, high controller memory usage, or certificate expiration. Set up Slack or email notifications via ArgoCD notifications controller. In production, monitor reconciliation lag closely; sustained delays indicate undersized controllers or excessive application count requiring horizontal scaling.

Choose ArgoCD for superior UI visualization, multi-cluster ApplicationSets, and broader community support. Choose Flux for lighter footprint, native Helm controller, and tighter Weave ecosystem integration. Both implement Open GitOps standards. For Nepal agencies managing diverse client stacks, ArgoCD's visual debugging and extensive documentation reduce onboarding friction, though Flux excels in resource-constrained edge deployments.

Share this article

Quick Contact Options
Choose how you want to connect me: