Background

Why Even Run Docker Containers with Ansible?

Well, I'm running my stuff in a Swarm. The problem is that Swarm does not (yet) allow you to configure Linux Kernel Capabilities on a container. But you can configure them with docker-compose or docker run. Lame.

Fortunately, I'm using Ansible to deploy some things on this server, so I have things in place already to use it to run a container.

Error Messages

I'm using Traefik as my Reverse Proxy. Traefik works best for dynamic service discovery through the use of Container Labels, or Service Labels. The distinction is very important, depending upon how you're scheduling your containers.

What's weird though, is with the labels shown below for my Ansible play... I would get cryptic errors about type conversion. YAML tries to implicitly detect the type of the value (See Ansible Docs on YAML for more detail).

labels:
  traefik.port: 9980

Will yield this error:

msg: 'Error creating container: 500 Server Error: Internal Server Error ("json: cannot unmarshal number into Go value of type string")'
labels:
  traefik.enable: true

Will yield this error

msg: 'Error creating container: 500 Server Error: Internal Server Error ("json: cannot unmarshal bool into Go struct field ContainerConfigWrapper.Labels of type string")'

To avoid YAML interpreting the type for the value of a dictionary, enclose the value in quotes:

labels:
  traefik.enable: "true"
  traefik.port: "9980"

Ansible Troubleshooting Tip

One pain about Ansible is the inconsistency with configuration files. It's just all over the place with presenting data structures..

  • Ansible's config file, ansible.cfg, by default is in an ini format. Same for hosts, except that can be in YAML too.
  • stdout from Ansible is not composed in a very structured way, by default.

But you can have it output things in a more consistent way (since plays are written in YAML). Export this environment variable to make verbose output print as YAML:

ANSIBLE_STDOUT_CALLBACK=yaml

And here's example output of an error when using -vvv flags, but much more readable than default:

The full traceback is:
  File "/tmp/ansible_xhulz3r_/ansible_module_docker_container.py", line 1966, in container_create
    new_container = self.client.create_container(image, **create_parameters)
  File "/usr/lib/python3/dist-packages/docker/api/container.py", line 449, in create_container
    return self.create_container_from_config(config, name)
  File "/usr/lib/python3/dist-packages/docker/api/container.py", line 460, in create_container_from_config
    return self._result(res, True)
  File "/usr/lib/python3/dist-packages/docker/api/client.py", line 226, in _result
    self._raise_for_status(response)
  File "/usr/lib/python3/dist-packages/docker/api/client.py", line 222, in _raise_for_status
    raise create_api_error_from_http_exception(e)
  File "/usr/lib/python3/dist-packages/docker/errors.py", line 31, in create_api_error_from_http_exception
    raise cls(e, response=response, explanation=explanation)

fatal: [104.248.184.48]: FAILED! => changed=false 
  invocation:
    module_args:
      api_version: null
      auto_remove: false
      blkio_weight: null
      cacert_path: null
      capabilities:
      - MKNOD

References