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

Add self-hosting documentation #419

Merged
merged 66 commits into from
Nov 16, 2023
Merged
Show file tree
Hide file tree
Changes from 49 commits
Commits
Show all changes
66 commits
Select commit Hold shift + click to select a range
a0084b0
Update README.md
cloudymax Jun 3, 2023
9ad4023
Add files via upload
cloudymax Jun 3, 2023
fc851bc
remove extra line break
cloudymax Jun 3, 2023
89f9165
Update README.md
cloudymax Jun 4, 2023
3368605
Update README.md
cloudymax Jun 4, 2023
6c784e3
Update README.md
cloudymax Jun 4, 2023
6e5fa83
Update README.md
cloudymax Jun 4, 2023
d821fc1
Update README.md
cloudymax Jun 4, 2023
f010069
fix formatting
cloudymax Jun 15, 2023
c4e5ba4
change link format from html to markdown
cloudymax Jun 15, 2023
0bb7abe
missed a link
cloudymax Jun 15, 2023
1f64e53
Run prettier
cloudymax Jun 15, 2023
df4ad52
run prettier with yarn instead of npx?
cloudymax Jun 15, 2023
3a2a071
fix codeblock formatting
cloudymax Jun 24, 2023
5a17baf
run prettier formatting
cloudymax Jun 24, 2023
f2db0be
Merge branch 'main' into main
davidmfinol Jul 4, 2023
1b2525d
adding self-hosting docs
cloudymax Sep 10, 2023
4ce6f92
Merge branch 'self-hosting-docs' into self-hosting2
cloudymax Sep 10, 2023
76ad692
revise language based on feedback, add instructions for runner applic…
cloudymax Sep 22, 2023
b628a6c
start adding QEMU
Oct 9, 2023
a85e4ad
add images to vm setup docs, separate out qemu types
cloudymax Oct 10, 2023
d3f5aef
add new qemu dir
cloudymax Oct 10, 2023
b76a19a
finish up Windows and add macos
Oct 11, 2023
d0a8e5a
run prettier on readme
Oct 11, 2023
68b76c7
add images to windows, cleanup formatting, fix spelling errors
Oct 15, 2023
8e695eb
change organasation structure and fix typos
Oct 16, 2023
a009b59
re-roganize, add cloud-init details, dogfood testing
Oct 18, 2023
26c8702
Fix spellign errors, dogfooding, add advanced qemu config guides
Oct 18, 2023
48dd2fd
testing some style stuff that the linter doesnt like
Oct 18, 2023
98d1867
testing some style stuff that the linter doesnt like
Oct 18, 2023
349074b
changing the syle to abuse titles less
Oct 18, 2023
a3b86e7
changing the syle to abuse titles less
Oct 18, 2023
1fa9ff5
changing the syle to abuse titles less
Oct 18, 2023
b0c9d86
changing the syle to abuse titles less
Oct 18, 2023
a601556
changing the syle to abuse titles less
Oct 18, 2023
03fe6fc
cleanup dangling :
Oct 18, 2023
0d54d45
Formatting pass, add new diagrams
Oct 28, 2023
b415d27
center images and lint
Oct 28, 2023
7847591
proof-reading and docgfood pass on k8s docs
Oct 28, 2023
60715a3
add info on creating secrets, minor formatting
Oct 29, 2023
8134d3f
move k8s to new branch to unblock the rest of the docs
Nov 1, 2023
7881aa3
re-center images
Nov 1, 2023
2f5404a
add paddig above ssh image
Nov 1, 2023
20bbf9e
change image indent so linter wont wreck the spacing
Nov 1, 2023
236e54e
remove text artifact inserted by linter
Nov 1, 2023
15671f4
center images
Nov 1, 2023
7d464a4
add disclaimers to advanced configs, add more examples to windows
Nov 1, 2023
f94cbd7
remove text artifact introduced by linter and minor formatting fix
Nov 1, 2023
c1398c5
Merge branch 'main' into self-hosting2
cloudymax Nov 1, 2023
2be1df0
add missing image file
Nov 9, 2023
c3f23a4
Update docs/12-self-hosting/01-overview.mdx
cloudymax Nov 9, 2023
bd90456
Update docs/12-self-hosting/03-host-creation/03-QEMU/01-overview.mdx
cloudymax Nov 9, 2023
10e6d78
Update docs/12-self-hosting/03-host-creation/03-QEMU/01-overview.mdx
cloudymax Nov 9, 2023
8bbf93a
Update docs/12-self-hosting/03-host-creation/03-QEMU/03-linux-liveiso…
cloudymax Nov 9, 2023
e6c6986
fix issue with metal diagram failing to render as a svg, its a png now
Nov 9, 2023
ffb2654
remove accidental file addition
Nov 9, 2023
1289fc1
fix formatting
Nov 9, 2023
194f438
Update docs/12-self-hosting/03-host-creation/03-QEMU/03-linux-liveiso…
cloudymax Nov 9, 2023
0ffff35
add power usage blurb
Nov 15, 2023
b7d5010
add doublequotes to VNC invocation
Nov 15, 2023
1b6d057
add sections to overview
Nov 15, 2023
a2d56f7
add not on hackintosh legality
Nov 16, 2023
bdcf1f7
add note about remote access security to MacOS
Nov 16, 2023
f1338de
fix typo in link
Nov 16, 2023
a958137
fix linux path for multipass
Nov 16, 2023
8f74d7e
Merge branch 'main' into self-hosting2
davidmfinol Nov 16, 2023
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
68 changes: 68 additions & 0 deletions docs/12-self-hosting/01-overview.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
toc_max_heading_level: 4
---

