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