Skip to content

Commit ca6963d

Browse files
author
Niko Virtala
committed
initial version.
1 parent ea2b847 commit ca6963d

12 files changed

+6648
-21
lines changed

README.md

+30-9
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,35 @@
1-
# Welcome to your CDK TypeScript project!
1+
# GitHub Actions runners on AWS Fargate
22

3-
This is a blank project for TypeScript development with CDK.
3+
This repository contains an example how to run self-hosted GitHub Actions runners on AWS Fargate!
44

5-
The `cdk.json` file tells the CDK Toolkit how to execute your app.
5+
## Docker image
6+
7+
Docker image is based on [`ubuntu:rolling`](https://hub.docker.com/_/ubuntu), which is currently pointed to `19.10` / `eoan`.
8+
9+
On top the base image I have installed GitHub Actions Runner based on [About self-hosted runners](https://help.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners) in GitHub documentation.
10+
11+
## Deployment
12+
13+
The application is deployed to AWS using [AWS Cloud Development Kit (AWS CDK)](https://docs.aws.amazon.com/cdk/latest/guide/home.html).
14+
15+
- Store two parameters `GITHUB_ACCESS_TOKEN` and `GITHUB_REPOSITORY_URL` in to SSM Parameter Store.
16+
- Run `cdk synth --profile <your-aws-cli-profile>`
17+
- Run `cdk deploy --profile <your-aws-cli-profile>`
18+
- Wait a little while ...
19+
20+
Now you should be able find your self-hosted runner from repository setting in GitHub:
21+
22+
![](./self-hosted-runner-in-actions-settings.png "Self-hosted runner in GitHub Actions Settings")
23+
24+
We can see also from the Fargate Task Logs that the runner is successfully registered:
25+
26+
![](./fargate-task-logs-in-aws-console.png "Fargate Task Logs in AWS Console")
627

728
## Useful commands
829

9-
* `npm run build` compile typescript to js
10-
* `npm run watch` watch for changes and compile
11-
* `npm run test` perform the jest unit tests
12-
* `cdk deploy` deploy this stack to your default AWS account/region
13-
* `cdk diff` compare deployed stack with current state
14-
* `cdk synth` emits the synthesized CloudFormation template
30+
- `npm run build` compile typescript to js
31+
- `npm run watch` watch for changes and compile
32+
- `npm run test` perform the jest unit tests
33+
- `cdk deploy` deploy this stack to your default AWS account/region
34+
- `cdk diff` compare deployed stack with current state
35+
- `cdk synth` emits the synthesized CloudFormation template

bin/github-actions-runner.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
#!/usr/bin/env node
2-
import 'source-map-support/register';
3-
import * as cdk from '@aws-cdk/core';
4-
import { GithubActionsRunnerStack } from '../lib/github-actions-runner-stack';
2+
import "source-map-support/register";
3+
import * as cdk from "@aws-cdk/core";
4+
import { GithubActionsRunnerStack } from "../lib/github-actions-runner-stack";
55

66
const app = new cdk.App();
7-
new GithubActionsRunnerStack(app, 'GithubActionsRunnerStack');
7+
new GithubActionsRunnerStack(app, "GithubActionsRunnerStack", {
8+
env: {
9+
account: process.env.CDK_DEFAULT_ACCOUNT,
10+
region: process.env.CDK_DEFAULT_REGION,
11+
},
12+
});

cdk.context.json

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"@aws-cdk/core:enableStackNameDuplicates": "true",
3+
"aws-cdk:enableDiffNoFail": "true",
4+
"availability-zones:account=827333031966:region=eu-west-1": [
5+
"eu-west-1a",
6+
"eu-west-1b",
7+
"eu-west-1c"
8+
]
9+
}

cdk.json

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
11
{
2-
"app": "npx ts-node bin/github-actions-runner.ts",
3-
"context": {
4-
"@aws-cdk/core:enableStackNameDuplicates": "true",
5-
"aws-cdk:enableDiffNoFail": "true"
6-
}
2+
"app": "npx ts-node bin/github-actions-runner.ts"
73
}

fargate-task-logs-in-aws-console.png

112 KB
Loading

image/.dockerignore

Whitespace-only changes.

image/Dockerfile

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
FROM ubuntu:rolling
2+
3+
RUN apt-get update && apt-get install -y \
4+
curl \
5+
jq \
6+
&& rm -rf /var/lib/apt/lists/*
7+
8+
RUN addgroup runner && \
9+
adduser \
10+
--system \
11+
--disabled-password \
12+
--home /home/runner \
13+
--ingroup runner \
14+
runner
15+
16+
WORKDIR /home/runner
17+
18+
RUN GITHUB_RUNNER_VERSION=${GITHUB_RUNNER_VERSION:-$(curl -s https://api.github.com/repos/actions/runner/releases/latest | jq -r .tag_name | sed 's/v//g')} \
19+
&& curl -sSLO https://github.com/actions/runner/releases/download/v${GITHUB_RUNNER_VERSION}/actions-runner-linux-x64-${GITHUB_RUNNER_VERSION}.tar.gz \
20+
&& tar -zxvf actions-runner-linux-x64-${GITHUB_RUNNER_VERSION}.tar.gz \
21+
&& rm -f actions-runner-linux-x64-${GITHUB_RUNNER_VERSION}.tar.gz \
22+
&& ./bin/installdependencies.sh \
23+
&& chown -R runner:runner /home/runner
24+
25+
COPY entrypoint.sh entrypoint.sh
26+
27+
USER runner
28+
29+
ENTRYPOINT ["./entrypoint.sh"]

image/entrypoint.sh

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/bin/bash
2+
3+
RUNNER_NAME=${RUNNER_NAME:-default}
4+
RUNNER_WORKDIR=${RUNNER_WORKDIR:-_work}
5+
6+
if [[ -z "${GITHUB_ACCESS_TOKEN}" || -z "${REPOSITORY_URL}" ]]; then
7+
echo 'One of the mandatory parameters is missing. Quit!'
8+
exit 1
9+
else
10+
AUTH_HEADER="Authorization: token ${GITHUB_ACCESS_TOKEN}"
11+
USERNAME=$(cut -d/ -f4 <<< ${REPOSITORY_URL})
12+
REPOSITORY=$(cut -d/ -f5 <<< ${REPOSITORY_URL})
13+
14+
RUNNER_TOKEN="$(curl -XPOST -fsSL \
15+
-H "Accept: application/vnd.github.v3+json" \
16+
-H "${AUTH_HEADER}" \
17+
"https://api.github.com/repos/${USERNAME}/${REPOSITORY}/actions/runners/registration-token" \
18+
| jq -r '.token')"
19+
fi
20+
21+
./config.sh --url "${REPOSITORY_URL}" --token "${RUNNER_TOKEN}" --name "${RUNNER_NAME}" --work "${RUNNER_WORKDIR}"
22+
./run.sh

lib/github-actions-runner-stack.ts

+55-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,62 @@
1-
import * as cdk from '@aws-cdk/core';
1+
import * as cdk from "@aws-cdk/core";
2+
import * as ec2 from "@aws-cdk/aws-ec2";
3+
import * as ecs from "@aws-cdk/aws-ecs";
4+
import * as ssm from "@aws-cdk/aws-ssm";
5+
import path = require("path");
6+
import { FargatePlatformVersion } from "@aws-cdk/aws-ecs";
27

38
export class GithubActionsRunnerStack extends cdk.Stack {
49
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
510
super(scope, id, props);
611

7-
// The code that defines your stack goes here
12+
const vpc = new ec2.Vpc(this, "GitHubActionsRunnerVpc", {
13+
maxAzs: 1, // Default is all AZs in region
14+
});
15+
16+
const cluster = new ecs.Cluster(this, "GitHubActionsRunnerCluster", {
17+
vpc: vpc,
18+
});
19+
20+
const taskDefinition = new ecs.FargateTaskDefinition(
21+
this,
22+
"GitHubActionsRunnerTaskDefinition"
23+
);
24+
25+
taskDefinition.addContainer("GitHubActionsRunnerContainer", {
26+
image: ecs.ContainerImage.fromAsset(path.resolve(__dirname, "../image")),
27+
logging: ecs.LogDrivers.awsLogs({ streamPrefix: "GitHubActionsRunner" }),
28+
secrets: {
29+
GITHUB_ACCESS_TOKEN: ecs.Secret.fromSsmParameter(
30+
ssm.StringParameter.fromSecureStringParameterAttributes(
31+
this,
32+
"GitHubAccessToken",
33+
{
34+
parameterName: "GITHUB_ACCESS_TOKEN",
35+
version: 0,
36+
}
37+
)
38+
),
39+
REPOSITORY_URL: ecs.Secret.fromSsmParameter(
40+
ssm.StringParameter.fromSecureStringParameterAttributes(
41+
this,
42+
"GitHubRepositoryUrl",
43+
{
44+
parameterName: "REPOSITORY_URL",
45+
version: 0,
46+
}
47+
)
48+
),
49+
},
50+
});
51+
52+
const ecsService = new ecs.FargateService(
53+
this,
54+
"GitHubActionsRunnerService",
55+
{
56+
cluster,
57+
taskDefinition,
58+
platformVersion: FargatePlatformVersion.VERSION1_3,
59+
}
60+
);
861
}
962
}

0 commit comments

Comments
 (0)