Docker and OCI Runtimes

Avijit Sarkar
Nov 5 · 7 min read
Photo by frank mckenna on Unsplash

The objective of this blog post is to deep dive into the various aspcts of OCI aka Open Container Initiative and how Docker fits in there.

What is Open Container Initiative (OCI)?

  • The Open Container Initiative (OCI) is a Linux Foundation project to design open standards for containers.
  • Established in June 2015 by Docker and other leaders in the container industry.
  • OCI currently contains two specifications: the Runtime Specification (runtime-spec) and the Image Specification (image-spec).
  • OCI runtime spec defines how to run the OCI image bundle as a container.
  • OCI image spec defines how to create an OCI Image, which includes an image manifest, a filesystem (layer) serialization, and an image configuration.

What are the various Container Runtimes?

Some of the the popular container runtimes are below ones:

  • containerd: A CNCF project, it manages the complete container lifecycle of its host system that includes image management, storage and container lifecycle, supervision, execution and networking.
  • lxc: LXC provides OS level virtualization through a virtual environment that has its own process and network space, it uses linux cgroups and namespaces to provide the isolation.
  • runc: runc is a CLI tool for spawning and running containers according to the OCI specification. It was developed by Docker Inc and donated to OCI as the first OCI runtime-spec compliant reference implementation.
  • cri-o: CRI-O is an implementation of the Kubernetes CRI (Container Runtime Interface) to enable using OCI (Open Container Initiative) compatible runtimes. It is a lightweight alternative to using Docker as the runtime for Kubernetes.
  • rkt: rkt is an application container engine developed by

So in a nutshell the container runtimes does some or all of the below tasks:

  • Container image management
  • Container lifecycle management
  • Container creation
  • Container resource management

Some of the runtimes like “rkt” does most of the tasks by itself, where as runtime like “containerd” does some of the high level functions and uses others like “runc” for some of the low level tasks.

Okay, So what is Docker then?

Docker engine used to be a single monolith before version 1.11.0, the engine was responsible for all the aspects of container management like image management, lifecycle, creation, resource managment etc.

In docker version 1.11.0 major restructuring happened in the Docker engine as below:

  • The low level container runtime features were moved to a different project called runc, it was the first OCI runtime spec reference implementation. Docker donated it to OCI.
  • Docker also created the “containerd” project for the supervision of the containers spawns out using “runc”
  • containerd has full support for starting OCI bundles and managing their lifecycle.
  • Docker published two blog posts behind the rational for createion of “runc” and “containerd”.

So, I have a vagrant CentOS box and have installed docker in it, the running docker processes looks like below:

Its very evident here that docker engine under the hood running containerd and runc as container runtimes.


Playing around with containerd

As mentioned above containerd is a high level runtime and can be installed on any linux machine following the instructions here

When we install containerd it installs the downstream dependencies as well like:

  • runc: to run containers
  • ctr: A CLI for containerd
  • containerd-shim: to support daemonless containers

What all I can do using containerd?

  • Manage images (like downloading from docker registry)
  • Manage containers (like create and running containers)
  • Manage namespaces

How to interact with containerd?

We will be using the ctr cli for containerd.

  • Downloading images:
  • Listing images:
  • Running and listing containers:

What is this containerd-shim (refer the docker image above)?

So based on above command, we start a python3 container using containerd, we know that containerd doesn’t run the actual container, its the runc that responsible for running the container.

  • The shim allows for daemonless containers. It basically sits as the parent of the container’s process to facilitate a few things.
  • It allows the runtimes, i.e. runc, to exit after it starts the container. This way we don’t have to have the long running runtime processes for containers.
  • It allows the container’s exit status to be reported back to a higher level tool like docker without having the actual parent of the container’s process running.

This is very much evident from the below command, we do see containerd running but no runc, instead we have the containerd-shim process running for the python container.

Note: To know more about it please watch this excellent youtube video by Michael Crosby.


Playing around with runc

So runc is the low level container runtime (based on OCI runtime-spec) whose only job is to run containers using OCI image-spec based resource bundle.

In the above section we already saw how containerd can be used to start and run containers and under the good it uses containerd-shim to run the container using runc

What that means is we should be able to run a container manually using runc as well.

runc binary got installed as containerd dependency.

Based on above documentation all we need is an OCI image-spec based bundle (a spec file named config.json and the container image root filesystem) to run a container.

Lets create the container image root filesystem:

We just used docker here to run a alpine image and then exported the container as tarball. Extracting the tarball gave us the root filesystem for the alpine image.

Now lets create the runtime-spec config file:

Now to run a container is as simple as below command:

Based on the spec config.json file, the default command is sh for the image, so we entered into the shell of the container.


What we can summarize here is that the whole container runtimes under OCI is very flexible and pluggable, as long we are meeting the image-spec and runtime-spec requirements we can have custom runtimes for containers.

Docker is no longer a monolith and under the hood its using the containerd and runc runtimes to manage containers.

containerd enables us to have container ecosystem without docker, for example cri-o in Kubernetes world can have the container runtime without docker.

References:

Avijit Sarkar

Written by

Cloud, Serverless, Containers and Devops enthusiast

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade