/ devops

Packer and Windows Server 2016 AMI

This is the third post in AMI with Packer series. First being and introduction and then the baking recipe.

Here we are going to talk about the gotchas of creating a Windows Server AMI with Packer.

The provisioner that will be of most help for Windows platform is powershell and windows-shell for running any .bat/.cmd files.

The communicator we use for building this Windows AMI is winrm. WinRM works on port 5985/5986 (SSL).

  "builders": [{
    ...
    "communicator": "winrm",
    "winrm_username": "Administrator",
    "winrm_use_ssl": false,
    "winrm_insecure": true,
    ...
    }]

But first we must enable WinRM service itself and open up winrm ports in firewall. We can add the script for this in user-data. User Data is bunch of commands/script run by default only once after the first boot cycle.

In AWS Windows instances user-data is processed by EC2-Config or EC2-Launch tools and in Linux Machines its handled by Cloud-Init

We must execute the following commands to enable/configure WinRM and Windows Firewall.

winrm quickconfig -q 
winrm set winrm/config/winrs @{MaxMemoryPerShellMB="1024"} 
winrm set winrm/config @{MaxTimeoutms="1800000"} 
winrm set winrm/config/service @{AllowUnencrypted="true"} 
winrm set winrm/config/service/auth @{Basic="true"} 
netsh advfirewall firewall add rule name="WinRM 5985" protocol=TCP dir=in localport=5985 action=allow 
netsh advfirewall firewall add rule name="WinRM 5986" protocol=TCP dir=in localport=5986 action=allow 
net stop winrm 
sc config winrm start= auto 
net start winrm

This must be added to a .cmd file inside <script></script> tags and use user_data_file property of builders section of our packer template (refer full example given below).

Where is EC2Config ??

In Windows Server 2016 AMI, AWS replaced the EC2Config tool with EC2Launch, the implications of this is EC2Config will sent Windows Ready message on every boot where as EC2Launch will only sent it on the first boot. Why is this important ? Some tools consider this message as sign of successful startup of an instance.

Sent "Windows is ready"

To be backward compatible AWS provide some scripts to sent this message to EC2 Console. We can schedule it using :

"C:\\ProgramData\\Amazon\\EC2-Windows\\Launch\\Scripts\\SendWindowsIsReady.ps1 -Schedule"

Sysprep / System Preparation

We must remove all installation/machine specific information before creating the customized image. Sysprep do exactly this. Read more about sysprep here.

InitializeInstance.ps1 script will schedule to run the initialization task on next book. This must be called before SysprepInstance.ps1

It does the following :

  • Set the computer name.
  • Set up new wallpaper.
  • Add DNS suffix list.
  • Extend the boot volume size.
  • Set the administrator password.

Read more about initialization here.

Lastly we call the powershell script that runs sysprep and pass in a flag to not shutdown the instance (default behavior is to shutdown after sysprep). It use a answer file unattend.xml located at C:\ProgramData\Amazon\EC2-Windows\Launch\Sysprep .

{
      "type": "powershell",
      "inline": [
        "C:\\ProgramData\\Amazon\\EC2-Windows\\Launch\\Scripts\\SendWindowsIsReady.ps1 -Schedule",
        "C:\\ProgramData\\Amazon\\EC2-Windows\\Launch\\Scripts\\InitializeInstance.ps1 -Schedule",
        "C:\\ProgramData\\Amazon\\EC2-Windows\\Launch\\Scripts\\SysprepInstance.ps1 -NoShutdown"
      ]
    }

Full template

{
    "variables": {
      "name": "Windows_2016",
      "source_ami": "ami-xxxxxx"
    },
    "builders": [{
      "ami_name": "{{user `name`}}",
      "type": "amazon-ebs",
      "region": "us-east-1",
      "source_ami": "{{user `source_ami`}}",
      "user_data_file":"../user_data.cmd",
      "instance_type": "t2.micro",
      "communicator": "winrm",
      "winrm_username": "Administrator",
      "winrm_use_ssl": false,
      "winrm_insecure": true
     }],
    "provisioners": [
      {
        "type": "powershell",
        "inline":"Install-WindowsFeature -name Web-Server -IncludeManagementTools"
      },
      {
      "type": "powershell","inline": [
        "C:\\ProgramData\\Amazon\\EC2-Windows\\Launch\\Scripts\\SendWindowsIsReady.ps1 -Schedule",
        "C:\\ProgramData\\Amazon\\EC2-Windows\\Launch\\Scripts\\InitializeInstance.ps1 -Schedule",
        "C:\\ProgramData\\Amazon\\EC2-Windows\\Launch\\Scripts\\SysprepInstance.ps1 -NoShutdown"
      ]
    }]
  }
  

References :

AWS EC2 Launch

Packer WinRM Communicator Docs