Docker 很奇怪
Docker is weird

原始链接: https://codeandcake.dev/posts/2026-10-22-docker-is-weird

作者正在构建容器运行时,并总结了 Docker 的怪异之处:容器只是受限进程而非虚拟机,依赖命名空间、cgroups 和网络隔离;镜像是通过 chroot/pivot_root 访问的文件夹。Docker 下载镜像、存储它,然后运行其中的路径。runc 用 Go 编写,其多线程运行时和缺少 fork 使系统调用密集的容器设置复杂化,需要变通方法。Docker 通常需要 root,尤其用于网络;无 root 运行时可能在用户空间重新实现网络。构建该工具让作者学到了很多。

一篇题为“Docker Is Weird”的 Hacker News 帖子(codeandcake.dev)获得了 16 个点和 6 条评论。Docker 创建者 Solomon Hykes(shykes)参与了讨论,称其为对其设计的怀旧回顾并表示愿意回答问题。评论者询问了他现在会有什么不同做法、是否预料到 Docker 的成功,以及他的最初愿景,同时有人抱怨 Docker 常被过度用作通用解决方案。其他人分享了学习资源,包括 Liz Rice 的“Containers From Scratch”演讲和 LWN 关于 Linux namespaces 的系列文章,并建议采用 rootless Podman 的 fork-exec 方式。页面还包含 Y Combinator Winter 2027 申请推广。
相关文章

原文

I decided to make my own container runtime for fun, and even though I’m still early on, I’ve learned that Docker is weird. Here’s some weird things I learned about Docker.

Containers aren’t real

Unlike VMs, containers are just processes with special restrictions on them. Your kernel is still running that process! And if you know where to look, you can even find that process in /proc.

Containers really aren’t real

There’s not really a linux feature that’s just “containers” either. Instead, containers are really 5 different linux kernel features in trenchcoat.

Namespaces hide what the host and container can see, cgroups limit container resource usage, and there’s a whole bunch of networking magic I don’t understand that lets you isolate a container’s network.

Images are just folders

Images are just folders that Docker puts somewhere and then calls chroot (or pivot_root) to make that folder your container process’s new root directory. So if you run docker run -it --rm ubuntu /bin/bash, Docker is going to:

  • Download the ubuntu image from Dockerhub.
  • Put that image somewhere.
  • Run /some/weird/docker/path/bin/bash

Go is kind of a terrible language for a container runtime

Docker’s container runtime, runc, is written in Go, and Go has some design choices that make it less suited for a container runtime. Go’s runtime is natively multi-threaded. That’s a really cool feature, but it leads to some challenges in runc.

Many of the Linux syscalls a container runtime needs to make have to be done in a single-threaded environment, so runc has a crazy C module that runs before Go’s runtime initializes so it can run those syscalls.

Go also doesn’t have fork! Fork only forks the main thread, so it’s kind of a footgun in a runtime like Go’s. But a container runtime really wants to fork, set up a bunch of restrictions, and then exec the process you actually put in docker run. To get around this, runc execs /proc/self/exe with a special command line arguement that identifies it as a child process to approximate a fork.

Docker requires root!

This is pretty easy to miss if you, like me, run Docker in MacOS. Many of the Linux kernel APIs that container runtimes use require, or at least used to, to be run as root, so the Docker daemon usually runs as root. I can only imagine that container security is a very tough job.

This seems better these days. The big exception seems to be networking. If you’re running a rootless container runtime, it looks like it has to reimplement the whole networking stack in userspace to actually give you the same features!

Learning is fun!

I’ve only just started my own container runtime, and I already feel like I’ve learned so much about Docker. Writing your own version of a tool you use is a great way to learn about it!

联系我们 contact @ memedata.com