Skip to main content
DevOps Insightsguides & answers

Learn

Learn DevOps in an order that holds

On this page · 11 sections

Most DevOps material is organised the way the documentation is: by feature, in the order the API happens to list them. That works for reference and badly for learning, because it means you meet “use a volume” as a rule before you know what a writable layer is — and a rule without its cause does not survive contact with a real problem.

So there are two ways in here. If you want a sequence, the paths below are ordered by dependency: each step exists because the previous one raises the question it answers. If you already have a specific question, go straight to the kind of explanation that matches it.

If you want a sequence

Docker, in the order that makes it stick

You have run docker run and it worked, and you are not confident you could explain why.

The usual Docker curriculum teaches features in the order the documentation lists them. This orders them by dependency instead — each step exists because the previous one raises a question it answers.

Before you start: You can install Docker and start a container. No Linux internals are assumed; the first step supplies the ones you need.

By the end you can

  • Explain what a container shares with its host, and what that changes compared with a virtual machine.
  • Say where a file written inside a container goes, and why it is gone when the container is removed.
  • Tell EXPOSE from a published port, and fix a service that is not reachable from the host.
  • Write an ENTRYPOINT and CMD that let your process receive the stop signal.
  1. Why containers are not lightweight VMs

    Start here because the shared kernel explains almost every other Docker behaviour. Learn this last and everything before it was memorised.

  2. Image vs container

    The writable layer is the second load-bearing idea. It has to come before anything about persistence, or “use a volume” is a rule instead of a consequence.

  3. EXPOSE vs published ports

    Often the first thing that actually goes wrong, and it needs the container's network namespace — which you now have.

  4. ENTRYPOINT vs CMD

    Introduces PID 1 and signal handling, which is where Docker stops being about packaging and starts being about process lifecycle.

  5. exec format error

    Right after ENTRYPOINT because this is the kernel refusing to start exactly the program those settings name. It also brings back step one: the container shares the host's kernel, so it needs a binary built for the host's CPU.

  6. Analyse a real Dockerfile

    Paste one you have written. The findings will name things from the previous four steps, which is the point at which they stop being trivia.

  7. Docker interview chain

    Ends here because it tests exactly this sequence, and the last question in it is the one you can only answer if the earlier steps landed.

Check yourself

Run an image of your own, write a file inside the container, remove the container and start a fresh one: say why the file is gone and what you would change to keep it. Then time docker stop on it. About ten seconds means your process never received SIGTERM and was killed when the default timeout ran out.

Kubernetes troubleshooting, from symptom to cause

You can deploy to Kubernetes and you lose time when something breaks.

Ordered the way an incident actually unfolds rather than the way the API is organised. Each step is either a failure you will meet or the concept you need to have already understood when you meet it.

Before you start: You can apply a manifest and use kubectl get, describe and logs. The Docker path, or equivalent experience, helps with the exit codes.

By the end you can

  • Tell a Pod that cannot be scheduled because of its requests from one killed because of its limits.
  • Tell a restart caused by a failing probe from an application that exits on its own.
  • Explain the errors that appear for a moment during every rolling update.
  • Say why a successful rollout does not prove the application works.
  1. Why Kubernetes uses desired state

    First because it explains why failures are asynchronous and show up somewhere other than the command you ran. Without it, kubectl apply succeeding while nothing happens is baffling.

  2. Requests vs limits

    Two of the four common failures are here, and they are opposite: Pending is about requests; OOMKilled is about limits, except when the whole node runs out of memory and the kernel picks a victim by QoS class. Separating them early saves a lot of wrong turns.

  3. Pod stuck in Pending

    The first real failure to work through, and the one where the guided narrowing is most useful because the causes look alike from the outside.

  4. Readiness vs liveness

    Needed before CrashLoopBackOff, because failing liveness or startup probes are one of the documented causes of a restart loop, separate from the application exiting on its own.

  5. Readiness probe failed

    The failure the previous comparison predicts: the pod keeps running but gets no traffic, because readiness never restarts anything. The message after the colon says which of a handful of causes it is.

  6. CrashLoopBackOff

    Now the cause list reads as a set of distinct things rather than one confusing state, because you can already tell a probe-induced restart from an application exit.

  7. What happens if a Pod is deleted

    Moves from single-pod faults to the concurrency between components — and explains the errors you see on every deploy.

  8. What happens if a deploy reports success

    The hardest of the four, because nothing is broken from Kubernetes' point of view. Needs readiness probes understood first.

  9. Kubernetes debugging interview chain

    A check on whether the sequence transferred. Most of its questions are steps above, asked without warning; the rest build on them.

