Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prebuilt runner image using packer #1444

Merged
merged 36 commits into from
Dec 3, 2021
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
ccf78b3
Initial creation of runner image
ScottGuymer Nov 25, 2021
563391b
Refactored startup script and added it to the per-boot folder
ScottGuymer Nov 25, 2021
d8da7a4
Make the runner location a variable
ScottGuymer Nov 27, 2021
9a4bb2f
Retrieve external config setting via tags
ScottGuymer Nov 27, 2021
45b4aaa
Enable tag based config
ScottGuymer Nov 27, 2021
17e83d9
Add a CI job
ScottGuymer Nov 27, 2021
64a8b59
Fix the CI build
ScottGuymer Nov 27, 2021
e8b3571
Fix the formatting
ScottGuymer Nov 27, 2021
9d4e660
Retain user_data provisioning and remove duplication
ScottGuymer Nov 29, 2021
f8ad58c
Fix interpolation issues in template file
ScottGuymer Nov 29, 2021
b3d2fcf
fix build
ScottGuymer Nov 29, 2021
9e0612e
Fix formatting
ScottGuymer Nov 29, 2021
8233ca9
minor tweaks and fixes
ScottGuymer Nov 29, 2021
4144634
Fixes from testing
ScottGuymer Nov 30, 2021
80b1b90
Enable docker on boot
ScottGuymer Nov 30, 2021
33e9105
Add in output of start time for the runner
ScottGuymer Nov 30, 2021
af9198f
Scoop up the runner log
ScottGuymer Nov 30, 2021
08a0a66
Add a powershell build script for windows users
ScottGuymer Nov 30, 2021
925ffb9
Fix formatting
ScottGuymer Nov 30, 2021
11f5a2c
Use SSM parameters for configuration
ScottGuymer Dec 1, 2021
72e77dc
Make the SSM policy more specific
ScottGuymer Dec 1, 2021
632de43
Update .github/workflows/packer-build.yml
ScottGuymer Dec 2, 2021
318bdde
Added condition to the describe tags policy
ScottGuymer Dec 2, 2021
eb1910f
Dont use templatefile on the tags policy
ScottGuymer Dec 2, 2021
82db546
Added an option to turn off userdata scripting
ScottGuymer Dec 2, 2021
0f8f114
Added/updated documentation
ScottGuymer Dec 2, 2021
eb15f6b
Revert policy as it has no effect on the permissions
ScottGuymer Dec 2, 2021
280a680
Add reference to prebuilt images in the main readme
ScottGuymer Dec 2, 2021
46918e2
Add an example of deploying with prebuilt images
ScottGuymer Dec 2, 2021
a76731f
Update readme
ScottGuymer Dec 2, 2021
55004cd
Use current user as ami_owner
ScottGuymer Dec 3, 2021
cf44a5e
Update example to 5 secs
ScottGuymer Dec 3, 2021
c155774
Updated ami name to include the arch
ScottGuymer Dec 3, 2021
5d5aaa4
Fixed log file variable
ScottGuymer Dec 3, 2021
49b8a5c
Added explicit info about required settings to the readme
ScottGuymer Dec 3, 2021
8e987a8
Change userdata_enabled to enabled_userdata
ScottGuymer Dec 3, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .ci/build.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
$TOP_DIR=$(git rev-parse --show-toplevel)
$OUTPUT_DIR="$TOP_DIR/lambda_output"

New-Item "$OUTPUT_DIR" -ItemType Directory -ErrorAction SilentlyContinue

$env:DOCKER_BUILDKIT=1
docker build --no-cache --target=final --output=type=local,dest="$OUTPUT_DIR" -f "$TOP_DIR/.ci/Dockerfile" "$TOP_DIR"

2 changes: 2 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[*]
end_of_line = lf
35 changes: 35 additions & 0 deletions .github/workflows/packer-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: "Packer checks"
on:
push:
branches:
- master
- develop
pull_request:
paths:
- "images/**"
- ".github/workflows/packer-build.yml"

