1# Build containerd from source 2 3This guide is useful if you intend to contribute on containerd. Thanks for your 4effort. Every contribution is very appreciated. 5 6This doc includes: 7* [Build requirements](#build-requirements) 8* [Build the development environment](#build-the-development-environment) 9* [Build containerd](#build-containerd) 10* [Via docker container](#via-docker-container) 11* [Testing](#testing-containerd) 12 13## Build requirements 14 15To build the `containerd` daemon, and the `ctr` simple test client, the following build system dependencies are required: 16 17* Go 1.13.x or above except 1.14.x 18* Protoc 3.x compiler and headers (download at the [Google protobuf releases page](https://github.com/google/protobuf/releases)) 19* 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. 20 21## Build the development environment 22 23First you need to setup your Go development environment. You can follow this 24guideline [How to write go code](https://golang.org/doc/code.html) and at the 25end you need to have `GOPATH` and `GOROOT` set in your environment. 26 27At this point you can use `go` to checkout `containerd` in your `GOPATH`: 28 29```sh 30go get github.com/containerd/containerd 31``` 32 33For 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: 34 35``` 36$ wget -c https://github.com/google/protobuf/releases/download/v3.11.4/protoc-3.11.4-linux-x86_64.zip 37$ sudo unzip protoc-3.11.4-linux-x86_64.zip -d /usr/local 38``` 39 40`containerd` uses [Btrfs](https://en.wikipedia.org/wiki/Btrfs) it means that you 41need to satisfy this dependencies in your system: 42 43* CentOS/Fedora: `yum install btrfs-progs-devel` 44* Debian/Ubuntu: `apt-get install btrfs-tools` 45 * Debian Buster/Ubuntu 19.10: 46 `apt-get install btrfs-progs libbtrfs-dev` 47 48At this point you are ready to build `containerd` yourself! 49 50## Build runc 51 52`runc` is the default container runtime used by `containerd` and is required to 53run containerd. While it is okay to download a runc binary and install that on 54the system, sometimes it is necessary to build runc directly when working with 55container runtime development. You can skip this step if you already have the 56correct version of `runc` installed. 57 58For the quick and dirty installation, you can use the following: 59 60 go get github.com/opencontainers/runc 61 62This is not recommended, as the generated binary will not have version 63information. Instead, cd into the source directory and use make to build and 64install the binary: 65 66 cd $GOPATH/src/github.com/opencontainers/runc 67 make 68 make install 69 70Make sure to follow the guidelines for versioning in [RUNC.md](RUNC.md) for the 71best results. Some pointers on proper build tag setupVersion mismatches can 72result in undefined behavior. 73 74## Build containerd 75 76`containerd` uses `make` to create a repeatable build flow. It means that you 77can run: 78 79``` 80cd $GOPATH/src/github.com/containerd/containerd 81make 82``` 83 84This is going to build all the project binaries in the `./bin/` directory. 85 86You can move them in your global path, `/usr/local/bin` with: 87 88```sudo 89sudo make install 90``` 91 92When making any changes to the gRPC API, you can use the installed `protoc` 93compiler to regenerate the API generated code packages with: 94 95```sudo 96make generate 97``` 98 99> *Note*: Several build tags are currently available: 100> * `no_btrfs`: A build tag disables building the btrfs snapshot driver. 101> * `no_cri`: A build tag disables building Kubernetes [CRI](http://blog.kubernetes.io/2016/12/container-runtime-interface-cri-in-kubernetes.html) support into containerd. 102> See [here](https://github.com/containerd/cri-containerd#build-tags) for build tags of CRI plugin. 103> * `no_devmapper`: A build tag disables building the device mapper snapshot driver. 104> * `apparmor`: Enables apparmor support in the cri plugin 105> * `selinux`: Enables selinux support in the cri plugin 106> 107> For example, adding `BUILDTAGS=no_btrfs` to your environment before calling the **binaries** 108> Makefile target will disable the btrfs driver within the containerd Go build. 109 110Vendoring of external imports uses the [`vndr` tool](https://github.com/LK4D4/vndr) 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. 111 112Please refer to [RUNC.md](/RUNC.md) for the currently supported version of `runc` that is used by containerd. 113 114### Static binaries 115 116You can build static binaries by providing a few variables to `make`: 117 118```sudo 119make EXTRA_FLAGS="-buildmode pie" \ 120 EXTRA_LDFLAGS='-linkmode external -extldflags "-fno-PIC -static"' \ 121 BUILDTAGS="netgo osusergo static_build" 122``` 123 124> *Note*: 125> - static build is discouraged 126> - static containerd binary does not support loading shared object plugins (`*.so`) 127 128# Via Docker container 129 130## Build containerd 131 132You can build `containerd` via a Linux-based Docker container. 133You can build an image from this `Dockerfile`: 134 135``` 136FROM golang 137 138RUN apt-get update && \ 139 apt-get install -y libbtrfs-dev 140``` 141 142Let's suppose that you built an image called `containerd/build`. From the 143containerd source root directory you can run the following command: 144 145```sh 146docker run -it \ 147 -v ${PWD}:/go/src/github.com/containerd/containerd \ 148 -e GOPATH=/go \ 149 -w /go/src/github.com/containerd/containerd containerd/build sh 150``` 151 152This mounts `containerd` repository 153 154You are now ready to [build](#build-containerd): 155 156```sh 157 make && make install 158``` 159 160## Build containerd and runc 161To have complete core container runtime, you will need both `containerd` and `runc`. It is possible to build both of these via Docker container. 162 163You can use `go` to checkout `runc` in your `GOPATH`: 164 165```sh 166go get github.com/opencontainers/runc 167``` 168 169We can build an image from this `Dockerfile`: 170 171```sh 172FROM golang 173 174RUN apt-get update && \ 175 apt-get install -y libbtrfs-dev libseccomp-dev 176 177``` 178 179In our Docker container we will use a specific `runc` build which includes [seccomp](https://en.wikipedia.org/wiki/seccomp) and [apparmor](https://en.wikipedia.org/wiki/AppArmor) support. Hence why our Dockerfile includes `libseccomp-dev` as a dependency (apparmor support doesn't require external libraries). Please refer to [RUNC.md](/RUNC.md) for the currently supported version of `runc` that is used by containerd. 180 181Let's suppose you build an image called `containerd/build` from the above Dockerfile. You can run the following command: 182 183```sh 184docker run -it --privileged \ 185 -v /var/lib/containerd \ 186 -v ${GOPATH}/src/github.com/opencontainers/runc:/go/src/github.com/opencontainers/runc \ 187 -v ${GOPATH}/src/github.com/containerd/containerd:/go/src/github.com/containerd/containerd \ 188 -e GOPATH=/go \ 189 -w /go/src/github.com/containerd/containerd containerd/build sh 190``` 191 192This mounts both `runc` and `containerd` repositories in our Docker container. 193 194From within our Docker container let's build `containerd`: 195 196```sh 197cd /go/src/github.com/containerd/containerd 198make && make install 199``` 200 201These binaries can be found in the `./bin` directory in your host. 202`make install` will move the binaries in your `$PATH`. 203 204Next, let's build `runc`: 205 206```sh 207cd /go/src/github.com/opencontainers/runc 208make BUILDTAGS='seccomp apparmor selinux' && make install 209``` 210 211When working with `ctr`, the simple test client we just built, don't forget to start the daemon! 212 213```sh 214containerd --config config.toml 215``` 216 217# Testing containerd 218 219During 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: 220 - `make test`: run all non-integration tests that do not require `root` privileges 221 - `make root-test`: run all non-integration tests which require `root` 222 - `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**. 223 224To execute a specific test or set of tests you can use the `go test` capabilities 225without using the `Makefile` targets. The following examples show how to specify a test 226name and also how to use the flag directly against `go test` to run root-requiring tests. 227 228```sh 229# run the test <TEST_NAME>: 230go test -v -run "<TEST_NAME>" . 231# enable the root-requiring tests: 232go test -v -run . -test.root 233``` 234 235Example output from directly running `go test` to execute the `TestContainerList` test: 236```sh 237sudo go test -v -run "TestContainerList" . -test.root 238INFO[0000] running tests against containerd revision=f2ae8a020a985a8d9862c9eb5ab66902c2888361 version=v1.0.0-beta.2-49-gf2ae8a0 239=== RUN TestContainerList 240--- PASS: TestContainerList (0.00s) 241PASS 242ok github.com/containerd/containerd 4.778s 243``` 244 245## Additional tools 246 247### containerd-stress 248In 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`. 249 250With 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: 251 252```sh 253containerd-stress -c 5 -t 120 254``` 255 256For more information on this tool's options please run `containerd-stress --help`. 257 258### bucketbench 259[Bucketbench](https://github.com/estesp/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. 260 261Bucketbench differs from the `containerd-stress` tool in a few ways: 262 - 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. 263 - 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). 264 - Bucketbench generates detailed reports and timing data at the end of the configured test run. 265 266More details on how to install and run `bucketbench` are available at the [GitHub project page](https://github.com/estesp/bucketbench). 267