The Docker engine is modular in design and based heavily on open-standards from the OCI.
The Docker daemon implements the Docker API, which is currently a rich versioned HTTP API that has developed alongside the rest of the Docker project.
Container execution is handled by
containerd was written by Docker, Inc. and contributed to the CNCF. You can think of it as a container supervisor that handles container lifecycle operations. It is small and lightweight and can be used by other projects and third-party tools. For example, it’s becoming the most common container runtime in Kubernetes.
containerd needs to talk to an OCI-compliant container runtime to actually create containers. By default, Docker uses
runc as its default container runtime.
runc is the de facto implementation of the OCI runtime-spec and expects to start containers from OCI-compliant bundles.
containerd talks to
runc and ensures Docker images are presented to
runc as OCI-compliant bundles.
runc can be used as a standalone CLI tool to create containers. It’s based on code from libcontainer and can also be used by other projects and third-party tools.
There is still a lot of functionality implemented in the Docker daemon. More of this may be broken out over time. The functionality that is currently still inside of the Docker daemon includes but is not limited to: the Docker API, image management, authentication, security features, and core networking.