env:
AWS_REGION: eu-west-1

jobs:
verify_packer:
name: Verify image
ScottGuymer marked this conversation as resolved.
Show resolved Hide resolved
runs-on: ubuntu-latest
container:
image: hashicorp/packer:1.7.8
defaults:
run:
working-directory: images/linux-amzn2
steps:
- name: "Checkout"
uses: actions/checkout@v2

- name: packer init
run: packer init .

- name: check terraform formatting
run: packer fmt -recursive -check=true .

- name: packer validate
run: packer validate .
8 changes: 8 additions & 0 deletions images/install-runner.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/bin/bash -e

user_name=ec2-user

## This wrapper file re-uses scripts in the /modules/runners/templates directory
## of this repo. These are the same that are used by the user_data functionality
## to bootstrap the instance if it is started from an existing AMI.
${install_runner}
87 changes: 87 additions & 0 deletions images/linux-amzn2/github_agent.linux.pkr.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
packer {
required_plugins {
amazon = {
version = ">= 0.0.2"
source = "github.com/hashicorp/amazon"
}
}
}

variable "action_runner_url" {
description = "The URL to the tarball of the action runner"
type = string
default = "https://github.com/actions/runner/releases/download/v2.284.0/actions-runner-linux-x64-2.284.0.tar.gz"
}

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

source "amazon-ebs" "githubrunner" {
ami_name = "github-runner-amzn2-${formatdate("YYYYMMDDhhmm", timestamp())}"
ScottGuymer marked this conversation as resolved.
Show resolved Hide resolved
instance_type = "m3.medium"
region = var.region
source_ami_filter {
filters = {
name = "amzn2-ami-hvm-2.*-x86_64-ebs"
root-device-type = "ebs"
virtualization-type = "hvm"
}
most_recent = true
owners = ["137112412989"]
}
ssh_username = "ec2-user"
tags = {
OS_Version = "amzn2"
Release = "Latest"
Base_AMI_Name = "{{ .SourceAMIName }}"
}
}

build {
name = "githubactions-runner"
ScottGuymer marked this conversation as resolved.
Show resolved Hide resolved
sources = [
"source.amazon-ebs.githubrunner"
]
provisioner "shell" {
environment_vars = []
inline = [
"sudo yum update -y",
"sudo yum install -y amazon-cloudwatch-agent curl jq git",
"sudo amazon-linux-extras install docker",
"sudo systemctl enable docker.service",
"sudo systemctl enable containerd.service",
"sudo service docker start",
"sudo usermod -a -G docker ec2-user",
]
}

provisioner "shell" {
environment_vars = [
"RUNNER_TARBALL_URL=${var.action_runner_url}"
]
inline = [templatefile("../install-runner.sh", {
install_runner = templatefile("../../modules/runners/templates/install-runner.sh", {
ARM_PATCH = ""
S3_LOCATION_RUNNER_DISTRIBUTION = ""
})
})]
}

provisioner "file" {
content = templatefile("../start-runner.sh", {
start_runner = templatefile("../../modules/runners/templates/start-runner.sh", {})
})
destination = "/tmp/start-runner.sh"
}

provisioner "shell" {
inline = [
"sudo mv /tmp/start-runner.sh /var/lib/cloud/scripts/per-boot/start-runner.sh",
"sudo chmod +x /var/lib/cloud/scripts/per-boot/start-runner.sh",
]
}

}
9 changes: 9 additions & 0 deletions images/start-runner.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/bash -e
exec > >(tee /var/log/runner-startup.log | logger -t user-data -s 2>/dev/console) 2>&1

cd /home/ec2-user/actions-runner

