Everything for Harness in one place — pick a section below. 15 reviewed items across 4 content types.
Quick Answer
Harness Delegate is a lightweight worker process you install inside your VPC or cluster that polls the Harness Manager (the SaaS control plane) for tasks over outbound HTTPS, so no inbound firewall rule into your network is ever needed. It executes deployment tasks (kubectl apply, Helm installs, cloud API calls) locally using credentials that never leave your network. If the Delegate can't reach the Manager, running pipelines stall in a "Waiting" state; if it can't reach the target cluster, the specific task fails fast with a connectivity error while the pipeline itself keeps running.
Detailed Answer
Think of a Harness Delegate like a hotel concierge who works inside the building instead of a remote call-center agent trying to unlock your hotel room door from outside. The concierge (Delegate) sits inside your network, walks over to reception (your Kubernetes cluster, cloud account, Vault instance) using the keys you already gave it, and only calls the corporate office (Harness Manager, the SaaS control plane) to ask for its next instruction. Nobody outside the building ever gets a key to your rooms — the concierge always initiates the call outward, never the other way around.
Harness's SaaS control plane orchestrates pipelines (definitions of build and deploy stages) but deliberately never holds direct network access to a customer's infrastructure. This was designed for a real problem: most enterprises will not open inbound ports from a public SaaS vendor into a production VPC or on-prem data center. So Harness inverted the connection model — the Delegate, a process running as a container, pod, or VM inside the customer's network, polls the Manager over outbound HTTPS, picks up queued tasks, executes them locally with locally-scoped credentials such as a kubeconfig, cloud IAM role, or Vault token, and reports results back over that same outbound channel.
When a pipeline stage runs, the Manager doesn't reach into your cluster — it publishes a task, such as "apply this Helm chart to namespace payments-api," onto a queue tied to a Delegate selector (tags like env:prod or region:us-east-1). Any Delegate matching that selector picks up the task on its next poll cycle, executes it using the local kubeconfig or cloud SDK, streams logs back to the Manager in near real time, and acknowledges completion. If multiple Delegates share the same tags, Harness distributes work across whichever is idle, giving basic load distribution without any inbound connection ever being required.
At scale, teams typically run three or more Delegate replicas per cluster for high availability, since a single Delegate is a single point of failure for anything targeting that cluster. What to monitor: Delegate heartbeat and connectivity status in the Harness UI, Delegate pod CPU and memory (large Helm charts or big kubectl diffs can spike memory), and certificate or token expiry for the Delegate's connection to the Manager. A common failure mode is the Delegate running out of disk on its ephemeral volume from accumulated task logs, causing new tasks to fail even though the Delegate still shows "Connected."
The non-obvious gotcha is that a "Connected" Delegate in the UI only proves it can reach the Manager — it says nothing about whether it can reach the deployment target. Engineers get paged for a stuck deployment, check the Delegate page, see green, and waste twenty minutes before realizing the Delegate's outbound route to a newly peered VPC was never added to a security group. Always verify target-side connectivity, such as running kubectl get ns from inside the Delegate pod, separately from Delegate-to-Manager health.
Code Example
# Check the status and connectivity of Harness Delegates in the payments-api cluster namespace kubectl get pods -n harness-delegate-ng -l harness.io/name=payments-api-delegate # Tail delegate logs to see poll cycles and task pickups in real time kubectl logs -n harness-delegate-ng deploy/payments-api-delegate -f --tail=200 # Exec into the delegate pod to verify it can actually reach the target cluster API server kubectl exec -n harness-delegate-ng deploy/payments-api-delegate -- kubectl --kubeconfig=/opt/harness-delegate/config/kubeconfig get ns # Confirm outbound connectivity from the delegate to the Harness SaaS Manager endpoint kubectl exec -n harness-delegate-ng deploy/payments-api-delegate -- curl -sf https://app.harness.io/api/version # Restart the delegate deployment to force a fresh poll registration after a network change kubectl rollout restart deployment/payments-api-delegate -n harness-delegate-ng
Interview Tip
A junior engineer typically answers that the Delegate is "just an agent that runs commands," but for a senior or architect role, the interviewer is actually looking for you to explain the trust and network boundary the Delegate creates: outbound-only polling, no inbound exposure, and credential locality. They also want you to distinguish Delegate-to-Manager connectivity from Delegate-to-target connectivity, since these fail independently and produce very different symptoms — a stalled queue versus a fast task failure. Bonus points for mentioning Delegate selectors and tags for routing tasks to the right environment, running multiple Delegate replicas for high availability, and the fact that Delegate compromise is a serious blast-radius concern because it typically holds broad deployment credentials for an entire cluster or cloud account.
◈ Architecture Diagram
┌─────────┐ outbound poll ┌──────────┐
│ Delegate│────────────────▶│ Manager │
│ (in VPC)│←────────────────│ (SaaS) │
└────┌────┘ task + result └──────────┘
│ kubeconfig / IAM
↓
┌─────────┐
│ Cluster │
└─────────┘💬 Comments
Quick Answer
This mismatch usually means the Delegate lost its connection back to the Harness Manager after starting the task, so the cluster-side action finished but Harness never received the completion signal. Isolate it by checking Delegate connectivity and logs first to rule in or out a lost callback, then verify actual cluster state directly with kubectl or helm rather than trusting what the pipeline UI reports.
Detailed Answer
This is like a courier who delivers a package, but the delivery confirmation text message gets lost because their phone died right after drop-off — the customer, in this case the Harness Manager, has no idea the package, your Kubernetes rollout, actually arrived, so the tracking page just spins forever showing "out for delivery."
Harness pipelines model each stage as a set of tasks it queues for a Delegate, then waits for a completion callback. This asynchronous design lets Harness support long-running deployments, such as Helm installs that take minutes, without holding an open connection the whole time, but it introduces a specific failure class: the Delegate executes the task and the underlying action genuinely finishes, yet if the Delegate process dies, gets OOMKilled, or loses network to the Manager before it reports back, Harness has no way to know the task's final outcome and leaves the stage spinning until an internal task timeout, commonly several hours by default, eventually fails it.
Diagnosing this starts by pulling the specific task ID for the stuck step from the pipeline execution details, then checking whether the Delegate that picked up that task is even still running — a Delegate restart from pod eviction, node drain, or an out-of-memory kill mid-task orphans it. Next, check kubectl rollout status or helm list directly against the target cluster to confirm the actual deployment state independent of what Harness believes. If the cluster shows the rollout complete but Harness shows running, the callback path broke; if the cluster also shows an incomplete or failed rollout, the Delegate is genuinely still working, or truly stuck on something like an image pull.
In production this pattern is the number one cause of "pipeline stuck" tickets in Harness-heavy platforms. Teams should monitor Delegate restart counts, Delegate CPU and memory utilization since undersized Delegates get OOMKilled during large Helm template renders, and set a reasonable step timeout in the pipeline YAML rather than trusting the default multi-hour timeout, so stuck stages fail fast and page someone instead of silently blocking a release train for hours.
The subtle gotcha is that manually aborting a stuck pipeline in the UI does not roll back or undo whatever the Delegate already applied to the cluster — Harness only forgets about the task, it doesn't reach back into Kubernetes to reverse the Helm release. Engineers who abort and re-run without checking cluster state end up applying the same release twice or fighting a partially-applied rollout, so always reconcile actual cluster state before retrying.
Code Example
# Get the execution details and specific task/step IDs for the stuck pipeline run
harness pipeline execution get --pipeline checkout-worker-deploy --execution-id <exec-id>
# Check whether the delegate that owned the task has restarted recently (orphaned task indicator)
kubectl get pod -n harness-delegate-ng -l harness.io/name=checkout-worker-delegate -o jsonpath='{.items[0].status.containerStatuses[0].restartCount}'
# Verify the actual rollout state directly against the cluster, independent of Harness's belief
kubectl rollout status deployment/checkout-worker -n production --timeout=30s
# Cross-check the Helm release revision to see if the install/upgrade truly completed
helm history checkout-worker -n production --max 3
# If cluster state is healthy but Harness is stuck, abort the run so the pipeline doesn't block the queue
harness pipeline execution abort --pipeline checkout-worker-deploy --execution-id <exec-id>Interview Tip
A junior engineer typically says they'd just click abort and retry the pipeline, but for a senior or architect role, the interviewer is actually looking for you to reconcile the control plane's belief, the Harness Manager, against the actual system state, the cluster, before taking any action. The mature answer is: never trust a stuck orchestrator's status as ground truth — verify the target system directly, understand that abort doesn't roll back already-applied changes, and know that Delegate task callbacks are the fragile link in this architecture. Mentioning default task timeouts, Delegate restart correlation, and the risk of double-applying a Helm release during a careless retry signals real production experience with this class of tool.
◈ Architecture Diagram
┌────────┐ queue ┌─────────┐ apply ┌────────┐
│Manager │──────▶│Delegate │──────▶│Cluster │
└────────┘ └────┌────┘ └────────┘
↑ ack (lost) │ restarts
└─────✗───────────┘💬 Comments
Quick Answer
Alert on Delegate heartbeat or connectivity loss, pipeline step duration exceeding a historical baseline, and Continuous Verification risk scores approaching threshold during a canary analysis — because a plain "pipeline failed" alert misses the much more common and dangerous case of a pipeline that's silently stuck or a canary that's degrading but hasn't failed yet. The goal is to catch stalls and slow degradation, not just terminal failures.
Detailed Answer
Imagine an assembly line where the only alarm is a bell that rings when a machine completely breaks down. That misses the much more common problem: a machine that's still running but producing defective parts, or one that's jammed and silently not moving anything down the line at all. A good factory floor has gauges for speed and defect rate, not just a single "broken" light.
Harness pipelines fail in three very different ways that a single "pipeline failed" notification collapses into one: a hard failure, such as a bad manifest or a failed test gate, that Harness correctly reports; a silent stall, such as a Delegate that lost connectivity or a manual approval gate nobody remembered to click, that never triggers "failed" because the pipeline is technically still "running"; and a canary rollout that Continuous Verification, or CV, Harness's automated analysis comparing canary metrics against a baseline, is quietly flagging as risky but that a human hasn't looked at yet. Each of these needs a distinct signal because they have different root causes and different urgency.
Delegate heartbeat is reported to the Manager on every poll cycle; missing several consecutive heartbeats is a leading indicator of an upcoming stall long before any pipeline actually times out. Step duration should be compared against a rolling historical baseline per step, since a deploy step for checkout-worker that usually takes ninety seconds but has been running ten minutes is a stall even though Harness hasn't marked it failed. CV risk score is calculated per verification window during a canary analysis by comparing metrics like error rate and latency between the canary and baseline pods; a rising risk score is the earliest signal of a bad deploy, well before error budgets or user-facing alerts would fire.
In practice, mature Harness setups wire these into three separate alert rules: a Delegate-down alert paging within two to three minutes of a lost heartbeat, a step-duration-anomaly alert comparing against a seven-day rolling baseline per step rather than a fixed timeout since deploy times vary by chart size and image size, and a CV-risk-score alert that pages when the automated rollback threshold is close to being crossed, so a human can intervene before the fully automatic rollback kicks in and potentially masks a real problem worth investigating.
The non-obvious gotcha is that manual approval gates look identical to a stalled Delegate from a "time since last progress" perspective — both show a pipeline sitting idle. Teams that only alert on elapsed time without distinguishing "waiting on Delegate" from "waiting on human approval" end up paging on-call engineers for approvals that were simply waiting for business hours, training people to ignore the alert entirely, which is exactly when a genuine stuck-Delegate incident gets missed.
Code Example
# Query Harness's delegate heartbeat API to check freshness across the fleet
curl -s "https://app.harness.io/gateway/pm/api/delegates/heartbeat?accountId=$HARNESS_ACCOUNT" | jq '.resource[] | {name, lastHeartBeat}'
# Alert rule firing when a delegate misses 3 consecutive heartbeats (roughly 90 seconds)
# harness_delegate_heartbeat_age_seconds > 90
# Alert rule comparing current step duration to a 7-day rolling p95 baseline per step name
# harness_pipeline_step_duration_seconds > (harness_pipeline_step_duration_seconds:p95_7d * 1.5)
# Pull the current Continuous Verification risk score for an in-flight canary analysis
curl -s "https://app.harness.io/gateway/cv/api/verify-step/risk?accountId=$HARNESS_ACCOUNT&executionId=$EXEC_ID" | jq '.riskScore'
# Alert rule paging when the CV risk score approaches the auto-rollback threshold
# harness_cv_risk_score{service="checkout-worker"} > 0.7Interview Tip
A junior engineer typically says "alert when the pipeline fails," but for a senior or SRE role, the interviewer is actually looking for you to separate symptom classes: hard failures, silent stalls, and slow degradation each need a different detection mechanism and a different urgency. Strong answers distinguish leading indicators, such as Delegate heartbeat gaps and a rising CV risk score, from lagging indicators like a pipeline marked failed, and explain why alerting purely on elapsed time conflates "waiting for human approval" with "stuck on a dead Delegate" — a distinction that determines whether the fix is pinging the approver or paging infra on-call. Mentioning per-step historical baselines instead of fixed timeouts, and treating CV risk score as an early-warning metric rather than just a binary rollback trigger, signals real operating experience.
◈ Architecture Diagram
┌────────┐ ┌───────────┐ ┌──────────┐
│Heartbt │ │Step Durtn │ │CV Risk │
│ gap │ │ anomaly │ │ score ↑ │
└───┌────┘ └─────┌─────┘ └────┌─────┘
└─────────────▶ Alert ←───────┘💬 Comments
Quick Answer
Configure a CV verification step in the canary stage that pulls the same metric query, such as error rate or p99 latency, for both the canary and baseline pod groups, scores the statistical deviation between them over a sliding analysis window, and only triggers rollback when the deviation stays above threshold across multiple consecutive windows — a single noisy data point should never trigger rollback on its own. The key design choice is windowed, multi-sample comparison rather than instantaneous point comparison.
Detailed Answer
Think of a canary deployment like a food safety inspector tasting a new recipe, the canary, against the current one, the baseline, side by side, sip by sip, over several courses — not just one bite. If the new recipe tastes slightly off on a single spoonful, a good inspector doesn't send the whole batch back; they keep tasting a few more spoonfuls to see if it's a consistent problem or just one under-salted bite.
Harness CV was designed because naive canary analysis, comparing canary error rate to baseline error rate once at one point in time, produces too many false positives — a canary pod that happens to get one slow database connection, or restarts once during rollout, looks identical to a genuinely broken release if you only look at a single snapshot. So CV instead pulls a metric time series for both canary and baseline over a rolling verification window, commonly five to ten minutes sampled every minute, and scores similarity using statistical comparison rather than a single threshold check.
In practice you configure a Verify step referencing a health source such as Prometheus or Datadog, specify the exact metric query parameterized by pod group label so it can pull canary and baseline series separately, and set the analysis to run continuously during the canary bake time. Each analysis window produces a risk score between zero and one based on how much the canary's metrics deviate from baseline; Harness accumulates these scores across consecutive windows, and only when a rolling number of windows, say three out of five, exceed the configured risk threshold does it trigger the configured on-failure action, typically an automatic rollback via a stage-rollback step.
At scale, the metric query design matters more than the threshold number. Teams commonly get burned by comparing raw counts instead of rates, since a canary with five percent of traffic will always show lower absolute error counts than baseline, which looks better and hides real problems, or by picking a verification window shorter than their p99 latency's natural noise cycle, causing constant false-positive rollbacks. What to monitor: the CV risk score trend over time per service, since a service that's frequently near-threshold even on healthy deploys means the threshold is miscalibrated for that service's normal metric variance, and rollback frequency, since an unusually high automatic-rollback rate is itself an incident worth investigating, often pointing to a monitoring or traffic-split bug rather than actual bad releases.
The non-obvious gotcha is traffic skew during a canary: if your load balancer doesn't evenly distribute traffic by request pattern, for example if all requests from one heavy customer land on the canary group by sticky session, the canary's metrics will look anomalous purely due to traffic composition, not code quality, and CV will roll back a perfectly good release. Senior engineers explicitly verify that the traffic-splitting mechanism randomizes fairly across request types before trusting CV's statistical comparison, and often exclude known-heavy or known-different traffic segments from the canary pool entirely.
Code Example
# Harness pipeline snippet: Continuous Verification step inside a canary deployment stage
- step:
name: Verify Canary Metrics
identifier: verify_canary
type: Verify
spec:
type: Canary # Compare canary pod group against baseline pod group
spec:
sensitivity: MEDIUM # Controls how aggressively deviation triggers risk
duration: 10m # Total verification window across the bake time
deploymentTag: "<+serviceConfig.artifacts.primary.tag>"
healthSources:
- identifier: prometheus_checkout_worker
type: Prometheus
spec:
metricDefinitions:
- metricName: error_rate
query: |
# Rate query scoped per pod group label so canary/baseline compare fairly
sum(rate(http_requests_total{service="checkout-worker",status=~"5..",group="$podGroup"}[1m]))
/
sum(rate(http_requests_total{service="checkout-worker",group="$podGroup"}[1m]))
riskProfile:
category: Errors
metricType: ERROR
failureStrategies:
- onFailure:
errors: [Verification]
action:
type: StageRollback # Automatically roll back the stage on sustained riskInterview Tip
A junior engineer typically describes CV as "Harness compares canary and baseline and rolls back if something looks wrong," but for a senior or architect role, the interviewer is actually looking for you to explain the statistical design that prevents false-positive rollbacks: multi-window sampling instead of single-point comparison, rate-based instead of count-based metric queries, and consecutive-window thresholds instead of one-shot triggers. The strongest answers also flag traffic-composition skew as a hidden confound that can make a healthy canary look broken, and note that an unusually high automatic-rollback rate is itself a signal worth investigating rather than just a safety net working as intended. This shows you understand CV as a statistical system with failure modes, not a magic safety switch.
◈ Architecture Diagram
┌────────┐ ┌────────┐
│Baseline│───┐ │ Canary │───┐
└────────┘ │ └────────┘ │
↓ ↓
┌─────────────────────┐
│ Windowed Compare │
└──────────┌──────────┘
↓
risk > thresh?
✓ pass │ ✗ rollback💬 Comments
Quick Answer
Templates (pipeline/stage/step level) centralize the golden path with versioned, org-scoped definitions services reference rather than copy; input sets capture per-service/per-environment parameter bundles; Git Experience stores all of it in your repos so changes flow through PR review. Together: 50 services share one reviewed deployment pattern instead of 50 divergent pipelines.
Detailed Answer
The sprawl problem Harness templates solve is the same one reusable workflows solve in GitHub Actions: without them, every service clones a pipeline and they drift apart — one gets the new verification step, others don't; an incident fix lands in 12 of 50 copies. Structure: org/project-level pipeline and stage templates with version labels (v1, v2...), where services attach a thin pipeline referencing the template plus their variables; template changes are versioned so consumers upgrade deliberately (pin stable, canary the new version on low-risk services first). Input sets bundle runtime inputs (image tag, environment, feature flags) — CI triggers reference an input set rather than passing loose parameters, and overlays compose them (base + env-specific). Git Experience keeps pipeline/template/input-set YAML in Git with branch/PR semantics, giving CI-grade review and audit for delivery changes — plus environment promotion via the same PR flow as code. The governance layer on top: OPA policies (Policy as Code) can require, e.g., that prod deployments use an approved template version and include an approval stage — turning the paved road from convention into constraint.
Code Example
pipeline:
name: checkout-svc-deploy
template:
templateRef: org.golden_k8s_deploy
versionLabel: v3
variables:
serviceRef: checkout
# input set: {image_tag: <runtime>, env: prod, approval: cab}
# OPA: deny if template.versionLabel < v3 and env == prodInterview Tip
Map it to the pattern interviewers know from other CI/CD: templates = reusable workflows, input sets = parameter bundles, plus OPA to enforce template adoption — the paved-road-to-guardrail progression.
💬 Comments
Quick Answer
A canary stage ships a small instance percentage, then a CV step compares the canary's metrics/logs (from your APM — Prometheus, Datadog, etc.) against the stable baseline using ML-scored deviation; verification failure triggers the stage's rollback strategy automatically, restoring the previous verified release without a human in the loop.
Detailed Answer
Moving parts: (1) the canary deployment strategy in a CD stage — e.g., 10% -> verify -> 50% -> verify -> full, each increment a step group; (2) a health source per verification step — connectors to Prometheus/Datadog/CloudWatch/logs mapping which metrics and log queries define 'healthy' for this service (error rate, latency percentiles, exception patterns); (3) the CV analysis itself: Harness compares canary pods' signals against the current-version baseline over the analysis window (canary-vs-baseline for metrics, plus log clustering that flags novel error patterns the old version never emitted); sensitivity and duration are tunable per risk tier; (4) failure strategy on the stage: on verification failure, execute rollback — for K8s, revert to the previous release's manifests/artifact; for more complex topologies, a rollback step group you define; (5) guardrails around the automation: approval steps before prod for high-tier services, deployment freeze windows, and notification rules so rollbacks page the owning team with the CV report attached. Design points interviewers probe: baseline choice (previous version's live pods, not historical averages — traffic mix changes), analysis duration vs deploy velocity tradeoff, and ensuring the rollback path itself is exercised regularly (a never-tested rollback is a hope, not a strategy).
Code Example
execution:
steps:
- stepGroup: canary-10pct
steps:
- K8sCanaryDeploy: {instanceSelection: {count: 10, type: Percentage}}
- Verify:
type: Canary
spec: {sensitivity: HIGH, duration: 15m,
healthSources: [prometheus: error_rate, p99_latency]}
failureStrategies:
- onFailure: {errors: [Verification], action: {type: StageRollback}}Interview Tip
Name the baseline decision (canary vs current-version live pods, not historical data) and the untested-rollback trap — those two details show deployment-safety thinking beyond the product's marketing page.
💬 Comments
Context
A scale-up deploying via a mix of Jenkins scripts, hand-run Helm, a homegrown deployer, and two teams' experimental GitOps — four ways to ship, four ways to fail, no shared audit trail.
Problem
Deployment knowledge was tribal per team; rollback procedures ranged from 'helm rollback' to 'find Raj'; compliance needed a single audit trail of who deployed what where; and platform improvements (canary, verification) would have to be built four times.
Solution
Standardized on Harness CD: one org-level golden K8s deployment template (rolling for tier-3, canary+CV for tier-1/2) with service/environment abstractions mapping the existing clusters, delegates installed per environment (prod delegates in the prod VPC with scoped permissions), and OPA policies requiring the golden template + approval stage for prod. Migration ran tier-3 services first (low risk, high count) to bake the template, then tier-1 with CV enabled. The four legacy paths were decommissioned on a published schedule with a freeze on changes to them.
Commands
template: org.golden_k8s_deploy v1..v4 (canary+CV variant for tier1)
delegate install: helm upgrade -i harness-delegate --set delegateName=prod-vpc
OPA: deny prod pipelines missing approval stage or non-golden template
Outcome
All 60 services on one deployment platform in two quarters; deployment audit became a query instead of an investigation; rollback is the same button everywhere (exercised monthly by game day); the first platform-wide improvement (CV tuning) shipped once and reached every tier-1 service the same week.
Lessons Learned
Migrating the easy tier first was right — the template hit reality (init containers, odd health checks) on low-stakes services. Delegate permission scoping per environment was the security review's main focus; getting it strict from day one avoided a later re-plumb.
💬 Comments
Context
A payments team deploying 3-4 times weekly where two incidents in a quarter followed the same arc: deploy looks fine, subtle error-rate elevation for 40+ minutes, human notices, manual rollback under pressure.
Problem
Human-speed detection of deploy-caused regressions: dashboards existed but nobody stares at them post-deploy; by the time alerts (tuned for steady-state) fired, thousands of requests had degraded. Rollback required finding the right person with the right runbook.
Solution
Moved the service to canary deployment with CV: 10% canary analyzed for 15 minutes against the live stable baseline (error rate, p99, plus log-cluster analysis for novel exceptions), then 50%, then full — with verification failure auto-executing rollback and paging the team with the CV report. Sensitivity started LOW in shadow mode (verify but don't act) for two weeks of tuning against real deploys, then enforcement. Deployment freeze windows cover payment-network cutoff hours.
Commands
Verify step: {type: Canary, sensitivity: MEDIUM, duration: 15m, healthSources: [prom: err_rate, p99; logs: novel_clusters]}failureStrategy: Verification -> StageRollback + notify #payments-oncall
shadow phase: same config, action=ManualIntervention, 2 weeks
Outcome
Next regression-shipping deploy (a connection-pool misconfiguration) was caught at 10% traffic and rolled back automatically in 9 minutes end-to-end — versus the 40-70 minute human arc; blast radius was ~2% of requests for 9 minutes instead of 100% for an hour. Deploy frequency went up after trust in the safety net grew.
Lessons Learned
The shadow-mode tuning fortnight was essential — first-pass sensitivity flagged two clean deploys on known-noisy metrics, which would have destroyed trust as false rollbacks. Log-cluster novelty caught the real incident before the metric thresholds did.
💬 Comments
Context
An insurer adopting Harness SaaS with workloads across on-prem VMware, AWS, and a restricted zone with no inbound connectivity and allowlisted egress only.
Problem
The security team's default position was 'SaaS CD cannot touch the restricted zone'; every environment had different network rules; and the initial PoC had installed one over-privileged delegate that could reach everything — exactly what review would reject.
Solution
Designed delegates as the security boundary: one delegate group per zone (aws-prod, aws-nonprod, onprem, restricted), each installed inside its zone with outbound-only connections to Harness (satisfying the no-inbound rule — the restricted zone's egress allowlist got exactly the Harness endpoints), scoped to its environments via delegate selectors, and granted least-privilege credentials local to its zone (IRSA in AWS, a dedicated vSphere role on-prem, a namespace-scoped service account in restricted). Pipelines bind stages to delegate selectors so a prod stage physically executes on the prod delegate. Delegate health, version skew, and task-queue metrics feed the platform dashboard; auto-upgrade is on except in the restricted zone, where bundle upgrades ride the monthly change window.
Commands
helm install delegate-restricted ... --set tags='restricted' --set proxy... # egress allowlist: app.harness.io
stage: {delegateSelectors: [restricted]}monitor: delegate_connected, task_queue_depth, version vs latest
Outcome
Security signed off with the delegate-per-zone model as the control (outbound-only + zone-local credentials + selector binding); all four zones deploy through one pipeline experience; the restricted zone went from quarterly hand-deployments to weekly pipeline deployments within its change process.
Lessons Learned
Presenting delegates as 'our agent, in our network, with our credentials, outbound-only' reframed the SaaS conversation with security. Version-skew monitoring mattered immediately — the restricted zone's manually-upgraded delegates lagged and hit a task-compatibility warning within two months.
💬 Comments
Symptom
Every deployment to prod sits at the first K8s step with tasks queued; non-prod deploys work. The delegate pods show Running and the UI shows the delegates as connected — but no prod task makes progress.
Error Message
Delegate task logs: 'Unable to get KubernetesClient: Unauthorized (401)' — the delegate is connected to Harness but its cluster credential is dead.
Root Cause
The prod delegates authenticated to the cluster via a service-account token that was rotated by a cluster-hardening job (token TTLs shortened org-wide). The delegate's connectivity heartbeat to Harness (which drives the green 'connected' status) tests the Harness control-plane link, not downstream credentials — so the fleet looked healthy while every task requiring the cluster failed and retried into a growing queue. Non-prod used IRSA-style auth unaffected by the rotation.
Diagnosis Steps
Solution
Reissued the credential (moved prod delegates to the same workload-identity auth as non-prod, eliminating the static token class entirely), drained the task queue, and re-ran the stuck pipelines. Added a synthetic 'connector test' schedule: every connector used by prod pipelines is validated hourly and failures page — turning dead-credential-behind-green-delegate into an explicit alert.
Commands
kubectl logs deploy/harness-delegate -n harness | grep -i 'unauthorized\|kubernetes'
harness UI: connector 'prod-k8s' -> Test — fails; schedule this as a probe
task queue: delegate group metrics — queue_depth, oldest_task_age
Prevention
Distinguish 'delegate connected' from 'delegate can do its job': schedule connector/credential validation as a monitored probe. Prefer workload identity over static tokens for delegate-to-infra auth so cluster credential rotations can't strand the CD plane. Alert on task queue depth/age per delegate group.
💬 Comments
Symptom
Monday morning, 40+ service pipelines fail at the deploy stage with a schema/variable error none of those teams changed anything to cause. The platform team had merged a golden-template update Friday evening.
Error Message
Pipeline compile error: 'Variable "namespaceOverride" is required by template org.golden_k8s_deploy but not provided' — for every pipeline referencing the template with versionLabel: 'latest'/stable auto-tracking.
Root Cause
The golden template's new version added a required variable (part of a namespace-standardization effort), and most consuming pipelines referenced the template's stable/latest label rather than a pinned version — so the change propagated to all consumers instantly, without any per-service validation. The template had CI for its own YAML validity, but nothing exercised representative consumer pipelines against a candidate version before promotion.
Diagnosis Steps
Solution
Rolled the stable label back to the previous version (single change, restored all consumers), then re-shipped properly: the new variable made optional with a sane default, a consumer-canary process (template CI compiles and dry-runs the top-10 representative consumer pipelines against the candidate), and a policy shift — tier-1 services must pin explicit template versions and upgrade via PR; only tier-3 may track stable.
Commands
harness template list --name golden_k8s_deploy --versions
template update: stable -> v3 (rollback)
template CI addition: for p in consumers_top10: harness pipeline compile --template-candidate v4 $p
Prevention
Template version labels are a blast-radius dial: auto-tracking labels mean template merges are instant org-wide deploys of pipeline logic. Require consumer-representative validation in template CI, prefer additive/optional changes, and reserve breaking changes for explicit major-version migrations with deprecation windows.
💬 Comments
Symptom
A deploy that visibly elevated error rates sails through CV at every canary step and rolls to 100%; the incident is caught by customer reports. The CV report shows 'no significant deviation' with suspiciously flat, sparse metrics on both canary and baseline.
Error Message
No error. CV analysis window shows near-empty series for the configured queries; the analysis compared two effectively-null signals and found them identical.
Root Cause
A monitoring migration had relabeled workloads (app= -> app.kubernetes.io/name=) two weeks earlier. The CV health source's Prometheus queries still selected the old label, matching almost nothing — so canary-vs-baseline comparison ran on empty series and passed trivially. CV had no minimum-data guard configured, and nobody noticed the reports had gone flat because passing verifications don't get read.
Diagnosis Steps
Solution
Fixed the health-source queries to the new labels and re-validated against a historical bad deploy (replay confirmed CV would have failed it). Enabled the fail-on-no-data option so empty analysis windows fail verification instead of passing, and added a weekly 'CV sanity' check that asserts each tier-1 service's health-source queries return non-trivial series volume.
Commands
promql (as configured): sum(rate(http_errors{app='checkout'}[5m])) # ~emptypromql (correct): sum(rate(http_errors{app_kubernetes_io_name='checkout'}[5m]))CV config: failOnNoAnalysis: true
Prevention
Verification that can pass on no data is a rubber stamp — always configure minimum-data/fail-on-no-analysis behavior. Treat monitoring relabels/migrations as changes to every consumer of those metrics (CV, alerts, dashboards) with a consumer inventory. Periodically test the safety net against a known-bad historical deploy.
💬 Comments