DevOps Interview Questions

Reviewed by Mark Dickie · Last updated

DevOps is the practice of shortening the path from a code change to running software by treating delivery, infrastructure, and operations as engineering problems rather than handoffs. Interviews probe the cross-cutting reasoning that no single tool teaches: how a CI/CD pipeline promotes a build through stages and gates, when a canary beats a blue-green or rolling release, why infrastructure as code must be idempotent, what the three pillars of observability actually buy you, and how SRE concepts like SLOs and error budgets turn reliability into a budget you spend. These questions cover the principles behind the tools — what separates someone who has run a pipeline from someone who can reason about why it is shaped that way.

At a glance

Questions15
Difficulty2–4 of 5
FormatsMultiple choice, Multiple answer, True / false, Code output, Find the bug, Short answer, Flashcard, Ordering, Fill in the blank

What you'll review

  1. canary release
  2. continuous delivery vs deployment
  3. logs metrics traces
  4. immutable infrastructure
  5. error budgets
  6. feature flags
  7. config management
  8. build artifacts
  9. structured logging
  10. idempotency
  11. postmortems
  12. secret management
  13. gitops
  14. incident response
  15. declarative vs imperative

Practice questions

DevOps/release-strategies/canary-release

Your team wants to ship a risky checkout rewrite to a large user base and limit the blast radius if it misbehaves under real traffic. Which release strategy best fits, and why?

Options

  • Canary: route a small percentage of live traffic to the new version, watch its metrics, and progressively increase the share — so a regression is caught while it affects only a fraction of users
  • Blue-green: cut 100% of traffic from the old environment to a fully-provisioned new one at once — so any regression is observed under the full production load
  • Rolling update: replace instances in place a few at a time, which guarantees the new version is never exposed to real user traffic until every instance is healthy
  • A big-bang deploy during a maintenance window, because limiting blast radius is only possible with downtime
Show answer

Canary releasing fits best. You route a small percentage of live traffic to the new version, compare its error rate, latency, and business metrics against the stable version, and ramp up only if it holds — so a regression affects a fraction of users and rolls back by shifting traffic away. Blue-green gives instant cutover and rollback but sends the full load to the new version at once, so a load-sensitive bug hits everyone. Rolling updates replace instances gradually but offer no metric-gated traffic split.

Why:

Canary releasing exists precisely for this scenario: you expose the new version to a small slice of real traffic (say 1–5%), compare its error rate, latency, and business metrics against the stable version, and only ramp up if it holds. A regression is therefore detected while it harms a fraction of users, and you can roll back by shifting that slice back. Blue-green (b) is excellent for instant cutover and instant rollback, but at the moment of cutover the new version takes the entire load, so a load-sensitive regression hits everyone — it minimizes downtime, not blast radius under live traffic. Rolling updates (c) do gradually replace instances, but the claim is wrong: as soon as a new instance is in the pool it serves real traffic, and rolling gives you no metric-gated traffic split. (d) is false — the whole point of these strategies is progressive exposure without a downtime window.

DevOps/delivery-flow/continuous-delivery-vs-deployment

What is the precise difference between continuous delivery and continuous deployment?

Options

  • Continuous delivery keeps every change build-tested and release-ready, but a human approves the final push to production; continuous deployment removes that gate, so every change passing the pipeline goes to production automatically
  • Continuous delivery means merging to main frequently; continuous deployment means running tests on every commit
  • Continuous delivery ships to staging only; continuous deployment is the same thing renamed for marketing
  • Continuous deployment requires a manual approval step, while continuous delivery is fully automated end to end
Show answer

Both keep the codebase continuously releasable — every change is automatically built, tested, and proven deployable. The one difference is the production gate. Continuous delivery makes each change release-ready but a human approves the final push to production. Continuous deployment removes that gate: any change that passes the automated pipeline ships to production with no manual step. Continuous integration is the upstream practice both build on — frequent merges with automated testing on each commit.

Why:

