Ansible's docker module volumes option is a mystery (to me)

Hi all,

I tried to use the volumes option and nothing seems to work for me.

I want to mount 2 directories ~/dockerstorage/model and ~/repo/ops/ansible to the container and I used either of these commands and nothing worked.

docker: image:5000=registry.my.com/steven/centos65_prod_ready:v1 docker_url=tcp://{{ ansible_default_ipv4.address }}:7777 publish_all_ports=True state=running volumes=/home/kafka/models:{{ myhome.stdout }}/dockerstorage/models:rw,/usr/local/src/ansible:{{ myhome.stdout }}/repo/ops/ansible:ro

docker: image:5000=registry.my.com/steven/centos65_prod_ready:v1 docker_url=tcp://{{ ansible_default_ipv4.address }}:7777 publish_all_ports=True state=running volumes={{ myhome.stdout }}/dockerstorage/models:/home/kafka/models:rw,{{ myhome.stdout }}/repo/ops/ansible:/usr/local/src/ansible:ro

I sshed into the containers and the mounted points in either case were all empty.

I ran using docker directly and it worked for me:



docker run -d -P  -v /home/steven/dockerstorage/models:/home/kafka/models:rw -v /home/steven/repo/ops/ansible:/usr/local/src/ansible:ro registry.my.com:5000/steven/centos65_prod_ready:v1


Please let me know what is the right ways to use “volumes” for docker. >From the comments in the docker module, it appears to me that the /mnt:/tmp is in reversed orders from those of the docker command line because of the case when we just want to create a volume such as /mnt and there is no equivalent mounted point from the host. I think that this is confusing and users have to read the codes to find out.

Thanks,
Steven.

[root@sc2-dock1 cloud]# pwd
/usr/local/ansible/library/cloud

class DockerManager:

counters = {‘created’:0, ‘started’:0, ‘stopped’:0, ‘killed’:0, ‘removed’:0, ‘restarted’:0, ‘pull’:0}

def init(self, module):
self.module = module

self.binds = None
self.volumes = None
if self.module.params.get(‘volumes’):
self.binds = {}
self.volumes = {}
vols = self.module.params.get(‘volumes’)
for vol in vols:
parts = vol.split(“:”)

host mount (e.g. /mnt:/tmp, bind mounts host’s /tmp to /mnt in the container)

if len(parts) == 2:
self.volumes[parts[1]] = {}
self.binds[parts[0]] = parts[1]

docker mount (e.g. /www, mounts a docker volume /www on the container at the same location)

else:
self.volumes[parts[0]] = {}

If you remove the variables and hard-code the paths, does it work for you then? I’m curious if things like spaces/newlines in the stdout variables you’re using are causing the problem.

You might want to put in a “- debug: var=myhome” before the docker task to view the value of stdout there.

TASK: [echo $myhome] **********************************************************
ok: [localhost] => {
“myhome”: {
“changed”: true,
“cmd”: “echo $HOME”,
“delta”: “0:00:00.165168”,
“end”: “2014-08-26 19:22:36.055947”,
“invocation”: {
“module_args”: “echo $HOME”,
“module_name”: “shell”
},
“rc”: 0,
“start”: “2014-08-26 19:22:35.890779”,
“stderr”: “”,
“stdout”: “/root”,
“stdout_lines”: [
“/root”
]
}
}

I removed :rw and :ro and it still did not work. I think that Ansible does not support these third fields yet.

Steven.

I merged in support for specifying :ro/:rw a few weeks ago, and it was included in the 1.7.1 release.

Volumes also don’t appear to be working for me either. I can start the container, but the mounted volume is always empty inside the container, despite the host having two volumes. As the original poster says, if I just use the docker command directly, the volume mount works as expected.

  • name: Start Registry
    docker: image={{docker_image}} state=running volumes=“/etc/docker-registry/keys:/etc/docker-registry/keys” name=registry

See anything wrong?

Can you share the version of Ansible, docker-py, and Docker being used in this case?

Thanks!

[clduser@docker-registry ~]$ sudo docker -v
Docker version 1.1.2, build d84a070/1.1.2

[clduser@docker-registry ~]$ pip list | grep docker
docker-py (0.4.0)

Using the latest ‘devel’ branch of Ansible. Just repulled now and still experiencing this as of commit c610783f900586b170a6dfa3a02696f568a11728.