# Overview

Projects often encounter a constraint or requirement which makes free-tier hosted CI/CD runners
insufficient for their needs. In these cases hosting your own CI/CD runner can be a viable
alternative to premium-tier services or subscriptions. Self-hosting may also provide access to
resources that are simply not available on many CI/CD services such as GPUs, faster drives, and
newer CPU models.

This guide will cover basic methods for hosting CI/CD runners on Bare-Metal, Virtual Machines, or
using Cloud Runner. Containerized hosts will not be discussed because of their inherent reliance on
insecure practices such as
[Docker-in-Docker](http://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/),
[Privileged Containers](https://www.trendmicro.com/en_th/research/19/l/why-running-a-privileged-container-in-docker-is-a-bad-idea.html)
and the additional tooling required to mitigate those risks such as
[Kaniko](https://github.com/GoogleContainerTools/kaniko) or
[Kata Containers](https://katacontainers.io/).

## Constraints
Copy link
Member

@GabLeRoux GabLeRoux Nov 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before talking about constraints and requirements, I think it would be interesting to also add a disclaimer about security and Prerequisites Knowledge.

Here's a draft


Security Disclaimer

This guide strives for best security practices, yet the evolving nature of threats demands user vigilance. Conduct your own security assessments and stay updated with best practices.

Prerequisites Knowledge

Users should be familiar with basic Linux commands and have a basic grasp of CI/CD concepts. New to these? Seek beginner resources to build a foundation before continuing in this path.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added in commit 1b6d057


There are many ways to self-host CI/CD runners, and which one is best for you will depend on your on
cloudymax marked this conversation as resolved.
Show resolved Hide resolved
situation and constraints. For the purpose of this guide we will make the following assumptions:

- 💻 User already has their own hardware
- 💸 Budget is $0
cloudymax marked this conversation as resolved.
Show resolved Hide resolved
- 🛠️ FOSS tools should be prioritized where possible
- 📜 We define `Self-Hosting` in this context to refer to a user taking responsibility for the
operating-system level configuration and life-cycle-management of a given compute resource (metal,
on-prem, cloud VM, VPS etc...)

## Requirements

This guide is tested on devices which meet the following requirements:

- x86 or amd64 processor
- Ubuntu 22.04 LTS Server or Debian 12 Bookworm
- Root access to the operating system
- Network connectivity

## Host Creation

"Host Creation" in this context is the process of installing an operating system onto a piece of
physical hardware, or the creation and configuration of virtualised compute resources.

- [Bare-Metal](./03-host-creation/02-bare-metal.mdx)
- [Virtual Machines using Multipass](./03-host-creation/02-multipass.mdx)
- [Virtual Machines using QEMU](./03-host-creation/03-QEMU/01-overview.mdx)

## Host Provisioning

"Provisioning" here refers to the process of installing additional resources onto, and the
configuration of your host beyond installing the base operating-system. Both manual and declarative
workflows are supported.

- [Manual Ubuntu 22.04 Setup](./04-host-provisioning/02-ubuntu-setup.mdx)
- [Manual Debian 12 Setup](./04-host-provisioning/01-debian-setup.mdx)
- [Declarative provisioning via Cloud-Init](./04-host-provisioning/03-cloud-init/01-about.mdx)

## Runner Application Installation

Once your host has been provisioned, you will then need to install the appropriate runner
application. The guides below will walk you through that process.

- [Github Actions](./05-runner-application-installation/02-github-actions.mdx)
- [GitLab Pipelines](./05-runner-application-installation/01-gitlab-pipelines.mdx)
127 changes: 127 additions & 0 deletions docs/12-self-hosting/02-host-types.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import Virtualisation from '/assets/images/Virtualization.drawio.png';
import Metal from '/assets/images/Metal.drawio.svg';
import Docker from '/assets/images/DockerHost.drawio.png';
import Kubernetes from '/assets/images/kubernetes.drawio.png';
import Layers from '/assets/images/k8s-layers.drawio.png';
import Layer0 from '/assets/images/k8s-layer0.drawio.png';
import Layer1 from '/assets/images/k8s-layer1.drawio.png';
import Layer2 from '/assets/images/k8s-layer2.drawio.png';
import Layers01 from '/assets/images/k8s-layers01.drawio.png';
import Layers012 from '/assets/images/k8s-layers012.drawio.png';

# Types of Hosts

## Bare-Metal

"Bare Metal" means that your host OS is running directly on a piece of hardware without any
virtualisation. This reduces the complexity of deployment at the cost of increased time and effort
for re-provisioning the host.

<div style={{ textAlign: 'center' }}>
<Metal width="500" />
</div>
<br />

## Virtual Machines

Virtual Machines are a software-defined layer of abstraction atop a Bare-Metal host which makes
deployments more consistent and easier to manage declaratively. This greatly reduces the difficulty
of re-deployment and creates the conditions required for securely running multiple guests within the
same physical host. Virtual Machines can also be used to create hosts that run different operating
systems (Windows, MacOS) or architectures (ARM) than the host machine. This added functionality
comes at the cost of added complexity, a slight performance penalty, and you need to already have a
Bare-Metal host on which to run the VMs.

<div style={{ textAlign: 'center' }}>
<a target="\_blank" href={require('/assets/images/Virtualization.drawio.png').default}>
<img src={Virtualisation} width="500" />
</a>
</div>
<br />

Additional Reading:

- [A Study of Performance and Security Across the Virtualization Spectrum](https://repository.tudelft.nl/islandora/object/uuid:34b3732e-2960-4374-94a2-1c1b3f3c4bd5/datastream/OBJ/download) -
Vincent van Rijn
- [Hyper-converged infrastructure](https://en.wikipedia.org/wiki/Hyper-converged_infrastructure) -
Wikipedia
- [Rethinking the PC](https://www.computerworld.com/article/3518849/rethinking-the-pc-why-virtual-machines-should-replace-operating-systems.html) -
Rob Enderle

## Containers

Containers are built on 'cgroups' (control groups), which are a feature of the Linux kernel that
limits monitors, and isolates the resource usage of a collection of processes. This means that
running containers on Linux is very lightweight form of virtualisation. However, on other operating
systems which do not use the Linux kernel, a Linux virtual machine or translation-layer must be
created to run containers. The manner by which each Operating System resolves this issue varies
greatly as shown below. Because of this variance, the self-hosting documentation targets Linux as a
means of avoiding excess complexity.

<div style={{ textAlign: 'center' }}>
<a target="\_blank" href={require('/assets/images/DockerHost.drawio.png').default}>
<img src={Docker} width="500" />
</a>
</div>
<br />

Additional Reading:

- [The Mental Model Of Docker Container Shipping](https://bernhardwenzel.com/2022/the-mental-model-of-docker-container-shipping/) -
Bernhard Wenzel
- [Why is Docker-in-Docker considered bad?](https://devops.stackexchange.com/questions/676/why-is-docker-in-docker-considered-bad)
- [Why it is recommended to run only one process in a container?](https://devops.stackexchange.com/questions/447/why-it-is-recommended-to-run-only-one-process-in-a-container)

## Kubernetes (Cloud Runner)

Kubernetes is somewhat of a combination of all other host types. Since it is an API, it must be
installed on an existing host (called a "Node") which is usually either a VM or physical device. A
Kubernetes "Cluster" is usually made up of 3 or more nodes - though you can have as few as one, or
as many 5,000 per cluster.

<br />
<div style={{ textAlign: 'center' }}>
<a target="\_blank" href={require('/assets/images/k8s-layer0.drawio.png').default}>
<img src={Layer0} width="700" />
</a>
<br />
</div>
<br />

Once installed, Kubernetes creates
[standardised interfaces](https://matt-rickard.com/kubernetes-interfaces) to control the hardware &
software components of the underlying nodes (networking, storage, GPUs, CPU cores etc...) as well as
a distributed key-value store which facilitates communication between all nodes in the cluster.

<br />
<div style={{ textAlign: 'center' }}>
<a target="\_blank" href={require('/assets/images/k8s-layers01.drawio.png').default}>
<img src={Layers01} width="750" />
</a>
<br />
</div>
<br />

With the underlying hardware abstracted into a generic pool of resources, Kubernetes is then able to
re-compose those assets into isolated environments called "Namespaces" where it deploys
containerised workloads in groups called "Pods". This layer of Kubernetes is very similar to a
typical container host but with many more features for multi-tenancy, security, and life-cycle
management.

<br />
<div style={{ textAlign: 'center' }}>
<a target="\_blank" href={require('/assets/images/k8s-layers012.drawio.png').default}>
<img src={Layers012} width="800" />
</a>
</div>
<br />

Additional Reading:

- [Kubernetes Components](https://kubernetes.io/docs/concepts/overview/components/) - kubernetes.io
- [A visual guide to Kubernetes networking fundamentals](https://opensource.com/article/22/6/kubernetes-networking-fundamentals) -
Nived Velayudhan
- [Thinking about the complexity of the Kubernetes ecosystem](https://erkanerol.github.io/post/complexity-of-kubernetes/) -
Erkan Erol
- [Ephemeral, Idempotent and Immutable Infrastructure ](https://cloudnativenow.com/topics/ephemeral-idempotent-and-immutable-infrastructure/) -
Marc Hornbeek
40 changes: 40 additions & 0 deletions docs/12-self-hosting/03-host-creation/02-bare-metal.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import Metal from '/assets/images/Metal.drawio.svg';

# Bare-Metal

The Host is the computer that will execute the runner application. This can be a desktop computer,
laptop, Virtual Machine, or VPS from a cloud provider.

<div style={{ textAlign: 'center' }}>
<Metal />
cloudymax marked this conversation as resolved.
Show resolved Hide resolved
</div>
<br />
<br />

## If your host is a local machine:

For a local machine you will need to perform a clean installation of the operating system. This
means creating a bootable USB drive from an ISO file, booting the machine from the USB drive, and
installing the OS. Links to download an official Live ISO file and installation guides are provided
below. If you would like to create a custom ISO, try [PXEless](https://github.com/cloudymax/pxeless)
or [Cubic](https://github.com/PJ-Singh-001/Cubic).

### Ubuntu

- Download the Ubuntu 22.04 LTS
[server installer](https://ftp.snt.utwente.nl/pub/os/linux/ubuntu-releases/22.04.3/ubuntu-22.04.3-live-server-amd64.iso)
- [Guide: Install Ubuntu 22.04 LTS on a local machine](https://ostechnix.com/install-ubuntu-server/)

### Debian

- Download the Debian 12
[installation image](https://cdimage.debian.org/debian-cd/current/amd64/iso-dvd/debian-12.1.0-amd64-DVD-1.iso)
- [Guide: Install Debian on a local system](https://www.linuxtechi.com/how-to-install-debian-11-bullseye/)

## If your host is a virtual-machine:

If you are using a VPS or VM, the OS should already be installed and admin user should already
exist. Follow the appropriate guide in the provisioning section for your operating-system.

- [Ubuntu 22.04](../04-host-provisioning/02-ubuntu-setup.mdx)
- [Debian 12](../04-host-provisioning/01-debian-setup.mdx)
152 changes: 152 additions & 0 deletions docs/12-self-hosting/03-host-creation/02-multipass.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
---
toc_max_heading_level: 4
---

# VMs with Multipass (Basic)

Multipass is a light-weight Virtual Machine Manager for Linux, Windows and MacOS. It's designed for
developers who want to quickly create a fresh Ubuntu environment with a single command. It uses the
native hypervisor for whichever platform it is installed on (KVM on Linux, Hyper-V on Windows and
HyperKit on MacOS) to run VMs with minimal overhead. It can also use VirtualBox on Windows and
MacOS. The biggest limitation of Multipass is that it only creates Ubuntu VMs.

- [Official Website](https://multipass.run/)
- [Official Github Repo](https://github.com/canonical/multipass)

## Installation

To install multipass on Linux use the commands below.

```bash
sudo apt-get install snapd
sudo snap install core
sudo snap install multipass
```

For installation on Windows and MacOS, refer to the official installation instructions:

- [How to install Multipass on Windows](https://multipass.run/docs/installing-on-windows)
- [How to install Multipass on MacOS](https://multipass.run/docs/installing-on-macos)

## Creating a VM

- Set values

```bash
# The name of the Virtual Machine
export VM_NAME="gameci"

# The name of the user to create
export VM_USER="vmadmin"

# Number of CPU cores to allocate to the VM
export VM_CPUS="2"

# Amount of Disk Space to allocate to the VM.
# Cannot exceed available on host.
export VM_DISK="32G"

# Amount of RAM to allocate to the VM.
# Cannot exceed available RAM on host.
export VM_MEM="8G"

# Set path on MacOS systems
export PATH="$PATH:/usr/local/bin/multipass"

# Set path on Linux system
export PATH="$PATH:/usr/local/bin/multipass"
```

- Create a password

```bash
# Install the mkpasswd utility
sudo apt install -y whois

read PW_STRING
export PASSWORD=$(mkpasswd -m sha-512 --rounds=4096 "$PW_STRING" -s "saltsaltlettuce")
```

- Create an ssh-key for authenticating with the VM

```bash
ssh-keygen -C $VM_USER -f runner
```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be helpful to comment something about security implications here concenring password generation and ssh key generation. Something like

Note on Security: For password and SSH key generation, always use strong, unique passwords, and safeguard SSH private keys.


- Add the public ssh-key and password to a cloud-init file

See the [cloud init](https://cloudinit.readthedocs.io/en/latest/topics/examples.html) official
docs for more information about cloud-init. More advanced templates are available in the
[Host Provisioning](../04-host-provisioning/03-cloud-init.mdx) directory.

```bash
VM_KEY=$(cat runner.pub)

cat << EOF > cloud-init.yaml
#cloud-config
groups:
- docker
users:
- default
- name: ${VM_USER}
sudo: ALL=(ALL) NOPASSWD:ALL
shell: /bin/bash
groups: docker, admin, sudo, users
no_ssh_fingerprints: true
lock_passwd: false
passwd: ${PASSWORD}
ssh-authorized-keys:
- ${VM_KEY}
packages:
- docker.io
EOF
```

- Start the VM

See the [multipass launch](https://multipass.run/docs/launch-command) command docs for more
information.

```bash
export VERBOSITY="-vvvvvv"

/snap/bin/multipass launch --name $VM_NAME \
--cpus $VM_CPUS \
--disk $VM_DISK \
--mem $VM_MEM \
--cloud-init cloud-init.yaml \
$VERBOSITY
```

- Get the VM's IP address

```bash
VM_IP=$(/snap/bin/multipass list |grep "${VM_NAME}" |awk '{print $3}')
```

- Connect to the VM via ssh or cli

ssh:

```bash
ssh -i runner $VM_USER@$VM_IP -o StrictHostKeyChecking=no -vvvv
```

CLI:

```bash
multipass shell $VM_NAME
```

- Install the runner application

- [GitHub Actions](../05-runner-application-installation/02-github-actions.mdx)
- [GitLab Pipelines](../05-runner-application-installation/01-gitlab-pipelines.mdx)

## Cleanup

```bash
/snap/bin/multipass stop $VM_NAME
/snap/bin/multipass delete $VM_NAME
/snap/bin/multipass purge
```
Loading
Loading