DevOps

Packer, Ansible and Docker Part 2: Using Ansible Galaxy

Previously we setup packer, docker and ansible to build a very simple docker image that simply placed a file under /root with some content, a very simple start. Today we’ll go further and explore using ansible roles and making some pieces a bit more dynamic.

A Real World Example

In this tutorial, we’ll build a docker image that has Redis installed. While we could go through the steps of adding an apt repository, installing and configuring Redis ourselves why not go strong and take advantage of the fact that someone else has already done this? Enter ansible-galaxy.

Using Ansible Galaxy

Simply put, ansible galaxy is pretty much like any package manager for your favorite language like pip for python or npm for node. You can install packages stand-alone by running something like ansible-galaxy install geerlinguy.redis or you can define a requirements file just like in python to specify multiple dependencies.

Finding the Right Role

If we do a search we’ll soon discover that there are 150 or so odd redis roles out there… which do we use? Usually we’ll want to temper our choice to the one with the most downloads. A very quick method I use is to just google ansible-galaxy <service> and run with the first result. Thankfully the search for ansible-galaxy redis returns geerlingguy.redis which is by a guy I know puts out some pretty high quality roles. But if I didn’t know that, the number of downloads are a good indicator!

Adding our Requirements File

Our requirements.yml file is off to a simple start.

---
- src: geerlingguy.redis
  version: 1.1.5

While the ansible-local provisioner lets you define a galaxy_file and installs roles for you the ansible-remote provisioner (which we’re using) does not. So we’ll need to install the roles and specify the directory in they’ll be installed in. While roles is typically a good directory name I prefer to store my galaxy related roles in a separate directory and leave roles for my own roles (which we’ll cover in a later blog post). For today, let’s use galaxyfor roles installed from ansible-galaxy. You can specify the target path with the -p option below.

$ ansible-galaxy install -p galaxy -r requirements.yml

This is also a good time to update our playbook to use the role.

---
- name: A demo to run ansible in a docker container
  hosts: all
  tasks:
    - name: Add a file to root's home dir
      copy:
        dest: /root/foo
        content: Hello World!
        owner: root
  roles:
    - geerlingguy.redis

Finally, we need to tell ansible where our role directories are. We can do this by defining the ANSIBLE_ROLES_PATH environment variable. So we update our template.json to the below content with that added.

{
  "variables": {
    "ansible_host": "default",
    "ansible_connection": "docker",
    "ansible_roles_path": "galaxy"
  },
  "builders": [{
    "type": "docker",
    "image": "ubuntu:16.04",
    "commit": "true",
    "run_command": [ "-d", "-i", "-t", "--name", "{{user `ansible_host`}}", "{{.Image}}", "/bin/bash" ]
  }],
  "provisioners": [
    {
      "type": "shell",
      "inline": [
        "apt-get update",
        "apt-get install python -yq"
      ]
    },
    {
      "type": "ansible",
      "ansible_env_vars": [
        "ANSIBLE_ROLES_PATH={{user `ansible_roles_path` }}"
      ],
      "user": "root",
      "playbook_file": "./playbook.yml",
      "extra_arguments": [
        "--extra-vars",
        "ansible_host={{user `ansible_host`}} ansible_connection={{user `ansible_connection`}}"
      ]
    }
  ],
  "post-processors": [
    [
      {
        "type": "docker-tag",
        "repository": "jamescarr/demo",
        "tag": "0.1"
      }
    ]
  ]
}

With all of these changes made, let’s run packer again.

$ packer build template.json

If all goes well, we’ll see the tasks to install redis get executed.

And if we run our container we can see redis is indeed installed!

$ docker run -it jamescarr/demo:0.1 bash


For reference, you can see the project in its entirety at https://github.com/jamescarr/pad-tutorial/tree/part-two.
This is pretty nifty stuff… no more Dockerfiles masquerading as glorified bash scripts. How about we take this further and use the same docker template to build out multiple different types of docker images?

Next Up

Tomorrow I’ll write up part three and we’ll explore making this template more dynamic and utilize our own roles to layout specific tasks.

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button