Docker and add_host: I'm doing it wrong.

So I’ve got to manage a relatively dynamic fleet of machines in the wild.

Wanting to keep the running environment of these things as bare-bones as possible, so decision was made to have all the complex bits inside of docker containers, what-for relative immutability and the like.

Clearly we want to use ansible to make sure the containers are doing what they ought to do when they’re supposed to be doing it.

Likewise, getting the hardware setup is a bit of a pain, so we use Ansible for this as well.

My first attempt goes something like this:

`

  • name: apply docker role
    hosts: docker-hosts
    roles:

  • role: docker_host # role that make sure docker is up to date, running, deploys the right images, starts containers

  • name: apply worker role
    hosts: workers # group that contains all the containers started on the docker-hosts
    roles:

  • role: worker
    `

And of course the final tasks in the docker_host role is:

`

  • name: add container as host
    add_host:
    name: “{{ inventory_hostname }}-container”
    ansible_host: “{{ ansible_eth0.ipv4.address }}”
    ansible_port: “{{ ssh_port }}”
    groups: workers
    `

Of course, this doesn’t work because add_host bypasses the host loop and only runs once.

Now I can’t imagine I’m the first person that’s wanted to spin up containers on multiple hosts, so there’s got to be a sane way to go about this.

I could just statically create both the host and the container in ansible_hosts, but that feels like exactly the sort of error-prone kludge we’re trying to avoid in the first place.

What am I missing? Is there a more sensible way to go about this?

You know what, I tried to be civil and do this the right way, but you’ve simply pushed me too far.

So, until I have some kind of answer about why add_host bypasses the host loop and what the idiomatic way to accomplish this is, I’m just going to say ‘to hell with it’ and unbypass that shizz.

That’s right, I LIVE DANGEROUS. Deal with it.

ansible/plugins/action/add_host.py, line 40:
    BYPASS_HOST_LOOP = False  # biatch!

which yields:

TASK [docker_host : run deployable image] ************************
ok: [h2]
ok: [h1]

TASK [docker_host : add container as host] ******************************
changed: [h1]
changed: [h2]

I’m still certain there’s some perfectly valid reason they have this disabled, but what we’ve got here is failure to communicate. Some developers you just can’t reach. So you get what we have here, which is the way they wants it. Well, they gets it. I don’t like it any more than you.

With add_host, generally speaking you want to use a with_items loop. You could do something like:

  • name: add containers as hosts
    add_host:
    name: “{{ item }}-container”
    ansible_host: “{{ hostvars[item].ansible_eth0.ipv4.address }}”
    ansible_port: “{{ hostvars[item].ssh_port }}”
    groups: workers

with_items: “{{ groups[‘docker-hosts’] }}”

That should do what you need.

That looks sensible. I guess the reason I didn’t go this route to begin with is I was hoping to have something that was more tied to the state of the earlier steps, but in the end I suppose it doesn’t matter.

Would it be sane to include this in a role? Or should this be outside of the role?

Also, if the ssh_port were dynamic/randomly assigned and I registered it in earlier steps, would the above still work?

Reading into it more, ‘post_tasks’ in site.yml seems like the right place for this, and is working fine.

I’d prefer to have the role be able to dictate the value of ssh_port, but I can’t seem to figure out a way to use that variable from post_tasks in site.yml. Not the end of the world I guess.

Thanks for the help though!