Both practices keep the codebase in a continuously releasable state — every change is automatically built, tested, and proven deployable. The single distinction is the production gate. Continuous delivery stops just short of production: the artifact is release-ready and could ship at the click of a button, but a human decides when. Continuous deployment removes that button — any change that passes the full automated pipeline is released to production with no manual step. Option d inverts the definitions. Option b confuses these with continuous integration (frequent merges plus automated testing on each commit), which is the upstream practice both build on. Option c is wrong: continuous delivery is about being able to release to prod at any time, not deploying only to staging, and the two terms are genuinely different, not a rename. The interview tell is naming the manual-approval gate as the one differentiator.

DevOps/observability/logs-metrics-traces

A service is up but slow, and you cannot tell which downstream call is responsible. Which of the 'three pillars' of observability is designed to answer 'where in the request path is the time going?'

Options

  • Distributed traces, which stitch the spans of a single request across services so you can see the latency contribution of each hop
  • Metrics, because a single latency gauge tells you exactly which service is slow
  • Logs, because grepping each service's log lines reconstructs the full causal request path automatically
  • Alerting, which is the fourth pillar and pinpoints the slow hop directly
Show answer

Distributed tracing answers this. A trace stitches together the spans of a single request as it crosses service boundaries, with each span timed, so you can read off exactly which downstream hop dominates the latency. Metrics aggregate away the per-request path — they tell you that latency is up, not where. Logs are per-service discrete events that don't automatically reconstruct one request's journey without a shared trace or correlation id. The three pillars are logs, metrics, and traces; alerting is built on them, not a separate pillar.

Why:

