Home » DevOps » Packer, Ansible and Docker Part 3: Multiple Roles

About James Carr

Packer, Ansible and Docker Part 3: Multiple Roles

Previously we modified our setup to use a role from ansible galaxy to install and configure redis. One key thing lacking here is that one rarely needs to just use a role from ansible galaxy by itself so next up we’ll modify our playbook to define the server as a role that uses the redis role.

Creating Our Role

First up we’ll create a role directory containing our role and a few subdirectories we’ll use later.

mkdir -p roles/redis/{meta,tasks,defaults}

Next up, we’ll move the geerlingguy.redis role into a dependency for this new role in roles/meta/main.yml.

---
dependencies:
  - role: geerlingguy.redis

We also change the playbook.yml to reference this new role and remove the Hello World task we added in part one.

---
- name: A demo to run ansible in a docker container
  hosts: all
  roles:
    - redis

That’s all for now. We’ll run packer build template.json one more time before we move on to make sure everything is working fine. If it’s not, check out the current directory structure at https://github.com/jamescarr/pad-tutorial/tree/part-3-a.

Making It Dynamic

This has been nice and all but now we’ve reached a point where we need to create more server roles. We could just copy and paste the existing template.json and change a few bits but that will become a headache, won’t it? What we should do is use a variable in packer to dynamically change which role we use.
The good news is that we already have a packer variable named ansible_role that we can repurpose for this need. We previously set it to default but we’re going to change it to specify the role to run. With this in mind, we modify our playbook.yml to use the ansible_host variable as the role that is included.

---
- name: A demo to run ansible in a docker container
  hosts: all
  roles:
    - "{{ ansible_host }}"

While we’re at it, let’s also change the docker image name and add a variable for the version number too. Add a version variable to the variables section of template.json and default it to latest.

"variables": {
    "ansible_host": "",
    "version": "latest",
    "ansible_connection": "docker",
    "ansible_roles_path": "galaxy"
  },

We also update the post-processor section to use the ansible_host and version.

"post-processors": [
    [
      {
        "type": "docker-tag",
        "repository": "jamescarr/{{ user `ansible_host` }}",
        "tag": "{{ user `version` }}"
      }
    ]

Now we can run packer again but this time we specify the ansible_host. We’ll just build a docker image with the latest tag but if we wanted to override it we could specify the version too.

> $ packer build -var 'ansible_host=redis' template.json

Now we can create separate roles for any new docker image we want to build with this template and can include any cross cutting, “all images get this” tasks to the playbook.yml but it is good to keep them all encapsulated in a single role.

Add Another Role

With all this snazzy dynamic pieces in place, let’s add one more role to build a docker image for. For fun, we’ll select RabbitMQ. A quick google makes it appear that Mayeu.RabbitMQ is the role to use so let’s run with that and add it to our requirements.yml.

---
- src: geerlingguy.redis
  version: 1.1.5
- src: https://github.com/jamescarr/ansible-playbook-rabbitmq/archive/e303777.tar.gz
  name: Mayeu.RabbitMQ

In this case, I actually discovered a defect in the latest release of the role that I was able to easily fix so I instead reference the git commit hash of my fork. Thankfully anisble-galaxy is flexible like that.
Since we’ll probably find ourselves changing this often, let’s add a shell-local provisioner to packer under the provisioners section to run ansible-galaxy all the time as the first step.

{
   "type": "shell-local",
   "command": "ansible-galaxy install -p galaxy -r requirements.yml"
}

Next up we’ll create the role structure for our RabbitMQ role.

> $ mkdir -p roles/rabbitmq/{meta,tasks,defaults}

This time around we won’t just use the galaxy role, we’ll also configure it to our likings. For our needs we want to configure RabbitMQ with a host of plugins and define a default vhost with one user that can write to any exchange (but not configure or read from queues) and one user that is the administrator. With this in mind we add the following to roles/rabbitmq/meta/main.yml.

---
dependencies:
  - role: Mayeu.RabbitMQ 
    rabbitmq_ssl: false
    rabbitmq_plugins:
      - rabbitmq_management
      - rabbitmq_management_agent
      - rabbitmq_shovel
      - rabbitmq_federation
      - rabbitmq_shovel_management
    rabbitmq_vhost_definitions:
      - name: "{{ main_vhost }}"
    rabbitmq_users_definitions:
      - vhost:    "{{ main_vhost }}"
        user:     user1
        password: password
        configure_priv: "^$"
        read_priv: "^$" # Disallow reading.
        write_priv: ".*" # allow writing.
      - vhost:    "{{ main_vhost }}"
        user:     admin
        password: password
        force:    no
        tags:
        - administrator

We also use the same vhost name multiple times so rather than duplicate it all over we define a variable for it in roles/rabbitmq/defaults/main.yml.

---
main_vhost: /faxanadu

With all of these bits in place, let’s run packer to build out our new rabbitmq docker image!

> $ packer build -var 'ansible_host=rabbitmq' template.json

When this is done, we should have a docker image that can run rabbitmq with our expected configuration details!

[email protected] ~/Projects/docker-ansible                                                                                                                        [11:47:53]
> $ docker run -it -p 15672:15672 -p 5672:5672 jamescarr/rabbitmq:latest rabbitmq-server
⬡6.2.2 [±master ●]
RabbitMQ 3.6.6. Copyright (C) 2007-2016 Pivotal Software, Inc.
  ##  ##      Licensed under the MPL.  See http://www.rabbitmq.com/
  ##  ##
  ##########  Logs: [email protected]
  ######  ##        [email protected]
  ##########
              Starting broker...
 completed with 9 plugins.


Looks good! You can see the latest state of the project at https://github.com/jamescarr/pad-tutorial/tree/efc9e035eaa0a27ba2d6066ed04a37f5efa4bf42.

Next

Unfortunately when we try to login to the rabbitmq management console we’ll notice that none of our configured users work. That’s because they were created under the hood by rabbitmqctl and not persisted. In the next post we’ll modify our little build system we have going here to run a subset of tasks on container start!

Reference: Packer, Ansible and Docker Part 3: Multiple Roles from our WCG partner James Carr at the James Carr blog.

Do you want to know how to develop your skillset to become a Web Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!

 

1. Building web apps with Node.js

2. HTML5 Programming Cookbook

3. CSS Programming Cookbook

4. AngularJS Programming Cookbook

5. jQuery Programming Cookbook

6. Bootstrap Programming Cookbook

 

and many more ....

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *

*

Want to take your WEB dev skills to the next level?

Grab our programming books for FREE!

Here are some of the eBooks you will get:

  • PHP Programming Cookbook
  • jQuery Programming Cookbook
  • Bootstrap Programming Cookbook
  • Building WEB Apps with Node.js
  • CSS Programming Cookbook
  • HTML5 Programming Cookbook
  • AngularJS Programming Cookbook