- 0-2 years experience. - Roles: Junior DevOps Engineer, DevOps Associate, Infrastructure Engineer. - 70 checklist questions, 30 real interview Q&A, 10 live scenarios, 15 behavioral questions. - Companies: Razorpay, PhonePe, Swiggy, CRED, Freshworks, Juspay.
You are 0-2 years into your DevOps career. You have set up a pipeline, run some Docker containers, and touched a Kubernetes cluster. The junior round tests whether you can operate confidently — debug real problems, explain what you did and why, and handle production situations without panicking. What changes from a college interview to a junior DevOps interview: the questions shift from "what is X" to "you are on a server and X is broken, what do you do." Theory is table stakes. Interviewers want to see that you have actually run commands, made mistakes, and learned from them. This module has three tiers. Every question across Tier 2 and Tier 3 is numbered continuously so you always know exactly where you are. **Tier 1 — Fundamentals Checklist (no answers)** 70 questions across 8 topics: Linux, Git, Docker, Kubernetes, CI/CD, Infrastructure as Code, Networking, and Monitoring. No answers are given. If you cannot answer these from memory, go back to the relevant module and study first. These are the bare minimum every Junior DevOps candidate is expected to know before walking into any interview. Treat this as your readiness gate before Tier 2. **Tier 2 — Real Interview Questions (Q1 to Q30)** 30 questions with full answers — the kind asked at Razorpay, PhonePe, Swiggy, CRED, Freshworks, Juspay, and similar Indian product startups. Covers Linux debugging, Git operations, Docker internals, Kubernetes troubleshooting, CI/CD pipeline design, Terraform, AWS, and observability. Every answer explains what to say, what commands to run, and what makes a strong answer versus a weak one. Topics span every area a junior DevOps engineer is expected to know on day one. **Tier 3 — Scenario Round (Q31 to Q40)** 10 real production scenarios interviewers drop on you to watch how you think — a production outage, broken pipeline, slow deploy, config mistake, missing logs, angry developer, monitoring gap, forgotten credentials, and more. No single correct answer exists. The interviewer is watching how you approach the problem, communicate under pressure, and whether you ask the right questions before jumping to solutions. **Behavioral Round (Q41 to Q55)** 15 behavioral questions with full answers covering how to handle mistakes, things you do not know, disagreements with seniors, asking for help, negative feedback, prioritisation, colleague process violations, and what interviewers are actually evaluating when they ask them. ---
No answers given. If you cannot answer these cold, go back to the relevant module first. These are the floor, not the ceiling. ### Linux * What is the difference between a process and a thread? * How do you check which process is using port 8080? * What does `chmod 755` mean and what do the three digits represent? * What is the difference between a symbolic link and a hard link? * How do you check disk usage on a Linux server? * What does `sudo` do and why does it matter for security? * How do you manage services with `systemctl`? * What is `cron` used for and what does a cron expression look like? * What is the difference between `/etc`, `/var`, `/tmp`, and `/opt`? * How do you check memory usage? What is the difference between free and available? * What does `ps aux` show and what do the columns mean? * How do you follow a log file in real time? * What is a file descriptor and what are stdin, stdout, and stderr? * How does `grep` work and what is a pipe `|` used for? ### Git * What is the difference between `git fetch` and `git pull`? * What is a merge conflict and how do you resolve it? * What is `git stash` used for? * What is the difference between `git reset` and `git revert`? * What is a `.gitignore` file? * What is the difference between `git merge` and `git rebase`? * What is a pull request and what is code review? * How do you undo a commit that has already been pushed? * What is `git cherry-pick`? ### Docker * What is the difference between a Docker image and a Docker container? * What is a Dockerfile and what does each instruction do? * What does `EXPOSE` do in a Dockerfile -- does it actually open a port? * What is Docker Compose used for? * What is the difference between `CMD` and `ENTRYPOINT`? * What is a Docker volume and why do you need one? * What is a Docker registry? * What does `docker build -t myapp:1.0 .` do? * What is a multi-stage Docker build? ### Kubernetes * What is Kubernetes and what problem does it solve over plain Docker? * What is a Pod and why does Kubernetes use pods instead of containers directly? * What is the difference between a Deployment and a Pod? * What is a Service in Kubernetes and why do you need one? * What is a Namespace used for? * What is a ConfigMap and what is a Secret? * What is a readiness probe and what is a liveness probe? * What does `kubectl describe pod` show that `kubectl get pod` does not? * What is a node in Kubernetes? ### CI/CD * What is Continuous Integration and why does it matter? * What is the difference between Continuous Delivery and Continuous Deployment? * What is a pipeline artifact? * What is the difference between a unit test and an integration test? * Name three CI/CD tools and when you would use each. * What does a basic GitHub Actions workflow YAML look like? ### Infrastructure as Code and Cloud * What is Infrastructure as Code and why is it better than manual provisioning? * What is Terraform used for? * What is the difference between `terraform plan` and `terraform apply`? * What is Terraform state? * What is an AWS IAM role and how is it different from a user? * What is a VPC in AWS? * What is a Security Group in AWS? * What is the difference between a public and a private subnet? * What is S3 used for? ### Networking * What is DNS and how does it work at a basic level? * What is the difference between TCP and UDP? * What is a load balancer and what does it do? * What is the difference between HTTP and HTTPS? * What port numbers are used for SSH, HTTP, HTTPS, PostgreSQL? * What is the difference between a private IP and a public IP? ### Monitoring * What is the difference between metrics, logs, and traces? * What is Prometheus used for? * What is Grafana used for? * What is an alert and what makes a good alert vs a noisy one? ---
### Linux and Operating Systems ### 1. You SSH into a production server and the disk is at 99%. Walk me through exactly what you do. First, do not delete anything immediately. Understand what is filling the disk before touching it. ```bash # Step 1 — find which filesystem is full df -h # Step 2 — go to the full partition and find what is consuming space du -sh /* 2>/dev/null | sort -rh | head -20 # Step 3 — narrow down further du -sh /var/log/* | sort -rh | head -10 # Step 4 — check for large log files find /var/log -type f -size +100M # Step 5 — check for deleted files still held open by processes lsof | grep deleted ``` The most common causes are: * Log files that were never rotated — check `/var/log` first * Docker images and stopped containers taking space — run `docker system df` * Application logs writing to `/tmp` or a data directory without cleanup * A process that deleted a file but is still holding the file descriptor open — this is the `lsof | grep deleted` case. The disk space is not freed until the process releases it. Restart that process to reclaim the space. Once you find the cause, clear it safely — rotate logs, prune docker, or restart the process. Never just `rm -rf` until you know what you are deleting. --- ### 2. What is the difference between `kill`, `kill -9`, and `kill -15`? Every `kill` command sends a signal to a process. The number is the signal type. * `kill -15` or just `kill` — sends `SIGTERM`. This is a polite request to stop. The process can catch this signal, finish what it is doing, clean up temporary files, close database connections, and then exit gracefully. This is always the right first choice. * `kill -9` — sends `SIGKILL`. This goes directly to the kernel. The process cannot catch it, ignore it, or clean up. The kernel terminates it immediately. Use this only when `-15` has not worked after a few seconds, because `-9` can leave behind orphaned files, locked database records, or corrupted state. ```bash # Graceful stop first kill -15 <PID> # Wait 5 seconds, check if still running sleep 5 && ps aux | grep <PID> # Force kill only if still alive kill -9 <PID> ``` A good follow-up answer to give unprompted: "After a `-9` on a database process, I would always check for lock files or socket files left behind before restarting the service." --- ### 3. A developer tells you their application deployed fine but is responding very slowly. You have no monitoring. What do you check first? Start at the four common bottlenecks — CPU, memory, disk I/O, and network — then move to the application itself. ```bash # CPU — is any process maxing out a core? top # Press '1' in top to see individual core usage # Memory — is the system swapping? free -h # If swap usage is high, the server is out of RAM and paging to disk — this kills response time # Disk I/O — are reads/writes saturated? iostat -x 1 5 # Network — is there packet loss or high latency? ping <database host> netstat -s | grep retransmit # Application — check logs for errors or slow queries tail -f /var/log/app/error.log # Open connections — is the app running out of connections? netstat -an | grep ESTABLISHED | wc -l ``` The most common causes for slow response after a fresh deploy: * Memory leak in the new code — `free -h` shows swap usage climbing over time * Slow database query introduced in the new version — check slow query logs * New code calling an external API synchronously on every request * The deployment process left the server with only 1 replica running briefly **Key point to make:** "I would not jump to restarting services immediately. I would first capture the state — metrics, logs, connections — because once you restart, the evidence is gone." --- ### 4. What is a zombie process and when does it appear? A zombie process is a process that has finished executing but its entry is still sitting in the process table. It has completed its work but the parent process has not yet called `wait()` to collect its exit status. ```bash # You can see zombie processes in top top # Look for 'Z' in the status column # Or with ps ps aux | grep 'Z' ``` A zombie process consumes no CPU and almost no memory — just a process table slot. The real problem is when a parent process creates thousands of zombies without collecting them, eventually exhausting the process table and preventing new processes from starting. **How to fix it:** * You cannot kill a zombie directly — it is already dead * Send `SIGCHLD` to the parent process to tell it to collect its children * If the parent is misbehaving, kill the parent — orphaned zombie processes are then adopted by `init` (PID 1) which immediately collects them This comes up in interviews for companies running high-concurrency services where poorly written worker processes create this problem at scale. --- ### Git and Version Control ### 5. Your team is using trunk-based development. A developer pushed a broken commit directly to main and the CI pipeline is failing. Three other developers are trying to push their work. What do you do? First, communicate immediately. Post in the team Slack channel that main is broken and ask developers to hold their pushes until it is fixed. Nothing is worse than people trying to merge on top of a broken main. Then fix it: ```bash # Option 1 — Revert the bad commit (safest, preserves history) git log --oneline # find the bad commit hash git revert <commit-hash> # creates a new commit that undoes it git push origin main # Option 2 — If the commit was the very last one and nobody else pulled it git reset --hard HEAD~1 # removes the commit locally git push origin main --force-with-lease # force push safely ``` **Why `--force-with-lease` and not `--force`:** `--force` pushes regardless of what is on the remote. If someone pulled the bad commit in the 30 seconds before you force-pushed, their history now diverges and they get a confusing error. `--force-with-lease` checks that the remote is still in the state you last saw it. If someone else pushed in the meantime, it fails safely and warns you. After fixing, add branch protection rules that require CI to pass before merging. This prevents the same situation from happening again. --- ### 6. What is `git bisect` and when would you actually use it in a real job? `git bisect` is a binary search tool that helps you find which specific commit introduced a bug. Instead of checking every commit manually, it cuts the search space in half each time. Real scenario: Your application was working fine in last week's release. Today's build is broken. There are 200 commits between the two releases. You cannot check each one manually. ```bash # Start bisect git bisect start # Tell git the current state is bad git bisect bad # Tell git the last known good commit (or tag) git bisect good v2.1.0 # Git now checks out a commit in the middle # Test your application — does it work? # If it works: git bisect good # If it does not work: git bisect bad # Git keeps narrowing down until it finds the exact bad commit # Usually takes 7-8 steps to search through 200 commits # When done git bisect reset ``` You can also automate this by giving bisect a test script: ```bash git bisect run ./test-script.sh # Git runs the script on each commit automatically # Script exits 0 for good, non-zero for bad ``` In a real job this is invaluable for regression bugs — where something was working and suddenly stopped working after a series of commits. --- ### Docker and Containers ### 7. You pull your Docker image and run it. The container starts and immediately exits. How do you debug this? When a container exits immediately, the process inside it crashed or finished. Docker does not keep a container running if the main process exits. ```bash # Step 1 — check the exit code and last logs docker ps -a # Look at the STATUS column — shows exit code docker logs <container-id> # This shows stdout/stderr from inside the container before it died # Step 2 — if logs are empty, override the entrypoint to get a shell docker run -it --entrypoint /bin/sh <image-name> # Now you are inside — run your app command manually to see the real error # Step 3 — check if the CMD in the Dockerfile is wrong docker inspect <image-name> | grep -A5 "Cmd" ``` **Common causes:** * The application binary or script does not exist at the path specified in CMD * A required environment variable is missing — app crashes on startup * A config file is not found — app exits with error code 1 * The entrypoint script has a syntax error * Port binding conflict — app tries to bind a port already in use **Key follow-up:** "I always check exit code 1 vs exit code 137. Exit code 137 means the container was killed by the OOM killer — the container ran out of memory. Exit code 1 is usually an application error. They need different fixes." --- ### 8. Your Docker image is 1.2 GB. Your tech lead says it needs to be under 200 MB. How do you reduce it? This is a real task in every serious DevOps role. Here is the step-by-step approach: **Step 1 — Diagnose what is large** ```bash docker history <image-name> # Shows size of each layer dive <image-name> # Tool that shows what files are in each layer ``` **Step 2 — Switch to a minimal base image** ```dockerfile # Before FROM ubuntu:22.04 # 77 MB base + everything you install on top # After FROM alpine:3.18 # 5 MB # Or for compiled apps FROM scratch # literally empty, 0 MB # Or for Java/Python FROM python:3.11-slim # stripped down version ``` **Step 3 — Use multi-stage builds** This is the biggest win. Build in one stage, copy only the output to a clean final stage. ```dockerfile # Stage 1 — build FROM golang:1.21 AS builder WORKDIR /app COPY . . RUN go build -o server . # Stage 2 — run (only 10-15 MB) FROM alpine:latest COPY --from=builder /app/server . CMD ["./server"] ``` The Go compiler (500+ MB) never makes it into the final image. **Step 4 — Clean up in the same RUN layer** ```dockerfile # WRONG — deleted files still exist in the layer below RUN apt-get install -y curl RUN apt-get clean # RIGHT — install and clean in one layer RUN apt-get install -y curl && apt-get clean && rm -rf /var/lib/apt/lists/* ``` **Step 5 — Use `.dockerignore`** ``` node_modules/ .git/ *.log test/ docs/ ``` Combined, these steps regularly bring a 1.2 GB image down to under 100 MB. --- ### 9. What is the difference between `docker stop` and `docker kill`? `docker stop` sends `SIGTERM` to the main process inside the container, waits 10 seconds for it to shut down gracefully, then sends `SIGKILL` if it is still running. This gives the application time to finish in-flight requests, flush buffers, and close database connections. `docker kill` sends `SIGKILL` immediately with no grace period. The process is terminated instantly. ```bash # Graceful — always prefer this docker stop <container> # Adjust the grace period (for slow-starting apps) docker stop --time 30 <container> # Force kill immediately docker kill <container> ``` **Why this matters in production:** If you `docker kill` a container running a database or a payment service, you risk corrupted state, uncommitted transactions, or customers getting double-charged. Always use `docker stop` in production and give enough grace time for the app to drain connections. --- ### Kubernetes ### 10. A pod is in `CrashLoopBackOff`. Walk me through your complete debugging process. `CrashLoopBackOff` means the container is starting, crashing, Kubernetes is trying to restart it, and it keeps crashing. The backoff timer grows exponentially — 10s, 20s, 40s, etc. ```bash # Step 1 — get the full picture kubectl describe pod <pod-name> -n <namespace> # Look at the Events section at the bottom — this tells you WHY it is crashing # Step 2 — get logs from the current crash kubectl logs <pod-name> -n <namespace> # Step 3 — get logs from the previous crash (often more useful) kubectl logs <pod-name> -n <namespace> --previous # The current container may have barely started before crashing # The previous run has the actual error # Step 4 — check if resources are the problem kubectl top pod <pod-name> -n <namespace> # Is the container being OOM-killed? # Step 5 — check events for the namespace kubectl get events -n <namespace> --sort-by='.lastTimestamp' ``` **Common causes and their fixes:** | Symptom in logs | Cause | Fix | |---|---|---| | `Error: cannot find config file` | ConfigMap/Secret not mounted | Check volume mounts | | `OOMKilled` in describe | Memory limit too low | Increase memory limit | | `exec format error` | Wrong architecture image | Rebuild for linux/amd64 | | `Connection refused` to DB | App starts before DB is ready | Add init container or retry logic | | Exit code 1, no logs | CMD is wrong path | Override entrypoint and check | **What to say at the end:** "After fixing the immediate crash, I would look at why we did not catch this in staging. Usually it means a missing environment variable or a secret that exists in prod but not staging." --- ### 11. What is the difference between a Deployment and a StatefulSet in Kubernetes? A **Deployment** is for stateless applications — web servers, APIs, background workers. Every pod is identical. You can kill any pod and replace it with a new one, and the application does not care. Pods get random names like `nginx-7d8f9b-x4k2p`. A **StatefulSet** is for stateful applications — databases, message queues, anything that needs to remember who it is and where its data is. Each pod gets: * A stable, predictable name: `postgres-0`, `postgres-1`, `postgres-2` * Its own persistent volume that follows it — if `postgres-0` is rescheduled to a different node, it reconnects to the same disk * Ordered startup and shutdown — `postgres-0` starts before `postgres-1`, and `postgres-2` is deleted before `postgres-1` ```yaml # Deployment — pods are interchangeable apiVersion: apps/v1 kind: Deployment spec: replicas: 3 # All 3 pods are identical, can be replaced in any order --- # StatefulSet — pods have identity apiVersion: apps/v1 kind: StatefulSet spec: replicas: 3 # postgres-0 is the primary # postgres-1 and postgres-2 are replicas # Each has its own PVC ``` **Real example:** Razorpay's payment service APIs run as Deployments — any pod can handle any request. Their PostgreSQL database runs as a StatefulSet — the primary node must stay the primary, and each replica needs its own data directory. --- ### 12. What happens when you run `kubectl apply -f deployment.yaml`? This is actually a multi-step process that shows how Kubernetes works internally: 1. `kubectl` sends an HTTP PUT/PATCH request to the **API Server** with the YAML content 2. The API Server validates the YAML against the schema and checks your RBAC permissions 3. The API Server stores the desired state in **etcd** — the cluster's database 4. The **Controller Manager** detects that the desired state (3 replicas) does not match the actual state (0 replicas) and creates a ReplicaSet 5. The **Scheduler** watches for new pods with no assigned node and decides which worker node each pod goes to based on resources, taints, and affinities 6. The **kubelet** on each worker node sees new pods assigned to it, pulls the container image, and starts the containers 7. Once running, the pod is registered with the **Service** endpoints and starts receiving traffic The key concept here is **reconciliation** — Kubernetes continuously compares desired state vs actual state and takes action to close the gap. This is why if you delete a pod manually, it comes back — the controller sees the actual count dropped below the desired count and creates a replacement. --- ### CI/CD and Pipelines ### 13. Design a CI/CD pipeline from scratch for a Node.js application that deploys to Kubernetes. What stages do you include and why? A production-grade pipeline should have these stages in order: ``` Code Push → Lint → Unit Tests → Build Image → Scan Image → Push to Registry → Deploy to Staging → Integration Tests → Manual Approval → Deploy to Production → Smoke Tests → Notify ``` **Breaking each stage down:** **Lint** — catch syntax errors and style violations before wasting compute on tests. Takes 10 seconds. Catches 20% of bugs for almost zero cost. **Unit Tests** — fast, isolated, no external dependencies. These should pass in under 2 minutes. If they take longer, split them to run in parallel. **Build Docker Image** — build once, deploy everywhere. Tag with the commit SHA so every build is traceable. ```bash docker build -t myapp:${GIT_SHA} . ``` **Scan Image** — use Trivy or Snyk to scan the image for known CVEs before it ever reaches a registry. Block the pipeline on CRITICAL vulnerabilities. ```bash trivy image --exit-code 1 --severity CRITICAL myapp:${GIT_SHA} ``` **Push to Registry** — only push if all previous steps passed. Tag with both the commit SHA and `latest`. **Deploy to Staging** — update the image tag in the Kubernetes manifest and apply. Use Helm or Kustomize for environment-specific values. **Integration Tests** — test against the real staging environment. Check API endpoints, database connections, third-party integrations. **Manual Approval** — a human reviews the staging deployment before production goes live. This is a gate, not optional. **Deploy to Production** — same process as staging but targeting the production namespace/cluster. **Smoke Tests** — a small set of critical checks that verify production is alive: can the homepage load, can a user log in, is the payment API responding? **Notify** — post to Slack with deployment status, commit author, and link to the pipeline run. **Key point to make in the interview:** "I would also make sure every failed stage posts the failure reason to Slack immediately. Nobody should be checking pipeline status manually — the pipeline should tell you." --- ### 14. Your CI pipeline takes 45 minutes to run. Developers are complaining. How do you speed it up? 45 minutes is far too long for a CI pipeline. Target under 10 minutes. Here is the systematic approach: **Step 1 — Measure where time is going** Look at the pipeline logs and identify the slowest stages. Usually it is one of: dependency installation, test execution, or Docker build. **Step 2 — Cache dependencies** ```yaml # GitHub Actions example - uses: actions/cache@v3 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }} ``` If `package-lock.json` has not changed, `npm install` is skipped entirely. Saves 3-5 minutes. **Step 3 — Parallelize test execution** ```yaml jobs: test: strategy: matrix: shard: [1, 2, 3, 4] steps: - run: npm test -- --shard=${{ matrix.shard }}/4 ``` Run tests in 4 parallel jobs. A 20-minute test suite becomes 5 minutes. **Step 4 — Use Docker layer caching** ```dockerfile # Copy package files first — this layer is cached if deps did not change COPY package.json package-lock.json ./ RUN npm ci # Copy source code last — this layer only rebuilds when code changes COPY . . ``` **Step 5 — Run stages in parallel where possible** Lint and unit tests do not depend on each other. Run them at the same time. **Step 6 — Only run expensive stages on main branch** Integration tests and staging deployment do not need to run on every feature branch push. Run them only on PRs targeting main or on main itself. A well-optimized pipeline for a medium-sized Node.js app should run in 6-8 minutes. --- ### 15. What is a canary deployment and how would you implement one in Kubernetes? A canary deployment sends a small percentage of real production traffic to the new version while the majority continues hitting the stable version. You watch metrics on the canary — error rate, latency, business metrics — and only promote it to 100% if everything looks healthy. **Why it is better than blue/green for risk management:** Blue/green is all or nothing — you switch 100% of traffic instantly. Canary is gradual — if the new version is broken, only 5% of users are affected, and you roll back quickly. **Simple implementation with Kubernetes labels:** ```yaml # Stable deployment — 9 replicas apiVersion: apps/v1 kind: Deployment metadata: name: myapp-stable spec: replicas: 9 selector: matchLabels: app: myapp version: stable --- # Canary deployment — 1 replica (10% of traffic) apiVersion: apps/v1 kind: Deployment metadata: name: myapp-canary spec: replicas: 1 selector: matchLabels: app: myapp version: canary --- # Service selects both — 90/10 split by replica ratio apiVersion: v1 kind: Service spec: selector: app: myapp # matches both stable and canary pods ``` The Service selects all pods with `app: myapp`. With 9 stable pods and 1 canary pod, roughly 10% of requests go to the canary. **Promotion steps:** 1. Watch canary error rate for 30 minutes 2. If error rate is normal → scale canary to 5 replicas, scale stable to 5 3. If still healthy → scale canary to 10, scale stable to 0 4. Delete the canary deployment, the stable deployment now runs the new version 5. If unhealthy at any step → scale canary to 0, scale stable back to 10 --- ### Networking and Troubleshooting ### 16. After deploying a new version of your application, it cannot connect to the database. The database was working fine before. What do you investigate? The key insight is: the database itself is probably fine since it worked before. Something changed in the deploy that broke the connection. Narrow down systematically. ```bash # Step 1 — confirm the DB is actually running kubectl get pods -n database # or systemctl status postgresql # Step 2 — test connectivity from inside the app pod kubectl exec -it <app-pod> -- /bin/sh # Now inside the container: ping <db-hostname> # DNS resolution + basic connectivity nc -zv <db-host> 5432 # TCP connection to specific port telnet <db-host> 5432 # Alternative # Step 3 — check if the hostname/connection string changed kubectl describe pod <app-pod> | grep -A10 "Environment" # Is DB_HOST pointing to the right service name? # Step 4 — check Security Groups or NetworkPolicy # Did the new deployment change the pod labels? # If NetworkPolicy selects by label and the label changed, connection is blocked # Step 5 — check secrets and credentials kubectl get secret db-credentials -o yaml # Was the secret rotated? Does the app have the new credentials? # Step 6 — check connection pool settings # New version might have a lower pool timeout or max connections ``` **The most common causes after a deploy:** * Environment variable `DB_HOST` pointing to old hostname or IP that no longer exists * Pod labels changed, breaking a NetworkPolicy that was allowing traffic * Database credentials in a Secret were rotated but the new version is reading the old ones from an environment variable baked into the image * New version has a stricter SSL configuration — DB requires TLS but new app config disables it --- ### 17. Explain what happens at the network level when a user types `app.company.com` in their browser and your application responds. This covers DNS, TCP, TLS, load balancing, and application routing: 1. **DNS Resolution** — browser checks local cache, then OS cache, then asks the configured DNS resolver (usually ISP or 8.8.8.8). The resolver queries Route 53 (or your DNS provider) for `app.company.com` and gets back an IP address (your load balancer's IP). 2. **TCP Handshake** — browser sends a SYN packet to the load balancer. Load balancer responds with SYN-ACK. Browser sends ACK. Connection established. Three packets, typically under 5ms within the same region. 3. **TLS Handshake** — browser and load balancer negotiate the TLS version, exchange certificates. Browser verifies the certificate is signed by a trusted CA and has not expired. Session keys are derived. All subsequent data is encrypted. This is what the padlock means. 4. **HTTP Request** — browser sends `GET / HTTP/1.1` with headers including `Host: app.company.com`. 5. **Load Balancer Routing** — ALB (in AWS) reads the Host header and path, matches against listener rules, and forwards the request to a healthy target (your EC2 or pod) using its target group health checks. 6. **Application Processing** — your Node.js / Go / Python app receives the request, queries the database if needed, and builds a response. 7. **Response** — travels back through the load balancer to the user. Browser renders the HTML. **Key points that impress interviewers:** * TLS terminates at the load balancer — traffic between ALB and pods is plain HTTP inside the VPC (acceptable for most use cases) * The browser uses HTTP/2 which multiplexes multiple requests over one TCP connection * DNS TTL means the IP is cached — if you change the IP, old users still hit the old one until TTL expires --- ### Terraform and Infrastructure as Code ### 18. What is Terraform state and why is it important? What happens if two people run `terraform apply` at the same time? Terraform state is a file (`terraform.tfstate`) that maps your Terraform configuration to the real resources in AWS (or any cloud). It stores the IDs, attributes, and relationships of every resource Terraform manages. **Why it is critical:** Without state, Terraform does not know what it has already created. If you run `terraform apply` twice without state, it tries to create everything again — duplicate VPCs, duplicate EC2 instances, conflicts. State also tracks resource dependencies — it knows that a subnet must be deleted before the VPC, and that an EC2 must be detached from a security group before the group can be deleted. **The two-people-at-the-same-time problem:** If both people run `terraform apply` simultaneously with local state, they each have their own state file. Person A creates a resource, Person B's state does not know about it. Person B's apply now conflicts with reality. Infrastructure drift happens silently. **The solution — remote state with locking:** ```hcl terraform { backend "s3" { bucket = "company-terraform-state" key = "prod/vpc/terraform.tfstate" region = "ap-south-1" dynamodb_table = "terraform-state-lock" encrypt = true } } ``` * State is stored in S3 — one shared source of truth for the whole team * DynamoDB table provides **state locking** — when Person A runs `terraform apply`, a lock is written to DynamoDB. Person B's apply sees the lock and either waits or fails with a message saying "state is locked by Person A" * `encrypt = true` ensures the state file (which can contain passwords and secrets) is encrypted at rest **Important warning:** State files often contain sensitive values like database passwords. Never commit `terraform.tfstate` to Git. Always use remote state. --- ### 19. What is the difference between `terraform plan` and `terraform apply`? Why should you always run plan before apply? `terraform plan` is a dry run. It reads your configuration, compares it to the current state, and shows you exactly what it will create, modify, or destroy — without touching anything. It outputs a human-readable diff. `terraform apply` actually makes the changes to your infrastructure. ```bash # Always run plan first terraform plan -out=tfplan.out # Review the output carefully # Then apply the saved plan terraform apply tfplan.out # This applies exactly what you reviewed — no surprises ``` **Why `-out=tfplan.out` matters:** If you run `terraform plan`, review it, then run `terraform apply` without saving the plan, Terraform runs a fresh plan at apply time. If someone else changed the infrastructure in the 2 minutes between your plan and apply, you might apply something different from what you reviewed. Saving the plan and applying that exact plan file guarantees what you reviewed is what runs. **What to look for in plan output:** ``` # aws_security_group.web will be updated in-place ~ resource "aws_security_group" "web" { + ingress { + from_port = 22 + cidr_blocks = ["0.0.0.0/0"] # <-- this should alarm you } } ``` A junior DevOps engineer should be able to read plan output and spot dangerous changes — especially anything involving `destroy` (shown as `-`) on databases or security groups being opened to `0.0.0.0/0`. --- ### AWS and Cloud ### 20. What is the difference between a Security Group and a NACL in AWS? When would you use each? Both control traffic but at different levels and with different behaviour: **Security Group:** * Operates at the **instance level** (attached to EC2, RDS, Lambda, etc.) * **Stateful** — if you allow inbound traffic on port 80, the response is automatically allowed outbound. You do not need a separate outbound rule. * **Allow rules only** — you cannot explicitly deny traffic. Everything not allowed is implicitly denied. * Rules reference IP ranges OR other Security Groups by ID **NACL (Network Access Control List):** * Operates at the **subnet level** — applies to all resources in that subnet * **Stateless** — you must explicitly allow both inbound AND outbound traffic, including ephemeral ports (1024-65535) for responses * Supports **both allow and deny rules** * Rules are evaluated in number order — lower number wins ``` Security Group use case: "Allow port 443 from the internet to my web servers" "Allow port 5432 only from my application Security Group to my database" NACL use case: "Block all traffic from IP 1.2.3.4 — this IP is attacking us" Security Groups cannot explicitly deny, so you need NACL for this ``` **The exam question that trips people up:** A security group allows inbound SSH (port 22). A NACL on the subnet denies port 22. What happens? The NACL wins — it is evaluated first at the subnet boundary before the traffic even reaches the instance. --- ### 21. You are asked to set up an EC2 instance that can read from an S3 bucket. How do you do it securely? **Never use access keys on an EC2 instance.** Access keys stored on a server are a credential leak waiting to happen — a compromised instance means the attacker gets permanent access to your AWS account. **The correct approach — IAM Instance Role:** ```bash # Step 1 — Create an IAM Role with a trust policy for EC2 { "Effect": "Allow", "Principal": { "Service": "ec2.amazonaws.com" }, "Action": "sts:AssumeRole" } # Step 2 — Attach a least-privilege policy to the role { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:ListBucket" ], "Resource": [ "arn:aws:s3:::company-data-bucket", "arn:aws:s3:::company-data-bucket/*" ] } # Step 3 — Attach the role to the EC2 instance at launch # or add it to a running instance: Actions → Security → Modify IAM Role ``` Now the EC2 instance automatically gets temporary credentials from the instance metadata service. The AWS SDK on the instance discovers these credentials automatically — no configuration needed in your application code. **The credentials rotate every few hours automatically.** Even if an attacker gets the credentials from the instance metadata, they expire quickly. This is fundamentally safer than long-lived access keys. **Follow-up point to make:** "I would also block access to the instance metadata service from the application code itself using IMDSv2, which requires a session token and prevents SSRF attacks from reading your credentials." --- ### 22. What is the difference between horizontal scaling and vertical scaling? Which does AWS prefer and why? **Vertical scaling (Scale Up)** — make the existing server bigger. Upgrade from `t3.medium` (2 vCPU, 4 GB RAM) to `c5.4xlarge` (16 vCPU, 32 GB RAM). Simple but has limits — there is a maximum instance size, requires downtime to resize, and is a single point of failure. **Horizontal scaling (Scale Out)** — add more servers of the same size. Run 10 `t3.medium` instances instead of one `c5.4xlarge`. More complex (need load balancer, stateless application design) but has no ceiling — you can keep adding instances. **Why AWS is designed for horizontal scaling:** AWS's core services are built around horizontal scaling: * **Auto Scaling Groups** — automatically add/remove EC2 instances based on CPU, memory, or custom metrics * **Elastic Load Balancer** — distributes traffic across multiple instances * **RDS Read Replicas** — add more read capacity by adding replicas * **DynamoDB** — scales horizontally by adding partitions automatically **Real example from an Indian company:** Swiggy during Diwali sale. Their order volume increases 10x in an hour. With vertical scaling they would need to pre-provision the largest possible instance and pay for it year-round. With horizontal scaling, Auto Scaling adds instances when load increases and removes them when load drops. They pay for capacity only when they need it. **When vertical scaling still makes sense:** Databases that are hard to shard, legacy monolithic apps that cannot run multiple instances, or single-threaded workloads that benefit from a faster CPU more than more CPUs. --- ### Security ### 23. A developer accidentally committed an AWS access key to a public GitHub repository. You get an alert 5 minutes later. What do you do? This is a security incident. Move fast but in the right order. **Immediate actions (first 5 minutes):** ```bash # Step 1 — Disable the key immediately in AWS Console or CLI aws iam update-access-key \ --access-key-id AKIAIOSFODNN7EXAMPLE \ --status Inactive \ --user-name developer-name # Do this BEFORE doing anything else # An active key exposed publicly can be found by scanners within 60 seconds ``` **Step 2 — Investigate what happened with the key** ```bash # Check CloudTrail for API calls made with this key aws cloudtrail lookup-events \ --lookup-attributes AttributeKey=AccessKeyId,AttributeValue=AKIAIOSFODNN7EXAMPLE \ --start-time "2024-01-15T00:00:00Z" ``` Look for: new IAM users created, EC2 instances launched, S3 buckets accessed or created, data exfiltration (large downloads). **Step 3 — Rotate the key** Disabling is temporary. Generate a new key, update all systems using the old key, then delete the old key permanently. **Step 4 — Remove from GitHub (but this does not make it safe)** ```bash git filter-branch or git-secrets or BFG Repo Cleaner ``` **Important:** Even after removing from GitHub history, assume the key was seen. GitHub's API scanners and malicious bots index public repositories in real time. A key that was public for 5 minutes should be treated as fully compromised. **Step 5 — Post-incident** * Enable AWS Config rule to detect committed credentials * Add pre-commit hooks using `detect-secrets` or `git-secrets` to all developer machines * Enable GitHub secret scanning alerts * Add branch protection that blocks pushes containing key patterns --- ### 24. What is the principle of least privilege and how do you apply it in a real DevOps environment? Least privilege means giving a user, service, or system only the exact permissions it needs to do its specific job — nothing more. **Why it matters:** If an application with broad permissions is compromised, the attacker has broad permissions. If it has narrow permissions, the blast radius is contained. **How it applies in practice:** **For IAM roles:** ```json // BAD — application can do anything in S3 { "Effect": "Allow", "Action": "s3:*", "Resource": "*" } // GOOD — application can only read from one specific bucket { "Effect": "Allow", "Action": ["s3:GetObject", "s3:ListBucket"], "Resource": [ "arn:aws:s3:::payment-receipts-bucket", "arn:aws:s3:::payment-receipts-bucket/*" ] } ``` **For Kubernetes:** ```yaml # RBAC — give a service account only what it needs apiVersion: rbac.authorization.k8s.io/v1 kind: Role rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list"] # can read pods but not delete or create ``` **For Linux:** ```bash # Application runs as a dedicated non-root user useradd -r -s /bin/false appuser # Not as root, not as your personal user ``` **For CI/CD:** Your CI pipeline needs to push Docker images to ECR and deploy to Kubernetes. Give it exactly those two permissions, scoped to exactly those resources. Not admin access because it is "easier". **Common mistake juniors make:** Giving `AdministratorAccess` to everything because it "works" and planning to restrict it later. Later never comes. --- ### Monitoring and Observability ### 25. What is the difference between metrics, logs, and traces? Why do you need all three? These are the three pillars of observability. Each tells you something different about your system. **Metrics** — numeric measurements over time. CPU is at 78%. Request count is 1,200/second. Error rate is 0.2%. * What they are good for: seeing trends, triggering alerts, dashboards * What they cannot tell you: why the error rate jumped — just that it did **Logs** — text records of discrete events. `ERROR: payment failed for user 1234, reason: timeout after 30s` * What they are good for: debugging specific failures, audit trails * What they cannot tell you: how this request related to other requests in a chain **Traces** — records of a single request as it travels through multiple services. A payment request goes from API → order service → payment service → bank API → notification service. * What they are good for: understanding end-to-end latency, finding which service in a chain is slow * What they cannot tell you on their own: whether this slowness is a pattern or a one-off **Why you need all three:** Scenario: Users are reporting that payments are slow. * **Metrics** tell you: yes, P99 latency on the payment endpoint jumped from 200ms to 3s at 14:32 * **Logs** tell you: errors show `bank API timeout` repeated hundreds of times * **Traces** show you: the bank API call is taking 2.8s, but your own services are fine — the problem is the upstream bank Without traces, you might spend hours optimizing your own code when the problem is entirely external. Without metrics, you would not have been alerted in the first place. Without logs, you would not know the specific error. **Tools:** Prometheus (metrics), Loki or ELK (logs), Jaeger or Zipkin (traces). Many teams use Grafana as the unified frontend for all three. --- ### 26. You set up a Prometheus alert for when CPU exceeds 80%. You come in Monday morning to 200 alert notifications from the weekend. How do you fix the alerting? This is alert fatigue — too many notifications means engineers stop paying attention to alerts, including real ones. The solution is not to raise the threshold but to make alerts more meaningful. **Fix 1 — Add duration to the alert** ```yaml # Bad — fires every time CPU crosses 80% even for 1 second - alert: HighCPU expr: cpu_usage > 0.80 # Good — fires only if CPU stays above 80% for 5 minutes continuously - alert: HighCPU expr: cpu_usage > 0.80 for: 5m ``` Transient spikes are normal. Sustained high CPU is a problem. **Fix 2 — Group alerts with AlertManager** ```yaml # AlertManager config route: group_by: ['alertname', 'cluster'] group_wait: 30s # wait 30s before sending first notification (group more alerts) group_interval: 5m # send grouped updates every 5 minutes repeat_interval: 4h # do not re-notify about the same alert for 4 hours ``` 200 alerts become 1 grouped notification. **Fix 3 — Use inhibition rules** If the entire cluster is down, suppress individual service alerts. The root cause alert is enough. **Fix 4 — Set different severity levels** * P1/Critical → PagerDuty, wake someone up at 3am * P2/Warning → Slack alert during business hours * P3/Info → Daily digest only Not every alert deserves to wake someone up at 3am. **Fix 5 — Question whether the alert is useful** Ask: "What action does an engineer take when they see this alert?" If the answer is "usually nothing" or "check if it resolved itself", the alert should not exist. --- ### Scenario Round ### 27. It is 2 PM on a Friday. Swiggy is running a 50% cashback promotion. Order volume is 5x normal. Your monitoring shows response times climbing. What do you do in the next 10 minutes? **0-2 minutes: Assess and communicate** Post in the on-call channel immediately: > "Response times elevated on order service. P99 at 4.2s vs normal 400ms. Investigating. Do not push anything to production until further notice." This is critical — if someone pushes a deploy right now and it makes things worse, you need to know about it. **2-5 minutes: Identify the bottleneck** ```bash # Is it compute? kubectl top pods -n production # Is it the database? # Check your DB monitoring — connections, query times # Is it an external dependency? # Check your payment gateway latency, notification service ``` Look at your distributed traces. The trace will show you which service in the chain is the slow one. **5-7 minutes: Apply immediate relief** If it is CPU — scale up the deployment: ```bash kubectl scale deployment order-service --replicas=20 ``` If it is database connections — check connection pool, restart if pool is exhausted. If it is an external API — can you implement a fallback? Can you cache responses? **7-10 minutes: Verify and monitor** Watch the graphs. Are response times coming down? Update stakeholders in Slack. **After it stabilizes:** Write a brief incident timeline. Do a proper postmortem on Monday. The 5x traffic was predicted (it was a planned promotion) — why was there no auto-scaling policy configured to handle it? **Key point:** "I would not start pushing fixes to production during an active incident unless a rollback. Every change during an incident is another potential cause of the incident." --- ### 28. You join a new company as a Junior DevOps. On day three, your manager asks you to reduce the AWS bill by 30% without breaking anything. Where do you start? Start by understanding before cutting. Cutting randomly breaks things. **Week 1 — Understand the bill** ```bash # Enable Cost Explorer in AWS Console # Group by Service to see what is costing most # Group by Tag to see which team or project # Enable resource-level granularity ``` Typically the top three cost drivers are: EC2 instances, NAT Gateway, and RDS. **Quick wins (low risk, high savings):** **Stop idle instances outside business hours:** Dev and staging environments should not run 24/7. Schedule them to shut down at 8 PM and start at 8 AM on weekdays. Saves 65% on those instances. ```bash aws ec2 stop-instances --instance-ids i-xxxxx # Or use AWS Instance Scheduler ``` **Delete unused resources:** ```bash # Find unattached EBS volumes (you pay for storage even if not attached) aws ec2 describe-volumes --filters Name=status,Values=available # Find unused Elastic IPs (charged when not attached) aws ec2 describe-addresses --filters Name=association-id,Values=null # Find old snapshots nobody is using aws ec2 describe-snapshots --owner-ids self ``` **Right-size EC2 instances:** Use AWS Compute Optimizer. It analyzes actual CPU and memory usage and recommends smaller instance types. A t3.xlarge running at 5% CPU should be a t3.small. **Review NAT Gateway costs:** If EC2 instances are downloading S3 data through NAT Gateway, set up a VPC Endpoint for S3 — it is free and removes the NAT Gateway charge. **Medium-term savings:** Purchase Reserved Instances or Savings Plans for instances that run 24/7. Saves 30-40% vs on-demand. **Report to manager:** Show a before/after dashboard with actual savings per action. Attribute each saving to a specific change so you can justify it. --- ### 29. You are asked to migrate a monolithic application running on a single large EC2 instance to containers on Kubernetes. The application has never been containerized. Where do you start and what risks do you address? **Start with understanding, not containerizing:** Before writing a single Dockerfile, spend a week on discovery: * How does the application start? What process does it run? * What ports does it listen on? * What files does it write to disk? (Containers are ephemeral — this is a major issue) * What environment variables or config files does it need? * What external services does it connect to? (Database, cache, APIs) * How is it deployed today? Shell scripts? Manual? * What are the runtime dependencies? What OS packages does it need? **The three biggest risks in this migration:** **Risk 1 — Stateful files** The monolith probably writes logs, uploads, temp files, or config to local disk. In a container, these disappear when the container stops. Fix: Identify every file write. Move logs to stdout (so Docker captures them). Move uploads to S3. Move config to environment variables or ConfigMaps. **Risk 2 — The application was never designed to run as multiple instances** Kubernetes runs multiple replicas. If the app stores session data in local memory, user A logs in on pod 1, their next request goes to pod 2, and they are logged out. Fix: Move session storage to Redis. Use sticky sessions as a temporary bridge. **Risk 3 — The big-bang migration** Containerizing and moving to Kubernetes at the same time as moving to production is too many changes at once. Fix: Containerize the app and run it on EC2 first. Validate it behaves identically. Then move to Kubernetes. Decouple the changes. **Migration steps:** 1. Write Dockerfile, test locally — does the app start and behave the same? 2. Deploy containerized version behind a feature flag or on a separate test domain 3. Run old and new in parallel and compare responses 4. Shift 5% of traffic to the new version (canary) 5. Monitor for 48 hours 6. Gradually shift 100% traffic 7. Decommission old EC2 only after 2 weeks of stable running on containers --- ### 30. Your company's senior DevOps engineer resigned yesterday. You are inheriting their work. The documentation is poor. How do you get up to speed without breaking production? This is a governance and risk management challenge more than a technical one. **First 48 hours — stop, do not touch:** Do not change anything yet. Production is running. Your first job is to understand it, not improve it. ```bash # Map what exists aws ec2 describe-instances kubectl get all --all-namespaces terraform state list # Document everything you find, even if it seems obvious ``` **Find the critical systems:** Ask the developer team: what breaks first if something goes wrong? That is your priority for understanding. Identify: * How is production deployed? What triggers a deployment? * Where are secrets stored? (AWS Secrets Manager? GitLab CI variables? Someone's laptop?) * What are the on-call procedures? Are there runbooks? * What monitoring exists? Where are the dashboards? * Is there a disaster recovery plan? **Get access:** Make sure you have access to every system before you need it under pressure. The worst time to discover you cannot log into the cloud console is during an incident at 2 AM. **Make changes only through version control:** Every infrastructure change goes through a PR, even small ones. This creates a record of what you changed and when — so if something breaks, you can identify your change as a potential cause. **Create a handover document as you learn:** Write down what you discover as you discover it. Your documentation will be better than what you inherited, and future engineers will thank you. **Key point to make:** "I would communicate clearly to my manager that I need two to three weeks of observation time before taking on changes. Making changes to a system you do not fully understand is how incidents happen. Understanding first is not slowness — it is professionalism." ---
These are live problems interviewers put in front of you and watch how you think. There is no single correct answer. They are evaluating your approach, your communication, and whether you ask the right clarifying questions before jumping to solutions. ### Q31. Scenario - Production is Down at 11 PM You are on-call. At 11 PM you get a message in Slack: "The checkout page is not loading for users. Orders are failing." You have access to the server, the CI/CD pipeline, and basic monitoring. Walk me through the next 10 minutes. The first thing you do is not SSH into the server. The first thing you do is acknowledge in the channel: "On it. Investigating now." This keeps stakeholders from wondering if anyone is looking. Then establish what you know. Did something deploy recently? Check the pipeline for the last deployment. A deployment 20 minutes ago that coincides with the reports is your primary suspect until proven otherwise. ```bash # What changed recently? git log --oneline -10 # Is the application process even running? systemctl status app-service # or for containers: docker ps kubectl get pods -n production ``` If a recent deployment exists, your first action is to roll it back rather than debug forward. Restoring service is more important than understanding the cause. ```bash # Kubernetes rollback kubectl rollout undo deployment/checkout-service # Watch it recover kubectl rollout status deployment/checkout-service ``` If no recent deployment, check the basics in order: is the process running, is the database reachable, is disk full, is memory exhausted. ```bash # Can the app reach the database? curl -v http://checkout-service/health # Quick resource check free -h && df -h && top -bn1 | head -20 ``` Throughout: post an update in the channel every 5 minutes even if you have not found anything yet. "Still investigating — no obvious deployment correlation, checking infrastructure now." Silence during an incident is worse than bad news. After resolution: write a short incident note — what happened, what was the impact, what was the fix, what you will do to prevent it. Even two paragraphs. This is what separates engineers who grow from those who stay at the same level. --- ### Q32. Scenario - You Broke Staging You ran `kubectl delete namespace staging` by mistake instead of `kubectl delete namespace feature-test`. The entire staging environment is gone. Your team uses staging for QA before every production deployment. There is a production release scheduled in 4 hours. Do not panic and do not hide it. Tell your manager immediately: "I accidentally deleted the staging namespace. I am working on restoring it now. The 4-hour release window may be affected." Then assess what you have. Is your infrastructure in Terraform or Kubernetes manifests in Git? If yes, you can rebuild: ```bash # Recreate the namespace kubectl create namespace staging # Re-apply all manifests from Git kubectl apply -f k8s/staging/ --namespace staging # Or with Helm helm upgrade --install app ./charts/app -f values-staging.yaml -n staging ``` If the infrastructure is not in code and was built manually, you have a harder problem. You will need to recreate it by memory or from documentation. While rebuilding, communicate the timeline honestly. "I can have staging back in approximately 90 minutes. The 4 PM release is still possible if QA can run in 2 hours." Do not promise times you cannot hit. What you should say in the interview unprompted: "After this I would add a confirmation prompt or alias that prevents namespace deletion without explicitly typing the full name. I would also ensure all infrastructure is in Git so any environment can be rebuilt in minutes." The interviewer is not evaluating whether you made a mistake — everyone does. They are evaluating whether you communicate immediately, take ownership, and have a plan. --- ### Q33. Scenario - The New Job First Week You joined a startup three days ago as a Junior DevOps. The senior engineer who hired you resigned on your second day. You are now the only person who touches infrastructure. Production is running. You have no documentation. Your manager says "just keep things running and don't break anything." Your first priority is not making things better. It is understanding what exists. Week 1: build a map. What services are running, where, and how. ```bash # What EC2 instances exist? aws ec2 describe-instances --query 'Reservations[*].Instances[*].[InstanceId,State.Name,Tags[?Key==`Name`].Value|[0]]' --output table # What Kubernetes workloads are running? kubectl get deployments --all-namespaces kubectl get services --all-namespaces # What does the CI/CD look like? # Find the pipeline config files — .github/workflows/, .gitlab-ci.yml, Jenkinsfile ``` Write down everything you find. A simple spreadsheet: service name, where it runs, what it does, who uses it. This becomes your documentation. Week 1, do not touch production. Do not optimise anything. Do not migrate anything. Your only goal is to understand and document. Week 2: identify the single highest-risk thing — the thing most likely to break and most painful if it does. That becomes your first improvement. Not a full modernisation — one specific risk reduced. What you tell the manager at end of week 1: "Here is what I have found. Here are the three things I think are the biggest risks. I want to fix X first because it is most likely to cause an outage. Can we discuss?" This answer shows maturity. Junior engineers try to fix everything at once and break things. Smart junior engineers understand the system before touching it. ### Q34. Scenario - The Broken Pipeline You pushed a code change and the CI pipeline is now failing for the entire team. Nobody can merge. Three developers are blocked. Your senior is in a meeting. What do you do? First, own it publicly and immediately. Post in the team Slack: "I think my last push broke the pipeline. Investigating now. Sorry for the block." Do not wait until you have a fix. Check the pipeline error output. Is it a syntax error in your code, a failing test, or did you accidentally change a shared config file like the pipeline YAML itself? If it is your code: fix it and push. If you cannot fix it in under 10 minutes, revert your change so the team is unblocked. ```bash git revert HEAD git push origin your-branch ``` After it is fixed, tell the team in one line what caused it and that it is resolved. --- ### Q35. Scenario - The Slow Deploy A deployment that normally takes 5 minutes is now taking 45 minutes. It has not failed — it is just very slow. Your tech lead asks you to look into it. What do you check? Start with what changed. A deploy that was fast last week and slow today almost always has a specific cause. Check the pipeline step timings — GitHub Actions shows per-step duration. Which specific step is taking 40 of the 45 minutes? The most common causes: a new `RUN apt-get install` line in the Dockerfile without caching, dependency installation downloading everything from scratch because the cache key changed, or a new test suite running hundreds of integration tests. Once you identify which step is slow, the fix is usually: add caching, fix the Dockerfile layer order, or move slow tests to a separate pipeline stage. What you tell your tech lead: "The Docker build step went from 2 minutes to 38 minutes. A new install command was added without layer caching. I can fix it in 15 minutes by restructuring the Dockerfile." --- ### Q36. Scenario - The Config Mistake You updated a ConfigMap in production to fix a bug. The change worked. Two hours later your colleague points out that the ConfigMap change was never made in Git. It only exists in the live cluster. What do you do? Fix it immediately before anyone deploys — the next deployment will overwrite your manual change and the bug will come back. ```bash # Export the current ConfigMap to see exactly what you changed kubectl get configmap app-config -n production -o yaml > current-config.yaml ``` Open the corresponding file in Git, apply the same change, and raise a PR. Clear title: "Fix: sync production ConfigMap change made manually." What you tell your colleague: "You are right, I should have updated Git first. Raising a PR now to sync it." No excuses — just fix it. --- ### Q37. Scenario - The Missing Logs A production error was reported by a user 3 hours ago. You go to check the logs and find a 2.5 hour gap — logs exist before and after but nothing during that window. What happened and how do you investigate? A log gap usually means the logging agent stopped and restarted, the pod restarted and logs were lost, or log storage had an issue. ```bash # Was the pod restarted during that window? kubectl describe pod <pod-name> -n production | grep -i restart kubectl get events -n production --sort-by='.lastTimestamp' # Get logs from the previous container run if still available kubectl logs <pod-name> -n production --previous ``` If the pod was OOMKilled during that window, logs before the restart are gone unless your logging agent shipped them before it died. What you report: "The pod was OOMKilled at 2:15 PM. Logs from that window were not shipped before the restart. I have added a memory alert so this gets caught before it becomes a user-visible problem next time." --- ### Q38. Scenario - The Angry Developer A developer comes to you frustrated. "Every time I try to deploy, the pipeline fails on the linting step. I have been trying for two hours." What do you do? Do not immediately try to solve the technical problem. Start with "Show me the error output." Look at the actual lint failure — is it real code issue, a misconfigured rule, or a broken tool? If it is real code: explain what the rule checks for, show them the specific line, help them understand the fix. If it is a misconfigured rule blocking valid code: that is a platform problem. Acknowledge it immediately — "This rule is wrong for this case. Let me fix it." Do not make the developer feel like they did something wrong when the tooling is broken. After it is resolved, follow up: "All sorted — the issue was X. Let me know if you hit anything else." People remember when you followed up. --- ### Q39. Scenario - The Monitoring Gap Your manager tells you a production service had a 20-minute outage last Tuesday. You check your monitoring — zero alerts fired during that window. How do you figure out what went wrong and fix it? Two things failed: the service went down, and monitoring did not catch it. Focus on the second. Check if an alert rule even existed for this service: ```bash curl http://prometheus:9090/api/v1/rules | jq '.data.groups[].rules[].name' ``` If no rule existed, add one. A basic availability alert: ```yaml - alert: ServiceDown expr: up{job="your-service"} == 0 for: 2m labels: severity: critical ``` If a rule existed but did not fire, the threshold was wrong — maybe alerting on HTTP errors but the service was returning zero requests, not error responses. What you tell your manager: "No alert rule was configured for this failure mode. I have added one that fires within 2 minutes if the service becomes unreachable. I am also auditing other services for similar gaps." --- ### Q40. Scenario - The Forgotten Credential You need to connect to a production database to investigate a data issue. The credentials in AWS Secrets Manager do not work. The engineer who set it up is on leave. What do you do? Do not guess passwords. Do not hardcode a new one. Work through the proper process. Check if there are multiple versions of the secret — maybe it was recently rotated and the stored version is stale: ```bash aws secretsmanager list-secret-version-ids --secret-id prod/db/credentials ``` Check if the application itself is connecting fine. If the app is running normally, the Secrets Manager entry may just be out of date documentation — the app might be reading from a different path. If the secret is genuinely wrong and you need to reset it: tell your manager before doing it. Resetting a production database password affects every application using it. This is not a solo decision. What you do not do: ask someone to share the password over Slack or email.
15 behavioral questions with full answers covering how to handle mistakes, things you do not know, disagreements with seniors, asking for help, negative feedback, prioritisation, colleague process violations, and what interviewers are actually evaluating when they ask them. Q41. Tell me about a project you built that you are proud of. What did you learn from it? Pick something real - a home lab, a college project, a side project, an internship task. The interviewer does not care how impressive it is. They care that you can describe it clearly, explain what you decided and why, and articulate what you learned. Good structure: what the project was in one sentence, what technical decisions you made and why, what went wrong, and what you would do differently. The "what went wrong" part is important - candidates who say everything went perfectly are not believable. Example: "I built a monitoring dashboard for our college server room using Prometheus and Grafana. I made the mistake of alerting on every metric I could find - within a week I had 200 alerts firing constantly and nobody was looking at them anymore. I learned that alerting on outcomes matters more than alerting on every data point. I rebuilt it with five alerts that actually needed action and the team started responding again." Q42. You do not know how to do something your manager asks. What do you do? The wrong answer is to say yes and quietly struggle for three days without asking for help. The right answer: tell them you have not done this before and ask if there is documentation, a runbook, or a colleague who has done it you can talk to. Give a realistic estimate of how long it might take you to figure it out. If you are stuck after a reasonable effort - maybe 2 hours - ask for help rather than block the work. What interviewers are looking for: honesty about your limits, a plan for how you learn, and the judgment to know when to ask for help versus when to keep trying. Q43. Tell me about a time you made a mistake at work or in a project. What happened? Every engineer makes mistakes. Interviewers ask this to see if you take ownership, learn from errors, and do not repeat them. Bad answer: deflecting ("the system was confusing"), minimising ("it was not really a big deal"), or claiming you have never made a significant mistake. Good answer structure: what you did, what the impact was, what you did immediately to fix it, and specifically what you changed in your process afterward. The change you made is the most important part - it shows you learned from it. Example: "I ran a database migration script on the production database instead of staging because the connection strings in the config file were confusing. No data was lost but the migration ran twice and I had to manually clean up duplicate records. After that I added a prompt in every migration script that prints the database name and asks you to type it to confirm before running. I also added a rule that all connection strings must have the environment name explicitly in the variable name." Q44. How do you handle working on something you do not fully understand yet? This is a reality check question. DevOps covers a huge surface area. Nobody knows everything. Good answer: break the problem into the part you understand and the part you do not. Start with documentation and official guides. Build a small test in a safe environment (local, sandbox, staging) before touching production. Ask a specific question rather than a vague one - "I am trying to configure the readiness probe for this service. The probe is returning 503 but the app is running. Here is the config I have. Does anything look wrong?" is a question someone can help with. "I do not understand readiness probes" is not. Q45. You disagree with how a senior engineer wants to do something. What do you do? You do not just stay silent and do it their way. You also do not argue in a meeting and make it personal. The right approach: ask questions first. "I wanted to understand your thinking on X - I was wondering about Y approach because of Z. Is there a reason you prefer this way?" Sometimes you will learn they are right and you were missing context. Sometimes they will change their mind when they hear your point. Either way the conversation is productive. If they still want to do it their way after the conversation, do it their way - unless it is a genuine safety or security issue. One disagreement is not worth damaging the relationship. Document your concern briefly in the PR or ticket comment so it is on record. Q46. Tell me about a time you had to learn something new quickly. Be specific about how you actually learned it - documentation first, then a small working example, then integration into the real problem. Describe what you found difficult and how you got past it, not just that you "read the docs." Example: "I had never touched Terraform before joining a project that used it everywhere. I spent one evening working through the official Terraform tutorial, then rebuilt one small existing resource in a sandbox account to see how state worked in practice. Within two days I could read and modify existing modules confidently, even though I would not have called myself an expert." Q47. Why do you want to work in DevOps specifically? Honest answers work better than rehearsed ones. If you find the intersection of software and infrastructure interesting, say that. What does not work: "it pays well" or vague answers that suggest you wanted any technical role and DevOps was just available. Q48. How do you prioritise when you have multiple things to do at once? Production issues first. Then things blocking other people. Then your own planned work. If you have more than you can handle, tell your manager which to deprioritise rather than silently dropping things and hoping nobody notices. Q49. Tell me about something in DevOps you are currently learning. Have a real answer. "I have been setting up a home lab with Kubernetes on a VPS to understand how pod scheduling works" is better than "I keep up with industry trends" - specificity is what makes an answer believable. Q50. Where do you want to be in two years? A strong answer describes wanting a solid foundation across the core DevOps stack, owning a production system end-to-end, and being comfortable debugging production issues independently - concrete skill and ownership growth, not just a title change. Q51. Tell me about a time you had to ask for help. What stopped you from asking sooner? The honest answer is usually pride or not knowing how to frame the question specifically. What interviewers want to hear is that you now have a rule for yourself: if stuck for more than 30 minutes on the same problem, ask - but come with a specific question, what you have already tried, and your current hypothesis, rather than just "it's not working." Q52. How do you handle getting negative feedback on your work? Feedback on work you care about stings a little and that is normal. What matters is what you do with it. You listen without getting defensive, ask clarifying questions if the feedback is vague, and act on the specific things that are valid. The code is not you - it is a thing you made that can be improved. Q53. You notice a colleague pushing directly to main instead of creating PRs. What do you do? Talk to them directly, not to your manager first. "I noticed a few direct pushes to main - is something making the PR process difficult?" This gives them the benefit of the doubt and opens a conversation instead of starting with an accusation. If it continues after the conversation, involve your tech lead as a process problem to solve, not a complaint about a person. Q54. What do you do when you disagree with a decision that has already been made? Express your disagreement once, clearly and specifically. Then commit to executing the decision fully. Half-hearted implementation is the worst outcome - it produces bad results and damages trust, without even having the honesty of an open disagreement. Q55. Tell me about a time you made someone else's job easier. The best answers are small and specific. You noticed a colleague ran the same command every morning and wrote a one-line script for it. You updated a README because you got confused by it and knew the next person would too. You added a comment to a tricky section of code that you wished had been there when you were reading it. Saving someone 10 minutes a day is worth more over a year than one dramatic fix.
Company Type Range Early-stage startup Rs 4L - Rs 8L Mid-stage product startup Rs 7L - Rs 12L Large product company (Swiggy, Razorpay tier) Rs 10L - Rs 16L Service/IT company Rs 3.5L - Rs 7L These numbers assume you can answer questions in Tier 2 confidently with real examples from projects, internships, or labs. Candidates who answer only conceptually, with no hands-on examples, land at the lower end of each range.
You are 0-2 years into your DevOps career. You have set up a pipeline, run some Docker containers, and touched a Kuberne...
No answers given. If you cannot answer these cold, go back to the relevant module first. These are the floor, not the ce...
Linux and Operating Systems 1. You SSH into a production server and the disk is at 99%. Walk me through exactly what you...
These are live problems interviewers put in front of you and watch how you think. There is no single correct answer. The...
15 behavioral questions with full answers covering how to handle mistakes, things you do not know, disagreements with se...
Company Type Range Early-stage startup Rs 4L - Rs 8L Mid-stage product startup Rs 7L - Rs 12L Large product company (Swi...
Aligns directly with DevOps, Site Reliability (SRE), and Platform Engineering job descriptions.