Check yourself

In a test namespace, create one Pod whose memory request is larger than any node can offer, and one whose memory limit is smaller than it uses. Name the state each ends in, and the line in kubectl describe pod that told you: an event for the first, the last state of the container for the second.

Securing a pipeline you did not design

You inherited a CI/CD setup and you are not sure what to worry about first.

Ordered by likelihood and irreversibility rather than by risk number. The first two are where one mistake does the most lasting damage; the rest matter more once those are handled.

Before you start: You can read your pipeline's configuration, and you have admin rights on the repository, or someone who has them is willing to help.

By the end you can

  • Say what to do in the first hour after a secret is committed, and why deleting it is not on the list.
  • Require review on the branch that deploys, with administrators included in the rule.
  • Install dependencies strictly from the lockfile with install scripts switched off.
  • Explain what a green pipeline does and does not prove about the artifact it built.
  1. Why you cannot remove a secret from Git

    First because it is the one where the mistake cannot be undone. Everything else on this list is fixable at leisure; this one needs a revocation.

  2. Credential hygiene

    The practical follow-on: where secrets leak from, and the handling rules that stop it. Build arguments and image layers are the two people miss.

  3. Insufficient flow control

    Second highest value for the least effort. One required review on the branch that deploys, with administrators included in the rule.

  4. Dependency chain abuse

    Installing strictly from the lockfile with install scripts switched off is cheap and shuts two direct routes in — a silently updated malicious version, and code running at install time — which makes this the best ratio of protection to work on the whole list.

  5. Why artifacts should be immutable

    Explains what your green pipeline actually proves, and why a version tag is a weaker guarantee than it appears.

  6. Analyse a Dockerfile

    Turns the reading into findings on your own file. Most of the rules above show up as line numbers.

  7. CI/CD security interview chain

    Last because the final question asks you to prioritise these — which you can now do from reasoning rather than from the order they were listed in.

Check yourself

For one repository: list every place the pipeline can read a secret from — variables, build arguments, image layers, logs. Check whether an administrator can push straight to the branch that deploys. And check whether the install step uses the lockfile with scripts off (for npm, npm ci --ignore-scripts).

Linux and networking for the server you look after

You can SSH into a server and run commands, and you are the one people ask when it misbehaves.

Ordered from getting onto the machine, to reading what it is doing, to the traffic going in and out. Trust bookends it — the SSH host key near the start and the TLS certificate chain at the end — because they are the same idea, and meeting it twice is what makes it stick.

Before you start: A Linux shell you are comfortable in: moving around, reading files, running a command with sudo. Nothing about networking is assumed.

