The website uses cookies. By using this site, you agree to our use of cookies as described in the Privacy Policy.
I Agree
Text direction?

Build containerd from source

This guide is useful if you intend to contribute on containerd. Thanks for your effort. Every contribution is very appreciated.

This doc includes:

Build requirements

To build the containerd daemon, and the ctr simple test client, the following build system dependencies are required:

  • Go 1.13.x or above except 1.14.x
  • Protoc 3.x compiler and headers (download at the Google protobuf releases page)
  • Btrfs headers and libraries for your distribution. Note that building the btrfs driver can be disabled via the build tag no_btrfs, removing this dependency.

Build the development environment

First you need to setup your Go development environment. You can follow this guideline How to write go code and at the end you need to have GOPATH and GOROOT set in your environment.

At this point you can use go to checkout containerd in your GOPATH:

go get

For proper results, install the protoc release into /usr/local on your build system. For example, the following commands will download and install the 3.11.4 release for a 64-bit Linux host:

$ wget -c
$ sudo unzip -d /usr/local

containerd uses Btrfs it means that you need to satisfy these dependencies in your system:

  • CentOS/Fedora: yum install btrfs-progs-devel
  • Debian/Ubuntu: apt-get install btrfs-tools
    • Debian Buster/Ubuntu 19.10/ Ubuntu 20.04: apt-get install btrfs-progs libbtrfs-dev

At this point you are ready to build containerd yourself!

Build runc

runc is the default container runtime used by containerd and is required to run containerd. While it is okay to download a runc binary and install that on the system, sometimes it is necessary to build runc directly when working with container runtime development. You can skip this step if you already have the correct version of runc installed.

runc requires libseccomp. You may need to install the missing dependencies:

  • CentOS/Fedora: yum install libseccomp libseccomp-devel
  • Debian/Ubuntu: apt-get install libseccomp libseccomp-dev

For the quick and dirty installation, you can use the following:

go get

This is not recommended, as the generated binary will not have version information. Instead, cd into the source directory and use make to build and install the binary:

cd $GOPATH/src/
make install

Make sure to follow the guidelines for versioning in for the best results. Some pointers on proper build tag setupVersion mismatches can result in undefined behavior.

Build containerd

containerd uses make to create a repeatable build flow. It means that you can run:

cd $GOPATH/src/

This is going to build all the project binaries in the ./bin/ directory.

You can move them in your global path, /usr/local/bin with:

sudo make install

When making any changes to the gRPC API, you can use the installed protoc compiler to regenerate the API generated code packages with:

make generate

Note: Several build tags are currently available:

  • no_btrfs: A build tag disables building the btrfs snapshot driver.
  • no_cri: A build tag disables building Kubernetes CRI support into containerd. See here for build tags of CRI plugin.
  • no_devmapper: A build tag disables building the device mapper snapshot driver.
  • apparmor: Enables apparmor support in the cri plugin
  • selinux: Enables selinux support in the cri plugin

For example, adding BUILDTAGS=no_btrfs to your environment before calling the binaries Makefile target will disable the btrfs driver within the containerd Go build.

Vendoring of external imports uses the vndr tool which uses a simple config file, vendor.conf, to provide the URL and version or hash details for each vendored import. After modifying vendor.conf run the vndr tool to update the vendor/ directory contents. Combining the vendor.conf update with the changeset in vendor/ after running vndr should become a single commit for a PR which relies on vendored updates.

Please refer to for the currently supported version of runc that is used by containerd.

Static binaries

You can build static binaries by providing a few variables to make:

make EXTRA_FLAGS="-buildmode pie" \
	EXTRA_LDFLAGS='-linkmode external -extldflags "-fno-PIC -static"' \
	BUILDTAGS="netgo osusergo static_build"


  • static build is discouraged
  • static containerd binary does not support loading shared object plugins (*.so)

Via Docker container

Build containerd

You can build containerd via a Linux-based Docker container. You can build an image from this Dockerfile:

FROM golang

RUN apt-get update && \
    apt-get install -y libbtrfs-dev

Let's suppose that you built an image called containerd/build. From the containerd source root directory you can run the following command:

docker run -it \
    -v ${PWD}:/go/src/ \
    -e GOPATH=/go \
    -w /go/src/ containerd/build sh

