Skip to content

Commit da3365c

Browse files
committed
feat: windows 2025 image example
fix: windows 2025 uses ec2launchv2
1 parent 24a2987 commit da3365c

File tree

3 files changed

+239
-0
lines changed

3 files changed

+239
-0
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<powershell>
2+
3+
Write-Output "Running User Data Script"
4+
Write-Host "(host) Running User Data Script"
5+
6+
Set-ExecutionPolicy Unrestricted -Scope LocalMachine -Force -ErrorAction Ignore
7+
8+
# Don't set this before Set-ExecutionPolicy as it throws an error
9+
$ErrorActionPreference = "stop"
10+
11+
# Remove HTTP listener
12+
Remove-Item -Path WSMan:\Localhost\listener\listener* -Recurse
13+
14+
# Create a self-signed certificate to let ssl work
15+
$Cert = New-SelfSignedCertificate -CertstoreLocation Cert:\LocalMachine\My -DnsName "packer"
16+
New-Item -Path WSMan:\LocalHost\Listener -Transport HTTPS -Address * -CertificateThumbPrint $Cert.Thumbprint -Force
17+
18+
# WinRM
19+
Write-Output "Setting up WinRM"
20+
Write-Host "(host) setting up WinRM"
21+
22+
# I'm not really sure why we need the cmd.exe wrapper, but it works with it and doesn't work without it
23+
cmd.exe /c winrm quickconfig -q
24+
cmd.exe /c winrm set "winrm/config" '@{MaxTimeoutms="1800000"}'
25+
cmd.exe /c winrm set "winrm/config/winrs" '@{MaxMemoryPerShellMB="1024"}'
26+
cmd.exe /c winrm set "winrm/config/service" '@{AllowUnencrypted="true"}'
27+
cmd.exe /c winrm set "winrm/config/client" '@{AllowUnencrypted="true"}'
28+
cmd.exe /c winrm set "winrm/config/service/auth" '@{Basic="true"}'
29+
cmd.exe /c winrm set "winrm/config/client/auth" '@{Basic="true"}'
30+
cmd.exe /c winrm set "winrm/config/service/auth" '@{CredSSP="true"}'
31+
cmd.exe /c winrm set "winrm/config/listener?Address=*+Transport=HTTPS" "@{Port=`"5986`";Hostname=`"packer`";CertificateThumbprint=`"$($Cert.Thumbprint)`"}"
32+
cmd.exe /c netsh advfirewall firewall set rule group="remote administration" new enable=yes
33+
cmd.exe /c netsh firewall add portopening TCP 5986 "Port 5986"
34+
cmd.exe /c net stop winrm
35+
cmd.exe /c sc config winrm start= auto
36+
cmd.exe /c net start winrm
37+
38+
</powershell>
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
packer {
2+
required_plugins {
3+
amazon = {
4+
version = ">= 0.0.2"
5+
source = "github.com/hashicorp/amazon"
6+
}
7+
}
8+
}
9+
10+
variable "runner_version" {
11+
description = "The version (no v prefix) of the runner software to install https://github.com/actions/runner/releases. The latest release will be fetched from GitHub if not provided."
12+
default = null
13+
}
14+
15+
variable "region" {
16+
description = "The region to build the image in"
17+
type = string
18+
default = "eu-west-1"
19+
}
20+
21+
variable "instance_type" {
22+
description = "The instance type Packer will use for the builder"
23+
type = string
24+
default = "m4.xlarge"
25+
}
26+
27+
variable "iam_instance_profile" {
28+
description = "IAM instance profile Packer will use for the builder. An empty string (default) means no profile will be assigned."
29+
type = string
30+
default = ""
31+
}
32+
33+
variable "security_group_id" {
34+
description = "The ID of the security group Packer will associate with the builder to enable access"
35+
type = string
36+
default = null
37+
}
38+
39+
variable "subnet_id" {
40+
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"
41+
type = string
42+
default = null
43+
}
44+
45+
variable "root_volume_size_gb" {
46+
type = number
47+
default = 30
48+
}
49+
50+
variable "ebs_delete_on_termination" {
51+
description = "Indicates whether the EBS volume is deleted on instance termination."
52+
type = bool
53+
default = true
54+
}
55+
56+
variable "associate_public_ip_address" {
57+
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"
58+
type = string
59+
default = null
60+
}
61+
62+
variable "custom_shell_commands" {
63+
description = "Additional commands to run on the EC2 instance, to customize the instance, like installing packages"
64+
type = list(string)
65+
default = []
66+
}
67+
68+
variable "temporary_security_group_source_public_ip" {
69+
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."
70+
type = bool
71+
default = false
72+
}
73+
74+
data "http" github_runner_release_json {
75+
url = "https://api.github.com/repos/actions/runner/releases/latest"
76+
request_headers = {
77+
Accept = "application/vnd.github+json"
78+
X-GitHub-Api-Version : "2022-11-28"
79+
}
80+
}
81+
82+
locals {
83+
runner_version = coalesce(var.runner_version, trimprefix(jsondecode(data.http.github_runner_release_json.body).tag_name, "v"))
84+
}
85+
86+
source "amazon-ebs" "githubrunner" {
87+
ami_name = "github-runner-windows-core-2025-${formatdate("YYYYMMDDhhmm", timestamp())}"
88+
communicator = "winrm"
89+
instance_type = var.instance_type
90+
iam_instance_profile = var.iam_instance_profile
91+
region = var.region
92+
security_group_id = var.security_group_id
93+
subnet_id = var.subnet_id
94+
associate_public_ip_address = var.associate_public_ip_address
95+
temporary_security_group_source_public_ip = var.temporary_security_group_source_public_ip
96+
97+
source_ami_filter {
98+
filters = {
99+
name = "Windows_Server-2025-English-Full-ECS_Optimized-*"
100+
root-device-type = "ebs"
101+
virtualization-type = "hvm"
102+
}
103+
most_recent = true
104+
owners = ["amazon"]
105+
}
106+
tags = {
107+
OS_Version = "windows-core-2025"
108+
Release = "Latest"
109+
Base_AMI_Name = "{{ .SourceAMIName }}"
110+
}
111+
user_data_file = "./bootstrap_win.ps1"
112+
winrm_insecure = true
113+
winrm_port = 5986
114+
winrm_use_ssl = true
115+
winrm_username = "Administrator"
116+
117+
launch_block_device_mappings {
118+
device_name = "/dev/sda1"
119+
volume_size = "${var.root_volume_size_gb}"
120+
delete_on_termination = "${var.ebs_delete_on_termination}"
121+
}
122+
}
123+
124+
build {
125+
name = "githubactions-runner"
126+
sources = [
127+
"source.amazon-ebs.githubrunner"
128+
]
129+
130+
provisioner "file" {
131+
content = templatefile("../start-runner.ps1", {
132+
start_runner = templatefile("../../modules/runners/templates/start-runner.ps1", {})
133+
})
134+
destination = "C:\\start-runner.ps1"
135+
}
136+
137+
provisioner "powershell" {
138+
inline = concat([
139+
templatefile("./windows-provisioner.ps1", {
140+
action_runner_url = "https://github.com/actions/runner/releases/download/v${local.runner_version}/actions-runner-win-x64-${local.runner_version}.zip"
141+
})
142+
], var.custom_shell_commands)
143+
}
144+
post-processor "manifest" {
145+
output = "manifest.json"
146+
strip_path = true
147+
}
148+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
$ErrorActionPreference = "Continue"
2+
$VerbosePreference = "Continue"
3+
4+
# Install Chocolatey
5+
[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12
6+
$env:chocolateyUseWindowsCompression = 'true'
7+
Invoke-WebRequest https://chocolatey.org/install.ps1 -UseBasicParsing | Invoke-Expression
8+
9+
# Add Chocolatey to powershell profile
10+
$ChocoProfileValue = @'
11+
$ChocolateyProfile = "$env:ChocolateyInstall\helpers\chocolateyProfile.psm1"
12+
if (Test-Path($ChocolateyProfile)) {
13+
Import-Module "$ChocolateyProfile"
14+
}
15+
16+
refreshenv
17+
'@
18+
# Write it to the $profile location
19+
Set-Content -Path "$PsHome\Microsoft.PowerShell_profile.ps1" -Value $ChocoProfileValue -Force
20+
# Source it
21+
. "$PsHome\Microsoft.PowerShell_profile.ps1"
22+
23+
refreshenv
24+
25+
Write-Host "Installing cloudwatch agent..."
26+
Invoke-WebRequest -Uri https://s3.amazonaws.com/amazoncloudwatch-agent/windows/amd64/latest/amazon-cloudwatch-agent.msi -OutFile C:\amazon-cloudwatch-agent.msi
27+
$cloudwatchParams = '/i', 'C:\amazon-cloudwatch-agent.msi', '/qn', '/L*v', 'C:\CloudwatchInstall.log'
28+
Start-Process "msiexec.exe" $cloudwatchParams -Wait -NoNewWindow
29+
Remove-Item C:\amazon-cloudwatch-agent.msi
30+
31+
# Install dependent tools
32+
Write-Host "Installing additional development tools"
33+
choco install git awscli -y
34+
refreshenv
35+
36+
Write-Host "Creating actions-runner directory for the GH Action installation"
37+
New-Item -ItemType Directory -Path C:\actions-runner ; Set-Location C:\actions-runner
38+
39+
Write-Host "Downloading the GH Action runner from ${action_runner_url}"
40+
Invoke-WebRequest -Uri ${action_runner_url} -OutFile actions-runner.zip
41+
42+
Write-Host "Un-zip action runner"
43+
Expand-Archive -Path actions-runner.zip -DestinationPath .
44+
45+
Write-Host "Delete zip file"
46+
Remove-Item actions-runner.zip
47+
48+
$action = New-ScheduledTaskAction -WorkingDirectory "C:\actions-runner" -Execute "PowerShell.exe" -Argument "-File C:\start-runner.ps1"
49+
$trigger = New-ScheduledTaskTrigger -AtStartup
50+
Register-ScheduledTask -TaskName "runnerinit" -Action $action -Trigger $trigger -User System -RunLevel Highest -Force
51+
52+
Write-Host "Running EC2Launch v2 to signal instance ready..."
53+
& "$${env:ProgramFiles}\Amazon\EC2Launch\EC2Launch.exe" run

0 commit comments

Comments
 (0)