Skip to content

Commit

Permalink
add ubuntu and windows packer images for AWS (#300)
Browse files Browse the repository at this point in the history
* add ubuntu and windows packer images for AWS

* fixes to windows provisioner scripts

* increase EBS volume size for snapshot
  • Loading branch information
DaMandal0rian authored May 21, 2024
1 parent 74a6e00 commit c922a6e
Show file tree
Hide file tree
Showing 5 changed files with 374 additions and 0 deletions.
169 changes: 169 additions & 0 deletions resources/packer/ubuntu-jammy/aws.ubuntu.pkr.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
packer {
required_plugins {
amazon = {
version = ">= 0.0.2"
source = "github.com/hashicorp/amazon"
}
}
}

variable "region" {
description = "The region to build the image in"
type = string
default = "us-west-2"
}

variable "security_group_id" {
description = "The ID of the security group Packer will associate with the builder to enable access"
type = string
default = null
}

variable "subnet_id" {
description = "If using VPC, the ID of the subnet, such as subnet-12345def, where Packer will launch the EC2 instance. This field is required if you are using an non-default VPC"
type = string
default = null
}

variable "associate_public_ip_address" {
description = "If using a non-default VPC, there is no public IP address assigned to the EC2 instance. If you specified a public subnet, you probably want to set this to true. Otherwise the EC2 instance won't have access to the internet"
type = string
default = null
}

variable "instance_type" {
description = "The instance type Packer will use for the builder"
type = string
default = "t3.medium"
}

variable "root_volume_size_gb" {
type = number
default = 50
}

variable "ebs_delete_on_termination" {
description = "Indicates whether the EBS volume is deleted on instance termination."
type = bool
default = true
}

variable "global_tags" {
description = "Tags to apply to everything"
type = map(string)
default = {}
}

variable "ami_tags" {
description = "Tags to apply to the AMI"
type = map(string)
default = {}
}

variable "snapshot_tags" {
description = "Tags to apply to the snapshot"
type = map(string)
default = {}
}

variable "custom_shell_commands" {
description = "Additional commands to run on the EC2 instance, to customize the instance, like installing packages"
type = list(string)
default = []
}

variable "temporary_security_group_source_public_ip" {
description = "When enabled, use public IP of the host (obtained from https://checkip.amazonaws.com) as CIDR block to be authorized access to the instance, when packer is creating a temporary security group. Note: If you specify `security_group_id` then this input is ignored."
type = bool
default = false
}

source "amazon-ebs" "ubuntu-jammy-amd64" {
ami_name = "ubuntu-jammy-amd64-${formatdate("YYYYMMDDhhmm", timestamp())}"
instance_type = var.instance_type
region = var.region
security_group_id = var.security_group_id
subnet_id = var.subnet_id
associate_public_ip_address = var.associate_public_ip_address
temporary_security_group_source_public_ip = var.temporary_security_group_source_public_ip

source_ami_filter {
filters = {
name = "*ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*"
root-device-type = "ebs"
virtualization-type = "hvm"
}
most_recent = true
owners = ["099720109477"]
}
ssh_username = "ubuntu"
tags = merge(
var.global_tags,
var.ami_tags,
{
OS_Version = "ubuntu-jammy"
Release = "Latest"
Base_AMI_Name = "{{ .SourceAMIName }}"
})
snapshot_tags = merge(
var.global_tags,
var.snapshot_tags,
)

launch_block_device_mappings {
device_name = "/dev/sda1"
volume_size = "${var.root_volume_size_gb}"
volume_type = "gp3"
delete_on_termination = "${var.ebs_delete_on_termination}"
}
}

build {
name = "githubactions-runner"
sources = [
"source.amazon-ebs.githubrunner"
]
provisioner "shell" {
environment_vars = [
"DEBIAN_FRONTEND=noninteractive"
]
inline = concat([
"sudo cloud-init status --wait",
"sudo apt-get -y update",
"sudo apt-get -y install ca-certificates curl gnupg lsb-release",
"sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg",
"echo deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null",
"sudo apt-get -y update",
"sudo apt-get -y install docker-ce docker-ce-cli containerd.io jq git unzip pkg-config openssl libssl3 libtool cmake build-essential acl aria2 autoconf automake binutils brotli bzip2 coreutils dbus curl dnsutils fakeroot file findutils g++ gcc gnupg2 iproute2 iputils-ping jq atop nload locales lz4 make net-tools netcat openssh-client rsync shellcheck sqlite3 ssh sshpass sudo tar tzdata unzip wget zip zsync --no-install-recommends",
"sudo systemctl enable containerd.service",
"sudo service docker start",
"sudo usermod -a -G docker ubuntu",
"sudo curl -f https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb -o amazon-cloudwatch-agent.deb",
"sudo dpkg -i amazon-cloudwatch-agent.deb",
"sudo systemctl restart amazon-cloudwatch-agent",
"sudo curl -f https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip -o awscliv2.zip",
"unzip awscliv2.zip",
"sudo ./aws/install",
], var.custom_shell_commands)
}

provisioner "file" {
source = "./post_installer.sh"
destination = "/tmp/post_installer.sh"
}

provisioner "shell" {
environment_vars = [
"FOO=bar"
]
inline = [
"sudo chmod +x /tmp/post_installer.sh",
"sudo /tmp/post_installer.sh",
]
}

post-processor "manifest" {
output = "manifest.json"
strip_path = true
}
}
9 changes: 9 additions & 0 deletions resources/packer/ubuntu-jammy/post-installer.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/sh

set -e

exec > >(tee /var/log/user-data.log | logger -t user-data -s 2>/dev/console) 2>&1
echo "hello world"
echo "this is a post-install script"

exit 0
109 changes: 109 additions & 0 deletions resources/packer/windows-core-2022/aws.windows.pkr.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
packer {
required_plugins {
amazon = {
version = ">= 0.0.2"
source = "github.com/hashicorp/amazon"
}
}
}

variable "region" {
description = "The region to build the image in"
type = string
default = "us-west-2"
}

variable "security_group_id" {
description = "The ID of the security group Packer will associate with the builder to enable access"
type = string
default = null
}

variable "subnet_id" {
description = "If using VPC, the ID of the subnet, such as subnet-12345def, where Packer will launch the EC2 instance. This field is required if you are using an non-default VPC"
type = string
default = null
}

variable "root_volume_size_gb" {
type = number
default = 30
}

variable "ebs_delete_on_termination" {
description = "Indicates whether the EBS volume is deleted on instance termination."
type = bool
default = true
}

variable "associate_public_ip_address" {
description = "If using a non-default VPC, there is no public IP address assigned to the EC2 instance. If you specified a public subnet, you probably want to set this to true. Otherwise the EC2 instance won't have access to the internet"
type = string
default = null
}

variable "custom_shell_commands" {
description = "Additional commands to run on the EC2 instance, to customize the instance, like installing packages"
type = list(string)
default = []
}

variable "temporary_security_group_source_public_ip" {
description = "When enabled, use public IP of the host (obtained from https://checkip.amazonaws.com) as CIDR block to be authorized access to the instance, when packer is creating a temporary security group. Note: If you specify `security_group_id` then this input is ignored."
type = bool
default = false
}

source "amazon-ebs" "windows-core-2022" {
ami_name = "windows-core-2022-${formatdate("YYYYMMDDhhmm", timestamp())}"
communicator = "winrm"
instance_type = "m7.xlarge"
region = var.region
security_group_id = var.security_group_id
subnet_id = var.subnet_id
associate_public_ip_address = var.associate_public_ip_address
temporary_security_group_source_public_ip = var.temporary_security_group_source_public_ip

source_ami_filter {
filters = {
name = "Windows_Server-2022-English-Full-ECS_Optimized-*"
root-device-type = "ebs"
virtualization-type = "hvm"
}
most_recent = true
owners = ["amazon"]
}
tags = {
OS_Version = "windows-core-2022"
Release = "Latest"
Base_AMI_Name = "{{ .SourceAMIName }}"
}
user_data_file = "./bootstrap_win.ps1"
winrm_insecure = true
winrm_port = 5986
winrm_use_ssl = true
winrm_username = "Administrator"

launch_block_device_mappings {
device_name = "/dev/sda1"
volume_size = "${var.root_volume_size_gb}"
delete_on_termination = "${var.ebs_delete_on_termination}"
}
}

build {
name = "windows-core-2022"
sources = [
"source.amazon-ebs.windows-core-2022"
]

provisioner "powershell" {
inline = concat([
templatefile("./windows-provisioner.ps1")
], var.custom_shell_commands)
}
post-processor "manifest" {
output = "manifest.json"
strip_path = true
}
}
38 changes: 38 additions & 0 deletions resources/packer/windows-core-2022/bootstrap_win.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<powershell>

Write-Output "Running User Data Script"
Write-Host "(host) Running User Data Script"

Set-ExecutionPolicy Unrestricted -Scope LocalMachine -Force -ErrorAction Ignore

# Don't set this before Set-ExecutionPolicy as it throws an error
$ErrorActionPreference = "stop"

# Remove HTTP listener
Remove-Item -Path WSMan:\Localhost\listener\listener* -Recurse

# Create a self-signed certificate to let ssl work
$Cert = New-SelfSignedCertificate -CertstoreLocation Cert:\LocalMachine\My -DnsName "packer"
New-Item -Path WSMan:\LocalHost\Listener -Transport HTTPS -Address * -CertificateThumbPrint $Cert.Thumbprint -Force

# WinRM
Write-Output "Setting up WinRM"
Write-Host "(host) setting up WinRM"

# I'm not really sure why we need the cmd.exe wrapper, but it works with it and doesn't work without it
cmd.exe /c winrm quickconfig -q
cmd.exe /c winrm set "winrm/config" '@{MaxTimeoutms="1800000"}'
cmd.exe /c winrm set "winrm/config/winrs" '@{MaxMemoryPerShellMB="1024"}'
cmd.exe /c winrm set "winrm/config/service" '@{AllowUnencrypted="true"}'
cmd.exe /c winrm set "winrm/config/client" '@{AllowUnencrypted="true"}'
cmd.exe /c winrm set "winrm/config/service/auth" '@{Basic="true"}'
cmd.exe /c winrm set "winrm/config/client/auth" '@{Basic="true"}'
cmd.exe /c winrm set "winrm/config/service/auth" '@{CredSSP="true"}'
cmd.exe /c winrm set "winrm/config/listener?Address=*+Transport=HTTPS" "@{Port=`"5986`";Hostname=`"packer`";CertificateThumbprint=`"$($Cert.Thumbprint)`"}"
cmd.exe /c netsh advfirewall firewall set rule group="remote administration" new enable=yes
cmd.exe /c netsh firewall add portopening TCP 5986 "Port 5986"
cmd.exe /c net stop winrm
cmd.exe /c sc config winrm start= auto
cmd.exe /c net start winrm

</powershell>
49 changes: 49 additions & 0 deletions resources/packer/windows-core-2022/windows-provisioner.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
$ErrorActionPreference = "Continue"
$VerbosePreference = "Continue"

# Install Chocolatey
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
$env:chocolateyUseWindowsCompression = 'true'
Invoke-WebRequest https://chocolatey.org/install.ps1 -UseBasicParsing | Invoke-Expression

# Add Chocolatey to powershell profile
$ChocoProfileValue = @'
$ChocolateyProfile = "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
if (Test-Path($ChocolateyProfile)) {
Import-Module "$ChocolateyProfile"
}
refreshenv
'@
# Write it to the $profile location
Set-Content -Path "$PsHome\Microsoft.PowerShell_profile.ps1" -Value $ChocoProfileValue -Force
# Source it
. "$PsHome\Microsoft.PowerShell_profile.ps1"

refreshenv

Write-Host "Installing cloudwatch agent..."
Invoke-WebRequest -Uri https://s3.amazonaws.com/amazoncloudwatch-agent/windows/amd64/latest/amazon-cloudwatch-agent.msi -OutFile C:\amazon-cloudwatch-agent.msi
$cloudwatchParams = '/i', 'C:\amazon-cloudwatch-agent.msi', '/qn', '/L*v', 'C:\CloudwatchInstall.log'
Start-Process "msiexec.exe" $cloudwatchParams -Wait -NoNewWindow
Remove-Item C:\amazon-cloudwatch-agent.msi

# Install dependent tools
Write-Host "Installing additional development tools"
choco install git awscli 7zip-zstd curl wget jq mingw cmake openssl -y
refreshenv

$EC2LaunchFolder = "C:\EC2Launch"
New-Item -ItemType Directory -Force -Path $EC2LaunchFolder

$Url = "https://s3.amazonaws.com/ec2-downloads-windows/EC2Launch/latest/EC2-Windows-Launch.zip"
$DownloadZipFile = Join-Path -Path $EC2LaunchFolder -ChildPath $(Split-Path -Path $Url -Leaf)
Invoke-WebRequest -Uri $Url -OutFile $DownloadZipFile

$Url = "https://s3.amazonaws.com/ec2-downloads-windows/EC2Launch/latest/install.ps1"
$DownloadInstallFile = Join-Path -Path $EC2LaunchFolder -ChildPath $(Split-Path -Path $Url -Leaf)
Invoke-WebRequest -Uri $Url -OutFile $DownloadInstallFile

& $DownloadInstallFile

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

0 comments on commit c922a6e

Please sign in to comment.