Skip to content

Instantly share code, notes, and snippets.

@maxivak
Last active February 22, 2024 11:55
Show Gist options
  • Save maxivak/2d014f591fc8b7c39d484ac8d17f2a55 to your computer and use it in GitHub Desktop.
Save maxivak/2d014f591fc8b7c39d484ac8d17f2a55 to your computer and use it in GitHub Desktop.
Building Docker image with Packer and provisioning with Ansible

Building Docker image with Packer and provisioning with Ansible

Overview

Packer

  • Packer is used to build image from a base image, perform provisions and store (commit) the final image.

  • We use provisioners and Packer templates to do the actual work to create the final image.

  • We use Ansible for provisioning.

Ansible

  • Ansible runs playbooks on localhost (inside Docker container).
  • Ansible must be installed on the image you're provisioning.
  • Packer uploads the contents of the Ansible playbook to the Docker container instance, and runs it locally.

Install Packer

packer

usage: packer [--version] [--help] <command> [<args>]

Available commands are:
    build        build image(s) from template
    fix          fixes templates from old versions of packer
    inspect      see components of a template
    validate     check that a template is valid
    

Build image with Packer

Files:

build.json - main file with configuration for packer
playbook.yml - Ansible playbook for provisioning 
vars/prod.json - main config file for production environment
vars/default.yml - default variables passed to Ansible
vars/prod.yml - variables to pass to Ansible for production environment

Build workflow

Build image for production environment specified by prod.json file:

  • run build process with packer build command:
sudo packer build -var-file=prod.json build.json
  • packer start from the base image specified in build.json
# build.json
{
...
  "builders":[
    {
      "type": "docker",
      "image": "phusion/passenger-ruby22:0.9.18", 
      "commit": true,
      ...
    }
  ],
  ...
}
  • packer runs provisioners specified in build.json
  • first, it installs Ansible in Docker container:
"provisioners":[
    {
      "type": "shell",
      "inline": [
        "apt-get -y update",
        "apt-get install -y software-properties-common",
        "apt-add-repository ppa:ansible/ansible",
        "apt-get -y update",
        "apt-get install -y ansible"
      ]
    },
    
  • packer uploads vars/prod.yml to the Docker container and saves it as vars.yml
    {
      "type": "file",
      "source": "{{user `config_file`}}",
      "destination": "{{user `tmp_dir`}}/vars.yml"
    }
  • packer uploads playbook.yml to the Docker container

  • packer runs Ansible playbook.yml locally in the Docker container

    {
      "type": "ansible-local",
      "staging_directory": "{{user `tmp_dir`}}/ansible",
      "playbook_file": "playbook.yml",
      "extra_arguments": [ "--extra-vars \"tmp_dir={{user `tmp_dir`}} \"" ]
    }
  • Ansible playbook uses variables defined in corresponding vars.yml file
- hosts: 127.0.0.1
  user: root
  vars_files:
    - "{{tmp_dir}}/vars.yml"
  tasks:
  • The final image is saved as "my-nginx:0.1" specified in build.json

  "post-processors": [
    [
      {
        "type": "docker-tag",
        "repository": "my-nginx",
        "tag": "0.1"
      }
    ]
  ]

build configuration

Create build.json file with configuration how to build Docker image.

build.json:

{
  "variables": {
    "config_file": "vars/default.yml",
    "tmp_dir": "/tmp"
  },

  "builders":[
    {
      "type": "docker",
      "image": "nginx",
      "commit": true,
      "run_command": ["-d", "{{.Image}}", "nginx -g daemon off"]
    }
  ],
  "provisioners":[
    {
      "type": "shell",
      "inline": [
        "apt-get -y update",
        "apt-get install -y software-properties-common",
        "apt-add-repository ppa:ansible/ansible",
        "apt-get -y update",
        "apt-get install -y ansible"
      ]
    },
    {
      "type": "shell",
      "inline": [
        "mkdir -p {{user `tmp_dir`}}"
      ]
    }
    ,
    {
      "type": "file",
      "source": "{{user `config_file`}}",
      "destination": "{{user `tmp_dir`}}/vars.yml"
    }
    ,
    {
      "type": "ansible-local",
      "staging_directory": "{{user `tmp_dir`}}/ansible",
      "playbook_file": "playbook.yml",
      "extra_arguments": [ "--extra-vars \"tmp_dir={{user `tmp_dir`}} \"" ]
    }

  ],

  "post-processors": [
    [
      {
        "type": "docker-tag",
        "repository": "my-nginx",
        "tag": "0.1"
      }
    ]
  ]
}


Configs

Build image

sudo packer build -var-file=vars/prod.json build.json

Run Docker container

sudo docker run -d -p 8080:80 --name=my-server1 my-nginx:0.1
@aschwin
Copy link

aschwin commented Jul 17, 2017

It would be very welcome to see an example file structure described in this Gist. Can you help with that?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment