Build Your Own EC2 Machine Images with Packer & Ansible on AWS for Immutable AWS Deployments

What is Packer?

“Packer is an open source tool for creating identical machine images for multiple platforms from a single source configuration.”

Packer is lightweight, runs on every major operating system, and is highly performant, creating machine images for multiple platforms in parallel. Packer does not replace configuration management like Ansible or Chef. In fact, when building images, Packer is able to use tools like Ansible or Chef to install software onto the image.

Packer is a great tool for building machine images. Among supported platforms are also Amazon Machine Images (AMIs) for Amazon Web Services (AWS). To install packages you need and configure everything to taste, you can use a multitude of tools, such as Chef, Puppet, Salt or simple bash scripts.

A machine image is a single static unit that contains a pre-configured operating system and installed software which is used to quickly create new running machines. Machine image formats change for each platform. Some examples include AMIs for EC2, VMDK/VMX files for VMware, OVF exports for VirtualBox, etc.

You may find more information about Packer on

Why do we need Packer?

In the world of MicroServices, immutable deployments is a highly recommended strategy. It demands that every release get a fresh environment, all the way down to the lowest level — or in case of AWS, the AMI.

An AMI can bundle the base operating system, application server/runtime, scripts, agents, etc. along with a versioned application artifact. In the spirit of Infrastructure as Code, the AMI itself can be versioned as a simple json file, as we will see in this post.

Automation of AMI Creation Using Packer

Installing Packer

You can have the packer installation on your local workstation or on a cloud instance. All you need is the cli connectivity to AWS using access keys.

Note: If you are planning to setup Packer on the local workstation, make sure you have the aws access keys set on file ~/.aws/credentials. It is not mandatory to have credentials file. You can pass the AWS credentials using the packer variable declaration(not preferred for security).

1. Download the required package from here.

2. Unzip the package and set the path variable in ~/.bashrc

export PATH=$PATH:/path/to/packer

3. Refresh terminal

source ~/.bashrc

4. Verify packer installation by executing the packer command.

packer version

Building Image

Packer configuration templates are written in JSON format.

A template has the following three main parts.

1. variables — Where you define custom variables.

2. builders — Where you mention all the required AMI parameters.

3. provisioners — Where you can integrate a shell script, ansible play or a chef cookbook for configuring a required application in the AMI.

An example template for packaging an AWS AMI is given below.

Packer Template definition structure

We run below packer template file as packer build template.json

Here we are going to use Eu-west region and a Debian AMI with AMI id ami-6ece3f388

“variables”: {
“aws_access_key”: “”,
“aws_secret_key”: “”

“builders”: [{
“type”: “amazon-ebs”,
“access_key”: “{{user `aws_access_key`}}”,
“secret_key”: “{{user `aws_secret_key`}}”,
“region”: “eu-west-2”,
“source_ami”: “ami-ece3f388”,
“instance_type”: “t2.medium”,
“ssh_username”: “admin”,
"ami_name": "MiddleTier-{{isotime | clean_ami_name}}",
"ami_description": "EC2 AMI Debian 9.1",
"tags": {
"role": "web_Server"
"run_tags": {
"role": "production_Web"

“provisioners”: [
“type”: “shell”,
“script”: “”

Lets validate and inspect our template using the following commands.

packer validate template.json
packer inspect template.json

set -e
 sudo apt-get update
echo "apt-get update done."
sudo apt-get -y upgrade
sudo apt-get install -y python-dev python-pip
sudo pip install ansible
sudo timedatectl set-timezone Europe/Istanbul
sudo localectl set-locale LANG=en_US.utf8
sudo wget ‘'
echo "Running build."
sudo ansible-playbook i_playbook.yml

Also, we have used shell provisioner which calls a file.

Packer supports the following provisioners.

1. Ansible

2. Chef

3. Salt

4. Shell

5. Powershell

6. Windows cmd

7. File — For copying file from local directory to VM image.

Ansible Playbook File

hosts: localhost
connection: local
sudo: yes

— name: Install list of packages
apt: name={{item}} state=installed
— htop
— ctop
— screen
— unzip
— curl
— sudo
— mtr
— bash-completion
— tree
— colordiff
— ntp
— bwm-ng
— docker-compose
— apt-transport-https
- name: install docker
command: sudo apt-key adv --keyserver hkp:// --recv-keys 58118E89F3A912897C070ADBF76221572C52609D
- name: add deb repo
command: sudo touch /etc/apt/sources.list.d/docker.list
- lineinfile: dest="/etc/apt/sources.list.d/docker.list" line="{{item}}"
- "deb ubuntu-trusty main"
- name: apt update
apt: update_cache=yes
- apt: name=docker-engine state=present
- name: add user mod
command: sudo usermod -aG docker {{remote_user}}
- name: add user mod
command: sudo usermod -aG docker {{action_user}}
 — name: apt update
command: sudo apt-get update

— name: Download index.html
shell: sudo wget

— name: Download Dockerfile
command: wget

— name: Docker build image
command: sudo docker build -t “simple_worx:dockerfile” .
ignore_errors: yes

— name: Docker run even after restart
command: sudo docker run -dit — restart unless-stopped -p 80:80 simple_worx:dockerfile
ignore_errors: yes

— name: Docker running?
command: curl localhost:80
register: out
— debug: var=out.stdout_lines

There you go! Packer your AMIs for Immutable AWS Deployments

Now you can find your own custom image on AWS Images>AMIs section.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.