Managing Docker containers from Ansible plays

I am in the process of writing my first ever Ansible playbook and am in need of a bit of steering. I have a simple network that consists of 3 VMs:

  • ansible01 – my Ansible server (Ubuntu)
  • db01 – a DB (again, Ubuntu)
  • myapp01 – an Ubuntu VM hosting a Java app

I have configured my /etc/ansible/hosts file like so:

  • Why has Docker volume run out of space?
  • boot2docker startup script to mount local shared folder with host
  • how to create docker restricted network
  • docker elasticsearch container not forwarding port
  • Connect to RPC Server in Docker
  • What is the difference between the size and the virtual size of the docker images?
  • [databases]
    db01.example.com
    
    [app_servers]
    myapp01.example.com
    myapp02.example.com
    

    I have configured SSH correctly, and I can run ansible all ping -m and Ansible is able to ping the DB and app server nodes. So far so good.

    I’m trying to write three (3) Docker-related playbooks that will accomplish the following:

    • Ensure that Docker is running on all [databases] nodes as well as all [app_servers] nodes; if it is not installed and running, then install Docker engine and start running it. If it is installed but not running, restart it.
    • Stop/start/restart all containers running for a specific type of node (“role“?!?). For instance, I’d like to tell Ansible that I want to restart all containers running on all [app_servers] nodes.
    • Stop/start/restart an arbitrary container running on an arbitrary node. For instance, perhaps myapp01 has 2 containers running on it, fizz and buzz. I’d like to be able to tell Ansible to restart (specifically) myapp01’s fizz container, but not its buzz container, nor any myapp02 containers.

    I believe these belong in three separate playbooks (correct me if I’m wrong or if there’s a better way). I took a stab at them. The first is setup_docker.yml:

    - name: ensure docker engine is installed and running
      docker:
        name: *
        state: started
    

    Then for restarting all [databases], in restart_app_servers.yml:

    - name: restart app servers
      docker:
        name: app_servers
        state: restarted
    

    And for restarting an arbitrary container on a single node (restart_container.yml):

    - name: restart a specific container
      docker:
        name: %name_of_container_and node%
        state: restarted
    

    But several problems here:

    1. In setup_docker.yml, how do I specify that all node types ([databases] and [app_servers]) should be affected? I know that asterisk (“*”) isn’t correct.
    2. In restart_app_servers.yml, what is the proper value for the name field? How do I actually tell Ansible to restart all app_server nodes?
    3. In restart_container.yml, how do I “inject” (pass in as arguments/variables) the node’s and container’s names? Ideally I’d like to run this playbook against any node and any container.
    4. Anything else jumping out at you as wrong?

    Thanks in advance!

  • Pushing Docker Hub images to private Docker Registry
  • Running kubernetes autoscalar
  • Docker environmental variables as calculated parameters
  • docker odoo 9 install pika error
  • Docker : Unable to resolve the name of the machine host?
  • Host-based-containers vs image-based-containers
  • One Solution collect form web for “Managing Docker containers from Ansible plays”

    I think you have Plays and Playbooks mixed up in meaning here. The three things you have specified above, setup_docker.yml, restart_app_servers.yml, and restart_container.yml appear to be Plays. I recommend creating a Docker role which contains the tasks you have detailed here.

    To address your problems:

    1. In setup_docker.yml, how do I specify that all node types ([databases] and [app_servers]) should be affected? I know that asterisk (“*”) isn’t correct.

    This is done at the Playbook level. You can specify which hosts you want to be effected by which tasks, e.g:

    #docker.yml
    - hosts: all
      user: {{ privileged_user }} 
      gather_facts: false
      roles: 
        - install_docker
    

    Then in your install_docker role, you would have something along the lines of:

    - name: Add docker apt keys
      apt_key: keyserver=keyserver.ubuntu.com id=36A1D7869245C8950F966E92D8576A8BA88D21E9
    - name: update apt 
      apt_repository: repo='deb https://get.docker.com/ubuntu docker main' state=present
    - name: Install docker
      apt: pkg=lxc-docker update_cache=yes
    
    1. In restart_app_servers.yml, what is the proper value for the name field? How do I actually tell Ansible to restart all app_server nodes?

    I’m assuming you mean you wish to restart all Docker containers on each of the nodes which belong to the app-server group?
    I would keep an inventory of all of the container names for each group (since this example is relatively simple). e.g:

    #group_vars/app-server
    all_containers: [ 'container1', 'container2', 'container3',.. 'containern' ]
    

    From here you can use this inventory in your Play to restart each container. In your Playbook:

    #restart_app_containers.yml
    - hosts: app_server
      user: {{ privileged_user }}
      gather_facts: false
      roles: 
        - restart_app_servers
    

    Then in the Play itself:

    #restart_app_servers.yml
    - name: restart app servers
      docker:
        name: {{ item }}
        state: restarted
      with_items: all_containers
    
    1. In restart_container.yml, how do I “inject” (pass in as arguments/variables) the node’s and container’s names? Ideally I’d like to run this playbook against any node and any container.

    For this portion you would need to reference your container directly which you need to act against. This can be done with Dynamic Inventory, e.g

    #sample.yml
    - hosts: Tag_name_{{ public_name }}
      user: {{ privileged_user }}
      gather_facts: false
      roles:
        - example
    

    In the event you are on AWS. The hosts dictionary would vary by infrastructure.
    Then in your actual play you listed, you can pass in the specific variable. Since it’s a single container on a single host, you could do this via the command line:

    ansible-playbook -i $INVENTORY_FILE -e container_name=$CONTAINER_NAME restart_single_container_on_single_host.yml 
    

    Where your Play would look something like:

    - name: restart a specific container
      docker:
        name: {{ container_name }}
        state: restarted
    
    Docker will be the best open platform for developers and sysadmins to build, ship, and run distributed applications.