Docker

Docker - Hard

Page 3 of 3

Networking Internals

The bridge network from the medium tier isn't magic - here's roughly what's actually happening underneath. Docker creates a virtual network switch on the host, and each container gets its own network namespace - a private, isolated view of network interfaces, routing tables, and ports, so a container's "port 3000" is genuinely separate from the host's own port 3000 unless explicitly connected.

Each container connects to the bridge through a veth pair - a virtual cable with one end inside the container's namespace and the other plugged into the bridge on the host side. When you publish a port with -p, Docker sets up an iptables NAT rule that forwards traffic arriving on the host's port to the container's internal address and port.

docker network inspect bridge         # see every container attached to the default bridge, and their internal IPs
iptables -t nat -L DOCKER -n            # (Linux hosts) see the actual NAT rules Docker created

Knowing this matters mostly for debugging: "why can't this container reach that one" is very often actually a question about which network they're each attached to, since containers on different bridge networks can't reach each other by default, no matter how correctly configured each container itself is.


Docker Security Model

Beyond running as a non-root user, a few more security controls are worth knowing, since they come up constantly in production hardening guidance.

Linux capabilities break up what "root" traditionally means into much smaller, individually-grantable permissions (like "can bind to a low port" or "can change file ownership") instead of one all-or-nothing privilege. Docker drops most capabilities by default, but you can drop even more:

docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE my-app

seccomp profiles restrict which system calls a container is even allowed to make to the kernel - Docker applies a sensible default profile automatically, blocking a long list of rarely-needed, historically-risky syscalls.

Read-only root filesystem prevents a container from writing to its own filesystem at all, which - if your app doesn't genuinely need to write anything at runtime - closes off an entire category of attack (an attacker who compromises the app can't drop a malicious file onto disk, because nothing can be written anywhere):

docker run --read-only my-app

The Container Runtime Stack

"Docker" is actually a stack of several distinct pieces, and knowing the layers helps when something breaks and the error isn't coming from where you'd expect:

  • Docker Engine is the user-facing daemon and CLI you interact with directly.
  • containerd is a separate, lower-level daemon that actually manages container lifecycles (pulling images, starting/stopping containers) - Docker Engine delegates to it rather than doing this work itself.
  • runc is the low-level tool that does the actual work of creating an isolated container from a set of Linux kernel primitives (namespaces, cgroups) - it's the piece closest to the kernel.
  • The OCI (Open Container Initiative) spec is the standard all of this implements, which is why an image built by Docker can be run by other, completely different tools (Kubernetes doesn't use Docker Engine at all anymore - it talks to containerd directly, using the same OCI-standardized images Docker produces).
docker info | grep -i runtime          # see which low-level runtime your Docker installation is actually using

Debugging Production Containers

A few commands earn their place once you're troubleshooting something that's actually running, not just developing locally.

docker stats                                   # live CPU/memory usage for every running container
docker inspect <container-id>                   # full JSON detail - resource limits, mounts, network settings, everything
docker inspect <container-id> --format='{{.State.OOMKilled}}'   # specifically check if THIS container was killed for exceeding memory

OOMKilled is worth knowing by name specifically - it's what shows up when a container hits its memory limit and gets forcibly terminated. A container that keeps restarting with no obvious error in its logs, right before each restart, is a strong signal to check exactly this before looking anywhere else.

    Welcome to OpsQuiz!

    Real scenario-based DevOps questions, hands-on practice, and clear explanations for every answer.