# 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.