Kitchen-Docker or Kitchen-Dokken? Using Test Kitchen and Docker for fast cookbook testing

Chef’s Test Kitchen project allows for fast functional testing of infrastructure code. In the past few years, the rise of container technologies like Docker have allowed devops engineers to speed up this feedback cycle, since the startup time of a container is much faster than that of a VM image that needs to be cloned and then booted by a full hypervisor.

However, containers are not lightweight VMs, so there are some limitations when using them for testing infrastructure code. In particular, a container typically does not run a full init process, which makes it somewhat challenging to test low-level Chef resources like service. Additionally, base container images provided by operating system vendors are extraordinarily minimal, often containing just a kernel, GNU coreutils and a package manager. It is wasteful to have to install a userland every test cycle just to simulate a real system.

There are two community-maintained Test Kitchen drivers, kitchen-dokken and kitchen-docker, that take different approaches to solving some of these problems. ChefDK ships with kitchen-dokken because it is the most closely coupled to Chef, but kitchen-docker has valuable use cases as well.

Kitchen-Dokken

Kitchen-Dokken by Awesome Community Chef Sean O’Meara is optimized for speed and testing Chef recipes. It achieves this goal by using pre-built Docker images and using bind mounts to share data like the Chef Client itself and the cookbooks without the need to copy it into the container. This can result in significant speed improvements with no additional configuration burden. It blurs the lines between driver, provisioner, and transport and as such diverges from more “traditional” drivers. Currently it is specific to Chef use cases and is part of the ChefDK. It uses systemd as the PID 1 inside the container to allow for testing of resources like service.

One challenge is that the bind mounts may make it difficult to use this driver in a Docker-in-Docker scenario e.g. in a Docker-based CI system like GitLab. It can be challenging to make sure the mounts across two Docker boundaries are configured properly.

Kitchen-Docker

Kitchen-docker, primarily maintained by Noah Kantrowitz, another Awesome Community Chef, is similar to other drivers in being relatively provisioner-agnostic. In other words, it is not Chef specific. When provisioning with Chef, the default behavior downloads and installs Chef Client just like other drivers. It provides the ability for more complex configuration (as well as allowing the use of alternate provisioners) but in general requires a slightly higher familiarity with Docker. Kitchen-docker uses minimal operating system distribution-provided containers from Docker Hub but these often require additional configuration to be useful, as mentioned above. Finally, kitchen-docker uses sshd as the PID 1 inside the container and sends infrastructure code over the SSH connection, which makes for easier networking setup — no bind mounts are needed. However, this design means it is not possible to test resources like service that expect to talk to an init system.

Conclusion

If you are a Chef user with simple testing needs, use kitchen-dokken.

If you are a Chef user with more complex testing needs or require features kitchen-dokken doesn’t support, try kitchen-docker. This is true particularly if you are trying to use it in conjunction with a Docker-based CI system.

If you are an Ansible/Puppet/not-Chef user, use kitchen-docker.

Both drivers are are fast due to the nature of low container overhead, though kitchen-dokken may often appear faster because more of the configuration is pre-baked.

Seth Thomas

Seth is a member of the Workstation team and longtime community member. He maintains test-kitchen, bento, and loves helping new users. When not working he's an avid footballer (soccer) and goalkeeper.