Latest / Linux Server Admin with Fexingo: Sysadmin, Bash, and Server Engineering / How to Use Linux Container Runtimes for Server Deployment
Transcript
- Lucas: If you've been running containers on a Linux server for a while, you've almost certainly used Docker. But Docker itself is just one piece of the stack—underneath it sits a runtime that actually runs the container. And lately, people are asking whether they need Docker at all. Luna: You mean swapping Docker for something like containerd or Podman? I've seen that debate a lot on sysadmin forums. What's the real difference? Lucas: Great question. So, at a high level, a container runtime is the software that manages the lifecycle of a container: pulling images, creating namespaces, setting up cgroups, and running the actual process. Docker used to bundle everything—the CLI, the daemon, the runtime—into one monolithic package. But the industry has been standardizing around the Open Container Initiative, or OCI, which splits responsibilities. Luna: Right, OCI defines the image spec and the runtime spec. So any oci compliant runtime should be able to run any OCI image. That's the theory, anyway. Lucas: Exactly. And that's opened the door for specialized runtimes. containerd, for example, was originally extracted from Docker's core and donated to the Cloud Native Computing Foundation. It's a lightweight daemon that just handles container execution—no build tools, no docker-compose, no fancy CLI. You interact with it through a socket or via higher-level tools like nerdctl. Luna: So if I'm running a production server and I don't need to build images on the fly, I could drop Docker entirely and use containerd? What's the upside? Lucas: The biggest upside is resource efficiency. On a typical server, the Docker daemon consumes maybe 100 to 200 megabytes of RAM just sitting there. containerd is much leaner—often under 50 megabytes. I've seen benchmarks where switching from Docker to containerd reduced memory usage by 30 to 40 percent on lightweight VMs. That matters when you're running dozens of servers. Luna: Thirty percent savings is significant. But does containerd handle everything Docker does? Like logging, networking, volume mounts? Lucas: It handles the core operations, but it doesn't provide a high-level API for things like Swarm or Compose. You'd need separate tools for orchestration. For example, Kubernetes actually uses containerd under the hood by default these days. So if you're deploying containers manually on a single server, you can use nerdctl, which is a Docker-compatible CLI for containerd. Luna: And Podman? That's another big name. I hear it's daemonless—is that a game changer? Lucas: Podman takes a different architectural approach. Instead of a central daemon, Podman forks child processes directly from the user's session. That means every container is a child of the Podman process, not a separate daemon. The security implications are interesting—if you're running rootless, each container runs under your user ID, which limits the blast radius if a container gets compromised. Luna: So with Docker, if the daemon has root privileges and gets exploited, an attacker could potentially access all containers. With Podman's rootless mode, each container is sandboxed at the user level. Lucas: Exactly. And Podman also supports Kubernetes-style YAML files directly, so you can generate pod manifests without needing a separate tool. It's very popular among developers who want to test Kubernetes deployments locally. Luna: Alright, let's get concrete. Say I'm a sysadmin with a bare-metal server running Ubuntu 24.04. I need to deploy a Python web app in a container. Which runtime do you recommend? Lucas: Let's walk through a real scenario. Your app is a Flask-based REST API using a PostgreSQL backend. You've already built the image and pushed it to a private registry. Now you need to pull and run it on the server. Here's how you'd do it with containerd. Luna: I'm listening. Do I need to install containerd and nerdctl, or can I just use ctr? Lucas: ctr is the native CLI for containerd, but it's pretty bare-bones. I'd recommend nerdctl because it mimics Docker syntax. So first, install containerd from the official repo. Then install nerdctl. Then you pull the image: nerdctl pull your-registry.com/python-app:latest. Then run it with the appropriate flags for ports and volumes. Luna: And networking? Does containerd set up bridge networking automatically like Docker? Lucas: containerd uses the Container Network Interface, or CNI, plugins. You can configure a bridge network via a CNI config file. nerdctl has a --network flag that handles that. For a simple setup, you can just do --network bridge. But the default behavior is that each container gets its own network namespace, same as Docker. Luna: What about volume mounts? Say my app needs to write logs to a host directory. Lucas: nerdctl supports the -v flag just like Docker. So nerdctl run -v /var/log/app:/app/logs... works. Under the hood, it's using bind mounts. No surprises there. Luna: Okay, so the workflow is almost identical. But what about logging? Docker has built-in log drivers. Does containerd have that? Lucas: containerd itself doesn't provide a log driver. Instead, it writes container logs to a file in the standard JSON format, and you can use external tools like journald or syslog to forward them. nerdctl can also tail logs with the same --follow flag. It's a bit more manual, but some people prefer the flexibility. Luna: Let's talk security. If I'm running rootful with containerd, the daemon still runs as root. But with Podman rootless, I can run containers without any root privileges at all. Is that really better? Lucas: It's a trade-off. Rootless containers are more secure because they run under the user's namespace—a compromised container process can't escape to the host root. But rootless has limitations: you can't bind to ports below 1024 without additional configuration, and some system calls are restricted. For a production API server that needs to listen on port 443, you'd need to either use a reverse proxy or enable the CAP_NET_BIND_SERVICE capability. Luna: So for a simple web app on a single server, would you go with containerd or Podman? Lucas: Honestly, if you're comfortable with Docker's security model and just want the lowest overhead, containerd with nerdctl is a solid choice. If you're more security-conscious or running multi-tenant environments, Podman's rootless mode is hard to beat. One more thing to consider: system integration. Podman integrates with systemd natively—you can generate systemd unit files for your containers with podman generate systemd. That's huge for production deployments. Luna: Systemd integration is powerful. You can set up automatic restarts, dependencies, and logging through journald. Docker compose doesn't give you that out of the box. Lucas: Exactly. And speaking of practical tools, I want to mention something that's helped me a lot in testing these runtimes. A couple of dollars a month is genuinely what keeps these open-source projects and the shows like this one going. If you've gotten something out of our episodes, consider tossing a few bucks our way at buy me a coffee dot com slash fexingo. It helps us stay ad-free and focus on what matters. Luna: Yeah, it's a small thing that makes a big difference. We've had listeners tell us that a single tip covered a month of server costs for their homelab. It's humbling. Lucas: Absolutely. Now, back to runtimes—let's talk about testing your own setup. I recommend spinning up a test server, installing both containerd and Podman, and deploying the same app on each. Measure memory usage with 'ps aux' and startup time with 'time'. You'll quickly see the differences. Luna: I've done that. With Podman rootless, I saw about 80 megabytes per container versus 120 with Docker. And containerd came in around 50. The startup time was similar, maybe a second faster for containerd. Lucas: Those numbers match what I've seen. The key takeaway is: you don't have to pick one runtime forever. With OCI standards, you can switch between them as your needs evolve. Start with containerd if you want minimal overhead, go with Podman if security or systemd integration matters, and keep Docker in your toolbox for development environments where you need Compose and build features. Luna: What about orchestration? If I eventually scale to multiple servers, will containerd work with Kubernetes? Lucas: Absolutely. In fact, Kubernetes 1.24+ deprecated Docker as a container runtime and uses containerd by default. So if you're already using containerd on a single server, migrating to Kubernetes is seamless—you just add kubelet and kubeadm, and the runtime is already there. Luna: That's a great point. So learning containerd now gives you a head start on Kubernetes. Lucas: Exactly. And for Podman, there's Podman Machine and Podman Compose to mimic Docker's developer experience. But the real power is in the systemd integration. You can manage containers like any other system service. Luna: Any gotchas when switching? I've heard that some container images expect Docker-specific environment variables or mount points. Lucas: Rarely, but it happens. Some older images assume /var/run/docker.sock exists. With containerd, the socket is at /run/containerd/containerd.sock. For Podman, there's no socket at all. If an application needs to talk to the Docker API, you can use podman-docker, which emulates the Docker socket. That's a nice bridge. Luna: So there's a path for almost every scenario. I think the biggest barrier is just inertia. People know Docker, so they stick with it. Lucas: Right. But with the performance and security benefits, it's worth investing an afternoon to test. I'd suggest starting with containerd on a non-critical server. Deploy a stateless app, monitor it for a week, and see if you notice any issues. Most people find it's a drop-in replacement. Luna: And if you need Docker-specific features like buildkit or multi-stage builds, you can always run Docker alongside containerd. They don't conflict as long as you manage port mapping carefully. Lucas: Good point. In fact, many production setups use containerd for running containers and Docker for building images. Best of both worlds. Luna: So to wrap up: for a new server deployment today, would you recommend containerd or Podman? Lucas: If I had to pick one for a generic server, I'd go with Podman for its security model and systemd integration. But if I'm building a Kubernetes-ready environment, containerd is the obvious choice. The good news is, you can't go wrong either way—they're both mature, well-supported, and open source. Luna: And you can always docker exec into a container running on either runtime. The commands are mostly the same. Lucas: Yeah, the user experience has converged. So take the time to evaluate, and you'll likely end up with a leaner, more secure server. That's a win.