DevOps Engineer interview prep
A spaced-repetition deck of 210+ DevOps Engineer interview questions — organised by topic and difficulty, and resurfaced right before you'd forget. Preview a few cards below, then sign in to study the whole track on an Anki-style SM-2 schedule.
Free · sign in with GitHub · your progress stays yours.
What's covered
Every topic in this track, grouped the way you'd study it.
Linux & Troubleshooting
11 cardsNetworking in Operations
10 cardsContainer Internals
8 cardsKubernetes
13 cardsCI/CD & GitOps
8 cardsTerraform & Ansible (IaC)
8 cardsObservability & SRE
11 cardsCloud & Security
9 cardsDevOps & Infra
35 cardsCS Fundamentals
33 cardsSystem Design
29 cardsBehavioral
35 cardsSample questions
A few cards from the deck — reveal each answer, then sign in to study the full set on a schedule.
free shows almost no free memory. Is the server actually out of RAM?
free shows almost no free memory. Is the server actually out of RAM?
Short answer: Almost certainly not. Linux deliberately fills “spare” memory with page cache — it is handed back to applications instantly. Look at the available column, not free; real memory pressure shows up as swap-in and major page faults.
In depth:
| Metric | What it means | Worry? |
|---|---|---|
| free | memory occupied by nothing at all | no — near zero on a healthy server |
| buff/cache | page cache: file and block cache | no — evicted on demand |
| available | what can really be handed out without swapping | yes, if it steadily heads to zero |
- Empty memory is wasted memory — the kernel caches disk so repeated reads come from RAM instead of the device.
- Real signs of pressure — growing si in
vmstat 1(swap-in), major page faults, OOM-killer entries in dmesg.
free -h # watch available, not free
vmstat 1 5 # si/so columns — is active swapping happening
⚠️ Common mistake: “no free memory — let’s reboot” or dropping caches via drop_caches. Page cache is a feature: clearing it only slows the system down until it warms up again.
L4 vs L7 load balancing: what can each layer see, and what can it do?
L4 vs L7 load balancing: what can each layer see, and what can it do?
Short answer: An L4 balancer sees only IPs and ports — it spreads TCP/UDP flows, fast and cheap, but the protocol is opaque to it. L7 parses HTTP: routing by path and headers, retries, TLS termination, cookie affinity — at the cost of CPU spent parsing.
In depth:
| L4 | L7 | |
|---|---|---|
| Sees | IP:port, SYN | method, path, headers, cookies |
| Routing | round-robin/hash over flows | /api → one pool, /static → another |
| Retries & timeouts | none — can't tell where a request ends | per-request retries, circuit breaking |
| TLS | passthrough only | termination, X-Forwarded-For |
| Cost | near zero, millions of pps | HTTP parsing: CPU and latency |
Examples: L4 — IPVS, AWS NLB; L7 — nginx, Envoy, AWS ALB. A common cascade: L4 on the edge → L7 inside.
⚠️ Common mistake: expecting retries or path-based routing from L4 — it doesn't see HTTP and fundamentally can't tell where one request ends and the next begins.
What is a container at the Linux kernel level, and which mechanisms implement it?
What is a container at the Linux kernel level, and which mechanisms implement it?
Short answer: A container is just a regular Linux process that the kernel hands an isolated view of the system: namespaces hide everything else, cgroups cap resources, and a layered filesystem provides its own rootfs. There is no guest kernel — one kernel serves everyone, and that is the real difference from a VM.
In depth:
- Namespaces — visibility isolation: each type hides its own slice of the system.
- cgroups — limits on CPU, memory, IO: how much the process may use, not what it sees.
- Layered rootfs (overlayfs) — its own filesystem on top of shared read-only image layers.
| Namespace | What it isolates |
|---|---|
| pid | process tree: its own PID 1 inside |
| net | network stack: interfaces, routes, its own ports |
| mnt | mount points, its own rootfs |
| uts | hostname and domainname |
| ipc | System V IPC, POSIX queues |
| user | UID/GID mapping: root inside ≠ root outside |
| cgroup | the visible cgroup hierarchy |
⚠️ Common mistake: "a container is a lightweight VM." A VM has a hypervisor and its own guest kernel; a container shares the host kernel — that's why it starts in milliseconds, but isolation is weaker: one kernel vulnerability pierces every container at once.
What happens after kubectl apply -f deployment.yaml? Walk through the full chain to a running pod.
What happens after kubectl apply -f deployment.yaml? Walk through the full chain to a running pod.
Short answer: kubectl validates the manifest and sends it to the API server: authn → RBAC → admission webhooks → persisted to etcd. That is where the synchronous part ends — controllers, the scheduler, and kubelet notice changes asynchronously via watch and drive the cluster toward the desired state. Nobody pushes anything.
In depth:
- API server — authentication, authorization (RBAC), admission (mutating → validating webhooks), object stored in etcd.
- Deployment controller — sees the new Deployment (watch) and creates a ReplicaSet.
- ReplicaSet controller — creates Pod objects, with no node assigned yet.
- Scheduler — finds pods with an empty nodeName, filters and scores nodes, binds.
- kubelet — on the chosen node sees "its" pod: pulls images, starts containers via CRI, networking comes up via the CNI plugin.
- Readiness — probe passes → the pod joins the EndpointSlice and starts receiving traffic.
kubectl ──► API server (authn → RBAC → admission) ──► etcd
▲ watch ▲ watch ▲ watch ▲ watch
deploy-ctrl → RS rs-ctrl → Pods scheduler → bind kubelet → CRI/CNI
⚠️ Common mistake: "the API server schedules the pod and starts containers." It only stores and serves state — all the work is done by independent controllers via the watch/reconcile model.
Trunk-based development vs GitFlow: which model enables continuous deployment, and why?
Trunk-based development vs GitFlow: which model enables continuous deployment, and why?
Short answer: Continuous deployment is only real with trunk-based + feature flags: small batches, branches that live hours, main always deployable. GitFlow with long-lived develop/release branches means big batches and merge hell; its home is boxed, versioned software.
In depth:
| Trunk-based | GitFlow | |
|---|---|---|
| Branches | main + branches < 1–2 days | develop, release/, hotfix/ — long-lived |
| Batch size | small, integrate daily | large, integrate at release time |
| Deploy vs release | decoupled via feature flags | glued together: release = merging the release branch |
| Fits | SaaS, continuous deployment | boxed software, several supported versions |
- Flags decouple deploy from release — code ships to prod turned off; turning it on is config, not a deploy. That removes the fear of merging unfinished work into main.
- The argument is batch size, not taste: the longer a branch lives, the more conflicts, the longer the lead time, the scarier the rollback — DORA metrics are exactly about this.
⚠️ Common mistake: answering "whatever the team prefers." It is not taste: long branches → big batches → long lead time — a measurable argument.
Two engineers run terraform apply at the same time. What happens with and without state locking?
Two engineers run terraform apply at the same time. What happens with and without state locking?
Short answer: With locking, the second apply blocks or fails with "Error acquiring the state lock" — the first one holds the lock. Without it — a race: both read the same state version and overwrite each other's writes, leaving the state inconsistent.
In depth:
with lock: A: apply ──► lock OK ──► works ──► unlock
B: apply ──► Error acquiring the state lock ✗
without lock: A: read state v1 ──► write v2a ─┐
B: read state v1 ──► write v2b ─┴─► last writer
"wins"
- Consequences of the race — lost records: a resource exists in the cloud but not in state (orphan), or the state is corrupted and gets fixed by hand via
state rm/import. - Mechanics — the backend takes a lock for the duration of the operation (a DynamoDB table for S3);
force-unlockis only for stuck locks. - The full answer — applies run only through the CI pipeline, serially; humans run plan locally.
⚠️ Common mistake: treating locking as an optional nicety "for big teams" — one overlapping apply is enough to spend a day untangling state by hand.
Ready to make it stick?
Start your first session in under a minute. Your future self, mid-interview, will thank you.
Questions about this track
How should I prepare for a DevOps Engineer interview?
Study the concepts you'll be asked to explain, not just the ones you can code. RecallDeck's DevOps Engineer track gives you 210+ curated interview questions and resurfaces each one with an Anki-style SM-2 schedule right before you'd forget it — so the answers are still there under pressure on interview day.
What topics does the DevOps Engineer track cover?
The DevOps Engineer track is organised into the core areas DevOps Engineer interviews actually test, grouped by topic and by difficulty (Concept, Junior, Middle, Senior). You can preview the full outline and sample questions above before signing in.
Is spaced repetition effective for DevOps Engineer interview prep?
Yes. Actively recalling an answer and grading yourself honestly builds far more durable memory than re-reading notes. RecallDeck schedules each DevOps Engineer card to reappear at the moment you're about to forget it, so your daily reviews shrink while your recall holds.
Is the DevOps Engineer track free?
Yes — the DevOps Engineer track and the full SM-2 scheduler are free, with 20 new cards a day. Sign in with GitHub and your progress syncs to your account. RecallDeck Pro ($5/month or $29/year) raises the daily budget and adds cram mode.