This is a guide for people who would like a brief introduction to Docker and are too afraid to ask for one. I get it. Everyone around you already seems to know what they’re talking about. Looking ignorant is no fun.
A container is a strengthened process. Processes each have their own memory address space, all processes share the file system and the network. Containers are processes that have also been delegated with their own isolated file system and network.
If you think of isolation of concurrent applications as a spectrum. As you move from left-to-right in this table, isolation increases:
|CPU time||CPU time||CPU time|
Each step rightwards includes steps to the left. Containers contain 1 or more processes. Each process contains 1 or more threads.
One thing to note is that these abstractions are not created equally. Processes and containers are abstractions provided by the operating system. Threads are abstractions that are provided by the CPU.
In Linux, containers are implemented with a kernel feature called namespaces. Namespaces can have their access to resources such as the system’s memory restricted via _control _groups (“cgroups”). The
docker run command provides
--ulimit and other parameters to enable you to define the cgroup restrictions.
In addition to cgroups, Linux also enables you to restrict which syscalls are permitted by any processes running inside a container through secure computing mode (“seccomp” and its “secomp-bpf” extension) . This could be used, for example, to prevent a container exposed to the Internet from ever writing to file. In Docker, this feature is exposed as
--security-opt parameters to
Applications running in containers managed by Docker have an added trick: they carry their data along with them. Docker images, or more precisely, container images, are .tar files that contain an application and anything the application needs to run.
A Docker container is a fusion of the two concepts we’ve discussed: kernel namespaces and container image. Once that container image is created, it can be run by any
docker command on any (relatively recent) Linux kernel.
docker takes the image, creates a kernel namespace, applies the cgroup and seccomp-bpf policies, creates any required file system and networking resources, then the ENTRYPOINT defined in the Dockerfile.
Containers were moderately successful before Docker. But Docker solved something else apart from isolation. They were lightweight. The predominant alternative at the time Docker emerged was to run virtual machines to isolate development environment. So, every project required its own entire operating system, along with requisite disk space and memory.
Moreover, virtual machine images were too bulky to send from a laptop to a production server. While it’s possible to create container images weighing in at over 1GB, it’s uncommon. Virtual machines were the opposite. It was possible to create VM images that were less than 1GB, but it was uncommon.
Docker provided some things that set it apart:
- an easy-to-use, developer-centric CLI that simplified namespaces, cgroups, seccomp and container images
- creating Dockerfile, an easy-to-use, developer-centric format for specifying how to build container images
- hosting Docker Hub, an easy-to-use, developer-centric image hosting service
This ease-of-use looked quite attractive when compared against virtual machines, which were slow to boot and resource intensive to run.
If you’re in the late majority and are just coming to grips with the terminology, I have an admission to make: you’re probably going to need to learn some more language.
Despite the frequency of the word “Docker container”, very few containers are run directly by
docker these days. Not even Docker manages containers anymore. Most containers will be managed by a different container runtime environment, such as
containerd or CRI-O.
Depending on your audience, you may wish to change your language to use industry-neutral terminology:
- replace the term “Docker container” with “container”
- replace the term ”Docker image” with “container image”. Or even better, use the term “OCI image”
- replace “docker” with the name of the actual container runtime, such as