1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
|
# dockerutil
This package is for creating and controlling docker containers for testing
runsc, gVisor's docker/kubernetes binary. A simple test may look like:
```
func TestSuperCool(t *testing.T) {
ctx := context.Background()
c := dockerutil.MakeContainer(ctx, t)
got, err := c.Run(ctx, dockerutil.RunOpts{
Image: "basic/alpine"
}, "echo", "super cool")
if err != nil {
t.Fatalf("err was not nil: %v", err)
}
want := "super cool"
if !strings.Contains(got, want){
t.Fatalf("want: %s, got: %s", want, got)
}
}
```
For further examples, see many of our end to end tests elsewhere in the repo,
such as those in //test/e2e or benchmarks at //test/benchmarks.
dockerutil uses the "official" docker golang api, which is
[very powerful](https://godoc.org/github.com/docker/docker/client). dockerutil
is a thin wrapper around this API, allowing desired new use cases to be easily
implemented.
## Profiling
dockerutil is capable of generating profiles. Currently, the only option is to
use pprof profiles generated by `runsc debug`. The profiler will generate Block,
CPU, Heap, Goroutine, and Mutex profiles. To generate profiles:
* Install runsc with the `--profile` flag: `make configure RUNTIME=myrunsc
ARGS="--profile"` Also add other flags with ARGS like `--platform=kvm` or
`--vfs2`.
* Restart docker: `sudo service docker restart`
To run and generate CPU profiles run:
```
make sudo TARGETS=//path/to:target \
ARGS="--runtime=myrunsc -test.v -test.bench=. --pprof-cpu" OPTIONS="-c opt"
```
Profiles would be at: `/tmp/profile/myrunsc/CONTAINERNAME/cpu.pprof`
Container name in most tests and benchmarks in gVisor is usually the test name
and some random characters like so:
`BenchmarkABSL-CleanCache-JF2J2ZYF3U7SL47QAA727CSJI3C4ZAW2`
Profiling requires root as runsc debug inspects running containers in /var/run
among other things.
### Writing for Profiling
The below shows an example of using profiles with dockerutil.
```
func TestSuperCool(t *testing.T){
ctx := context.Background()
// profiled and using runtime from dockerutil.runtime flag
profiled := MakeContainer()
// not profiled and using runtime runc
native := MakeNativeContainer()
err := profiled.Spawn(ctx, RunOpts{
Image: "some/image",
}, "sleep", "100000")
// profiling has begun here
...
expensive setup that I don't want to profile.
...
profiled.RestartProfiles()
// profiled activity
}
```
In the above example, `profiled` would be profiled and `native` would not. The
call to `RestartProfiles()` restarts the clock on profiling. This is useful if
the main activity being tested is done with `docker exec` or `container.Spawn()`
followed by one or more `container.Exec()` calls.
|