Build a Windows Image
Should you decide to follow along and 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 section above to deregister the created AMI and delete the associated snapshot once you're done.
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. Any instances we subsequently create from this AMI will have all of our customizations baked in. This is the core benefit we are looking to achieve from using the Amazon EBS builder in this example.
One issue we run into when provisioning Windows AMIs on Amazon is that 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 to and customize our instance?
Packer can use an Amazon-provided mechanism called "user-data" to run a set of pre-supplied commands within the instance shortly after the instance starts.
This means we need to give Packer the commands required to configure the instance for a remote connection. 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 over WinRM. We will add this file to the build source
section of our build template.
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
for more info about what's going on behind the scenes here.
Warning
Please note that if you're setting up WinRM for provisioning, you'll probably want to turn it off or restrict its permissions as part of a shutdown script at the end of Packer's provisioning process. For more details on the why/how, check out this useful blog post and the associated code: https://cloudywindows.io/post/winrm-for-provisioning---close-the-door-on-the-way-out-eh/
Save the above code in a file named bootstrap_win.txt
.
Warning
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
over WinRM. Why all the extra effort to configure things manually?
Well, use of the winrm quickconfig -q
command can sometimes
cause the Packer build to fail shortly after the WinRM connection is
established. How?
- Among other things, as well as setting up the listener for WinRM, the quickconfig command also configures the firewall to allow management messages to be sent over HTTP.
- This undoes the previous command in the script that configured the firewall to prevent this access.
- The upshot is that the system is configured and ready to accept WinRM connections earlier than intended.
- 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 the connection. - 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!
Now that we've done the configuration necessary to connect Packer to our instance, let's get on with the real reason we're doing all this, which is actually configuring and customizing the instance. We do this with Provisioners.
The example config below shows the two different ways of using the PowerShell
provisioner: inline
and script
.
The first example, inline
, allows you to provide short snippets of code, and
Packer will create a script file for you. The second example allows you to run
more complex code by providing the path to a script to run on the guest VM.
Here's an example of a sample_script.ps1
that will work with the environment
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:
Finally, we need to create the actual build template. 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.
The template below demonstrates use of the 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 to it.
The "provisioners"
section of the template demonstrates use of the
powershell and
windows-restart provisioners to
customize and control the build process:
Save the build template as firstrun-windows.pkr.hcl
.
Before you can build the AMI, you need to provide your AWS credentials to
Packer. These credentials have permissions to create, modify and delete EC2
instances. Refer to the
documentation
to find the full list IAM permissions required to run the amazon-ebs
builder.
To alow Packer to access your IAM user credentials, set your AWS access key ID as an environment variable.
Now set your secret key.
Tip
If you don't have access to IAM user credentials, use another authentication method described in the Packer documentation.
Finally, we can create our new AMI by running
packer build firstrun-windows.pkr.hcl
You should see output like this:
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.
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:
For Windows 2016:
The bootstrapping and sample provisioning should work the same across all Windows server versions.