SRE Mock Interview: Production Is Down. Can You Fix It?
A full SRE interview with a live production incident on a real Kubernetes cluster: fundamentals, CrashLoopBackOff and OOMKilled, a rollback that didn't fix it, Linux on-call, observability, system design for four nines and a blameless postmortem.
Chapters
0:00Production is down (cold open)0:28The format + scoring1:32Round 1: SRE Fundamentals5:00Round 2: Live Incident14:11Round 3: Kubernetes Rapid Fire18:04Round 4: Linux On-Call20:45Round 5: Observability23:09Round 6: System Design25:33Round 7: The Postmortem27:13Round 8: On-Call & Behavioural28:49The Verdict
Every question in this interview
The full conversation for each question, including the follow-ups. Alex is a simulated candidate (AI voice); the answers are written to show what a strong answer sounds like.
SLI vs SLO vs SLA
SRE Fundamentals
Okay, warm-up. Explain SLI, SLO and SLA to me like I'm a new product manager who just joined the team.
Sure. An SLI is the thing you measure. A service level indicator. For checkout, that might be the percentage of payment requests that succeed in under five hundred milliseconds.
The SLO is the target we set for that number. Say, ninety-nine point nine percent of requests succeed, measured over thirty days. That's internal. It's the line the engineering team holds itself to.
And the SLA is the promise we make to customers, usually with money attached. If we break it, we pay credits. So the SLA is always looser than the SLO. You want to find out you're in trouble long before the lawyers do.
99.9% over 30 days = ?
SRE Fundamentals
I like that last line. Okay. Ninety-nine point nine percent over thirty days. How much downtime is that?
Thirty days is forty-three thousand two hundred minutes. Point one percent of that is forty-three point two minutes. So roughly forty-three minutes of total failure a month. That's your error budget.
And what do you do with an error budget?
You spend it. That's the part people miss. If we've barely touched it, we can ship faster, run riskier experiments, do that migration. If we've burned through it, we slow down. Feature releases pause, and the team spends its time on reliability until the budget recovers.
Who decides that? Who actually stops the releases?
It should be agreed before anything breaks. An error budget policy, signed off by engineering and product. Otherwise every freeze turns into an argument at the worst possible moment.
That's a strong answer. The policy point is what separates someone who read about SRE from someone who's lived it.
What is toil?
SRE Fundamentals
Next. What's toil? And give me an example from a real team.
Toil is work that's manual, repetitive, can be automated, and doesn't make the system better over time. And it grows as the service grows. The classic one is a person restarting a stuck job every morning because it leaks memory.
Google's SRE book suggests keeping toil under fifty percent of an SRE's time. If you're above that, you're an operator, not an engineer. My move is to track it. Tickets tagged as toil, so you can show the trend and justify the automation work.
Good. Measuring it is the part most candidates skip.
3 a.m. · CPU at 95% · wake up?
SRE Fundamentals
Last one in this round, and it's a trap. It's three a.m. An alert fires. CPU on one node is at ninety-five percent. Do you wake up?
Honestly? That alert shouldn't wake anyone up. CPU at ninety-five percent is a cause, not a symptom. Customers don't feel CPU. They feel errors and slow pages.
So I'd page on symptoms. Error rate, latency, the SLO burning too fast. And keep CPU as a dashboard signal or a ticket for the morning. If high CPU actually hurts users, the symptom alert will catch it.
You dodged the trap. A lot of people say, yes, of course I'd wake up, it's ninety-five percent!
I've been that person. You get paged for a batch job that's supposed to use all the CPU. Twice. Then you stop trusting the pager.
And a pager nobody trusts is worse than no pager. Five out of five.
Why exit code 137?
Live Incident
Why one thirty-seven? Interviewers love that one.
One twenty-eight plus nine. Nine is SIGKILL. When a process dies from a signal, the exit code is one twenty-eight plus the signal number. And SIGKILL can't be caught, so the app never gets to log anything. It just disappears.
Nice. Let's see what it said before it died.
It's warming an eighty megabyte product cache, loads forty, and then... nothing. And the memory limit on this deployment is sixty-four megabytes. So version two can never start. It's not flaky. It's mathematically dead.
Mathematically dead. I'm stealing that.
Okay. Customers are still failing. What do you do?
Roll back now, fix forward later. Undo the deployment to the previous revision.
Rolled back. Successfully rolled out.
Three version-one pods running, and the crashing pod is terminating. Let's run the test again.
Wait. Still forty out of forty failing.
Yeah. This is my favourite part of the interview.
The rollback worked. The pods are healthy. Customers are still down. Talk to me.
Okay. Healthy pods but failing requests means the traffic isn't reaching them. So I stop looking at the pods and follow the request. Storefront calls the checkout service. Does the service have any endpoints?
None. The service is pointing at nothing. So the selector doesn't match the pods. Show me the service with its selector.
The selector is app checkout, version two. And we just rolled every pod back to version one.
Yep. Every pod is labelled version one. So the release pipeline didn't just change the deployment. It also patched the service to point at version two. When we rolled back the deployment, the service didn't roll back with it.
That's it. That's the bug. A rollback only rolls back the thing you rolled back.
So the fix is to stop the service caring about version at all. It should select app checkout. Versioning belongs to the deployment, not the service.
Three endpoints. Now the test.
Forty for forty.
Okay. We're back.
Before the score, one thing you didn't do. The second you saw every request failing, who did you tell?
...No one. I went straight into the terminal.
And that's the difference between mid-level and senior. In a real incident someone declares it, someone runs comms, and someone fixes. Even if that's all you, you post a status update first. Customer support is getting yelled at right now and they have no idea why.
That's fair. Declare, post a status, then debug. And update every fifteen to thirty minutes even if the update is, still investigating.
Four out of five on triage. The debugging was excellent. Following the request after the rollback is exactly right. You lose a point on comms.
Requests vs limits
Kubernetes Rapid Fire
Requests versus limits. Go.
Requests are what the scheduler reserves for you. Limits are the ceiling. Go over the memory limit, you get OOMKilled, like we just saw. Go over a CPU limit, you don't die, you get throttled. Which is sneaky, because the pod looks healthy and it's just slow.
And QoS classes?
Three of them. Guaranteed, when requests equal limits for everything. Burstable, when you set requests but they're not equal to limits. BestEffort, when you set nothing. When a node runs out of memory, BestEffort pods get evicted first, then Burstable. Our checkout pods should be Burstable right now.
Burstable. Memory request forty-eight, limit one sixty. If checkout was critical enough, I'd make it Guaranteed.
How does service DNS work?
Kubernetes Rapid Fire
Next. A pod calls checkout dot shop. How does that name become an IP?
CoreDNS. Every service gets a DNS name, service dot namespace dot svc dot cluster dot local, and it resolves to the service's cluster IP. Then kube-proxy rules on the node send that traffic to one of the healthy pod endpoints. Let's look from inside the storefront pod.
Wait. Those aren't cluster IPs. That's the public internet. Dot shop is a real top-level domain, and this nslookup sent the name exactly as typed. Our app still works because the normal resolver tries the search domains first. Let's look at them.
Search domains, starting with shop dot svc dot cluster dot local. And ndots five. That ndots line is a famous performance trap. Any name with fewer than five dots gets tried against every search domain first. So calling an external API like api dot stripe dot com can fire off several DNS lookups before the real one.
Ooh. Bonus point for ndots. Most people have never looked at that file.
Draining a node: what can go wrong?
Kubernetes Rapid Fire
Okay. I need to patch a worker node tonight. I'm going to drain it. Anything that could go wrong?
A PodDisruptionBudget can block it. That's the point of a PDB. It says how many pods of an app are allowed to be down during voluntary disruptions, like drains and upgrades. If someone sets max unavailable to zero, the drain can never finish.
Funny you say that.
There it is. Cannot evict pod, as it would violate the pod's disruption budget. The drain is stuck, and the node's already cordoned, so nothing new lands on it either.
So what do you do? It's two a.m. and the patch window is closing.
I don't delete the PDB on my own. It's there for a reason. I'd talk to the owning team, and the fix is a sane budget, like max unavailable one, with enough replicas that losing one is fine. Max unavailable zero isn't safety. It just means you can never patch.
Correct. Last rapid fire. A pod's stuck in ImagePullBackOff.
Failed to pull image. It can't even resolve docker dot io, library, P-Y-H-T-O-N. Look at the name. It's a typo. Otherwise I'd check registry credentials, the image pull secret, and whether the tag exists. But first, always read the event. It usually tells you.
Pyhton. I have done that in production. Four out of five for the round. I'd have liked QoS tied to eviction order without me asking, but ndots saved you.
Deleted file still using space?
Linux On-Call
Why would a deleted file still use space?
Because deleting a file only removes its name. The space isn't freed until the last process closes it. Classic cause: someone runs rm on a big log file, but the app is still writing to it. The file's gone from ls, but not from the disk. lsof plus L one lists open files with zero links.
There it is. A python process holding app dot log, marked deleted. Around four hundred and seventy megabytes.
Restart the process?
That works, but it's checkout. I don't want a restart if I can avoid it. You can truncate the file through the process's file descriptor in proc. That frees the space instantly and the process keeps running.
Back to almost nothing used. Then the real fix: proper log rotation, with copytruncate or a signal so the app reopens its log, and an alert at eighty percent disk instead of a hundred.
Five out of five. You'd be amazed how many people say, I'd just reboot it.
First 4 things to monitor?
Observability
Round three. You've got a brand-new service and zero monitoring. What are the first four things you measure?
The four golden signals. Latency, traffic, errors, and saturation.
Latency, but split by success and failure, because failed requests are often fast and they make your averages look great. Traffic, so you know the load. Errors, both explicit five hundreds and wrong answers. And saturation, how full the most constrained resource is.
You said averages. Why not just use the average latency?
Because averages hide pain. If ninety-nine requests take a hundred milliseconds and one takes ten seconds, the average looks fine. But that one user is having a terrible day. I'd look at the ninety-ninth percentile. And the users stuck in p99 are often your biggest customers, the ones with the most data.
What is burn rate?
Observability
Good. Now alerting on an SLO. What's a burn rate?
Burn rate is how fast you're spending the error budget compared to the steady pace. A burn rate of one means you'll use exactly the whole budget in thirty days. A burn rate of fourteen point four means you'd use the whole month's budget in about two days.
The approach from Google's SRE workbook is multi-window alerts. Page if you're burning at fourteen point four times over the last hour, and still burning over the last five minutes. That second window stops the alert from paging after the problem's already gone.
Can you write it? Roughly. In PromQL.
Roughly, the error ratio is the rate of five hundreds over the rate of all requests. Then you compare it to fourteen point four times the allowed error, which is point one percent. And you do the same for the five-minute window and require both.
That's a solid four. You'd want recording rules in real life so that query isn't recalculated every evaluation, but the idea is right.
Logs vs metrics vs traces
Observability
Quick one. Logs, metrics, traces. When do you reach for each?
Metrics tell you something's wrong. Traces tell you where. Logs tell you why. In the incident we just did, the error rate told us something was wrong, following the request found the broken hop, and the pod logs showed the cache warm-up dying.
I like that you tied it back to the incident. That's what a senior does.
Design checkout for 99.99%
System Design
System design. Product wants checkout at ninety-nine point nine nine percent. Four nines. Design it. And start with whether that's even possible.
First, four nines is about four minutes and twenty seconds of downtime a month. That's less than one bad deploy. So it changes how you ship, not just how you build.
Second, the math of dependencies. Checkout calls the payment provider, inventory, and the database. If each one is ninety-nine point nine, and checkout needs all of them, you multiply. Point nine nine nine cubed is about ninety-nine point seven. You can't be more reliable than the things you hard-depend on.
So how do you get around that?
You stop hard-depending on them. Inventory: if it's slow, take the order and reconcile after. The payment provider: two providers, with failover. And put the order on a durable queue, so if a downstream service is down, the order waits instead of failing.
Then redundancy. At least three availability zones, with enough capacity that losing one zone doesn't overload the other two. Database with synchronous replication across zones and automatic failover.
And every network call gets a timeout, retries with exponential backoff and jitter, and a circuit breaker. Without jitter, every client retries at the same moment and you get a thundering herd that keeps the service down.
Retrying a payment: the danger?
System Design
Retries on a payment. What's the danger?
Charging someone twice. If the request times out, you don't know if the charge happened. So every payment request carries an idempotency key. The provider sees the same key twice and returns the first result instead of charging again.
That's the answer that gets people hired at payment companies. Last thing. How do you deploy to a four-nines service?
Small and slow. Canary to one percent, watch the SLO burn rate automatically, then ramp. Auto-rollback if the burn rate spikes. Feature flags so you can turn off code without a deploy. And everything we learned today: no version in service selectors, and test the image under real limits.
Four out of five. I'd have wanted you to push back on product a little. Does checkout really need four nines, or does payment authorisation? Not every part of the flow needs the same target. That's a senior move.
40 pages a week. Your first month?
On-Call & Behavioural
Last round. Your team is getting paged forty times a week. People are exhausted. You're the new SRE. What do you do in your first month?
First, I don't fix anything. I measure. Every page for the last month, grouped by alert. Usually it's five alerts causing eighty percent of the noise.
Then for each noisy alert, one of three things. Delete it if nobody acts on it. Turn it into a ticket if it can wait until morning. Or fix the real problem if it's a genuine symptom. And I'd make a rule: every page needs a runbook link, or it doesn't page.
And the humans?
A healthy rotation. At least six to eight people so you're not on call every other week. Time off after a bad night. And a weekly on-call handoff where we look at what paged and why. Burnout is a reliability problem too. Tired people make the three a.m. mistakes.
Tell me about a time you pushed back
On-Call & Behavioural
Last question. Tell me about a time you pushed back on a release.
We had a launch date fixed by marketing, and the load test showed the database falling over at about sixty percent of the expected traffic. I didn't just say no. I brought the graph, the error budget, and two options: launch to ten percent of users with a feature flag, or slip two days. They picked the flag. We fixed the query during the ramp, and nobody outside the team ever knew.
Data, options, and no drama. That's the answer. Four out of five. A senior answer would also say what you learned or changed afterwards, so it doesn't happen again.
