In the last post of this series we had a closer look at Container Runtimes.
However, for us developers interacting with Container Runtimes is tedious and not straightforward since they have not been designed to be consumed directly by the end-user.
This issue is solved by Container Engines!
They provide convenient APIs for interacting with Container Runtimes without having to know all the low-level details.
Furthermore, this abstraction allows using different Container Runtimes if necessary.
If you started a container on your local machine once, you already interacted with a Container Engine since Docker is one of the most popular engines out there.
docker Command Line Interface (CLI) allows us to interact with the heart of the Container engine.
In Docker terms called the Docker Daemon.
This CLI provides a high level of abstraction for the end-user since it focuses on the most important parts of a container's life cycle.
The CLI allows us to:
- start a new container
- stop a container
- restart a stopped container
- fetch a new image
- ... and much more
Based on that brief overview of functionality we can extract the main responsibilities of a Container Engine:
- Management of the container life cycle (forwarding proper commands to the underlying runtime)
- Pulling and pushing container images to image repositories
- Configuring storage for containers
Since we are now more familiar with the functionalities provided by a Container Engine, let's have a closer look at two very popular engines:
The Docker Engine consists of the following parts:
dockerda long-running daemon process which acts as server. Also called Docker daemon
dockerCLI which acts as a client and communicates with
Docker Engine API
The Docker daemon comes with it's one CLI called
It can be configured either by passing flags to
dockerd or a JSON configuration file.
Once a request from the
Docker Engine API is received, the Docker daemon takes care of processing the request and reporting the status back to the
Under the hood
containerd is used for interacting with the underlying Container runtime (in this case
So the Docker daemon does not interact with the Container runtime directly but makes use of another abstraction layer on top of
If you haven't heard about Container Runtimes, check out the first article of this series: Container Runtimes.
If you want to tinker with the
Docker Engine API you can use the API directly via HTTP or integrate a provided SDK into your code.
See API docs for more information.
The client-server architecture of Docker allows the
docker CLI to easily interact with remote Docker daemons as well. The Docker daemon process can listen to requests from the
Docker Engine API via three different socket types:
TCP sockets enable the possibility for remote connections. The other two socket types are bound to the host and cannot be access from a remote machine.
Docker is a prominent example of a Container Engine. It gained a lot of popularity since the initial release in 2013.
However, with the rise of Kubernetes another popular engine was born.
Let's have a look at
The CRI-O container engine provides a stable, more secure, and performant platform for running Open Container Initiative (OCI) compatible runtimes.
CRI-Os purpose is to be the container engine that implements the Kubernetes Container Runtime Interface (CRI) for OpenShift Container Platform and Kubernetes, replacing the Docker service.
The CRI-O container engine can launch a container by using an OCI-compliant Container Runtime like
containers/image library to pull images from a registry. Therefore, it supports Docker schema2/version 1 and schema2/version2.
Although it is not really necessary to interact with CRI-O directly, CRI-O comes with a bunch of CLIs and tools:
crictl: allows debugging issue with the underlying runtime without having to set up other Kubernetes components
runc: CLI for interacting directly with the runtime
podman: offers the same command-line features as the
dockerCLI and additional features on top of it
buildah: allows building of OCI images with and without a Dockerfile
skopeo: helps with the management of container images
For more information regarding the bundled tools see: CRI tools.
CRI-O was started by Red Hat, with the goal of decoupling Kubernetes from Docker.
It is now a project of the Cloud Native Computing Foundation.
With it, it is possible to use any OCI compliant Container Runtime in Kubernetes.
CRI-O implement the Kubernetes Container Runtime Interface both can be used easily in Kubernetes.
Let's summarize what was covered in this article:
First, we had a look at the responsibilities of a Container Engine.
Then we had a closer look at how the Docker Container Engine works under the hood.
Last but not least,
CRI-O was introduced as an alternative to Docker.