This mounts containerd repository

You are now ready to build:

 make && make install

Build containerd and runc

To have complete core container runtime, you will need both containerd and runc. It is possible to build both of these via Docker container.

You can use go to checkout runc in your GOPATH:

go get

We can build an image from this Dockerfile:

FROM golang

RUN apt-get update && \
    apt-get install -y libbtrfs-dev libseccomp-dev

In our Docker container we will use a specific runc build which includes seccomp and apparmor support. Hence why our Dockerfile includes libseccomp-dev as a dependency (apparmor support doesn't require external libraries). Please refer to for the currently supported version of runc that is used by containerd.

Let's suppose you build an image called containerd/build from the above Dockerfile. You can run the following command:

docker run -it --privileged \
    -v /var/lib/containerd \
    -v ${GOPATH}/src/ \
    -v ${GOPATH}/src/ \
    -e GOPATH=/go \
    -w /go/src/ containerd/build sh

This mounts both runc and containerd repositories in our Docker container.

From within our Docker container let's build containerd:

cd /go/src/
make && make install

These binaries can be found in the ./bin directory in your host. make install will move the binaries in your $PATH.

Next, let's build runc:

cd /go/src/
make BUILDTAGS='seccomp apparmor selinux' && make install

When working with ctr, the simple test client we just built, don't forget to start the daemon!

containerd --config config.toml

Testing containerd

During the automated CI the unit tests and integration tests are run as part of the PR validation. As a developer you can run these tests locally by using any of the following Makefile targets:

  • make test: run all non-integration tests that do not require root privileges
  • make root-test: run all non-integration tests which require root
  • make integration: run all tests, including integration tests and those which require root. TESTFLAGS_PARALLEL can be used to control parallelism. For example, TESTFLAGS_PARALLEL=1 make integration will lead a non-parallel execution. The default value of TESTFLAGS_PARALLEL is 8.

To execute a specific test or set of tests you can use the go test capabilities without using the Makefile targets. The following examples show how to specify a test name and also how to use the flag directly against go test to run root-requiring tests.

# run the test <TEST_NAME>:
go test	-v -run "<TEST_NAME>" .
# enable the root-requiring tests:
go test -v -run . -test.root

Example output from directly running go test to execute the TestContainerList test:

sudo go test -v -run "TestContainerList" . -test.root
INFO[0000] running tests against containerd revision=f2ae8a020a985a8d9862c9eb5ab66902c2888361 version=v1.0.0-beta.2-49-gf2ae8a0
=== RUN   TestContainerList
--- PASS: TestContainerList (0.00s)
ok	4.778s

Additional tools


In addition to go test-based testing executed via the Makefile targets, the containerd-stress tool is available and built with the all or binaries targets and installed during make install.

With this tool you can stress a running containerd daemon for a specified period of time, selecting a concurrency level to generate stress against the daemon. The following command is an example of having five workers running for two hours against a default containerd gRPC socket address:

containerd-stress -c 5 -t 120

For more information on this tool's options please run containerd-stress --help.


Bucketbench is an external tool which can be used to drive load against a container runtime, specifying a particular set of lifecycle operations to run with a specified amount of concurrency. Bucketbench is more focused on generating performance details than simply inducing load against containerd.

Bucketbench differs from the containerd-stress tool in a few ways:

  • Bucketbench has support for testing the Docker engine, the runc binary, and containerd 0.2.x (via ctr) and 1.0 (via the client library) branches.
  • Bucketbench is driven via configuration file that allows specifying a list of lifecycle operations to execute. This can be used to generate detailed statistics per-command (e.g. start, stop, pause, delete).
  • Bucketbench generates detailed reports and timing data at the end of the configured test run.

More details on how to install and run bucketbench are available at the GitHub project page.

Related Notes
Get a free MyMarkup account to save this article and view it later on any device.
Create account

End User License Agreement

Summary | 5 Annotations
Btrfs headers and libraries for your distribution
2020/07/28 05:27
Protoc 3.x compiler and headers
2020/07/28 05:27
Go 1.13.x or above except 1.14.x
2020/07/28 05:27
2020/07/28 05:21
make install
2020/08/06 08:33