Ok can you please file a ticket on this one so we can investigate?

Thanks!

So I actually got this working. It think some of my confusion comes from how to specify ‘list’ variables. The docker module, says the ‘volumes’ parameter was a ‘list’. Being new to Ansible and with no volumes example, I dug around a bit. EC2 module has a ‘list’ var of instance-ids and this example:

`
vars:
instance_ids:

  • ‘i-xxxxxx’
  • ‘i-xxxxxx’
  • ‘i-xxxxxx’
    region: us-east-1
    tasks:
  • name: Start the sandbox instances
    local_action:
    module: ec2
    instance_ids: ‘{{ instance_ids }}’
    `

So I tried to copy that with docker:

`
vars:
theVolumes:

  • ‘/etc/foo:/foo’
  • ‘/etc/bar:/bar’
    tasks:
  • name: run bash
    docker:
    image=centos
    volumes=‘{{ theVolumes }}’
    state=running
    stdin_open=yes tty=yes
    command=/bin/bash
    `

But docker client does not like that.

<96.119.0.167> REMOTE_MODULE docker image=centos volumes=‘[’/etc/foo:/foo’, ‘/etc/bar:/boo’]’ state=running stdin_open=yes tty=yes command=/bin/bash
msg: Docker API error: Cannot start container 35fb847fdc84ff5bcbdce19b9a443a4eb86de5018d96fd620ca22dcb7dc4f3b0: /etc/bar must be an absolute path

Despite the fact that it appears to have parse the volumes correctly, I get the absolute path error seen above. If I change the command to:

`
tasks:

  • name: run bash
    docker:
    image=centos
    volumes=‘/etc/foo:foo,/etc/bar:bar’
    state=running
    stdin_open=yes tty=yes
    command=/bin/bash

`

My guess is that this works with ec2 because that’s running locally, but docker has to serialize the list to the server? I think my other issues were red-herrings and I was getting confused reading the code. How does the docker module know that a string with commas in it is a list?

`
if self.module.params.get(‘volumes’):
self.binds = {}
self.volumes = {}
vols = self.module.params.get(‘volumes’)
for vol in vols:

`

Is the fact that it is annotated a ‘list’ in the module spec (volumes= dict(default=None, type=‘list’)) make Ansible ‘pre-parse’ that String into a List? Should the user really have to change how they specify a list based on whether it is executed locally or remotely? I am able to use var if I do this:

`
vars:
theVolumes:

  • ‘/etc/foo:/foo’
  • ‘/etc/bar:/bar’
    tasks:
  • name: run bash
    docker:
    image=centos
    volumes={{ theVolumes | join(‘,’) }}
    state=running
    stdin_open=yes tty=yes
    command=/bin/bash

`

But IMO if their is Ansible magic with lists going on, it should do that already.

Any final prognosis on this issue? Specfically, how should the volumes be specified. An example would be nice!
I’m urgently waiting to use this feature.
–BK

@Matt - the issue you’re seeing is due to the fact that your missing YAML lists with the k=v syntax for modules. If you used the “complex arguments” syntax for the module, you wouldn’t have to do the join. For example:

vars:
theVolumes:

  • ‘/etc/foo:/foo’
  • ‘/etc/bar:/bar’
    tasks:
  • name: run bash
    docker:
    image: centos
    volumes: “{{ theVolumes }}”
    state: running
    stdin_open: yes
    tty: yes
    command: /bin/bash

should work without any issues.

The user does not have to change how they specify a list based on it being local or remote - that is not a thing in Ansible.

You do need to use the “:” form in the arguments though, any time you want to pass structured data to a module.

Ah, so = does an implicit ‘toString’ on the variable I presume?

Yeah basically - it’s Jinja2 templated down to a string, losing any type info.

Hi all,

Docker volumes worked fine for me as long as I use ansible to run docker on local system, but not working fine when I try to use ansible to run docker on a remote node. My question is whether docker expects the host directory in volumes option to be on system running ansible or the remote node. I’ve got no results when I had host directory in remote node.

The volumes need to be where docker is running. So yes, host directory should be on the remote node running docker.

But ansible module is not working properly on remote nodes

Do you have the required Python module installed on the remote node? I believe it is docker-py but check the docket module to be sure.

Yeah latest version (0.7.0) of docker-py is installed. Except volumes option all other docker options are working fine.