Running `service` resources in Kitchen-Docker

When writing cookbooks, you need to actually test that they work. This is often done using Test Kitchen, a tool that allows you to converge your cookbooks on a real machine. There are a number of drivers that can be used, such as kitchen-vagrant and kitchen-docker.

For instance, I run against Docker due to its incredible speed compared to running on a virtual machine, and also due to the fact that this means I can use Docker with GitLab CI.

Getting kitchen-docker set up

For instance, let’s assume we have a .kitchen.yml configured to use Vagrant as a driver:

driver:
  name: docker

provisioner:
  name: chef_zero
  # You may wish to disable always updating cookbooks in CI or other testing environments.
  # For example:
  #   always_update_cookbooks: <%= !ENV['CI'] %>
  always_update_cookbooks: true

verifier:
  name: inspec

platforms:
  - name: debian
    driver_config:
      image: debian:jessie

suites:
  - name: default
    run_list:
      - recipe[cookbook::default]
    verifier:
      inspec_tests:
        - test/smoke/default
    attributes:

However, when running any of the kitchen commands, you may encounter the following error:

$ kitchen list
>>>>>> ------Exception-------
>>>>>> Class: Kitchen::UserError
>>>>>> Message: You must first install the Docker CLI tool http://www.docker.io/gettingstarted/
>>>>>> ----------------------
>>>>>> Please see .kitchen/logs/kitchen.log for more details
>>>>>> Also try running `kitchen diagnose --all` for configuration

This is due to the Docker driver not being able to correctly find the CLI tool. An easy fix is to add the following to our driver section in the .kitchen.yml:

 driver:
   name: docker
+  # make kitchen detect the Docker CLI tool correctly, via
+  # https://github.com/test-kitchen/kitchen-docker/issues/54#issuecomment-203248997
+  use_sudo: false

Running service commands

Next, we want to be able to interact with services via Chef’s service resources. Trying to interface with a service in a Docker container results in the following error:

$ sudo systemctl restart mysql
Failed to get D-Bus connection: Operation not permitted

This is due to the whole point of docker containers running a single application. When trying to interface with a service, this requires a full init system, with multiple processes running on top of it. This means that you’re using Docker for something it’s not built for (out of the box).

Therefore, you need to extend the Docker container to have its own init system, as well as giving it root access across the host system: that is, this new container that is meant to be separate, and have its own nicely sandboxed resources will have root access to your machine. Be aware of the security risks this can cause on your machine - I have no responsibility for issues caused.

Following the advice in Stack Overflow: Kitchen-Docker and Systemd:

 driver:
   name: docker
   # make kitchen detect the Docker CLI tool correctly, via
   # https://github.com/test-kitchen/kitchen-docker/issues/54#issuecomment-203248997
   use_sudo: false
+  run_command: /bin/systemd
+  cap_add:
+    - SYS_ADMIN
+  volume:
+    - /sys/fs/cgroup

run_command defines what command should be run by the container, which in this case would be systemd, the init system used by Debian Jessie.

As mentioned, we also need to give it the SYS_ADMIN capability, which gives it root access across the machine.

Finally, we also need to give it access to the cgroups config, which is an expectation of systemd.

*****

Written by Jamie Tanna on 03 September 2017, and last updated on 03 September 2017.

Tags

Categories