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

WIP: initial body of self-hosted runners TF modules #343

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
74 changes: 74 additions & 0 deletions .github/tf/arm64/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Amazon Linux ARM64

This module shows how to create GitHub action runners using AWS Graviton instances which have ARM64 architecture. Lambda release will be downloaded from GitHub.

## Usages

Steps for the full setup, such as creating a GitHub app can be found in the root module's [README](https://github.com/philips-labs/terraform-aws-github-runner). First download the Lambda releases from GitHub. Alternatively you can build the lambdas locally with Node or Docker, there is a simple build script in `<root>/.ci/build.sh`. In the `main.tf` you can simply remove the location of the lambda zip files, the default location will work in this case.

> Ensure you have set the version in `lambdas-download/main.tf` for running the example. The version needs to be set to a GitHub release version, see https://github.com/philips-labs/terraform-aws-github-runner/releases

```bash
cd ../lambdas-download
terraform init
terraform apply -var=module_version=<VERSION>
cd -
```

Before running Terraform, ensure the GitHub app is configured. See the [configuration details](https://github.com/philips-labs/terraform-aws-github-runner#usages) for more details.

```bash
terraform init
terraform apply
```

The example will try to update the webhook of your GitHub. In case the update fails the apply will not fail. You can receive the webhook details by running:

```bash
terraform output -raw webhook_secret
```

<!-- BEGIN_TF_DOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1.3.0 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | ~> 5.27 |
| <a name="requirement_local"></a> [local](#requirement\_local) | ~> 2.0 |
| <a name="requirement_random"></a> [random](#requirement\_random) | ~> 3.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_random"></a> [random](#provider\_random) | 3.6.0 |

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_base"></a> [base](#module\_base) | ../base | n/a |
| <a name="module_runners"></a> [runners](#module\_runners) | ../../ | n/a |
| <a name="module_webhook_github_app"></a> [webhook\_github\_app](#module\_webhook\_github\_app) | ../../modules/webhook-github-app | n/a |

## Resources

| Name | Type |
|------|------|
| [random_id.random](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_github_app"></a> [github\_app](#input\_github\_app) | GitHub App for API usages. | <pre>object({<br> id = string<br> key_base64 = string<br> })</pre> | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_runners"></a> [runners](#output\_runners) | n/a |
| <a name="output_webhook_endpoint"></a> [webhook\_endpoint](#output\_webhook\_endpoint) | n/a |
| <a name="output_webhook_secret"></a> [webhook\_secret](#output\_webhook\_secret) | n/a |
<!-- END_TF_DOCS -->
31 changes: 31 additions & 0 deletions .github/tf/arm64/lambdas-download/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!-- BEGIN_TF_DOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1 |

## Providers

No providers.

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_lambdas"></a> [lambdas](#module\_lambdas) | ../../../modules/download-lambda | n/a |

## Resources

No resources.

## Inputs

No inputs.

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_files"></a> [files](#output\_files) | n/a |
<!-- END_TF_DOCS -->
25 changes: 25 additions & 0 deletions .github/tf/arm64/lambdas-download/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
locals {
version = "5.10.2"
}

module "lambdas" {
source = "github.com/philips-labs/terraform-aws-github-runner//modules/download-lambda"
lambdas = [
{
name = "webhook"
tag = local.version
},
{
name = "runners"
tag = local.version
},
{
name = "runner-binaries-syncer"
tag = local.version
}
]
}

output "files" {
value = module.lambdas.files
}
3 changes: 3 additions & 0 deletions .github/tf/arm64/lambdas-download/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
terraform {
required_version = ">= 1"
}
99 changes: 99 additions & 0 deletions .github/tf/arm64/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
locals {
environment = "default"
aws_region = "us-east-1"
}

resource "random_id" "random" {
byte_length = 20
}


################################################################################
### Hybrid account
################################################################################

module "base" {
source = "../base"

prefix = local.environment
aws_region = local.aws_region
}


module "runners" {
source = "github.com/philips-labs/terraform-aws-github-runner"
create_service_linked_role_spot = true
aws_region = local.aws_region
vpc_id = module.base.vpc.vpc_id
subnet_ids = module.base.vpc.private_subnets

prefix = local.environment
tags = {
Project = "ProjectX"
}

github_app = {
key_base64 = var.github_app.key_base64
id = var.github_app.id
webhook_secret = random_id.random.hex
}

# Grab zip files via lambda_download, will automatically get the ARM64 build
webhook_lambda_zip = "../lambdas-download/webhook.zip"
runner_binaries_syncer_lambda_zip = "../lambdas-download/runner-binaries-syncer.zip"
runners_lambda_zip = "../lambdas-download/runners.zip"

enable_organization_runners = false
# Runners will automatically get the "arm64" label
runner_extra_labels = ["default", "example"]

# enable access to the runners via SSM
enable_ssm_on_runners = true

# use S3 or KMS SSE to runners S3 bucket
# runner_binaries_s3_sse_configuration = {
# rule = {
# apply_server_side_encryption_by_default = {
# sse_algorithm = "AES256"
# }
# }
# }

# enable S3 versioning for runners S3 bucket
# runner_binaries_s3_versioning = "Enabled"

# Uncommet idle config to have idle runners from 9 to 5 in time zone Amsterdam
# idle_config = [{
# cron = "* * 9-17 * * *"
# timeZone = "Europe/Amsterdam"
# idleCount = 1
# }]

# Let the module manage the service linked role
# create_service_linked_role_spot = true

runner_architecture = "arm64"
# Ensure all instance types have ARM64 architecture (ie. AWS Graviton processors)
instance_types = ["t4g.large", "c6g.large"]

# override delay of events in seconds
delay_webhook_event = 5
runners_maximum_count = 1

# set up a fifo queue to remain order
enable_fifo_build_queue = true

# override scaling down
scale_down_schedule_expression = "cron(* * * * ? *)"
}

module "webhook_github_app" {
source = "../../modules/webhook-github-app"

github_app = {
key_base64 = var.github_app.key_base64
id = var.github_app.id
webhook_secret = random_id.random.hex
}
webhook_endpoint = module.runners.webhook.endpoint
}
15 changes: 15 additions & 0 deletions .github/tf/arm64/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
output "runners" {
value = {
lambda_syncer_name = module.runners.binaries_syncer.lambda.function_name
}
}

output "webhook_endpoint" {
value = module.runners.webhook.endpoint
}

output "webhook_secret" {
sensitive = true
value = random_id.random.hex
}

3 changes: 3 additions & 0 deletions .github/tf/arm64/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
provider "aws" {
region = local.aws_region
}
8 changes: 8 additions & 0 deletions .github/tf/arm64/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
variable "github_app" {
description = "GitHub App for API usages."

type = object({
id = string
key_base64 = string
})
}
17 changes: 17 additions & 0 deletions .github/tf/arm64/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.27"
}
local = {
source = "hashicorp/local"
version = "~> 2.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.0"
}
}
required_version = ">= 1.3.0"
}
39 changes: 39 additions & 0 deletions .github/tf/base/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<!-- BEGIN_TF_DOCS -->
## Requirements

| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >= 1 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | ~> 5.27 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | 5.31.0 |

## Modules

| Name | Source | Version |
|------|--------|---------|
| <a name="module_vpc"></a> [vpc](#module\_vpc) | terraform-aws-modules/vpc/aws | 5.0.0 |

## Resources

| Name | Type |
|------|------|
| [aws_resourcegroups_group.resourcegroups_group](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/resourcegroups_group) | resource |

## Inputs

| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| <a name="input_aws_region"></a> [aws\_region](#input\_aws\_region) | AWS region to create the VPC, assuming zones `a` and `b` exists. | `string` | n/a | yes |
| <a name="input_prefix"></a> [prefix](#input\_prefix) | Prefix used for resource naming. | `string` | n/a | yes |

## Outputs

| Name | Description |
|------|-------------|
| <a name="output_vpc"></a> [vpc](#output\_vpc) | n/a |
<!-- END_TF_DOCS -->
8 changes: 8 additions & 0 deletions .github/tf/base/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
resource "aws_resourcegroups_group" "resourcegroups_group" {
name = "${var.prefix}-group"
resource_query {
query = templatefile("${path.module}/templates/resource-group.json", {
example = var.prefix
})
}
}
3 changes: 3 additions & 0 deletions .github/tf/base/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
output "vpc" {
value = module.vpc
}
9 changes: 9 additions & 0 deletions .github/tf/base/templates/resource-group.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"ResourceTypeFilters": ["AWS::AllSupported"],
"TagFilters": [
{
"Key": "Example",
"Values": ["${example}"]
}
]
}
9 changes: 9 additions & 0 deletions .github/tf/base/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
variable "prefix" {
description = "Prefix used for resource naming."
type = string
}

variable "aws_region" {
description = "AWS region to create the VPC, assuming zones `a` and `b` exists."
type = string
}
9 changes: 9 additions & 0 deletions .github/tf/base/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.27"
}
}
required_version = ">= 1"
}
16 changes: 16 additions & 0 deletions .github/tf/base/vpc.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.0.0"

name = "${var.prefix}-vpc"
cidr = "10.0.0.0/16"

azs = ["${var.aws_region}a", "${var.aws_region}b"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24"]
public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]

enable_dns_hostnames = true
enable_nat_gateway = true
map_public_ip_on_launch = false
single_nat_gateway = true
}