2013-06-21 19:48:01 -04:00
|
|
|
---
|
2015-07-22 22:31:00 -04:00
|
|
|
layout: intro
|
2017-03-25 18:13:52 -04:00
|
|
|
sidebar_current: intro-getting-started-build-image
|
|
|
|
page_title: Build an Image - Getting Started
|
|
|
|
description: |-
|
|
|
|
With Packer installed, let's just dive right into it and build our first
|
|
|
|
image. Our first image will be an Amazon EC2 AMI with Redis pre-installed.
|
|
|
|
This is just an example. Packer can create images for many platforms with
|
|
|
|
anything pre-installed.
|
|
|
|
---
|
2013-06-21 19:48:01 -04:00
|
|
|
|
|
|
|
# Build an Image
|
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
With Packer installed, let's just dive right into it and build our first image.
|
2017-10-13 07:27:28 -04:00
|
|
|
Our first image will be an [Amazon EC2 AMI](https://aws.amazon.com/ec2/).
|
2017-10-11 14:22:48 -04:00
|
|
|
This is just an example. Packer can create images for [many platforms][platforms].
|
2013-06-21 19:48:01 -04:00
|
|
|
|
2016-01-14 15:31:19 -05:00
|
|
|
If you don't have an AWS account, [create one now](https://aws.amazon.com/free/).
|
2014-12-30 14:55:16 -05:00
|
|
|
For the example, we'll use a "t2.micro" instance to build our image, which
|
2016-01-14 15:31:19 -05:00
|
|
|
qualifies under the AWS [free-tier](https://aws.amazon.com/free/), meaning it
|
2015-07-22 22:31:00 -04:00
|
|
|
will be free. If you already have an AWS account, you may be charged some amount
|
|
|
|
of money, but it shouldn't be more than a few cents.
|
2013-06-21 19:48:01 -04:00
|
|
|
|
2017-03-25 18:13:52 -04:00
|
|
|
-> **Note:** If you're not using an account that qualifies under the AWS
|
2015-07-22 22:31:00 -04:00
|
|
|
free-tier, you may be charged to run these examples. The charge should only be a
|
|
|
|
few cents, but we're not responsible if it ends up being more.
|
2013-06-21 19:48:01 -04:00
|
|
|
|
2017-03-28 18:28:34 -04:00
|
|
|
Packer can build images for [many platforms][platforms] other than
|
2013-06-21 19:48:01 -04:00
|
|
|
AWS, but AWS requires no additional software installed on your computer and
|
2016-01-14 15:31:19 -05:00
|
|
|
their [free-tier](https://aws.amazon.com/free/) makes it free to use for most
|
2013-06-21 19:48:01 -04:00
|
|
|
people. This is why we chose to use AWS for the example. If you're uncomfortable
|
|
|
|
setting up an AWS account, feel free to follow along as the basic principles
|
|
|
|
apply to the other platforms as well.
|
|
|
|
|
|
|
|
## The Template
|
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
The configuration file used to define what image we want built and how is called
|
|
|
|
a *template* in Packer terminology. The format of a template is simple
|
|
|
|
[JSON](http://www.json.org/). JSON struck the best balance between
|
2013-06-21 19:48:01 -04:00
|
|
|
human-editable and machine-editable, allowing both hand-made templates as well
|
|
|
|
as machine generated templates to easily be made.
|
|
|
|
|
|
|
|
We'll start by creating the entire template, then we'll go over each section
|
|
|
|
briefly. Create a file `example.json` and fill it with the following contents:
|
|
|
|
|
2017-03-25 18:13:52 -04:00
|
|
|
```json
|
2013-06-21 19:48:01 -04:00
|
|
|
{
|
2013-11-25 07:36:32 -05:00
|
|
|
"variables": {
|
|
|
|
"aws_access_key": "",
|
|
|
|
"aws_secret_key": ""
|
|
|
|
},
|
2013-06-21 19:48:01 -04:00
|
|
|
"builders": [{
|
|
|
|
"type": "amazon-ebs",
|
2013-11-25 07:36:32 -05:00
|
|
|
"access_key": "{{user `aws_access_key`}}",
|
|
|
|
"secret_key": "{{user `aws_secret_key`}}",
|
2013-06-21 19:48:01 -04:00
|
|
|
"region": "us-east-1",
|
2017-06-20 14:21:49 -04:00
|
|
|
"source_ami_filter": {
|
|
|
|
"filters": {
|
|
|
|
"virtualization-type": "hvm",
|
2017-09-05 20:20:48 -04:00
|
|
|
"name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*",
|
2017-06-20 14:21:49 -04:00
|
|
|
"root-device-type": "ebs"
|
|
|
|
},
|
|
|
|
"owners": ["099720109477"],
|
|
|
|
"most_recent": true
|
|
|
|
},
|
2016-01-13 16:52:17 -05:00
|
|
|
"instance_type": "t2.micro",
|
2013-06-21 19:48:01 -04:00
|
|
|
"ssh_username": "ubuntu",
|
2013-08-08 20:01:33 -04:00
|
|
|
"ami_name": "packer-example {{timestamp}}"
|
2013-06-21 19:48:01 -04:00
|
|
|
}]
|
|
|
|
}
|
2014-10-20 13:55:16 -04:00
|
|
|
```
|
2013-06-21 19:48:01 -04:00
|
|
|
|
2016-02-20 10:55:22 -05:00
|
|
|
When building, you'll pass in `aws_access_key` and `aws_secret_key` as
|
|
|
|
[user variables](/docs/templates/user-variables.html), keeping your secret keys
|
2015-07-22 22:31:00 -04:00
|
|
|
out of the template. You can create security credentials on [this
|
|
|
|
page](https://console.aws.amazon.com/iam/home?#security_credential). An example
|
|
|
|
IAM policy document can be found in the [Amazon EC2 builder
|
|
|
|
docs](/docs/builders/amazon.html).
|
|
|
|
|
|
|
|
This is a basic template that is ready-to-go. It should be immediately
|
|
|
|
recognizable as a normal, basic JSON object. Within the object, the `builders`
|
|
|
|
section contains an array of JSON objects configuring a specific *builder*. A
|
|
|
|
builder is a component of Packer that is responsible for creating a machine and
|
|
|
|
turning that machine into an image.
|
|
|
|
|
|
|
|
In this case, we're only configuring a single builder of type `amazon-ebs`. This
|
|
|
|
is the Amazon EC2 AMI builder that ships with Packer. This builder builds an
|
|
|
|
EBS-backed AMI by launching a source AMI, provisioning on top of that, and
|
|
|
|
re-packaging it into a new AMI.
|
|
|
|
|
|
|
|
The additional keys within the object are configuration for this builder,
|
2016-02-20 10:55:22 -05:00
|
|
|
specifying things such as access keys, the source AMI to build from and more.
|
2015-07-22 22:31:00 -04:00
|
|
|
The exact set of configuration variables available for a builder are specific to
|
2017-03-28 18:28:34 -04:00
|
|
|
each builder and can be found within the [documentation](/docs/index.html).
|
2015-07-22 22:31:00 -04:00
|
|
|
|
|
|
|
Before we take this template and build an image from it, let's validate the
|
|
|
|
template by running `packer validate example.json`. This command checks the
|
|
|
|
syntax as well as the configuration values to verify they look valid. The output
|
|
|
|
should look similar to below, because the template should be valid. If there are
|
2013-06-21 19:48:01 -04:00
|
|
|
any errors, this command will tell you.
|
|
|
|
|
2017-03-25 18:13:52 -04:00
|
|
|
```text
|
2013-06-21 19:48:01 -04:00
|
|
|
$ packer validate example.json
|
|
|
|
Template validated successfully.
|
|
|
|
```
|
|
|
|
|
|
|
|
Next, let's build the image from this template.
|
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
An astute reader may notice that we said earlier we'd be building an image with
|
|
|
|
Redis pre-installed, and yet the template we made doesn't reference Redis
|
|
|
|
anywhere. In fact, this part of the documentation will only cover making a first
|
|
|
|
basic, non-provisioned image. The next section on provisioning will cover
|
|
|
|
installing Redis.
|
2013-06-21 19:48:01 -04:00
|
|
|
|
|
|
|
## Your First Image
|
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
With a properly validated template. It is time to build your first image. This
|
|
|
|
is done by calling `packer build` with the template file. The output should look
|
|
|
|
similar to below. Note that this process typically takes a few minutes.
|
2013-06-21 19:48:01 -04:00
|
|
|
|
2017-03-25 18:13:52 -04:00
|
|
|
-> **Note:** For the tutorial it is convenient to use the credentials in the
|
2016-11-26 12:58:56 -05:00
|
|
|
command line. However, it is potentially insecure. See our documentation for
|
|
|
|
other ways to [specify Amazon credentials](/docs/builders/amazon.html#specifying-amazon-credentials).
|
2016-11-26 07:46:12 -05:00
|
|
|
|
2017-03-25 18:13:52 -04:00
|
|
|
-> **Note:** When using packer on Windows, replace the single-quotes in the
|
2016-08-21 15:04:05 -04:00
|
|
|
command below with double-quotes.
|
|
|
|
|
2017-03-25 18:13:52 -04:00
|
|
|
```text
|
2013-11-25 07:36:32 -05:00
|
|
|
$ packer build \
|
|
|
|
-var 'aws_access_key=YOUR ACCESS KEY' \
|
|
|
|
-var 'aws_secret_key=YOUR SECRET KEY' \
|
|
|
|
example.json
|
2013-06-21 19:48:01 -04:00
|
|
|
==> amazon-ebs: amazon-ebs output will be in this color.
|
|
|
|
|
|
|
|
==> amazon-ebs: Creating temporary keypair for this instance...
|
|
|
|
==> amazon-ebs: Creating temporary security group for this instance...
|
|
|
|
==> amazon-ebs: Authorizing SSH access on the temporary security group...
|
|
|
|
==> amazon-ebs: Launching a source AWS instance...
|
|
|
|
==> amazon-ebs: Waiting for instance to become ready...
|
|
|
|
==> amazon-ebs: Connecting to the instance via SSH...
|
|
|
|
==> amazon-ebs: Stopping the source instance...
|
|
|
|
==> amazon-ebs: Waiting for the instance to stop...
|
|
|
|
==> amazon-ebs: Creating the AMI: packer-example 1371856345
|
|
|
|
==> amazon-ebs: AMI: ami-19601070
|
|
|
|
==> amazon-ebs: Waiting for AMI to become ready...
|
|
|
|
==> amazon-ebs: Terminating the source AWS instance...
|
|
|
|
==> amazon-ebs: Deleting temporary security group...
|
|
|
|
==> amazon-ebs: Deleting temporary keypair...
|
|
|
|
==> amazon-ebs: Build finished.
|
|
|
|
|
|
|
|
==> Builds finished. The artifacts of successful builds are:
|
|
|
|
--> amazon-ebs: AMIs were created:
|
|
|
|
|
|
|
|
us-east-1: ami-19601070
|
|
|
|
```
|
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
At the end of running `packer build`, Packer outputs the *artifacts* that were
|
|
|
|
created as part of the build. Artifacts are the results of a build, and
|
|
|
|
typically represent an ID (such as in the case of an AMI) or a set of files
|
|
|
|
(such as for a VMware virtual machine). In this example, we only have a single
|
|
|
|
artifact: the AMI in us-east-1 that was created.
|
2013-06-21 19:48:01 -04:00
|
|
|
|
2017-10-13 07:27:28 -04:00
|
|
|
This AMI is ready to use. If you wanted you could go and launch this AMI right
|
2017-10-11 14:22:48 -04:00
|
|
|
now and it would work great.
|
2013-06-21 19:48:01 -04:00
|
|
|
|
2017-03-25 18:13:52 -04:00
|
|
|
-> **Note:** Your AMI ID will surely be different than the one above. If you
|
2015-07-22 22:31:00 -04:00
|
|
|
try to launch the one in the example output above, you will get an error. If you
|
|
|
|
want to try to launch your AMI, get the ID from the Packer output.
|
2013-06-21 19:48:01 -04:00
|
|
|
|
2017-01-05 14:29:15 -05:00
|
|
|
-> **Note:** If you see a `VPCResourceNotSpecified` error, Packer might not be
|
2017-01-05 15:58:22 -05:00
|
|
|
able to determine the default VPC, which the `t2` instance types require. This
|
2017-01-26 19:03:57 -05:00
|
|
|
can happen if you created your AWS account before `2013-12-04`. You can either
|
2017-01-05 15:58:22 -05:00
|
|
|
change the `instance_type` to `m3.medium`, or specify a VPC. Please see
|
|
|
|
http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/default-vpc.html for more
|
2017-03-25 18:13:52 -04:00
|
|
|
information. If you specify a `vpc_id`, you will also need to set `subnet_id`.
|
2017-01-27 18:03:02 -05:00
|
|
|
Unless you modify your subnet's [IPv4 public addressing attribute](
|
|
|
|
http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/vpc-ip-addressing.html#subnet-public-ip),
|
2017-03-25 18:13:52 -04:00
|
|
|
you will also need to set `associate_public_ip_address` to `true`, or set up a
|
2017-01-27 18:03:02 -05:00
|
|
|
[VPN](http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_VPN.html).
|
2017-01-05 14:29:15 -05:00
|
|
|
|
2013-06-21 19:48:01 -04:00
|
|
|
## Managing the Image
|
|
|
|
|
2015-07-22 22:31:00 -04:00
|
|
|
Packer only builds images. It does not attempt to manage them in any way. After
|
|
|
|
they're built, it is up to you to launch or destroy them as you see fit. If you
|
2017-05-09 14:37:49 -04:00
|
|
|
want to store and namespace images for quick reference, you can use [Atlas by
|
2015-07-22 22:31:00 -04:00
|
|
|
HashiCorp](https://atlas.hashicorp.com). We'll cover remotely building and
|
|
|
|
storing images at the end of this getting started guide.
|
|
|
|
|
2017-10-21 23:13:47 -04:00
|
|
|
After running the above example, your AWS account now has an AMI associated
|
|
|
|
with it. AMIs are stored in S3 by Amazon, so unless you want to be charged
|
|
|
|
about $0.01 per month, you'll probably want to remove it. Remove the AMI by
|
|
|
|
first deregistering it on the [AWS AMI management
|
2015-07-22 22:31:00 -04:00
|
|
|
page](https://console.aws.amazon.com/ec2/home?region=us-east-1#s=Images). Next,
|
|
|
|
delete the associated snapshot on the [AWS snapshot management
|
|
|
|
page](https://console.aws.amazon.com/ec2/home?region=us-east-1#s=Snapshots).
|
|
|
|
|
|
|
|
Congratulations! You've just built your first image with Packer. Although the
|
|
|
|
image was pretty useless in this case (nothing was changed about it), this page
|
2016-02-20 10:55:22 -05:00
|
|
|
should've given you a general idea of how Packer works, what templates are and
|
2015-07-22 22:31:00 -04:00
|
|
|
how to validate and build templates into machine images.
|
2017-03-28 18:28:34 -04:00
|
|
|
|
2017-10-05 17:01:16 -04:00
|
|
|
## Some more examples:
|
|
|
|
|
2017-10-13 16:48:48 -04:00
|
|
|
### Another GNU/Linux Example, with provisioners:
|
2017-10-05 17:01:16 -04:00
|
|
|
Create a file named `welcome.txt` and add the following:
|
2017-10-13 07:27:28 -04:00
|
|
|
|
2017-10-05 17:01:16 -04:00
|
|
|
```
|
|
|
|
WELCOME TO PACKER!
|
|
|
|
```
|
|
|
|
|
|
|
|
Create a file named `example.sh` and add the following:
|
2017-10-13 07:27:28 -04:00
|
|
|
|
2017-10-16 15:07:05 -04:00
|
|
|
|
2017-10-13 07:27:28 -04:00
|
|
|
```bash
|
2017-10-05 17:01:16 -04:00
|
|
|
#!/bin/bash
|
2017-10-13 07:27:28 -04:00
|
|
|
echo "hello"
|
2017-10-05 17:01:16 -04:00
|
|
|
```
|
|
|
|
|
2017-10-13 07:27:28 -04:00
|
|
|
Set your access key and id as environment variables, so we don't need to pass
|
2017-10-11 14:22:48 -04:00
|
|
|
them in through the command line:
|
2017-10-13 07:27:28 -04:00
|
|
|
|
2017-10-05 17:01:16 -04:00
|
|
|
```
|
|
|
|
export AWS_ACCESS_KEY_ID=MYACCESSKEYID
|
|
|
|
export AWS_SECRET_ACCESS_KEY=MYSECRETACCESSKEY
|
|
|
|
```
|
|
|
|
|
|
|
|
Now save the following text in a file named `firstrun.json`:
|
|
|
|
|
2017-10-13 07:27:28 -04:00
|
|
|
```json
|
2017-10-05 17:01:16 -04:00
|
|
|
{
|
|
|
|
"variables": {
|
|
|
|
"aws_access_key": "{{env `AWS_ACCESS_KEY_ID`}}",
|
|
|
|
"aws_secret_key": "{{env `AWS_SECRET_ACCESS_KEY`}}",
|
|
|
|
"region": "us-east-1"
|
|
|
|
},
|
|
|
|
"builders": [
|
|
|
|
{
|
|
|
|
"access_key": "{{user `aws_access_key`}}",
|
|
|
|
"ami_name": "packer-linux-aws-demo-{{timestamp}}",
|
|
|
|
"instance_type": "t2.micro",
|
|
|
|
"region": "us-east-1",
|
|
|
|
"secret_key": "{{user `aws_secret_key`}}",
|
2017-10-05 19:29:38 -04:00
|
|
|
"source_ami_filter": {
|
|
|
|
"filters": {
|
|
|
|
"virtualization-type": "hvm",
|
|
|
|
"name": "ubuntu/images/*ubuntu-xenial-16.04-amd64-server-*",
|
|
|
|
"root-device-type": "ebs"
|
|
|
|
},
|
|
|
|
"owners": ["099720109477"],
|
|
|
|
"most_recent": true
|
|
|
|
},
|
2017-10-05 17:01:16 -04:00
|
|
|
"ssh_username": "ubuntu",
|
|
|
|
"type": "amazon-ebs"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"provisioners": [
|
|
|
|
{
|
|
|
|
"type": "file",
|
|
|
|
"source": "./welcome.txt",
|
|
|
|
"destination": "/home/ubuntu/"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"type": "shell",
|
2017-10-05 19:29:38 -04:00
|
|
|
"inline":[
|
|
|
|
"ls -al /home/ubuntu",
|
|
|
|
"cat /home/ubuntu/welcome.txt"
|
|
|
|
]
|
2017-10-05 17:01:16 -04:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"type": "shell",
|
|
|
|
"script": "./example.sh"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
and to build, run `packer build firstrun.json`
|
|
|
|
|
2017-10-13 07:27:28 -04:00
|
|
|
Note that if you wanted to use a `source_ami` instead of a `source_ami_filter`
|
2017-10-11 14:22:48 -04:00
|
|
|
it might look something like this: `"source_ami": "ami-fce3c696",`
|
2017-10-05 17:01:16 -04:00
|
|
|
|
2017-10-13 07:27:28 -04:00
|
|
|
Your output will look like this:
|
2017-10-05 17:01:16 -04:00
|
|
|
|
|
|
|
```
|
|
|
|
amazon-ebs output will be in this color.
|
|
|
|
|
|
|
|
==> amazon-ebs: Prevalidating AMI Name: packer-linux-aws-demo-1507231105
|
|
|
|
amazon-ebs: Found Image ID: ami-fce3c696
|
|
|
|
==> amazon-ebs: Creating temporary keypair: packer_59d68581-e3e6-eb35-4ae3-c98d55cfa04f
|
|
|
|
==> amazon-ebs: Creating temporary security group for this instance: packer_59d68584-cf8a-d0af-ad82-e058593945ea
|
|
|
|
==> amazon-ebs: Authorizing access to port 22 on the temporary security group...
|
|
|
|
==> amazon-ebs: Launching a source AWS instance...
|
|
|
|
==> amazon-ebs: Adding tags to source instance
|
|
|
|
amazon-ebs: Adding tag: "Name": "Packer Builder"
|
|
|
|
amazon-ebs: Instance ID: i-013e8fb2ced4d714c
|
|
|
|
==> amazon-ebs: Waiting for instance (i-013e8fb2ced4d714c) to become ready...
|
|
|
|
==> amazon-ebs: Waiting for SSH to become available...
|
|
|
|
==> amazon-ebs: Connected to SSH!
|
|
|
|
==> amazon-ebs: Uploading ./scripts/welcome.txt => /home/ubuntu/
|
|
|
|
==> amazon-ebs: Provisioning with shell script: /var/folders/8t/0yb5q0_x6mb2jldqq_vjn3lr0000gn/T/packer-shell661094204
|
|
|
|
amazon-ebs: total 32
|
|
|
|
amazon-ebs: drwxr-xr-x 4 ubuntu ubuntu 4096 Oct 5 19:19 .
|
|
|
|
amazon-ebs: drwxr-xr-x 3 root root 4096 Oct 5 19:19 ..
|
|
|
|
amazon-ebs: -rw-r--r-- 1 ubuntu ubuntu 220 Apr 9 2014 .bash_logout
|
|
|
|
amazon-ebs: -rw-r--r-- 1 ubuntu ubuntu 3637 Apr 9 2014 .bashrc
|
|
|
|
amazon-ebs: drwx------ 2 ubuntu ubuntu 4096 Oct 5 19:19 .cache
|
|
|
|
amazon-ebs: -rw-r--r-- 1 ubuntu ubuntu 675 Apr 9 2014 .profile
|
|
|
|
amazon-ebs: drwx------ 2 ubuntu ubuntu 4096 Oct 5 19:19 .ssh
|
|
|
|
amazon-ebs: -rw-r--r-- 1 ubuntu ubuntu 18 Oct 5 19:19 welcome.txt
|
|
|
|
amazon-ebs: WELCOME TO PACKER!
|
|
|
|
==> amazon-ebs: Provisioning with shell script: ./example.sh
|
|
|
|
amazon-ebs: hello
|
|
|
|
==> amazon-ebs: Stopping the source instance...
|
|
|
|
amazon-ebs: Stopping instance, attempt 1
|
|
|
|
==> amazon-ebs: Waiting for the instance to stop...
|
|
|
|
==> amazon-ebs: Creating the AMI: packer-linux-aws-demo-1507231105
|
|
|
|
amazon-ebs: AMI: ami-f76ea98d
|
|
|
|
==> amazon-ebs: Waiting for AMI to become ready...
|
|
|
|
```
|
|
|
|
|
2017-10-13 07:27:28 -04:00
|
|
|
### A Windows Example
|
2017-10-05 17:01:16 -04:00
|
|
|
|
2017-10-13 16:48:48 -04:00
|
|
|
As with the GNU/Linux example above, should you decide to follow along and
|
2017-10-13 15:55:12 -04:00
|
|
|
build an AMI from the example template, provided you qualify for free tier
|
|
|
|
usage, you should not be charged for actually building the AMI.
|
|
|
|
However, please note that you will be charged for storage of the snapshot
|
|
|
|
associated with any AMI that you create.
|
|
|
|
If you wish to avoid further charges, follow the steps in the [Managing the
|
|
|
|
Image](/intro/getting-started/build-image.html#managing-the-image) section
|
|
|
|
above to deregister the created AMI and delete the associated snapshot once
|
|
|
|
you're done.
|
|
|
|
|
2017-10-15 18:50:59 -04:00
|
|
|
Again, in this example, we are making use of an existing AMI available from
|
|
|
|
the Amazon marketplace as the *source* or starting point for building our
|
|
|
|
own AMI. In brief, Packer will spin up the source AMI, connect to it and then
|
|
|
|
run whatever commands or scripts we've configured in our build template to
|
|
|
|
customize the image. Finally, when all is done, Packer will wrap the whole
|
|
|
|
customized package up into a brand new AMI that will be available from the
|
|
|
|
[AWS AMI management page](
|
|
|
|
https://console.aws.amazon.com/ec2/home?region=us-east-1#s=Images). Any
|
|
|
|
instances we subsequently create from this AMI will have our all of our
|
|
|
|
customizations baked in. This is the core benefit we are looking to
|
|
|
|
achieve from using the [Amazon EBS builder](/docs/builders/amazon-ebs.html)
|
|
|
|
in this example.
|
|
|
|
|
|
|
|
Now, all this sounds simple enough right? Well, actually it turns out we
|
|
|
|
need to put in just a *bit* more effort to get things working as we'd like...
|
|
|
|
|
|
|
|
Here's the issue: Out of the box, the instance created from our source AMI
|
|
|
|
is not configured to allow Packer to connect to it. So how do we fix it so
|
|
|
|
that Packer can connect in and customize our instance?
|
|
|
|
|
|
|
|
Well, it turns out that Amazon provides a mechanism that allows us to run a
|
|
|
|
set of *pre-supplied* commands within the instance shortly after the instance
|
|
|
|
starts. Even better, Packer is aware of this mechanism. This gives us the
|
|
|
|
ability to supply Packer with the commands required to configure the instance
|
|
|
|
for a remote connection *in advance*. Once the commands are run, Packer
|
|
|
|
will be able to connect directly in to the instance and make the
|
|
|
|
customizations we need.
|
|
|
|
|
|
|
|
Here's a basic example of a file that will configure the instance to allow
|
|
|
|
Packer to connect in over WinRM. As you will see, we will tell Packer about
|
|
|
|
our intentions by referencing this file and the commands within it from
|
|
|
|
within the `"builders"` section of our
|
|
|
|
[build template](/docs/templates/index.html) that we will create later.
|
|
|
|
|
|
|
|
Note the `<powershell>` and `</powershell>` tags at the top and bottom of
|
|
|
|
the file. These tags tell Amazon we'd like to run the enclosed code with
|
|
|
|
PowerShell. You can also use `<script></script>` tags to enclose any commands
|
|
|
|
that you would normally run in a Command Prompt window. See
|
|
|
|
[Running Commands on Your Windows Instance at Launch](
|
|
|
|
http://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ec2-windows-user-data.html)
|
|
|
|
for more info about what's going on behind the scenes here.
|
2017-10-05 17:01:16 -04:00
|
|
|
|
2017-10-13 07:27:28 -04:00
|
|
|
```powershell
|
2017-10-13 08:29:50 -04:00
|
|
|
<powershell>
|
2017-10-13 16:07:33 -04:00
|
|
|
# Set administrator password
|
2017-10-05 17:01:16 -04:00
|
|
|
net user Administrator SuperS3cr3t!
|
|
|
|
wmic useraccount where "name='Administrator'" set PasswordExpires=FALSE
|
|
|
|
|
2017-10-13 16:07:33 -04:00
|
|
|
# First, make sure WinRM can't be connected to
|
|
|
|
netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" new enable=yes action=block
|
|
|
|
|
|
|
|
# Delete any existing WinRM listeners
|
|
|
|
winrm delete winrm/config/listener?Address=*+Transport=HTTP 2>$Null
|
|
|
|
winrm delete winrm/config/listener?Address=*+Transport=HTTPS 2>$Null
|
|
|
|
|
|
|
|
# Create a new WinRM listener and configure
|
|
|
|
winrm create winrm/config/listener?Address=*+Transport=HTTP
|
2017-10-05 17:01:16 -04:00
|
|
|
winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="0"}'
|
|
|
|
winrm set winrm/config '@{MaxTimeoutms="7200000"}'
|
|
|
|
winrm set winrm/config/service '@{AllowUnencrypted="true"}'
|
|
|
|
winrm set winrm/config/service '@{MaxConcurrentOperationsPerUser="12000"}'
|
|
|
|
winrm set winrm/config/service/auth '@{Basic="true"}'
|
|
|
|
winrm set winrm/config/client/auth '@{Basic="true"}'
|
|
|
|
|
2017-10-13 16:07:33 -04:00
|
|
|
# Configure UAC to allow privilege elevation in remote shells
|
|
|
|
$Key = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'
|
|
|
|
$Setting = 'LocalAccountTokenFilterPolicy'
|
|
|
|
Set-ItemProperty -Path $Key -Name $Setting -Value 1 -Force
|
2017-10-05 17:01:16 -04:00
|
|
|
|
2017-10-13 16:07:33 -04:00
|
|
|
# Configure and restart the WinRM Service; Enable the required firewall exception
|
|
|
|
Stop-Service -Name WinRM
|
|
|
|
Set-Service -Name WinRM -StartupType Automatic
|
|
|
|
netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" new action=allow localip=any remoteip=any
|
|
|
|
Start-Service -Name WinRM
|
2017-10-13 08:29:50 -04:00
|
|
|
</powershell>
|
2017-10-05 17:01:16 -04:00
|
|
|
```
|
|
|
|
|
2017-10-13 07:27:28 -04:00
|
|
|
Save the above code in a file named `bootstrap_win.txt`.
|
2017-10-05 17:01:16 -04:00
|
|
|
|
2017-10-23 12:39:25 -04:00
|
|
|
-> **A quick aside/warning:**<br />
|
2017-10-15 21:45:56 -04:00
|
|
|
Windows administrators in the know might be wondering why we haven't simply
|
|
|
|
used a `winrm quickconfig -q` command in the script above, as this would
|
|
|
|
*automatically* set up all of the required elements necessary for connecting
|
2017-10-23 12:39:25 -04:00
|
|
|
over WinRM. Why all the extra effort to configure things manually?<br />
|
2017-10-15 21:45:56 -04:00
|
|
|
Well, long and short, use of the `winrm quickconfig -q` command can sometimes
|
|
|
|
cause the Packer build to fail shortly after the WinRM connection is
|
2017-10-23 12:39:25 -04:00
|
|
|
established. How?<br />
|
2017-10-15 21:45:56 -04:00
|
|
|
1. Among other things, as well as setting up the listener for WinRM, the
|
|
|
|
quickconfig command also configures the firewall to allow management messages
|
2017-10-23 12:39:25 -04:00
|
|
|
to be sent over HTTP.<br />
|
2017-10-15 21:45:56 -04:00
|
|
|
2. This undoes the previous command in the script that configured the
|
2017-10-23 12:39:25 -04:00
|
|
|
firewall to prevent this access.<br />
|
2017-10-15 21:45:56 -04:00
|
|
|
3. The upshot is that the system is configured and ready to accept WinRM
|
2017-10-23 12:39:25 -04:00
|
|
|
connections earlier than intended.<br />
|
2017-10-15 21:45:56 -04:00
|
|
|
4. If Packer establishes its WinRM connection immediately after execution of
|
|
|
|
the 'winrm quickconfig -q' command, the later commands within the script that
|
|
|
|
restart the WinRM service will unceremoniously pull the rug out from under
|
2017-10-23 12:39:25 -04:00
|
|
|
the connection.<br />
|
2017-10-15 21:45:56 -04:00
|
|
|
5. While Packer does *a lot* to ensure the stability of its connection in to
|
|
|
|
your instance, this sort of abuse can prove to be too much and *may* cause
|
|
|
|
your Packer build to stall irrecoverably or fail!
|
|
|
|
|
2017-10-15 18:50:59 -04:00
|
|
|
Now we've got the business of getting Packer connected to our instance
|
|
|
|
taken care of, let's get on with the *real* reason we're doing all this,
|
|
|
|
which is actually configuring and customizing the instance. Again, we do this
|
|
|
|
with [Provisioners](/docs/provisioners/index.html).
|
|
|
|
|
|
|
|
The example config below shows the two different ways of using the [PowerShell
|
|
|
|
provisioner](/docs/provisioners/powershell.html): `inline` and `script`.
|
2017-10-13 07:27:28 -04:00
|
|
|
The first example, `inline`, allows you to provide short snippets of code, and
|
|
|
|
will create the script file for you. The second example allows you to run more
|
2017-10-15 18:50:59 -04:00
|
|
|
complex code by providing the path to a script to run on the guest VM.
|
2017-10-05 17:01:16 -04:00
|
|
|
|
2017-10-13 07:27:28 -04:00
|
|
|
Here's an example of a `sample_script.ps1` that will work with the environment
|
2017-10-15 18:50:59 -04:00
|
|
|
variables we will set in our build template; copy the contents into your own
|
|
|
|
`sample_script.ps1` and provide the path to it in your build template:
|
2017-10-05 17:01:16 -04:00
|
|
|
|
2017-10-13 09:02:59 -04:00
|
|
|
```powershell
|
|
|
|
Write-Host "PACKER_BUILD_NAME is automatically set for you, " -NoNewline
|
|
|
|
Write-Host "or you can set it in your builder variables; " -NoNewline
|
|
|
|
Write-Host "The default for this builder is:" $Env:PACKER_BUILD_NAME
|
|
|
|
|
|
|
|
Write-Host "Use backticks as the escape character when required in powershell:"
|
|
|
|
Write-Host "For example, VAR1 from our config is:" $Env:VAR1
|
|
|
|
Write-Host "Likewise, VAR2 is:" $Env:VAR2
|
|
|
|
Write-Host "Finally, VAR3 is:" $Env:VAR3
|
2017-10-05 17:01:16 -04:00
|
|
|
```
|
|
|
|
|
2017-10-15 18:50:59 -04:00
|
|
|
Finally, we need to create the actual [build template](
|
|
|
|
/docs/templates/index.html).
|
|
|
|
Remember, this template is the core configuration file that Packer uses to
|
|
|
|
understand what you want to build, and how you want to build it.
|
|
|
|
|
|
|
|
As mentioned earlier, the specific builder we are using in this example
|
|
|
|
is the [Amazon EBS builder](/docs/builders/amazon-ebs.html).
|
|
|
|
The template below demonstrates use of the [`source_ami_filter`](
|
|
|
|
/docs/builders/amazon-ebs.html#source_ami_filter) configuration option
|
|
|
|
available within the builder for automatically selecting the *latest*
|
|
|
|
suitable source Windows AMI provided by Amazon.
|
|
|
|
We also use the `user_data_file` configuration option provided by the builder
|
|
|
|
to reference the bootstrap file we created earlier. As you will recall, our
|
|
|
|
bootstrap file contained all the commands we needed to supply in advance of
|
|
|
|
actually spinning up the instance, so that later on, our instance is
|
|
|
|
configured to allow Packer to connect in to it.
|
|
|
|
|
|
|
|
The `"provisioners"` section of the template demonstrates use of the
|
|
|
|
[powershell](/docs/provisioners/powershell.html) and
|
|
|
|
[windows-restart](/docs/provisioners/windows-restart.html) provisioners to
|
|
|
|
customize and control the build process:
|
2017-10-05 17:01:16 -04:00
|
|
|
|
2017-10-13 07:27:28 -04:00
|
|
|
```json
|
2017-10-05 17:01:16 -04:00
|
|
|
{
|
|
|
|
"variables": {
|
2017-10-13 07:27:28 -04:00
|
|
|
"aws_access_key": "{{env `AWS_ACCESS_KEY_ID`}}",
|
|
|
|
"aws_secret_key": "{{env `AWS_SECRET_ACCESS_KEY`}}",
|
|
|
|
"region": "us-east-1"
|
2017-10-05 17:01:16 -04:00
|
|
|
},
|
|
|
|
"builders": [
|
2017-10-13 07:27:28 -04:00
|
|
|
{
|
|
|
|
"type": "amazon-ebs",
|
|
|
|
"access_key": "{{ user `aws_access_key` }}",
|
|
|
|
"secret_key": "{{ user `aws_secret_key` }}",
|
2017-10-13 21:07:58 -04:00
|
|
|
"region": "{{ user `region` }}",
|
2017-10-13 15:55:12 -04:00
|
|
|
"instance_type": "t2.micro",
|
2017-10-13 07:27:28 -04:00
|
|
|
"source_ami_filter": {
|
|
|
|
"filters": {
|
|
|
|
"virtualization-type": "hvm",
|
2017-10-13 15:55:12 -04:00
|
|
|
"name": "*Windows_Server-2012-R2*English-64Bit-Base*",
|
2017-10-13 07:27:28 -04:00
|
|
|
"root-device-type": "ebs"
|
|
|
|
},
|
|
|
|
"most_recent": true,
|
|
|
|
"owners": "amazon"
|
2017-10-05 17:01:16 -04:00
|
|
|
},
|
2017-10-13 07:27:28 -04:00
|
|
|
"ami_name": "packer-demo-{{timestamp}}",
|
|
|
|
"user_data_file": "./bootstrap_win.txt",
|
|
|
|
"communicator": "winrm",
|
|
|
|
"winrm_username": "Administrator",
|
|
|
|
"winrm_password": "SuperS3cr3t!"
|
|
|
|
}
|
|
|
|
],
|
2017-10-05 17:01:16 -04:00
|
|
|
"provisioners": [
|
|
|
|
{
|
|
|
|
"type": "powershell",
|
|
|
|
"environment_vars": ["DEVOPS_LIFE_IMPROVER=PACKER"],
|
2017-10-13 09:02:59 -04:00
|
|
|
"inline": "Write-Host \"HELLO NEW USER; WELCOME TO $Env:DEVOPS_LIFE_IMPROVER\""
|
2017-10-05 17:01:16 -04:00
|
|
|
},
|
|
|
|
{
|
|
|
|
"type": "windows-restart"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"script": "./sample_script.ps1",
|
|
|
|
"type": "powershell",
|
|
|
|
"environment_vars": [
|
|
|
|
"VAR1=A`$Dollar",
|
|
|
|
"VAR2=A``Backtick",
|
|
|
|
"VAR3=A`'SingleQuote"
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2017-10-15 18:50:59 -04:00
|
|
|
Save the build template as `firstrun.json`.
|
|
|
|
|
|
|
|
Next we need to set things up so that Packer is able to access and use our
|
|
|
|
AWS account. Set your access key and id as environment variables, so we
|
|
|
|
don't need to pass them in through the command line:
|
2017-10-13 18:48:39 -04:00
|
|
|
|
|
|
|
```
|
|
|
|
export AWS_ACCESS_KEY_ID=MYACCESSKEYID
|
|
|
|
export AWS_SECRET_ACCESS_KEY=MYSECRETACCESSKEY
|
|
|
|
```
|
|
|
|
|
2017-10-15 18:50:59 -04:00
|
|
|
Finally, we can create our new AMI by running `packer build firstrun.json`
|
2017-10-05 17:01:16 -04:00
|
|
|
|
|
|
|
You should see output like this:
|
|
|
|
|
|
|
|
```
|
|
|
|
amazon-ebs output will be in this color.
|
|
|
|
|
2017-10-13 18:42:52 -04:00
|
|
|
==> amazon-ebs: Prevalidating AMI Name: packer-demo-1507933843
|
|
|
|
amazon-ebs: Found Image ID: ami-23d93c59
|
|
|
|
==> amazon-ebs: Creating temporary keypair: packer_59e13e94-203a-1bca-5327-bebf0d5ad15a
|
|
|
|
==> amazon-ebs: Creating temporary security group for this instance: packer_59e13ea9-3220-8dab-29c0-ed7f71e221a1
|
|
|
|
==> amazon-ebs: Authorizing access to port 5985 from 0.0.0.0/0 in the temporary security group...
|
2017-10-05 17:01:16 -04:00
|
|
|
==> amazon-ebs: Launching a source AWS instance...
|
|
|
|
==> amazon-ebs: Adding tags to source instance
|
|
|
|
amazon-ebs: Adding tag: "Name": "Packer Builder"
|
2017-10-13 18:42:52 -04:00
|
|
|
amazon-ebs: Instance ID: i-0349406ac85f02166
|
|
|
|
==> amazon-ebs: Waiting for instance (i-0349406ac85f02166) to become ready...
|
2017-10-05 17:01:16 -04:00
|
|
|
==> amazon-ebs: Skipping waiting for password since WinRM password set...
|
|
|
|
==> amazon-ebs: Waiting for WinRM to become available...
|
|
|
|
amazon-ebs: WinRM connected.
|
|
|
|
==> amazon-ebs: Connected to WinRM!
|
|
|
|
==> amazon-ebs: Provisioning with Powershell...
|
2017-10-13 18:42:52 -04:00
|
|
|
==> amazon-ebs: Provisioning with powershell script: /var/folders/15/d0f7gdg13rnd1cxp7tgmr55c0000gn/T/packer-powershell-provisioner175214995
|
2017-10-05 17:01:16 -04:00
|
|
|
amazon-ebs: HELLO NEW USER; WELCOME TO PACKER
|
|
|
|
==> amazon-ebs: Restarting Machine
|
|
|
|
==> amazon-ebs: Waiting for machine to restart...
|
2017-10-13 18:42:52 -04:00
|
|
|
amazon-ebs: WIN-TEM0TDL751M restarted.
|
2017-10-05 17:01:16 -04:00
|
|
|
==> amazon-ebs: Machine successfully restarted, moving on
|
|
|
|
==> amazon-ebs: Provisioning with Powershell...
|
2017-10-13 18:42:52 -04:00
|
|
|
==> amazon-ebs: Provisioning with powershell script: ./sample_script.ps1
|
|
|
|
amazon-ebs: PACKER_BUILD_NAME is automatically set for you, or you can set it in your builder variables; The default for this builder is: amazon-ebs
|
|
|
|
amazon-ebs: Use backticks as the escape character when required in powershell:
|
|
|
|
amazon-ebs: For example, VAR1 from our config is: A$Dollar
|
|
|
|
amazon-ebs: Likewise, VAR2 is: A`Backtick
|
|
|
|
amazon-ebs: Finally, VAR3 is: A'SingleQuote
|
2017-10-05 17:01:16 -04:00
|
|
|
==> amazon-ebs: Stopping the source instance...
|
|
|
|
amazon-ebs: Stopping instance, attempt 1
|
|
|
|
==> amazon-ebs: Waiting for the instance to stop...
|
2017-10-13 18:42:52 -04:00
|
|
|
==> amazon-ebs: Creating the AMI: packer-demo-1507933843
|
|
|
|
amazon-ebs: AMI: ami-100fc56a
|
2017-10-05 17:01:16 -04:00
|
|
|
==> amazon-ebs: Waiting for AMI to become ready...
|
|
|
|
==> amazon-ebs: Terminating the source AWS instance...
|
|
|
|
==> amazon-ebs: Cleaning up any extra volumes...
|
|
|
|
==> amazon-ebs: No volumes to clean up, skipping
|
|
|
|
==> amazon-ebs: Deleting temporary security group...
|
|
|
|
==> amazon-ebs: Deleting temporary keypair...
|
|
|
|
Build 'amazon-ebs' finished.
|
|
|
|
|
|
|
|
==> Builds finished. The artifacts of successful builds are:
|
|
|
|
--> amazon-ebs: AMIs were created:
|
2017-10-13 18:42:52 -04:00
|
|
|
us-east-1: ami-100fc56a
|
2017-10-05 17:01:16 -04:00
|
|
|
```
|
|
|
|
|
2017-10-15 18:50:59 -04:00
|
|
|
And if you navigate to your EC2 dashboard you should see your shiny new AMI
|
|
|
|
listed in the main window of the Images -> AMIs section.
|
2017-10-05 17:01:16 -04:00
|
|
|
|
2017-10-13 20:29:49 -04:00
|
|
|
Why stop there though?
|
|
|
|
|
|
|
|
As you'll see, with one simple change to the template above, it's
|
|
|
|
just as easy to create your own Windows 2008 or Windows 2016 AMIs. Just
|
|
|
|
set the value for the name field within `source_ami_filter` as required:
|
|
|
|
|
|
|
|
For Windows 2008 SP2:
|
|
|
|
|
|
|
|
```
|
|
|
|
"name": "*Windows_Server-2008-SP2*English-64Bit-Base*",
|
|
|
|
```
|
|
|
|
|
|
|
|
For Windows 2016:
|
|
|
|
|
|
|
|
```
|
|
|
|
"name": "*Windows_Server-2016-English-Full-Base*",
|
|
|
|
```
|
|
|
|
|
|
|
|
The bootstrapping and sample provisioning should work the same across all
|
|
|
|
Windows server versions.
|
2017-10-05 17:01:16 -04:00
|
|
|
|
2017-03-28 18:28:34 -04:00
|
|
|
[platforms]: /docs/builders/index.html
|