By the end you can

  • Find out from ssh -v and the server's log why a key was refused, and check a changed host key against a fingerprint you trust instead of deleting the line.
  • Read free without alarm, and say whether a machine is actually short of memory.
  • Tell a service that never launched from one that started and then exited.
  • Write an address range in CIDR notation, and the security group and network ACL rules that let a reply back out.
  • Say from a proxy's status code and its error log whether the service behind it refused, hung up or never answered.
  1. Permission denied (publickey)

    First because it is how you prove who you are to a server, and its causes — the wrong user, a key never offered, file permissions sshd will not trust — show where SSH looks before it lets anyone in.

  2. Host key verification failed

    The other direction: the server proving who it is to you. Together with the first step it is the whole of SSH trust, and the safe response to it is a habit worth forming before the day it matters.

  3. free vs available memory

    The first reading most people get wrong on a healthy machine. Learn why free looks alarming and available is the number to watch before diagnosing anything that uses memory.

  4. systemd service fails to start

    Now the services on the box. The exit status splits the failure into never launched and launched-then-quit, which tells you whether to read the unit file or the program's own output.

  5. Too many open files

    Placed between processes and networking on purpose: every socket costs a file descriptor, so this is where a per-process limit starts to look like a network fault. One of its fixes lives in the unit file from the previous step.

  6. CIDR calculator

    Addresses before rules about addresses. Work out what a /24 and a /26 contain, because the firewall rules in the next step are written in this notation.

  7. Security group vs network ACL

    Stateful against stateless filtering, and the outbound rule for ephemeral ports that people miss. It needs CIDR blocks to read, which is why it follows the calculator.

  8. 502 vs 504

    Traffic has reached your proxy; now the proxy reports on the service behind it. A 502 is an attempt that ended and a 504 is one that never did, and they need opposite fixes.

  9. 502 Bad Gateway

    The cause list for the more common of the two. It starts from the proxy's error log, which records whether the upstream refused the connection, hung up, or answered with something unusable.

  10. 413 Request Entity Too Large

    The proxy again, this time refusing the request itself instead of reporting on the service behind it. Reading which layer wrote the error page is the same skill as reading a 502.

  11. x509: certificate signed by unknown authority

    Ends on trust again, now for TLS. A chain of signatures leading back to an authority you already trust answers the same question the host key answered in step two, and every HTTPS client asks it.

Check yourself

On a server you run, pick a service and find its main PID with systemctl show -p MainPID <service>. Count its open descriptors with ls /proc/<pid>/fd | wc -l and compare that with the Max open files line in /proc/<pid>/limits. Then explain to someone else why free shows so little free memory on the same machine.

Git without losing work

You commit and push every day, and you reach for a search engine when Git refuses something.

Ordered around one line: whether a commit is still only yours, or somebody else may already have it. Every refusal in this path is Git protecting history that someone may depend on, and every safe fix starts from knowing which side of that line you are on.

Before you start: You can commit, push and pull, and you have a repository with a remote on GitHub, GitLab or similar.

By the end you can

  • Choose between merge and rebase by asking whether anyone else already has the commits.
  • Recover from a rejected push without --force, and know when --force-with-lease is the right exception.
  • Undo a pushed commit with revert and an unpushed one with reset, without losing uncommitted work.
  • Explain why a committed credential has to be revoked, not just deleted.
  1. Merge vs rebase

    First because it draws the line the rest of the path keeps returning to: rebase rewrites commits, which is harmless on work only you have and trouble on anything others have pulled.

  2. Push rejected as non-fast-forward

    The first refusal you will meet, and a direct consequence of the previous step: the remote has commits yours is not built on. The fix is to bring them in, not to force.

  3. refusing to merge unrelated histories

    The same refusal from the other end: two histories with no commit in common, usually because the repository was created on the host with its own first commit. It only makes sense once you know a merge starts from a shared commit.

  4. Reset vs revert

    Undoing comes after combining because the right tool depends on the line from step one: reset rewrites, revert adds. It is also where uncommitted work can be lost for good, with reset --hard.

  5. Why you cannot remove a secret from Git

    The undo that does not exist. After reset and revert it is clear why deleting a committed secret leaves it reachable, in your history and in every clone already made.

  6. Push declined: secret detected

    Ends with the host stopping the push for you. Fixing it means rewriting commits you have not pushed yet, which is everything above at once, and replacing the credential if it is real.

Check yourself

In a scratch repository with a second clone, commit in both and push both, so the second push is rejected. Fix it without --force. Then undo one of your commits with git revert <commit> and confirm with git log --graph --oneline that no existing commit was rewritten.

Terraform: state, plans and the errors between them

You run terraform apply on infrastructure other people share, or you are about to.

Ordered around state, because nearly every confusing Terraform error is about it: what it records, who may write it, and what happens when reality or another run moves it. The configuration language comes after state for the same reason.

Before you start: You can write a resource block and run init, plan and apply. A remote backend helps as context but is not required.

