Custom VM Images
Add your own custom VM images from your cloud providers to WarpBuild
WarpBuild allows you to use your own custom VM images in your custom runner configurations while running them on your own cloud. This is useful if you are using a custom VM image that you have built due to a specific need.
💡 Note: The "images" referred to in this section are VM images. This is distinct from the custom container images support.
VM Image requirements
AMIs
- Linux and Windows based AMIs are currently supported.
Linux
- The Linux distro the image is based on should be using
systemd
. WarpBuild relies on it to run its agent. For example, Ubuntu based AMIs are supported while CentOS/RHEL based AMIs are not. curl
andwget
should be present in the image.
Here's an example packer file for a Linux AMI that is supported:
variable "aws_region" {
type = string
default = "us-east-1"
}
locals {
version = "1.0.0"
}
source "amazon-ebs" "my-custom-ci" {
region = var.aws_region
instance_type = "t3.micro"
ami_name = "my-custom-ci-v${local.version}"
tags = {
Name = "my-custom-ci-v${local.version}"
team = "platform"
repo = "platform"
build_date = "{{timestamp}}"
version = local.version
provider = "packer"
pii = "none"
product = "github-actions"
}
source_ami_filter {
filters = {
name = "ubuntu/images/hvm-ssd-gp3/ubuntu-noble-24.*-amd64-server-*"
root-device-type = "ebs"
virtualization-type = "hvm"
}
owners = ["099720109477"] # Amazon Canonical
most_recent = true
}
ssh_username = "ubuntu"
launch_block_device_mappings {
device_name = "/dev/sda1"
volume_type = "gp3"
volume_size = 8
delete_on_termination = true
}
}
build {
sources = ["source.amazon-ebs.my-custom-ci"]
provisioner "shell" {
inline = [
# Create runner user and group
"sudo groupadd runner || echo 'Group runner already exists'",
"sudo useradd -m -g runner -s /bin/bash runner || echo 'User runner already exists'",
# Configure passwordless sudo for runner user
"echo 'runner ALL=(ALL) NOPASSWD:ALL' | sudo tee /etc/sudoers.d/runner",
"sudo chmod 440 /etc/sudoers.d/runner",
# Update system packages
"sudo apt-get update",
"sudo apt-get upgrade -y",
# Install essential tools
"sudo apt-get install -y curl wget unzip git jq",
# Verify installations
"curl --version",
"wget --version",
"git --version",
"jq --version",
# Setup GitHub Actions tool cache directories with proper permissions
"sudo mkdir -p /opt/hostedtoolcache",
"sudo mkdir -p /opt/hostedtoolcache/Python",
"sudo mkdir -p /opt/hostedtoolcache/Node",
"sudo mkdir -p /opt/hostedtoolcache/go",
"sudo chown -R runner:runner /opt/hostedtoolcache",
"sudo chmod -R 755 /opt/hostedtoolcache",
# Setup additional GitHub Actions directories with runner permissions
"sudo mkdir -p /home/runner/_work",
"sudo mkdir -p /home/runner/_tool",
"sudo mkdir -p /home/runner/_temp",
"sudo chown -R runner:runner /home/runner/_work /home/runner/_tool /home/runner/_temp",
"sudo chmod -R 755 /home/runner/_work /home/runner/_tool /home/runner/_temp",
# Create a startup script to verify tools on instance launch
"echo '#!/bin/bash\necho \"=== Checking installed tools at startup ===\"\nwhich git\ngit --version\nwhich curl\ncurl --version\nwhich wget\nwget --version\nwhich unzip\nunzip -h | head -n 1\nwhich jq\njq --version' | sudo tee /var/lib/cloud/scripts/per-boot/verify-tools.sh",
"sudo chmod +x /var/lib/cloud/scripts/per-boot/verify-tools.sh",
]
}
}
## Thanks to Joe Hutchinson for the sample packer file.
Here's a sample workflow to build the AMI:
name: Build My Custom CI AMI
## Thanks to Joe Hutchinson for the sample workflow.
on:
workflow_dispatch:
push:
branches:
- main
paths:
- "packer/github-actions-ami/**"
permissions:
contents: read
jobs:
build-ami:
runs-on: warp-ubuntu-2404-x64-4x
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Check execution user
run: |
echo "Workflow is running as user: $(whoami)"
echo "User groups: $(groups)"
echo "Home directory: $HOME"
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::ACCOUNT_ID:role/YOUR_ROLE_NAME
role-session-name: GitHubAction-BuildCIAMI
aws-region: us-east-1
- name: Set up Packer
uses: hashicorp/setup-packer@v3
with:
version: 1
- name: Install Packer plugins
run: packer plugins install github.com/hashicorp/amazon
- name: Validate Packer template
run: packer validate packer/github-actions-ami/my-custom-ci.pkr.hcl
- name: Build AMI with Packer
run: packer build packer/github-actions-ami/my-custom-ci.pkr.hcl
env:
AWS_REGION: us-east-1
Windows
aria2
is used for downloading the necessary artifacts since the default windows method is slow. The image needs to havearia2
present and it should be accessible through the systemPATH
. Below is sample script which can be used to install aria2.
New-Item -ItemType Directory -Path 'C:\Tools\aria2' -Force
# Use: https://github.com/aria2/aria2/releases/latest to fetch the latest release and replace it
Invoke-WebRequest -Uri 'https://github.com/aria2/aria2/releases/download/release-1.37.0/aria2-1.37.0-win-64bit-build1.zip' -OutFile 'C:\Tools\aria2\aria2.zip'
Expand-Archive -Path 'C:\Tools\aria2\aria2.zip' -DestinationPath 'C:\Tools\aria2' -Force
Remove-Item 'C:\Tools\aria2\aria2.zip' -Force
Move-Item -Path 'C:\Tools\aria2\aria2-1.37.0-win-64bit-build1\*' -Destination 'C:\Tools\aria2' -Force
Remove-Item -Path 'C:\Tools\aria2\aria2-1.37.0-win-64bit-build1' -Recurse -Force
[Environment]::SetEnvironmentVariable('Path', $Env:Path + ';C:\Tools\aria2', 'Machine')
- If working with AWS instances, the EC2 instance must be sysprepped before making a windows image out of it. Please look at the 'Additional Notes' > 'Windows' > 'Sysprep' section for details on sysprepping.
Additional Notes
Windows on AWS
The runners are run under the runneradmin user, the same user as github's windows runners. If this user is not present, it will be added. If you have user scoped environment variables, you might need to change them to system level or add them to the runneradmin user's environment instead.
Sysprep (GUI)
For generalizing using the GUI,
- RDP into the instance and open 'Amazon EC2Launch settings'. Press 'Shutdown with sysprep' > Press 'Yes' on the dialog box.
- The above step will disconnect you in some time. This is expected. Go to the instance in the ec2 dashboard and wait for the instance to reach 'Stopped' state (might take a min).
- Rest of the steps are mostly same. Use the console to create the image. Fill in the details. Unselect the 'reboot' option since we already have the machine in a shutdown state.
Wait for the AMI to be ready. The image should be a generalized one now.
Sysprep (Automation)
Refer to the following packer docs for sysprep automation. These commands can be invoked without the use of packer as well from a powershell instance.
Common issues
- Unable to RDP into the instance
We don't expose RDP port (3389) by default when you create a stack. You must add a security policy enabling the inbound TCP connections to 3389 from a.b.c.d/e (replace this with your CIDR block)
- Password incorrect when trying to login via Administrator
Administrator account for windows has a rotating password for each ec2 instance. AWS automatically creates and assigns this password. It is recommended that you create your own user and give it admin permissions. You can use the below commands to create the user and assign it admin.
Write-Host 'Creating custom user'
$MACHINE_USER = "customuser"
$MACHINE_PASSWORD = "CustomU$er!2025"
$Password = ConvertTo-SecureString $MACHINE_PASSWORD -AsPlainText -Force
New-LocalUser -Name $MACHINE_USER -Password $Password -FullName "Custom User" -Description "Custom User for CI/CD"
Add-LocalGroupMember -Group "Administrators" -Member $MACHINE_USER
Add-LocalGroupMember -Group "Users" -Member $MACHINE_USER
# Set customuser user to not require password change at next logon
Set-LocalUser -Name $MACHINE_USER -PasswordNeverExpires $true
Add the image
- Setup a WarpBuild Stack
- Add a VM image using the
Add Image
button on the custom images page. All the images in the region the stack is in will be listed. Select the image you want to use. - Create a custom runner using the image.
- Use the custom runner label in your workflows to run the jobs on this container image.
Pricing
There is no additional cost for using custom VM images.
Last updated on