GitOps interview questions
GitOps interview questions from fresher to senior — core principles, Argo CD and Flux, environment promotion and repo structure, and advanced multi-cluster and progressive delivery, tagged by experience level.
Fresher 0–1y · Junior 1–3y · Mid 3–6y · Senior 6+y — every answer is tagged so you can prep for your level.
What is GitOps?Fresher
An operating model where Git is the single source of truth for declarative infrastructure and apps, and an in-cluster agent continuously reconciles the live state to match the repo — so deploys are Git commits and the cluster is auditable.
What are the core GitOps principles?Fresher
Declarative desired state, versioned and immutable in Git, pulled automatically by an agent, and continuously reconciled. Together they make deploys reviewable, auditable, and self-healing.
Pull-based vs push-based deployment?Junior
Push means CI runs kubectl/helm against the cluster with credentials it holds. Pull (GitOps) means an in-cluster controller watches Git and applies changes itself, so cluster credentials never leave the cluster and drift is auto-corrected.
Push couples CI to every cluster and scatters kubeconfig credentials into pipelines; a leaked CI token becomes cluster access. Pull keeps credentials inside each cluster and turns deployment into a Git change the controller applies — more secure and auditable at scale.
What is the reconciliation loop?Junior
The controller continuously compares desired state (Git) to observed state (cluster) and converges them. It is level-based, not event-based, so it self-heals: a manually deleted resource is recreated on the next sync.
Level-based means it acts on the current gap, not on a stream of events, so a missed event never leaves you inconsistent — the next reconcile still converges. That is why a hand-deleted Deployment simply comes back.
What is drift and how does GitOps handle it?Mid
Drift is any live change that diverges from Git. GitOps detects it every sync and either flags it or reverts it (self-heal), making Git the enforced source of truth rather than a hopeful record.
argocd app diff web # live vs desired (Git) argocd app get web # Sync + Health status
What is an Argo CD Application?Mid
A CRD that pairs a source (repo path or Helm chart at a revision) with a destination (cluster/namespace) and a sync policy. Argo renders the manifests and reconciles them, reporting Sync and Health status.
kind: Application
spec:
source:
repoURL: https://github.com/org/config
path: apps/web/overlays/prod
targetRevision: main
destination:
namespace: web
syncPolicy:
automated: { prune: true, selfHeal: true }Sync status vs health status in Argo?Mid
Sync status says whether the live objects match Git (Synced / OutOfSync); health status says whether they are actually working (Healthy / Progressing / Degraded). You can be Synced but Degraded — the right YAML deployed, but the app is crashing.
What is the app-of-apps pattern and ApplicationSets?Mid
App-of-apps is a root Application that deploys child Applications, bootstrapping a whole cluster from one entry point. ApplicationSets generate Applications from a generator (list, Git directories, clusters), scaling GitOps across many apps/clusters.
App-of-apps bootstraps a cluster from a single root you point Argo at. ApplicationSets go further — a generator templates one Application per item (per Git folder, per registered cluster), so onboarding an app or cluster is adding an entry, not hand-writing YAML.
How do sync waves and hooks work?Mid
Annotations order resources into waves (e.g. CRDs and namespaces before workloads) and run PreSync/PostSync hook jobs (migrations, smoke tests). They give ordering and lifecycle control within a single sync.
metadata:
annotations:
argocd.argoproj.io/sync-wave: "-1" # CRDs/namespaces first
argocd.argoproj.io/hook: PreSync # e.g. a DB migration jobHow does Flux structure the same job?Mid
Flux is a set of controllers: a GitRepository/OCIRepository source plus Kustomization or HelmRelease objects that reconcile paths/charts, with dependsOn ordering and image-automation controllers to bump tags via commits.
kind: GitRepository
spec: { url: https://github.com/org/config, ref: { branch: main } }
---
kind: Kustomization
spec:
path: ./apps/web
prune: true
sourceRef: { kind: GitRepository, name: config }Argo CD vs Flux — how do you choose?Senior
Argo CD ships a rich UI and app-centric model (Applications, projects, SSO) that teams like for visibility; Flux is lean, CRD/GitOps-toolkit native, and composes well with Kustomize/Helm controllers. Both are CNCF-graduated — pick on UI needs, multi-tenancy model, and team preference.
How do you promote across environments in GitOps?Mid
Model each environment as a path/overlay or branch; promotion is a commit/PR that updates the target environment’s desired revision or image tag. Keep it a reviewed Git change, not an imperative action.
# bump the tag in the prod overlay, then commit cd overlays/prod && kustomize edit set image app=app:v2 git commit -am "promote app v2 to prod"
How do you manage secrets in GitOps?Mid
Never commit plaintext. Use Sealed Secrets (encrypted in Git, decrypted in-cluster), SOPS-encrypted manifests, or the External Secrets Operator pulling from Vault/cloud managers — so Git holds references or ciphertext only.
The rule is simple: Git never holds a readable secret. Sealed Secrets and SOPS put ciphertext in Git that only the cluster can decrypt; the External Secrets Operator keeps just a reference in Git and pulls the real value from Vault/SSM at runtime.
kubeseal < secret.yaml > sealed-secret.yaml # encrypted git add sealed-secret.yaml # safe to commit
Mono-repo vs repo-per-environment?Senior
One repo with per-env overlays is simpler and keeps shared bases DRY; separate repos give stronger access boundaries and independent history. Many teams use a config repo separate from app code, with environment overlays inside it.
The bigger split is app code vs config: keep manifests in a dedicated config repo so a deploy is a config commit, not an app commit, and so cluster credentials never touch app repos. Within it, per-env overlays (dev/stg/prod) share a common base.
How does image automation fit GitOps?Senior
An image updater (Argo Image Updater, Flux image-automation) watches the registry and writes the new tag/digest back to Git, so a build promotion becomes a commit the reconciler then applies — keeping Git the source of truth.
kind: ImagePolicy
spec:
imageRepositoryRef: { name: app }
policy: { semver: { range: ">=1.0.0" } }
# controller commits the new tag back to GitHow do you do progressive delivery with GitOps?Senior
Layer Argo Rollouts or Flagger on top: they drive canary/blue-green by analyzing metrics (Prometheus) and automatically promote or roll back, while GitOps still owns the desired state. GitOps deploys; the rollout controller manages the shift.
GitOps gets the new version into the cluster; the rollout controller (Argo Rollouts / Flagger) then shifts traffic in steps, runs metric analysis at each step, and promotes or rolls back automatically — so a bad version never fully rolls out.
How do you run GitOps across many clusters?Senior
A management cluster with ApplicationSet cluster generators (or Flux per cluster) fans the same config out, using per-cluster values/overlays and cluster labels — with RBAC and tenancy so teams only reconcile their own scope.
kind: ApplicationSet
spec:
generators:
- clusters: {} # every registered cluster
template:
spec:
destination: { name: '{{name}}', namespace: web }What is your disaster-recovery story with GitOps?Senior
Because desired state lives in Git, you rebuild a cluster by pointing a fresh GitOps controller at the repo and letting it reconcile. You still must restore stateful data (PV backups/Velero) and any bootstrap secrets separately.
Recreating workloads is easy — install the controller, point it at the config repo, let it reconcile. The parts Git does not hold are what you must plan for: persistent volume data (Velero/snapshots) and the bootstrap secret that lets the controller decrypt everything else.
A sync is stuck OutOfSync — how do you debug it?Mid
Read the status: get the app for conditions and the failing resource, diff to see what will not converge, and check for a failing hook, an immutable-field change, or a missing CRD. Then re-sync (with prune/replace if needed).
argocd app get web argocd app diff web argocd app sync web --prune
Someone changed the cluster by hand — what happens and how do you prevent it?Mid
With self-heal on, the next reconcile reverts it; without it, Argo shows OutOfSync. Prevent recurring drift with tight RBAC and admission policy so humans cannot mutate GitOps-managed namespaces directly.
argocd app set web --self-heal --auto-prune # plus RBAC so only the agent can write to that namespace