By the end you can

  • Say what state records that neither the configuration nor the cloud does.
  • Decide whether a stuck lock is safe to release, and what to check before you do.
  • Tell real drift from a provider describing the same value differently.
  • Choose count or for_each for a resource, and predict what removing one item will do.
  1. Why Terraform needs state

    First because everything else here follows from it: state maps blocks of code to real resources, and it is the only record of things the provider does not report back.

  2. Error acquiring the state lock

    Who may write state, and the one command in this path that can corrupt it. The whole question is whether the run holding the lock is dead or still alive, which only matters once you know what state is.

  3. A change nobody made (drift)

    Reality moving out from under the state, or a provider describing the same value in a different form. The two look identical in a plan and need opposite responses.

  4. Saved plan is stale

    A saved plan is worked out against one version of state. If anything writes state before you apply it, Terraform refuses, and after the lock and drift steps it is clear why there is no flag to force it.

  5. count vs for_each

    Now the language, because how instances are named decides what a plan does when a list changes: removing an item from the front of a count list rewrites every instance after it.

  6. Invalid for_each argument

    The error that comes with choosing for_each: every key must be known before apply. The fix the message suggests reads naturally once you know why instances need stable names.

  7. Inconsistent dependency lock file

    Last because it is about the providers rather than state. The lock file pins their versions and belongs in version control next to the configuration; the error is the two disagreeing.

Check yourself

In an empty directory with the default local backend, create three terraform_data resources from a list of three names, once with count and once with for_each over the same names, and apply both. Remove the first name and run terraform plan on each. Count shows two changes and a destroy; for_each shows one destroy. Explain why from the instance addresses in the plan.

Reliability: what to promise, what to page on

You own a service in production and decide, or will soon decide, what wakes someone up.

Ordered from the promise to the alarm: what you commit to, how much failure that leaves room for, and which signals deserve a page. The failure steps come after, because each is a case where a check passed while users suffered.

Before you start: You run something in production and have some kind of metrics system. The Prometheus step assumes you have seen a scrape configuration; the rest does not.

By the end you can

  • Write an SLO for a service and say how much downtime it allows in a month.
  • Sort a list of alerts into those that should page someone and those that should not.
  • Tell a monitoring failure from a service failure.
  • Explain why a green deploy is weaker evidence than a user-facing measurement.
  1. SLO vs SLA

    First because every other step uses the words: what you measure, the target you hold yourself to, and the contract, which should promise less than the target.

  2. Error budget calculator

    Turns a target into minutes. 99.9% over 30 days allows about 43 minutes of downtime, and seeing that number is what makes a target a decision rather than a slogan.

  3. Symptom vs cause alerting

    With a budget in hand the paging rule follows: page on what users feel, because a cause can look unusual while users are fine, and paging on causes is the route to alert fatigue.

  4. context deadline exceeded (Prometheus)

    The monitoring system failing on its own terms: a target too slow to answer is marked down. Worth meeting early, because a missed scrape leaves a gap in every graph and alert built on that target.

  5. Readiness vs liveness

    Health checks are signals too. The wrong one in the wrong place turns a slow start into a restart loop, which is a reliability problem the platform creates by itself.

  6. A deploy reports success, users see errors

    The case the path builds to: every check passed and the application is broken. It shows why the measurement behind an SLO has to be what users experience, not what the platform reports.

  7. Retry and backoff calculator

    What clients do when you fail. Retries without backoff and jitter add load to a service that is already struggling, so this belongs next to the failure it amplifies.

  8. On-call load assessment

    Last because it is where the earlier choices land on people: alerts on causes rather than symptoms show up here as a rotation nobody can sustain.

Check yourself

Take the pages your service sent in the last month. For each, say whether it fired on a symptom users felt or on a cause, and work out what share of the month's error budget the incident behind it used. Any page that used none of it is a candidate to stop paging on.

If you already have a question

Four kinds of explanation, each shaped for a different kind of question. The shape matters: a failure is a sequence, a confusion is a distinction, and flattening either into the other loses the thing that made it useful.

If you want to sit with something longer

Something failing right now? Start from the error instead — that route is built for people who do not have time to learn anything.