kitchen-dokken
Fast Chef Infra cookbook testing with Docker. kitchen-dokken is a
Test Kitchen plugin that converges your cookbooks inside
containers in seconds rather than minutes.
- Why kitchen-dokken?
- When not to use it
- Requirements
- Installation
- Quick start
- How it works
- Configuration reference
- Driver · Provisioner · Transport
- Recipes
- Images and platforms: Testing services and init systems · Minimalist images · Using dokken-images · Multi-architecture testing
- Chef Infra Client: Using Cinc · Using with Chef · Chef Infra Client options · Testing without Chef · Pre-release and archived Chef versions
- Networking: Networking · IPv6 · Testing behind a TLS-intercepting proxy
- Registries and daemons: Private registries · Pulling through a mirror · Remote and containerised Docker hosts · Using Podman
- Performance and resources: Caching downloaded packages · Preserving the Chef cache · Limiting container memory · tmpfs on /tmp
- Troubleshooting
- Contributing
- FAQ
- License
Also in this repository: Running under Podman and Accepting the Chef license.
Why kitchen-dokken?
Test Kitchen normally splits its work across four plugin types: a driver creates the machine, a transport connects to it, a provisioner puts it into the desired state, and a verifier checks the result.
kitchen-dokken ships the first three as one purpose-built unit. That lets it
take shortcuts no general-purpose driver can:
-
No Chef install step. Chef Infra Client is mounted into your container
from the official
chef/chefimage, so nothing is downloaded or installed per run. -
No image commits between phases. The container is kept alive by a
long-running PID 1, so
converge,verifyandloginall reuse it. -
No SSH by default. Commands run through
docker exec, and the kitchen sandbox is bind-mounted straight off your disk.
The result is a feedback loop measured in seconds, on a laptop, offline.
When not to use it
The trade-off for that speed is scope. kitchen-dokken only tests Chef Infra
cookbooks — there is no Puppet or Ansible provisioner here — and a container
is not a perfect stand-in for a full OS install. Official distro images are
extremely minimal, so you may need to install packages before your cookbook
will run at all (see Minimalist images).
If you need a faithful analog of a production machine and would rather not troubleshoot missing packages, reach for kitchen-vagrant instead. If you want a general-purpose Docker driver that works with other provisioners, use kitchen-docker.
Requirements
- Ruby 3.1 or later
- A reachable Docker daemon — Docker Engine, Docker Desktop, Rancher Desktop or Podman
- Test Kitchen 3.0 or later (below 5.0)
-
kitchen-omnibus-chef1.0 or later, which is where theChefInfraprovisioner this plugin extends now lives
The last two are gem dependencies and are installed for you.
The daemon is found via DOCKER_HOST, then /var/run/docker.sock, then
tcp://127.0.0.1:2375. Set docker_host_url to override.
Installation
kitchen-dokken is bundled with
Cinc Workstation and with
Chef Workstation, so if you
have either installed you already have it.
Otherwise, add it to your cookbook's Gemfile:
gem "kitchen-dokken"or install the gem directly:
gem install kitchen-dokkenThe examples below use Cinc. Everything works identically with Chef Infra Client — see Using Cinc and Using with Chef.
Quick start
Create a kitchen.yml in your cookbook:
---
driver:
name: dokken
chef_version: latest
transport:
name: dokken
provisioner:
name: dokken
product_name: cinc
verifier:
name: inspec
platforms:
- name: almalinux-9
driver:
image: dokken/almalinux-9
pid_one_command: /usr/lib/systemd/systemd
- name: ubuntu-24.04
driver:
image: dokken/ubuntu-24.04
pid_one_command: /bin/systemd
suites:
- name: default
run_list:
- recipe[my_cookbook::default]Then run it:
kitchen testUseful during development:
kitchen converge default-almalinux-9 # apply the run_list, keep the container
kitchen login default-almalinux-9 # shell into the running container
kitchen verify default-almalinux-9 # run InSpec against it
kitchen destroy # clean upThe dokken/* images used above come from
dokken-images: distro images
pre-loaded with the packages Ohai and a debugging session expect. See
Using dokken-images.
How it works
A single kitchen create builds up to three containers per suite.
┌───────────────────────────────┐
/opt/chef ─────▶ │ │
(volume) │ runner │
│ <hash>-default-almalinux-9 │ ◀── docker exec
/opt/kitchen ────▶│ │ (converge, verify,
/opt/verifier │ your cookbook converges │ login)
(bind or volume) │ in here │
└───────────────────────────────┘
The chef container is a stopped container created from chef/chef:<version>.
Nothing runs in it; it exists so its /opt/chef can be mounted into the runner
with VolumesFrom. It is shared by every suite using the same Chef version, so
the image is pulled once no matter how many suites you run.
The runner container is where your cookbook actually converges. It is built
from a per-suite work image — your platform image plus any
intermediate_instructions — and kept alive by
pid_one_command, so the same container serves every subsequent converge,
verify and login.
The data container is only created when the Docker daemon cannot read your local filesystem: a remote daemon, or Test Kitchen itself running inside a container. In that case the kitchen sandbox is copied into it over SSH and shared with the runner, instead of being bind-mounted. On a local daemon this container is never created.
Between them you will see something like this while a suite is up:
$ docker ps -a --format '{{.Names}}\t{{.Image}}\t{{.Status}}'
1f9d1cc06d-default-almalinux-9 1f9d1cc06d-default-almalinux-9:latest Up 2 minutes
chef-latest chef/chef:latest Createdkitchen destroy removes the runner and its work image. The chef container and
the dokken network are deliberately left behind — they are shared, and
rebuilding them is the slow part.
Configuration reference
Every option below is optional; the defaults are what you get from the
kitchen.yml in Quick start. Types are given because several
options accept more than one shape — anywhere String, Array<String> appears,
a bare scalar is wrapped for you, so cap_add: SYS_ADMIN and
cap_add: [SYS_ADMIN] mean the same thing.
Driver
Image and Chef Infra Client
| Option | Type | Default | Description |
|---|---|---|---|
image |
String | derived from the platform name | Base image for the platform under test, e.g. dokken/almalinux-9. Falls back to <platform>:<release>. |
chef_version |
String | latest |
Tag of the Chef Infra image to mount. Also accepts current for pre-releases, or stable as an alias for latest. |
chef_image |
String |
chef/chef (or cincproject/cinc) |
Repository the Chef Infra Client is mounted from. |
intermediate_instructions |
String, Array<String> | none | Extra Dockerfile lines baked into the work image. See Minimalist images. |
image_prefix |
String | none | Prefix for the locally built work image name. |
pull_platform_image |
Boolean | true |
Always pull the platform image. false pulls only when it is missing. |
pull_chef_image |
Boolean | true |
Always pull the Chef Infra image. false pulls only when it is missing. |
platform |
String |
"" (the daemon's own) |
OCI platform to pin containers and images to, e.g. linux/arm64/v8. See Multi-architecture testing. |
Container runtime
| Option | Type | Default | Description |
|---|---|---|---|
pid_one_command |
String | sh -c "trap exit 0 SIGTERM; while :; do sleep 1; done" |
Command run as PID 1 to keep the container alive. Set to an init for service testing. |
entrypoint |
String, Array<String> | none | Container Entrypoint. |
env |
Array<String> | none | Environment variables, as KEY=value strings. |
privileged |
Boolean | false |
Run privileged. Forces host user namespaces, because the daemon will not run a privileged container inside one. |
cap_add |
String, Array<String> | none | Linux capabilities to add. |
cap_drop |
String, Array<String> | none | Linux capabilities to drop. |
security_opt |
String, Array<String> | none | Values for --security-opt, e.g. seccomp=unconfined. |
userns_host |
Boolean | false |
Shorthand for user_ns_mode: host: disable user-namespace remapping for the container. |
user_ns_mode |
String | none | Docker UsernsMode for the container. Wins over userns_host; privileged forces host regardless. |
cgroupns_host |
Boolean | false |
Run in the host cgroup namespace. |
memory_limit |
Integer |
0 (unlimited) |
Container memory limit, in bytes. |
Volumes
| Option | Type | Default | Description |
|---|---|---|---|
volumes |
Array<String>, Hash | none | Anonymous volumes. Entries containing a colon are treated as host:container bind mounts and moved into binds for you. |
binds |
Array<String> | [] |
Bind mounts, in Docker host:container[:opts] form. |
tmpfs |
Hash, Array<String> | {} |
tmpfs mounts, as a /path: options mapping or "/path:options" strings. |
Networking
| Option | Type | Default | Description |
|---|---|---|---|
hostname |
String | dokken |
Container hostname, also registered as a network alias. |
hostname_aliases |
String, Array<String> | none | Extra network aliases resolving to the container. |
network_mode |
String | dokken |
Docker network to attach to. host and bridge skip alias configuration. |
ports |
String, Integer, Array, Hash | none | Published ports: container, host:container or ip:host:container, with optional /proto and low-high ranges. |
dns |
String, Array<String> | none | Nameservers for the container. |
dns_search |
String, Array<String> | none | DNS search domains for the container. |
links |
String, Array<String> | none | Legacy container links. |
ipv6 |
Boolean | false |
Create the dokken network with IPv6 enabled. |
ipv6_subnet |
String | 2001:db8:1::/64 |
Subnet used when ipv6 is on. |
Registries
| Option | Type | Default | Description |
|---|---|---|---|
docker_registry |
String | none | Registry prefix applied to every image pulled. |
creds_file |
String | none | Path to a JSON file of registry credentials. See Private registries. |
docker_config_creds |
Boolean | true |
Read credentials from ~/.docker/config.json. |
Daemon and data container
| Option | Type | Default | Description |
|---|---|---|---|
docker_host_url |
String | auto-detected | Docker daemon to talk to. |
read_timeout |
Integer | 3600 |
Docker API read timeout, in seconds. |
write_timeout |
Integer | 3600 |
Docker API write timeout, in seconds. |
api_retries |
Integer | 20 |
How many times to retry a retryable Docker API call. |
docker_info |
Hash | queried from the daemon | Cached docker info output, used to detect the daemon's operating system. Resolved automatically; set it only to override that detection. |
data_image |
String | dokken/kitchen-cache:latest |
Image the data container is built from. Only used when the daemon cannot read your filesystem — see Remote and containerised Docker hosts. |
data_ssh_port |
Integer, String | none | Fixed host port for the data container's SSH service. |
pre_create_command, which the Test Kitchen driver base class declares, is
not supported: kitchen-dokken replaces create outright and never runs
it.
Provisioner
| Option | Type | Default | Description |
|---|---|---|---|
product_name |
String | chef |
chef or cinc. See Using Cinc. |
product_version |
String | the driver's chef_version
|
Version of the client the provisioner reports running. Follows chef_version unless overridden. |
chef_license |
String | prompted, then remembered | License acceptance value, e.g. accept, accept-silent, accept-no-persist. Set it to avoid an interactive prompt in CI. |
chef_binary |
String | /opt/chef/bin/chef-client |
Client binary to run. Defaults to the Cinc path when product_name: cinc. |
chef_options |
String | " -z" |
Options passed to the client. A leading space is added if you omit it. |
chef_log_level |
String | warn |
Value for -l. This is the log level the client actually runs at: it also overwrites the inherited log_level, so setting log_level on its own has no effect. |
chef_output_format |
String | doc |
Value for -F. |
root_path |
String | /opt/kitchen |
Where the kitchen sandbox is mounted inside the container. |
clean_dokken_sandbox |
Boolean | true |
Empty the sandbox after each converge. See Preserving the Chef cache. |
profile_ruby |
Boolean | false |
Pass --profile-ruby. |
slow_resource_report |
Boolean, Integer | none | Pass --slow-report. An Integer sets the threshold. Requires Chef Infra Client 17.2+. |
docker_host_url |
String | auto-detected | Docker daemon the provisioner resolves its own docker_info against. |
docker_info |
Hash | queried from the daemon | Cached docker info output for the provisioner's docker_host_url. The driver, provisioner and transport resolve this independently. |
The provisioner inherits from ChefInfra, so enforce_idempotency,
multiple_converge, deprecations_as_errors, retry_on_exit_code,
max_retries, wait_for_retry, attributes, named_run_list,
policyfile, berksfile_path and the rest of the cookbook-resolution options all
work here too.
Two inherited options do not, because this provisioner replaces call
rather than extending it:
-
uploads— files are never copied in. -
downloads— files are never copied out. The transport implements nodownloadeither, so this one is a genuine gap rather than a decision.
Transport
| Option | Type | Default | Description |
|---|---|---|---|
login_command |
String | docker |
Executable used by kitchen login. |
write_timeout |
Integer | 3600 |
How long a single docker exec may run, in seconds. Despite the name this is a command timeout, not a Docker API timeout. |
read_timeout |
Integer | 3600 |
Accepted but unused. The transport's own API connection uses the global docker-api options; the driver's read_timeout is the one that has an effect. |
host_ip_override |
String, false
|
auto-detected | Address used to reach the data container's SSH service. Detected as host.docker.internal inside Docker Desktop, localhost against a Docker Desktop daemon, and unused otherwise. |
docker_host_url |
String | auto-detected | Docker daemon to talk to. |
docker_info |
Hash | queried from the daemon | Cached docker info output for docker_host_url. The driver, provisioner and transport resolve this independently. |
Recipes
Testing services and init systems
Containers are process-oriented, not machine-oriented, which matters as soon as
a recipe uses the service resource. To make systemd work, run it as PID 1:
platforms:
- name: almalinux-9
driver:
image: dokken/almalinux-9
privileged: true
pid_one_command: /usr/lib/systemd/systemdOlder kernels or daemons may also need the host cgroup filesystem mounted in:
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:roMinimalist images
Official distro images ship a package manager, coreutils and very little else — far less than a Vagrant box or a cloud image. You will often need to install prerequisites before Chef, InSpec or your own programs will run.
intermediate_instructions adds Dockerfile lines to the per-suite work image:
platforms:
- name: debian-12
driver:
image: debian:12
intermediate_instructions:
- RUN /usr/bin/apt-get update
- RUN /usr/bin/apt-get install -y apt-transport-https net-toolsAny valid Dockerfile instruction works. Use this as little as possible — it runs on every work-image build, and dokken-images usually solves the same problem for free.
Using dokken-images
dokken-images are distro
images pre-loaded with the packages that make Ohai behave and kitchen login
useful. They are rebuilt daily so package metadata stays fresh. Prefix a distro
with dokken/:
platforms:
- name: ubuntu-24.04
driver:
image: dokken/ubuntu-24.04
pid_one_command: /bin/systemdYou still need to specify pid_one_command yourself.
Using Cinc
Cinc Client is the community distribution of Chef Infra
Client. Set product_name: cinc on the provisioner; nothing else is required:
provisioner:
name: dokken
product_name: cincWith that set, kitchen-dokken pulls
cincproject/cinc instead of
chef/chef, uses a cinc-<version> volume container so it will not collide
with Chef Infra containers, runs /opt/cinc/bin/cinc-client, and skips the
Chef license prompt (Cinc is community-built and Apache-licensed).
Override chef_image or chef_binary if you need a custom Cinc image or a
non-standard install path.
Using with Chef
The examples in this README set product_name: cinc. Leaving it unset, or
setting product_name: chef, runs Chef Infra Client instead — that is the
driver's default:
provisioner:
name: dokken
product_name: chefWith Chef Infra Client you will need to accept the Chef licence, either by
setting chef_license on the provisioner or by answering the prompt. Cinc has
no such requirement.
Nothing else differs: the same driver, transport, and verifier options apply either way.
Using Podman
Multi-architecture testing
Set platform to test an architecture other than your host's. It is passed to
the daemon as an OCI platform, so emulation must be available (Docker Desktop
and binfmt_misc both provide it):
platforms:
- name: almalinux-9-arm
driver:
image: dokken/almalinux-9
platform: linux/arm64/v8The runner and the Chef volume container are both pinned to this platform,
since /opt/chef is mounted from one into the other. The data container is
not: it only serves files over SSH, and is always built for the host.
Networking
Publish ports, add aliases and set DNS on the driver:
driver:
name: dokken
hostname: web.example.com
hostname_aliases:
- web
- www
ports:
- '8080:80'
- '8301:8301/udp'
- '127.0.0.1:8500:8500'
- '9000-9002'
dns:
- 8.8.8.8
dns_search:
- example.comContainers join the dokken network by default, which is what lets suites
resolve each other by hostname. network_mode: host and network_mode: bridge
are also supported, but skip alias registration.
IPv6
driver:
name: dokken
ipv6: true
ipv6_subnet: "2001:db8:1::/64"This is effectively a global setting: kitchen-dokken does not reconfigure the
dokken network once it exists, so setting it per-suite will not do what you
expect. Check the current state with:
docker network inspect dokken --format='{{.EnableIPv6}}'If that prints false, delete the network and let dokken recreate it.
For IPv6 containers to reach the internet, the daemon needs ip6tables
support in /etc/docker/daemon.json (restart the daemon afterwards):
{
"experimental": true,
"ip6tables": true
}Some images additionally need the ip6table_filter module loaded on the host:
sudo lsmod | grep ip6table_filter || sudo modprobe ip6table_filterPrivate registries
Credentials are scoped to the registry an image is pulled from, the way the
docker CLI scopes them. An image whose registry has no matching entry is
pulled anonymously rather than with some other registry's credentials.
By default ~/.docker/config.json is read, so docker login is usually all
you need:
{
"auths": {
"quay.io": {
"auth": "<base64 encoded username:password>"
}
}
}Images with no registry prefix (almalinux:9, dokken/almalinux-8) resolve to
Docker Hub and use the https://index.docker.io/v1/ entry. docker.io and
registry-1.docker.io are accepted as Hub aliases too.
Credential helpers
work as well — kitchen-dokken runs docker-credential-<helper> on demand:
{
"credHelpers": {
"1234-cloud-registry.example.com": "example-cloud"
}
}Set docker_config_creds: false to ignore the Docker config entirely and pull
anonymously.
To supply credentials directly instead, point creds_file at a JSON file:
platforms:
- name: almalinux-9
driver:
image: registry.example.com/almalinux-9
creds_file: './creds.json'{
"username": "org_username",
"password": "password",
"email": "email@org.com",
"serveraddress": "https://registry.example.com/"
}A creds_file takes precedence over ~/.docker/config.json, and is used for
every registry.
Pulling through a mirror
To route every pull through your own registry or Docker Hub mirror:
driver:
docker_registry: docker.example.comThe mirror must carry the platform images you test with, plus the
almalinux:9 image used to build the data image.
Remote and containerised Docker hosts
When the daemon cannot read your local filesystem, kitchen-dokken
automatically builds the data container and ships the sandbox to it over SSH.
This happens when docker_host_url is a tcp:// URL (Docker Desktop and
Boot2Docker excepted — they share the host's files), or when Test Kitchen is
itself running inside a container.
The data container's SSH service is published on a random host port. Pin it if you need a predictable firewall rule:
driver:
name: dokken
data_ssh_port: 30000When Test Kitchen is the thing running in a container, that container also has
to be able to reach the containers it creates. They are attached to the
network_mode network — dokken by default — and Docker will not route from
the default bridge to a user-defined network, so attach kitchen's own container
to the same one:
docker network inspect dokken >/dev/null 2>&1 || docker network create dokken
docker run --rm \
--network dokken \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$PWD:/workspace" -w /workspace \
ruby:3.4 bundle exec kitchen testWithout it the converge fails at Transferring files with a connection
timeout.
Caching downloaded packages
Package downloads can be cached outside the container. On Debian and Ubuntu,
apt also needs to be told to stop deleting them:
driver:
name: dokken
volumes:
- /var/cache/apt/archives/:/var/cache/apt/archives/
platforms:
- name: ubuntu-24.04
driver:
image: dokken/ubuntu-24.04
pid_one_command: /bin/systemd
intermediate_instructions:
- RUN rm -f /etc/apt/apt.conf.d/docker-cleanPreserving the Chef cache
/opt/kitchen is emptied after every converge, which includes the Chef file
cache. For cookbooks that pull a lot of data with remote_file, keeping it
makes repeat converges much faster:
provisioner:
name: dokken
clean_dokken_sandbox: falseLimiting container memory
Memory is unbounded by default (or bounded by the Docker VM on macOS and Windows):
driver:
name: dokken
memory_limit: 2147483648 # 2GBtmpfs on /tmp
A container running an init system will usually mount a tmpfs over /tmp.
Because Docker bind-mounts the kitchen data before init starts, Bats and
Serverspec need to be pointed somewhere else. InSpec is unaffected.
verifier:
root_path: '/opt/verifier'
sudo: falseChef Infra Client options
provisioner:
name: dokken
chef_binary: /opt/chef/bin/chef-solo
chef_options: ""
chef_log_level: debug
chef_output_format: minimal
profile_ruby: true
slow_resource_report: trueUse chef_options: "" for old clients that predate -z.
Testing without Chef
If the image supplies a no-op binary that exits successfully, a suite can be verified without converging at all:
platforms:
- name: alpine
driver:
image: alpine:latest
provisioner:
chef_binary: /bin/truePre-release and archived Chef versions
Chef publishes every functioning build to
Docker Hub, including the current
channel:
driver:
chef_version: currentFor versions not published as chef/chef, point chef_image at another
repository:
driver:
chef_image: someara/chef
chef_version: 12.21.31Testing behind a TLS-intercepting proxy
Corporate networks often terminate TLS with an internal CA that containers do
not trust. intermediate_instructions plus entrypoint can install it into
both the system trust store and Chef's own bundle:
driver:
name: dokken
entrypoint: /bin/entrypoint
intermediate_instructions:
- RUN /usr/bin/openssl s_client -showcerts -verify 5 -connect example.com:443 </dev/null | /usr/bin/awk '/BEGIN/,/END/{if(/BEGIN/){a++}; certs[a]=(certs[a] "\n" $0)}; END {print certs[a]}' >> /usr/local/share/ca-certificates/ca.crt && update-ca-certificates
- RUN echo "#!/bin/sh -e\ncat /usr/local/share/ca-certificates/ca.crt >> /opt/chef/embedded/ssl/certs/cacert.pem\nexec \"\$@\"\n" >> /bin/entrypoint && chmod +x /bin/entrypointThe first instruction extracts the root CA from a live handshake and adds it to
the system trust store. The second writes an entrypoint that appends it to
Chef's CA bundle before exec'ing pid_one_command.
Note that each suite adds the certificate again, which accumulates disk usage over time. Prune regularly on CI.
A complete, non-trivial kitchen.yml lives in the
docker cookbook.
Troubleshooting
Two Test Kitchen commands answer most of the questions below without you having to guess:
kitchen doctor default-almalinux-9 # is the daemon reachable? is creds_file readable?
kitchen list --live # ask the daemon what is actually runningkitchen doctor reports the daemon it resolved, its version, and whether a
configured creds_file exists and parses — the two things that stop a run
before anything is built. kitchen list --live reads container state straight
from the daemon rather than from the last recorded action, so a container that
died out from under Test Kitchen shows as exited instead of created.
could not connect to the docker host ... Is docker running?
The daemon is unreachable. Check docker info, and set docker_host_url if
your daemon is not at DOCKER_HOST or /var/run/docker.sock.
Run kitchen doctor to see which daemon was resolved.
The service resource fails, or systemctl reports no init system.
Set pid_one_command to your init and run privileged: true. See
Testing services and init systems.
Ohai warnings, or a missing ip, ps or hostname command.
The base image is too minimal. Switch to a
dokken-image or add the packages with
intermediate_instructions.
A pull from a private registry returns 401.
Credentials are matched per registry. Confirm the registry host in your image
reference has an entry in ~/.docker/config.json, or supply a creds_file.
Changes to intermediate_instructions seem to be ignored.
The work image is cached per suite. Run kitchen destroy for that suite to
force a rebuild.
IPv6 settings do not take effect.
The dokken network is created once and never reconfigured. See
IPv6.
Transferring files to ... hangs or times out against a remote daemon.
The sandbox is shipped over SSH to a data container, and Test Kitchen has to
have a route to it. See
Remote and containerised Docker hosts
— when Test Kitchen is itself in a container, it has to join the dokken
network.
A container will not start, and the error names pid 1.
The image's PID 1 exited immediately. Check pid_one_command and
entrypoint, and read docker logs <instance-name>. If the daemon refused
outright the error says so instead, and quotes the daemon's own reason — a
capability the kernel would not grant, or a port already bound.
Stale containers or images are piling up.
kitchen destroy intentionally leaves the shared chef container and the
dokken network behind. Remove them by hand when you want a clean slate:
docker rm -f chef-latest
docker network rm dokkenContributing
Bug reports and pull requests are welcome. See CONTRIBUTING.md for how to set up, run the unit and integration suites, and what CI checks.
FAQ
What about kitchen-docker?
kitchen-docker bakes SSH, Chef and the kitchen data into the image, and works
as a general-purpose driver with any provisioner. kitchen-dokken blurs the
driver, transport and provisioner roles together to avoid all of that, at the
cost of only supporting Chef Infra.
See "Kitchen-Docker or Kitchen-Dokken?" for a longer comparison.
Can I publish the container I just tested?
There is no kitchen publish
(test-kitchen#329),
but you can do it by hand:
kitchen verify suite_name
docker stop suite_name
docker tag suite_name:latest registry.example.com:5043/org/image
docker push registry.example.com:5043/org/image
kitchen destroyDo I have to accept the Chef license?
Yes, for Chef Infra Client. See the license documentation. Cinc does not require it.
License
Apache-2.0. See LICENSE.