#!/bin/bash set -e export CONTAINERD_VERSION=1.7.0 export CNI_VERSION=1.6.0 export DEBIAN_FRONTEND=noninteractive export FIREACTIONS_VERSION=0.2.5 export FIRECRACKER_VERSION=1.4.1 export KERNEL_VERSION=5.10 usage() { echo "This script installs Fireactions on a Linux machine." echo echo "Usage: $0 [options]" echo echo "Options:" echo " --github-app-id Sepcify the ID of the GitHub App (required)" echo " --github-app-key-file Specify the path to the GitHub App private key file (required)" echo " --github-organization Specify the name of the GitHub organization (required)" echo " --fireactions-version Specify the Fireactions version to install (default: $FIREACTIONS_VERSION)" echo " --firecracker-version Specify the Firecracker version to install (default: $FIRECRACKER_VERSION)" echo " --kernel-version Specify the kernel version to install (default: $KERNEL_VERSION)" echo " --containerd-snapshotter-device Specify the device to use for Containerd snapshot storage (required)" echo " --containerd-version Specify the Containerd version to install (default: $CONTAINERD_VERSION)" echo " --cni-version Specify the CNI plugin version to install (default: $CNI_VERSION)" echo " -h, --help Show this help message" echo } has_yum() { [ -n "$(command -v yum)" ] } has_apt() { [ -n "$(command -v apt-get)" ] } print_error() { echo -e "\033[31mERROR:\033[0m $1" } check_kvm() { if [[ ! -e /dev/kvm ]]; then print_error "Virtualization is not available on this machine, /dev/kvm is missing. Enable virtualization and try again." exit 1 fi } install_dependencies() { if has_apt; then apt-get update -qq -y apt-get install -qq -y \ curl \ gnupg \ lvm2 \ tar elif has_yum; then yum install -q -y \ curl \ lvm2 \ tar else print_error "Unsupported package manager" exit 1 fi } install_firecracker() { if [[ -e /usr/local/bin/firecracker ]]; then return fi TEMP_DIR=$(mktemp -d) curl -sL -o "$TEMP_DIR/firecracker-v$FIRECRACKER_VERSION.tgz" \ "https://github.com/firecracker-microvm/firecracker/releases/download/v$FIRECRACKER_VERSION/firecracker-v$FIRECRACKER_VERSION-$(uname -m).tgz" tar -xf "$TEMP_DIR/firecracker-v$FIRECRACKER_VERSION.tgz" -C "$TEMP_DIR" --strip-components=1 mv "$TEMP_DIR/firecracker-v$FIRECRACKER_VERSION-$(uname -m)" /usr/local/bin/firecracker chmod +x /usr/local/bin/firecracker rm -rf "$TEMP_DIR" } install_containerd() { if [[ -e /usr/local/bin/containerd ]]; then return fi TEMP_DIR=$(mktemp -d) curl -sL -o "$TEMP_DIR/containerd-$CONTAINERD_VERSION-linux-$ARCH.tar.gz" \ "https://github.com/containerd/containerd/releases/download/v$CONTAINERD_VERSION/containerd-$CONTAINERD_VERSION-linux-$ARCH.tar.gz" tar -zxf "$TEMP_DIR/containerd-$CONTAINERD_VERSION-linux-$ARCH.tar.gz" -C "$TEMP_DIR" mv "$TEMP_DIR/bin/containerd" /usr/local/bin/containerd mv "$TEMP_DIR/bin/ctr" /usr/local/bin/ctr cat < /etc/systemd/system/containerd.service [Unit] Description=containerd container runtime Documentation=https://containerd.io After=network.target local-fs.target [Service] Type=notify ExecStartPre=-/sbin/modprobe overlay ExecStart=/usr/local/bin/containerd Delegate=yes KillMode=process Restart=always RestartSec=5 # Having non-zero Limit*s causes performance problems due to accounting overhead # in the kernel. We recommend using cgroups to do container-local accounting. LimitNPROC=infinity LimitCORE=infinity LimitNOFILE=infinity # Comment TasksMax if your systemd version does not supports it. # Only systemd 226 and above support this version. TasksMax=infinity OOMScoreAdjust=-999 [Install] WantedBy=multi-user.target EOF mkdir -p /etc/containerd cat < /etc/containerd/config.toml version = 2 root = "/var/lib/containerd" imports = [] state = "/run/containerd" oom_score = 0 [grpc] address = "/run/containerd/containerd.sock" uid = 0 gid = 0 [plugins] [plugins."io.containerd.snapshotter.v1.devmapper"] pool_name = "containerd-thinpool" root_path = "/var/lib/containerd/devmapper" base_image_size = "30GB" discard_blocks = true EOF # Setup LVM thin pool for Containerd pvcreate -f $CONTAINERD_SNAPSHOTTER_DEVICE vgcreate containerd $CONTAINERD_SNAPSHOTTER_DEVICE cat < /etc/cni/net.d/10-fireactions.conflist { "cniVersion": "0.4.0", "name": "fireactions", "plugins": [ { "bridge": "fireactions-br0", "forceAddress": false, "hairpinMode": true, "ipMasq": true, "ipam": { "dataDir": "/var/run/cni", "resolvConf": "/etc/resolv.conf", "subnet": "192.168.128.0/24", "type": "host-local" }, "isDefaultGateway": true, "mtu": 1500, "type": "bridge" }, { "type": "firewall" }, { "type": "tc-redirect-tap" } ] } EOF rm -rf "$TEMP_DIR" } install_fireactions() { if [[ -e /usr/local/bin/fireactions ]]; then return fi TEMP_DIR=$(mktemp -d) curl -sL -o "$TEMP_DIR/fireactions-v$FIREACTIONS_VERSION.tar.gz" \ "https://github.com/hostinger/fireactions/releases/download/v$FIREACTIONS_VERSION/fireactions-v$FIREACTIONS_VERSION-linux-$ARCH.tar.gz" tar -zxf "$TEMP_DIR/fireactions-v$FIREACTIONS_VERSION.tar.gz" -C "$TEMP_DIR" mv "$TEMP_DIR/fireactions" /usr/local/bin/fireactions chmod +x /usr/local/bin/fireactions cat < /etc/sysctl.d/99-fireactions.conf net.ipv4.conf.all.forwarding=1 net.ipv4.ip_forward=1 EOF sysctl -p /etc/sysctl.d/99-fireactions.conf > /dev/null mkdir -p /etc/fireactions cat < /etc/fireactions/config.yaml bind_address: 127.0.0.1:8080 metrics: enabled: true address: 127.0.0.1:8081 github: app_id: $GITHUB_APP_ID app_private_key: | $GITHUB_APP_PRIVATE_KEY pools: - name: default replicas: 1 runner: name: default image: ghcr.io/hostinger/fireactions-images/ubuntu22.04:v0.7.0 image_pull_policy: IfNotPresent group_id: 1 organization: $GITHUB_ORGANIZATION labels: - self-hosted - fireactions firecracker: binary_path: firecracker kernel_image_path: /var/lib/fireactions/kernels/$KERNEL_VERSION/vmlinux kernel_args: "console=ttyS0 noapic reboot=k panic=1 pci=off nomodules rw" machine_config: mem_size_mib: 2048 vcpu_count: 2 metadata: example1: value1 example2: value2 log_level: debug EOF cat < /etc/systemd/system/fireactions.service [Unit] Description=Fireactions Documentation=https://github.com/hostinger/fireactions After=network.target [Service] User=root Type=simple KillMode=process ExecStartPre=/usr/bin/which firecracker ExecStartPre=/usr/bin/which containerd ExecStart=fireactions server --config /etc/fireactions/config.yaml Restart=always RestartSec=10 [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable fireactions && systemctl start fireactions rm -rf "$TEMP_DIR" } install_kernel() { if [[ -e /var/lib/fireactions/kernels/$KERNEL_VERSION/vmlinux ]]; then return fi mkdir -p /var/lib/fireactions/kernels/$KERNEL_VERSION curl -sL -o "/var/lib/fireactions/kernels/$KERNEL_VERSION/vmlinux" \ "https://storage.googleapis.com/fireactions/kernels/$ARCH/$KERNEL_VERSION/vmlinux" } main() { if [ "$#" -eq 0 ]; then usage exit 1 fi while [ "$1" != "" ]; do case $1 in --github-app-id ) shift GITHUB_APP_ID=$1 ;; --github-app-id=* ) GITHUB_APP_ID="${1#*=}" ;; --github-app-key-file ) shift GITHUB_APP_PRIVATE_KEY_FILE=$1 ;; --github-app-key-file=* ) GITHUB_APP_PRIVATE_KEY_FILE="${1#*=}" ;; --github-organization ) shift GITHUB_ORGANIZATION=$1 ;; --github-organization=* ) GITHUB_ORGANIZATION="${1#*=}" ;; --fireactions-version ) shift FIREACTIONS_VERSION=$1 ;; --fireactions-version=* ) FIREACTIONS_VERSION="${1#*=}" ;; --firecracker-version ) shift FIRECRACKER_VERSION=$1 ;; --firecracker-version=* ) FIRECRACKER_VERSION="${1#*=}" ;; --kernel-version ) shift KERNEL_VERSION=$1 ;; --kernel-version=* ) KERNEL_VERSION="${1#*=}" ;; --containerd-snapshotter-device ) shift CONTAINERD_SNAPSHOTTER_DEVICE=$1 ;; --containerd-snapshotter-device=* ) export CONTAINERD_SNAPSHOTTER_DEVICE="${1#*=}" ;; --containerd-version ) shift CONTAINERD_VERSION=$1 ;; --containerd-version=* ) CONTAINERD_VERSION="${1#*=}" ;; --cni-version ) shift CNI_VERSION=$1 ;; --cni-version=* ) CNI_VERSION="${1#*=}" ;; -h | --help ) usage exit 0 ;; * ) usage exit 1 esac shift done if [ -z "$GITHUB_APP_ID" ]; then print_error "Option --github-app-id is required" usage exit 1 fi if [ -z "$GITHUB_APP_PRIVATE_KEY_FILE" ]; then print_error "Option --github-app-key-file is required" usage exit 1 else if [ ! -f "$GITHUB_APP_PRIVATE_KEY_FILE" ]; then print_error "GitHub App private key file not found: $GITHUB_APP_PRIVATE_KEY_FILE" exit 1 fi export GITHUB_APP_PRIVATE_KEY=$(cat $GITHUB_APP_PRIVATE_KEY_FILE | sed '1!s/^/ /') fi if [ -z "$GITHUB_ORGANIZATION" ]; then print_error "Option --github-organization is required" usage exit 1 fi if [ -z "$CONTAINERD_SNAPSHOTTER_DEVICE" ]; then print_error "Option --containerd-snapshotter-device is required" usage exit 1 fi if [ "$(id -u)" -ne 0 ]; then print_error "The installation must be run as sudo or root!" exit 1 fi case $(uname -m) in x86_64) export ARCH=amd64 ;; aarch64) export ARCH=arm64 ;; *) print_error "Unsupported architecture: $(uname -m)" exit 1 esac if [[ -e /usr/local/bin/fireactions ]]; then echo "Fireactions is already installed. Exiting..." exit 1 fi echo "Installing Fireactions v$FIREACTIONS_VERSION..." check_kvm install_dependencies install_kernel install_containerd install_cni install_firecracker install_fireactions echo "Fireactions v$FIREACTIONS_VERSION has been installed successfully! 🎉" } main "$@"