The three pillars are logs, metrics, and traces, and each answers a different question. Metrics are cheap aggregate time-series — great for 'is latency up?' and dashboards/alerts, but they aggregate away the per-request path, so they tell you that something is slow, not where in a multi-service call. Logs are discrete events rich in detail, but on their own they are per-service and don't automatically reconstruct one request's journey across services. Distributed tracing is purpose-built for this: a trace ties together the spans of a single request as it crosses service boundaries, each span timed, so you can read off exactly which downstream hop dominates the latency. Option b overstates what a single metric can do; option c assumes logs auto-correlate across services (they don't without a shared trace/correlation id); option d is wrong — alerting is built on metrics/logs, it is not a fourth pillar and does not localize a slow span.

DevOps/iac/immutable-infrastructure

Under the immutable-infrastructure pattern, how is a running server patched or upgraded, and what core problem does this prevent?

Options

  • You build a new machine image with the change, roll out fresh instances from it, and discard the old ones — never mutating a live server in place — which prevents configuration drift and unreproducible 'snowflake' hosts
  • You SSH into each live server and apply the patch in place, which keeps every host identical because the change is applied uniformly
  • You let a configuration-management agent continuously edit live servers toward the desired state, which makes the infrastructure immutable by definition
  • You freeze the servers so no process can write to disk, which is what 'immutable' literally means in this context
Show answer

Immutable infrastructure never modifies a live server. To patch or upgrade, you build a new machine image with the change, launch fresh instances from it, shift traffic over, and discard the old instances. Because the change is captured once in the image build, every instance is identical and reproducible from source. This prevents configuration drift and 'snowflake' servers — the undocumented divergence that accumulates when hosts are edited in place over time. In-place SSH patching and convergent config agents are the mutable approaches it replaces.

Why:

Immutable infrastructure means you never modify a provisioned server after it boots. To change anything — a patch, a new dependency, a config tweak — you bake a new image (AMI/container/VM template), launch fresh instances from it, shift traffic, and terminate the old ones. The change is captured once, in the image build, so every instance from that image is byte-for-byte identical and fully reproducible. This directly attacks configuration drift and 'snowflake servers': the gradual, undocumented divergence that happens when humans and agents make ad-hoc in-place edits over months until no two hosts match and none can be rebuilt from source. Option b (in-place SSH patching) is exactly the mutable anti-pattern that produces drift — manual changes are rarely uniform or recorded. Option c describes convergent configuration management (Puppet/Chef-style), which mutates live hosts and is the opposite of immutable. Option d misreads 'immutable' as a read-only filesystem; it's about not re-provisioning live hosts, not about disk writes.

DevOps/reliability/error-budgets

An SRE team runs a service with a 99.9% availability SLO. Which statements about the resulting error budget are correct? Select all that apply.

Options

  • The error budget is the allowed unreliability — 100% minus the SLO (here 0.1%) — i.e. the amount of failure the team is permitted to spend over the window
  • While budget remains, the team can spend it on shipping features and taking deploy risk; when it is exhausted, the policy is to freeze risky releases and prioritize reliability work
  • An error budget turns the reliability-vs-velocity argument into a shared, data-driven number rather than a recurring opinion-based fight between dev and ops
  • The goal is always to keep the error budget fully unspent; consistently spending zero budget means the team is doing everything right
  • The error budget is set by counting the number of incidents per quarter, independent of any SLO
Show answer

The error budget is the allowed unreliability — 100% minus the SLO, so a 99.9% target permits 0.1% failure over the window. While budget remains, the team can spend it on shipping features and deploy risk; once it is exhausted, the policy freezes risky releases and prioritizes reliability work. Its value is turning the velocity-versus-stability debate into a shared, data-driven number. Spending zero budget is not the goal — it signals the SLO is too loose or reliability is over-invested.

Why:

An error budget is derived directly from the SLO: it is 100% minus the objective, so a 99.9% target permits 0.1% unreliability over the measurement window (a). That budget is a currency. While it is unspent the team has room to move fast — deploy often, take calculated risk — and when it runs out, the agreed error-budget policy kicks in: stop shipping risky changes and redirect effort to reliability until the service earns budget back (b). Its real organizational value is making the eternal velocity-vs-stability tension an objective, shared number instead of a turf war between developers who want to ship and ops who want stability (c). Option d is the classic trap: a budget that is never spent means your SLO is too loose (or you're over-investing in reliability users don't perceive) — you're leaving velocity on the table, so consistently spending zero is a signal to recalibrate, not a victory. Option e is wrong: the budget is computed from the SLO/SLI math, not by tallying incident counts.

DevOps/release-strategies/feature-flags

Feature flags let you decouple deployment from release: code for an unfinished or risky feature can be merged and deployed to production while staying dark, then turned on for users independently of any deploy.

Show answer

True. Deploying ships code to servers; releasing exposes behaviour to users. A feature flag is a runtime switch around the new code path, so you can merge and deploy an unfinished or risky feature while it stays dark in production, then enable it for users on your own schedule — internal users, a canary cohort, or everyone — and kill it instantly without a rollback deploy. This makes trunk-based development and continuous deployment practical, but stale flags accumulate as debt and should be removed after full rollout.

Why:

True, and this decoupling is the main strategic reason teams adopt feature flags. Deploying ships code to the servers; releasing exposes behaviour to users. A flag is a runtime switch wrapping the new code path, so you can merge to trunk and deploy continuously — keeping branches short-lived — while the feature stays off ('dark') in production. You then enable it on your own schedule: for internal users first, for a 5% canary cohort, or for everyone, and you can kill it instantly without a rollback deploy if it misbehaves. This is what makes trunk-based development and continuous deployment practical for large, in-progress features, and it underpins experimentation (A/B tests) and progressive delivery. The cost is real and worth naming: flags are conditional logic that accumulate, so undisciplined teams drown in stale flag debt — short-lived flags should be removed once a feature is fully rolled out.

DevOps/config-secrets/config-management

A twelve-factor app reads config from the environment, falling back to a checked-in default. The container is started with DATABASE_URL set in its environment to postgres://prod-db/app, while the repo's committed .env.defaults file sets DATABASE_URL=postgres://localhost/app. The startup code is below. Which database does the app connect to, and why?

// load committed defaults first, then let the real environment win
const defaults = parseEnvFile('.env.defaults');
const config = { ...defaults, ...process.env };

connect(config.DATABASE_URL);

Options

  • postgres://prod-db/app — the spread merges process.env last, so the real environment variable overrides the committed default, which is the twelve-factor pattern
  • postgres://localhost/app — committed files always take precedence over environment variables for safety
  • It throws, because DATABASE_URL is defined in two places
  • postgres://localhost/app — process.env is read-only and cannot override a value loaded from a file
Show answer
postgres://prod-db/app — the spread merges process.env last, so the real environment variable overrides the committed default, which is the twelve-factor pattern
Why:

Object spread merges left to right, and on a key collision the last spread wins. { ...defaults, ...process.env } therefore lets any variable present in the real environment override the committed default — so DATABASE_URL resolves to postgres://prod-db/app. This is the twelve-factor 'store config in the environment' principle in miniature: the same artifact ships everywhere, and per-environment values (prod DB, secrets, feature toggles) come from the environment at runtime, while a committed defaults file gives a sane local-dev fallback that never contains real secrets. Option b inverts the precedence (committed defaults are the fallback, not the override). Option c is wrong — duplicate keys across the two sources is the normal, intended case, not an error. Option d is false: process.env is a readable map here and nothing about reading it from a file changes merge order. The interview point is that environment beats baked-in defaults, which is what keeps one build deployable to every environment.

DevOps/ci-cd-practice/build-artifacts

A pipeline builds an immutable artifact tagged with the commit SHA and promotes the same artifact through environments (it never rebuilds per env). After deploying v=git-9f3a1c to prod, a regression appears. The rollback script runs the commands below. What does the rollback do, and is it safe?

PREV=$(deploy-history prod --nth 2 --field artifact)   # -> app:git-2b7e08
echo "rolling back to $PREV"
deploy prod --artifact "$PREV"   # re-deploys the exact bytes that ran before

Options

  • It re-deploys the exact previously-running artifact (app:git-2b7e08) with no rebuild, so the rollback is fast and reproducible — you get back the bytes that were known-good in prod
  • It rebuilds the previous commit from source, so the rollback could produce a different artifact than what originally ran if any dependency drifted
  • It cannot roll back, because immutable artifacts can never be re-deployed once superseded
  • It reverts the prod database to the previous schema automatically as part of re-deploying the artifact
Show answer
It re-deploys the exact previously-running artifact (app:git-2b7e08) with no rebuild, so the rollback is fast and reproducible — you get back the bytes that were known-good in prod
Why:

The whole value of building once and promoting an immutable, SHA-tagged artifact shows up at rollback time. The script looks up the artifact that was running two deploys ago (app:git-2b7e08) and re-deploys those exact bytes — no recompilation, no dependency resolution, no fresh image build. That makes the rollback fast and, crucially, reproducible: you are restoring the artifact that was already proven in prod, not a hopefully-equivalent rebuild. Option b describes the rebuild-per-environment anti-pattern, which the prompt explicitly rules out — rebuilding from an old commit can silently pull newer transitive dependencies or a newer base image and yield a different binary, defeating the point of rolling back. Option c is the opposite of true: immutability is what enables clean rollback by tag. Option d is the important caveat stated as a wrong answer — re-deploying an artifact rolls back code only; database migrations are not reversed by this and must be handled separately (which is why backward-compatible, expand-then-contract migrations matter).

DevOps/observability/structured-logging

Two services log the same checkout event. Service A emits the first line, Service B the second. A log platform ingests both and you need to alert when amount > 100 for a given user_id. Which line lets you build that query reliably without brittle text parsing?

A: User 4823 checked out for $142.50 successfully
B: {"event":"checkout","user_id":4823,"amount":142.50,"status":"ok"}

Options

  • Line B — it is structured (JSON) with typed, named fields, so the platform indexes user_id and amount and you can query amount > 100 directly
  • Line A — free-text logs are easier for machines to query because they read like sentences
  • Both are equivalent to a log platform; structure makes no difference to querying
  • Neither — numeric thresholds can never be evaluated from logs, only from metrics
Show answer
Line B — it is structured (JSON) with typed, named fields, so the platform indexes user_id and amount and you can query amount > 100 directly
Why:

Line B is structured logging: a machine-readable object with named, typed fields. A log platform parses it into indexed fields (user_id as a number, amount as a number), so a query like event:checkout AND amount > 100 is exact and survives wording changes. Line A is a human sentence — to extract the amount you'd need a fragile regex that breaks the moment someone changes 'checked out for $' to 'purchased', drops the dollar sign, or localizes the message, and the value arrives as text, not a comparable number. That brittleness is exactly why production systems standardize on structured logs with consistent field names (and a correlation/trace id) across services. Option b has it backwards; prose is easy for humans, hard for machines. Option c is wrong because structure is precisely what makes reliable field queries possible. Option d is false — you absolutely can threshold over a parsed numeric log field; metrics are often derived from such logs, but the log field itself is queryable.

DevOps/iac/idempotency

This provisioning script is run by the configuration-management tool on every converge to ensure an 'app' user and its config line exist. It works the first time, but re-running it on an already-provisioned host fails or corrupts the file. Why is it not idempotent, and what is the fix?

#!/usr/bin/env bash
set -euo pipefail

# create the service account
useradd app

# ensure the app reads from the shared config dir
echo 'CONFIG_DIR=/etc/app' >> /etc/app.env

Options

  • Both operations assume a clean host: useradd app errors (and aborts under set -e) when the user already exists, and the >> append adds a duplicate CONFIG_DIR line every run — the script must check-then-act (e.g. id app || useradd app) and write the line only if absent, so repeated runs converge to the same state
  • The bug is set -euo pipefail; removing it makes the script idempotent
  • useradd should be usermod, which is the only difference; the append is already idempotent
  • Nothing is wrong — appending the same line repeatedly is harmless and useradd silently ignores existing users
Show answer

Both operations assume a clean host: useradd app errors (and aborts under set -e) when the user already exists, and the >> append adds a duplicate CONFIG_DIR line every run — the script must check-then-act (e.g. id app || useradd app) and write the line only if absent, so repeated runs converge to the same state

Why:

Idempotency means running the operation any number of times leaves the system in the same end state as running it once — the contract a convergent config tool depends on, since it re-applies on every run. This script breaks that contract twice. useradd app is a create that fails with a non-zero exit when the user already exists; under set -e that aborts the whole converge on the second run. And echo ... >> /etc/app.env appends, so each run adds another identical CONFIG_DIR=/etc/app line, growing the file and potentially changing how the app parses it. The fix is to make every step check-then-act so it's safe to repeat: guard the user creation (id app >/dev/null 2>&1 || useradd app) and add the config line only if it isn't already present (grep -qxF 'CONFIG_DIR=/etc/app' /etc/app.env || echo 'CONFIG_DIR=/etc/app' >> /etc/app.env). Option b is backwards — set -e correctly surfaces the latent failure; deleting it just hides a broken converge. Option c fixes only half the problem and wrongly calls the append idempotent. Option d is plainly false on both counts.

DevOps/reliability/postmortems

What makes a postmortem 'blameless', and why does blamelessness make an organization more reliable rather than less accountable?

Show answer

A blameless postmortem reviews an incident by focusing on the systems, processes, and contributing causes that let the failure happen, never on punishing the individual who happened to trigger it. It assumes people act reasonably given the information, tools, and pressures they had at the time, so the question is 'what about the system made this mistake easy and its consequences severe?' rather than 'who screwed up?'. The payoff is psychological safety: when engineers know they won't be blamed, they report incidents and near-misses honestly and in full detail, which surfaces the real root and contributing causes instead of a sanitized story. That honest signal is what lets the team fix the system — add guardrails, automation, better alerts, safer defaults — and file durable, tracked action items that prevent recurrence. Blame does the opposite: it drives reporting underground, so the same latent failure stays hidden and recurs. Blamelessness is about accountability to fixing the system, not the absence of accountability.

Why:

Blamelessness shifts the postmortem's question from 'who caused this?' to 'what about our systems and processes made this failure possible and its blast radius large?'. It rests on the assumption that people generally do their best with the context they had, so a human error is treated as a symptom of a system that allowed it (a missing guardrail, a confusing UI, an alert that fired too late), not as the cause to be punished. The reliability payoff is mechanistic, not soft: blame creates fear, fear suppresses honest reporting, and suppressed reports hide the real contributing causes — so the latent fault recurs. Remove blame and you get psychological safety, which produces candid, detailed accounts that reveal the true systemic gaps, which in turn become concrete, tracked action items (automation, safer defaults, better detection) that actually prevent recurrence. A strong answer stresses systems-over-individuals, psychological safety enabling honest reporting, and that accountability is redirected to fixing the system, not removed.

DevOps/config-secrets/secret-management

Name the main anti-patterns in handling application secrets (API keys, DB passwords) and what a sound secret-management approach does instead.

Show answer

The cardinal anti-pattern is committing secrets into source control — even in a private repo they live forever in git history and leak through forks, clones, and CI logs. Related anti-patterns: hardcoding secrets in the application image so every copy of the artifact carries them, baking them into Dockerfiles or build args, printing them to logs, sharing one static credential across all environments, and never rotating them. A sound approach keeps secrets out of code and out of the artifact entirely. They live in a dedicated secret store or vault (or the cloud provider's secret manager), are injected at deploy/runtime via environment variables or mounted files, and are scoped per environment with least-privilege access controls and audit logging. Crucially, secrets should be rotatable — short-lived or dynamically issued credentials limit the damage of a leak — and a leaked secret must be revoked and rotated, not just deleted from the latest commit, because the history still holds it.

Why:

Interviewers probe secret hygiene because the failure modes are common and costly. The headline anti-pattern is committing secrets to version control: git history is permanent, so a secret that ever touched a commit is exposed via every clone, fork, and the reflog even after you 'delete' it — which is why a leaked secret must be revoked and rotated, not merely removed from HEAD. Adjacent anti-patterns are hardcoding secrets into the application image or build args (every artifact copy now carries them), logging them, and reusing one un-rotated static credential everywhere. The sound model: keep secrets out of code and out of the build artifact, store them in a dedicated vault or cloud secret manager, inject them at deploy/runtime through environment variables or mounted files, scope them per environment with least-privilege access and an audit trail, and make them rotatable — ideally short-lived or dynamically issued so a leak has a small blast radius. A strong answer pairs the 'never in git/never in the image' rule with vault + runtime injection + rotation/revocation.

DevOps/delivery-flow/gitops

What is GitOps, and how does its reconciliation model differ from a traditional push-based CI/CD deploy?

Show answer

GitOps is an operating model where a git repository is the single source of truth for the desired state of your system — typically declarative infrastructure and application manifests. A controller (an agent running in the target environment) continuously reconciles the live state toward what git declares: it watches the repo, and on any divergence it pulls the desired state and converges the cluster to match. So you change production by committing/merging to the repo, not by running a deploy command against it. This differs from traditional push-based CI/CD, where a pipeline holds credentials to the environment and pushes changes outward at the end of a build. The pull/reconcile model has concrete benefits: git history is a complete, auditable, revertable record of every change (rollback = git revert); drift is automatically detected and corrected because the controller constantly compares actual vs declared; and the environment's credentials stay inside it rather than being handed to an external CI system. The trade-off is that you must keep the repo and reconciler healthy, and it fits declarative targets (like Kubernetes) far better than imperative ones.

Why:

The interview point is the pull-based reconciliation loop versus push-based deployment. In GitOps, declarative manifests in git define desired state and an in-cluster controller continuously diffs live state against the repo and converges to it — making git the audit log, the rollback mechanism (revert the commit), and the drift-correction engine all at once. Traditional CI/CD pushes: the pipeline ends by pushing artifacts/changes into the environment using credentials the external system holds. Strong answers name (1) git as single source of truth, (2) a controller that reconciles continuously, (3) the security win of pull-from-inside vs handing prod creds to CI, and (4) automatic drift detection. A common follow-up is the limitation: GitOps assumes a declarative target and a healthy reconciler, so it maps cleanly onto Kubernetes but awkwardly onto imperative provisioning.

DevOps/reliability/incident-response

Order the phases of a well-run production incident, from the moment something breaks to the work that prevents a recurrence.

Put these in order

  • Detect: an alert tied to an SLI (or a user report) fires, signalling the service is out of bounds
  • Triage & declare: assess severity, declare an incident, and assign an incident commander
  • Mitigate: restore service fastest — roll back, fail over, or flip a flag — before chasing root cause
  • Resolve: confirm the SLI is healthy again and stand the incident down
  • Postmortem: run a blameless review, find contributing causes, and file durable action items
Show answer

A well-run incident moves through five phases in order. Detect: an alert tied to an SLI, or a user report, signals the service is out of bounds. Triage and declare: assess severity, declare an incident, and assign an incident commander. Mitigate: restore service by the fastest safe lever — roll back, fail over, or flip a flag — before chasing root cause. Resolve: confirm the SLI is healthy and stand the incident down. Postmortem: run a blameless review, find contributing causes, and file durable action items so it can't recur.

Why:

Incident response follows a deliberate order. First you must detect the problem — ideally an automated alert wired to an SLI breach, not a customer tweet. Then triage and declare: size up impact and severity, formally declare an incident so the right people engage, and name an incident commander to coordinate (separating coordination from hands-on debugging). Next comes the phase juniors most often get wrong: mitigate before you diagnose. The first duty is to stop user pain by the fastest safe lever — roll back the last deploy, fail over to a healthy region, or disable the feature flag — even if you don't yet understand the root cause. Only once the bleeding stops do you resolve: verify the SLI is back in bounds and stand the incident down. Finally, after the adrenaline fades, the postmortem extracts lasting value through a blameless review that identifies contributing causes and produces tracked action items so the same failure can't recur. The two classic mistakes are chasing root cause before mitigating, and skipping the postmortem so nothing is learned.

DevOps/iac/declarative-vs-imperative

In a _____ approach to infrastructure as code, you describe the desired end state and let the tool compute the steps to reach it; in an _____ approach, you write the explicit sequence of commands that change the system step by step.

Show answer

In a declarative approach to infrastructure as code, you describe the desired end state and let the tool compute the steps to reach it; in an imperative approach, you write the explicit sequence of commands that change the system step by step.

Why:

This is the foundational IaC distinction. A declarative approach states what you want — 'three web servers behind a load balancer with this config' — and the tool diffs that desired state against reality and figures out how to converge (create what's missing, change what differs, leave correct things alone). Because the spec is the end state, re-applying it is naturally idempotent and the tool can detect and correct drift. An imperative (or procedural) approach states how: an ordered list of commands ('create server, then install package, then edit file') that you must make safe to re-run yourself, since the script doesn't inherently know the current state. Most modern IaC and orchestration tools are declarative for exactly these reasons — idempotency, drift detection, and reproducibility — while shell-style provisioning scripts are imperative. Knowing which model a tool uses tells you how it will behave on a second run.

Related interview questions

Job market

See devops salaries and hiring demand from live job postings.

Practice this for real

CodePrep turns your target job description into an adaptive quiz from a bank of tagged questions, scores your answers, and resurfaces the topics you miss.

New topics and job-market signal, in your inbox

Occasional updates — new question topics, launch news, and what the developer job market is hiring for. Confirm your email to join, and unsubscribe anytime.