Ansible for Docker Containers | Just YAML Things

Ansible for Docker Containers | Just YAML Things

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