## This wrapper file re-uses scripts in the /modules/runners/templates directory
## of this repo. These are the same that are used by the user_data functionality
## to bootstrap the instance if it is started from an existing AMI.
${start_runner}
3 changes: 2 additions & 1 deletion main.tf
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
locals {
tags = merge(var.tags, {
Environment = var.environment
Environment = var.environment,
"ghr:environment" = format("%s", var.environment)
ScottGuymer marked this conversation as resolved.
Show resolved Hide resolved
})

s3_action_runner_url = "s3://${module.runner_binaries.bucket.id}/${module.runner_binaries.runner_distribution_object_key}"
Expand Down
2 changes: 1 addition & 1 deletion modules/runners/logging.tf
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ resource "aws_cloudwatch_log_group" "gh_runners" {
}

resource "aws_iam_role_policy" "cloudwatch" {
count = var.enable_ssm_on_runners ? 1 : 0
count = var.enable_cloudwatch_agent ? 1 : 0
ScottGuymer marked this conversation as resolved.
Show resolved Hide resolved
name = "CloudWatchLogginAndMetrics"
role = aws_iam_role.runner.name
policy = templatefile("${path.module}/policies/instance-cloudwatch-policy.json",
Expand Down
45 changes: 19 additions & 26 deletions modules/runners/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,18 @@ locals {
{
"Name" = format("%s-action-runner", var.environment)
},
{
"Environment" = format("%s", var.environment)
ScottGuymer marked this conversation as resolved.
Show resolved Hide resolved
},
var.tags,
)

name_sg = var.overrides["name_sg"] == "" ? local.tags["Name"] : var.overrides["name_sg"]
name_runner = var.overrides["name_runner"] == "" ? local.tags["Name"] : var.overrides["name_runner"]
role_path = var.role_path == null ? "/${var.environment}/" : var.role_path
instance_profile_path = var.instance_profile_path == null ? "/${var.environment}/" : var.instance_profile_path
lambda_zip = var.lambda_zip == null ? "${path.module}/lambdas/runners/runners.zip" : var.lambda_zip
userdata_template = var.userdata_template == null ? "${path.module}/templates/user-data.sh" : var.userdata_template
userdata_arm_patch = "${path.module}/templates/arm-runner-patch.tpl"
userdata_install_config_runner = "${path.module}/templates/install-config-runner.sh"
name_sg = var.overrides["name_sg"] == "" ? local.tags["Name"] : var.overrides["name_sg"]
name_runner = var.overrides["name_runner"] == "" ? local.tags["Name"] : var.overrides["name_runner"]
role_path = var.role_path == null ? "/${var.environment}/" : var.role_path
instance_profile_path = var.instance_profile_path == null ? "/${var.environment}/" : var.instance_profile_path
lambda_zip = var.lambda_zip == null ? "${path.module}/lambdas/runners/runners.zip" : var.lambda_zip
userdata_template = var.userdata_template == null ? "${path.module}/templates/user-data.sh" : var.userdata_template
userdata_arm_patch = "${path.module}/templates/arm-runner-patch.tpl"
userdata_install_runner = "${path.module}/templates/install-runner.sh"
userdata_start_runner = "${path.module}/templates/start-runner.sh"

instance_types = distinct(var.instance_types == null ? [var.instance_type] : var.instance_types)

Expand Down Expand Up @@ -113,31 +111,26 @@ resource "aws_launch_template" "runner" {


user_data = base64encode(templatefile(local.userdata_template, {
pre_install = var.userdata_pre_install
install_runner = templatefile(local.userdata_install_runner, {
S3_LOCATION_RUNNER_DISTRIBUTION = var.s3_location_runner_binaries
ARM_PATCH = var.runner_architecture == "arm64" ? templatefile(local.userdata_arm_patch, {}) : ""
})
post_install = var.userdata_post_install
start_runner = templatefile(local.userdata_start_runner, {})
ghes_url = var.ghes_url
ghes_ssl_verify = var.ghes_ssl_verify
## retain these for backwards compatibility
environment = var.environment
pre_install = var.userdata_pre_install
post_install = var.userdata_post_install
enable_cloudwatch_agent = var.enable_cloudwatch_agent
ssm_key_cloudwatch_agent_config = var.enable_cloudwatch_agent ? aws_ssm_parameter.cloudwatch_agent_config_runner[0].name : ""
ghes_url = var.ghes_url
ghes_ssl_verify = var.ghes_ssl_verify
install_config_runner = local.install_config_runner
}))

tags = local.tags

update_default_version = true
}

locals {
arm_patch = var.runner_architecture == "arm64" ? templatefile(local.userdata_arm_patch, {}) : ""
install_config_runner = templatefile(local.userdata_install_config_runner, {
environment = var.environment
s3_location_runner_distribution = var.s3_location_runner_binaries
run_as_root_user = var.runner_as_root ? "root" : ""
arm_patch = local.arm_patch
})
}

resource "aws_security_group" "runner_sg" {
name_prefix = "${var.environment}-github-actions-runner-sg"
description = "Github Actions Runner security group"
Expand Down
11 changes: 10 additions & 1 deletion modules/runners/policies-runner.tf
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ resource "aws_iam_role_policy" "ssm_parameters" {
role = aws_iam_role.runner.name
policy = templatefile("${path.module}/policies/instance-ssm-parameters-policy.json",
{
arn_ssm_parameters = "arn:aws:ssm:${var.aws_region}:${data.aws_caller_identity.current.account_id}:parameter/${var.environment}-*"
arn_ssm_parameters = jsonencode([
ScottGuymer marked this conversation as resolved.
Show resolved Hide resolved
"arn:aws:ssm:${var.aws_region}:${data.aws_caller_identity.current.account_id}:parameter/${var.environment}-*",
"arn:aws:ssm:${var.aws_region}:${data.aws_caller_identity.current.account_id}:parameter/${var.environment}/*"
])
}
)
}
Expand All @@ -41,6 +44,12 @@ resource "aws_iam_role_policy" "dist_bucket" {
)
}

resource "aws_iam_role_policy" "describe_tags" {
name = "runner-describe-tags"
role = aws_iam_role.runner.name
policy = templatefile("${path.module}/policies/instance-describe-tags-policy.json", {})
}

resource "aws_iam_role_policy_attachment" "managed_policies" {
count = length(var.runner_iam_role_managed_policy_arns)
role = aws_iam_role.runner.name
Expand Down
10 changes: 10 additions & 0 deletions modules/runners/policies/instance-describe-tags-policy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
ScottGuymer marked this conversation as resolved.
Show resolved Hide resolved
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "ec2:DescribeTags",
"Resource": "*"
}
]
}
ScottGuymer marked this conversation as resolved.
Show resolved Hide resolved
7 changes: 4 additions & 3 deletions modules/runners/policies/instance-ssm-parameters-policy.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@
"Action": [
"ssm:DeleteParameter"
],
"Resource": "${arn_ssm_parameters}"
"Resource": ${arn_ssm_parameters}
},
{
"Effect": "Allow",
"Action": [
"ssm:GetParameter",
"ssm:GetParameters",
"ssm:GetParameter"
"ssm:GetParametersByPath"
],
"Resource": "${arn_ssm_parameters}"
"Resource": ${arn_ssm_parameters}
}
]
}
21 changes: 21 additions & 0 deletions modules/runners/runner-config.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
resource "aws_ssm_parameter" "runner_config_run_as" {
name = "/${var.environment}/runner/run-as"
type = "String"
value = var.runner_as_root ? "root" : "ec2-user"
tags = local.tags
}

resource "aws_ssm_parameter" "runner_agent_mode" {
ScottGuymer marked this conversation as resolved.
Show resolved Hide resolved
name = "/${var.environment}/runner/agent-mode"
type = "String"
# TODO: Update this to allow for ephemeral runners
value = "persistent"
tags = local.tags
}

resource "aws_ssm_parameter" "runner_enable_cloudwatch" {
name = "/${var.environment}/runner/enable-cloudwatch"
type = "String"
value = var.enable_cloudwatch_agent
tags = local.tags
}
35 changes: 0 additions & 35 deletions modules/runners/templates/install-config-runner.sh

This file was deleted.

Loading