404 lines
8.9 KiB
Bash
404 lines
8.9 KiB
Bash
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
############################################
|
||
# KrakenTech Gitea Runner Installer
|
||
############################################
|
||
|
||
# Usage:
|
||
# sudo ./install-gitea-runner.sh <GITEA_URL> <REG_TOKEN> <RUNNER_NAME>
|
||
#
|
||
# Example:
|
||
# sudo ./install-gitea-runner.sh \
|
||
# https://git.krkn.tech \
|
||
# ABC123TOKEN \
|
||
# worker-bigben-01
|
||
|
||
############################################
|
||
# Args
|
||
############################################
|
||
|
||
if [ "$#" -ne 3 ]; then
|
||
echo "Usage: $0 <gitea_url> <registration_token> <runner_name>"
|
||
exit 1
|
||
fi
|
||
|
||
GITEA_URL="$1"
|
||
REG_TOKEN="$2"
|
||
RUNNER_NAME="$3"
|
||
|
||
############################################
|
||
# Globals
|
||
############################################
|
||
|
||
RUNNER_USER="gitea-runner"
|
||
INSTALL_DIR="/opt/gitea-runner"
|
||
BIN_PATH="/usr/local/bin/gitea-runner"
|
||
SERVICE_PATH="/etc/systemd/system/gitea-runner.service"
|
||
WORK_DIR="$INSTALL_DIR/work"
|
||
CONFIG_PATH="$INSTALL_DIR/config.yaml"
|
||
|
||
############################################
|
||
# Cleanup
|
||
############################################
|
||
|
||
CLEANUP_SCRIPT="/usr/local/sbin/gitea-runner-cleanup"
|
||
CLEANUP_SERVICE="/etc/systemd/system/gitea-runner-cleanup.service"
|
||
CLEANUP_TIMER="/etc/systemd/system/gitea-runner-cleanup.timer"
|
||
|
||
############################################
|
||
# Versions
|
||
############################################
|
||
|
||
ACT_RUNNER_VERSION="0.2.13"
|
||
GO_VERSION="1.22.10"
|
||
|
||
############################################
|
||
# Helpers
|
||
############################################
|
||
|
||
log() {
|
||
echo -e "\033[1;32m[*]\033[0m $*"
|
||
}
|
||
|
||
warn() {
|
||
echo -e "\033[1;33m[!]\033[0m $*"
|
||
}
|
||
|
||
err() {
|
||
echo -e "\033[0;31m[✗]\033[0m $*" >&2
|
||
exit 1
|
||
}
|
||
|
||
############################################
|
||
# Root Check
|
||
############################################
|
||
|
||
if [ "$(id -u)" -ne 0 ]; then
|
||
err "Run as root."
|
||
fi
|
||
|
||
############################################
|
||
# OS Check
|
||
############################################
|
||
|
||
if ! command -v apt >/dev/null; then
|
||
err "This script supports Debian/Ubuntu only."
|
||
fi
|
||
|
||
############################################
|
||
# Remove Snap Docker (If Present)
|
||
############################################
|
||
|
||
if command -v snap >/dev/null && snap list 2>/dev/null | grep -q '^docker '; then
|
||
warn "Snap Docker detected. Removing..."
|
||
snap remove --purge docker || true
|
||
rm -rf /var/snap/docker /snap/docker /var/lib/snapd/snaps/docker*
|
||
fi
|
||
|
||
############################################
|
||
# Install Base Deps
|
||
############################################
|
||
|
||
log "Installing dependencies..."
|
||
|
||
apt update
|
||
|
||
apt install -y \
|
||
ca-certificates \
|
||
curl \
|
||
gnupg \
|
||
lsb-release \
|
||
git \
|
||
jq \
|
||
uidmap \
|
||
unzip \
|
||
tar \
|
||
build-essential \
|
||
apt-transport-https \
|
||
clang \
|
||
llvm
|
||
|
||
############################################
|
||
# Install Go
|
||
############################################
|
||
|
||
log "Installing Go..."
|
||
|
||
GO_TARBALL="go${GO_VERSION}.linux-amd64.tar.gz"
|
||
GO_URL="https://go.dev/dl/${GO_TARBALL}"
|
||
|
||
if ! command -v go >/dev/null || ! go version | grep -q "go${GO_VERSION}"; then
|
||
rm -rf /usr/local/go
|
||
curl -fL --retry 5 --retry-delay 2 "$GO_URL" -o "/tmp/${GO_TARBALL}"
|
||
tar -C /usr/local -xzf "/tmp/${GO_TARBALL}"
|
||
rm -f "/tmp/${GO_TARBALL}"
|
||
fi
|
||
|
||
# Make Go available system-wide
|
||
cat >/etc/profile.d/go.sh <<'EOF'
|
||
export GOROOT=/usr/local/go
|
||
export GOPATH=/opt/go
|
||
export PATH="$GOROOT/bin:$GOPATH/bin:$PATH"
|
||
EOF
|
||
|
||
chmod 644 /etc/profile.d/go.sh
|
||
mkdir -p /opt/go
|
||
chmod 777 /opt/go
|
||
|
||
# Verify
|
||
/usr/local/go/bin/go version
|
||
|
||
############################################
|
||
# Install Node.js (LTS)
|
||
############################################
|
||
|
||
log "Installing Node.js (LTS)..."
|
||
|
||
if ! command -v node >/dev/null; then
|
||
curl -fsSL https://deb.nodesource.com/setup_lts.x | bash -
|
||
|
||
apt install -y nodejs
|
||
fi
|
||
|
||
# Verify
|
||
node -v
|
||
npm -v
|
||
|
||
|
||
############################################
|
||
# Install Docker (Official)
|
||
############################################
|
||
|
||
if ! command -v docker >/dev/null; then
|
||
log "Installing Docker..."
|
||
|
||
curl -fsSL https://get.docker.com | sh
|
||
|
||
systemctl enable docker
|
||
systemctl start docker
|
||
fi
|
||
|
||
############################################
|
||
# NVIDIA Runtime (Optional)
|
||
############################################
|
||
|
||
if command -v nvidia-smi >/dev/null; then
|
||
log "NVIDIA detected. Installing container runtime..."
|
||
|
||
apt install -y nvidia-container-toolkit
|
||
|
||
nvidia-ctk runtime configure --runtime=docker
|
||
|
||
systemctl restart docker
|
||
fi
|
||
|
||
############################################
|
||
# Create Runner User
|
||
############################################
|
||
|
||
if ! id "$RUNNER_USER" &>/dev/null; then
|
||
log "Creating runner user..."
|
||
useradd \
|
||
--system \
|
||
--home "$INSTALL_DIR" \
|
||
--shell /bin/bash \
|
||
"$RUNNER_USER"
|
||
fi
|
||
|
||
usermod -aG docker "$RUNNER_USER"
|
||
|
||
############################################
|
||
# Setup Directory
|
||
############################################
|
||
|
||
log "Setting up directories..."
|
||
|
||
mkdir -p "$INSTALL_DIR"
|
||
chown -R "$RUNNER_USER:$RUNNER_USER" "$INSTALL_DIR"
|
||
|
||
############################################
|
||
# Download Gitea Runner
|
||
############################################
|
||
|
||
log "Downloading Gitea runner..."
|
||
|
||
TMP_FILE="/tmp/gitea-runner.bin"
|
||
|
||
curl -fL --retry 5 --retry-delay 2 \
|
||
"https://dl.gitea.com/act_runner/${ACT_RUNNER_VERSION}/act_runner-${ACT_RUNNER_VERSION}-linux-amd64" \
|
||
-o "$TMP_FILE"
|
||
|
||
# Ensure it isn’t HTML
|
||
file "$TMP_FILE" | grep -qi "ELF" >/dev/null || { echo "Download failed"; exit 1; }
|
||
|
||
mv "$TMP_FILE" "$BIN_PATH"
|
||
chmod +x "$BIN_PATH"
|
||
|
||
############################################
|
||
# Register Runner
|
||
############################################
|
||
|
||
log "Registering runner..."
|
||
|
||
systemctl stop gitea-runner 2>/dev/null || true
|
||
|
||
rm -f "$INSTALL_DIR/.runner"
|
||
|
||
# Create runner home atomically
|
||
install -d -m 750 -o "$RUNNER_USER" -g "$RUNNER_USER" "$INSTALL_DIR"
|
||
|
||
# Ensure work dir exists
|
||
install -d -m 750 -o "$RUNNER_USER" -g "$RUNNER_USER" "$WORK_DIR"
|
||
|
||
# Remove any stale identity
|
||
rm -f "$INSTALL_DIR/.runner"
|
||
|
||
# Register as runner user in correct dir
|
||
runuser -u "$RUNNER_USER" -- bash <<EOF
|
||
set -e
|
||
|
||
cd "$INSTALL_DIR"
|
||
|
||
"$BIN_PATH" register \
|
||
--no-interactive \
|
||
--instance "$GITEA_URL" \
|
||
--token "$REG_TOKEN" \
|
||
--name "$RUNNER_NAME" \
|
||
--labels "docker,linux,amd64,krkn-builder"
|
||
EOF
|
||
|
||
############################################
|
||
# Create runner config
|
||
############################################
|
||
|
||
runuser -u "$RUNNER_USER" -- bash <<EOF
|
||
set -e
|
||
cd "$INSTALL_DIR"
|
||
"$BIN_PATH" generate-config > "$CONFIG_PATH"
|
||
EOF
|
||
|
||
chown "$RUNNER_USER:$RUNNER_USER" "$CONFIG_PATH"
|
||
chmod 640 "$CONFIG_PATH"
|
||
|
||
############################################
|
||
# Create systemd Service
|
||
############################################
|
||
|
||
log "Creating systemd service..."
|
||
|
||
cat > "$SERVICE_PATH" <<EOF
|
||
[Unit]
|
||
Description=Gitea Actions Runner
|
||
After=network-online.target docker.service
|
||
Wants=network-online.target
|
||
Requires=docker.service
|
||
|
||
[Service]
|
||
Type=simple
|
||
User=$RUNNER_USER
|
||
Group=$RUNNER_USER
|
||
WorkingDirectory=$INSTALL_DIR
|
||
|
||
ExecStart=$BIN_PATH daemon --config $CONFIG_PATH
|
||
Restart=always
|
||
RestartSec=5
|
||
|
||
Environment="PATH=/usr/local/go/bin:/usr/local/bin:/usr/bin:/bin"
|
||
Environment=DOCKER_HOST=unix:///var/run/docker.sock
|
||
|
||
LimitNOFILE=1048576
|
||
LimitNPROC=1048576
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
EOF
|
||
|
||
############################################
|
||
# Cleanup Script Creation
|
||
############################################
|
||
|
||
log "Creating cleanup script..."
|
||
|
||
cat > "$CLEANUP_SCRIPT" <<EOF
|
||
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
# Remove stale runner workspace data
|
||
find "$WORK_DIR" -mindepth 1 -maxdepth 1 -mtime +2 -exec rm -rf {} +
|
||
|
||
# Remove stopped containers
|
||
docker container prune -f || true
|
||
|
||
# Remove unused Docker networks
|
||
docker network prune -f || true
|
||
|
||
# Remove dangling images/build cache
|
||
docker image prune -f || true
|
||
docker builder prune -af --filter "until=48h" || true
|
||
|
||
# Remove Gitea/act task volumes that failed jobs sometimes orphan
|
||
docker volume ls -q | grep -E '^GITEA-ACTIONS-TASK-' | xargs -r docker volume rm || true
|
||
EOF
|
||
|
||
chmod +x "$CLEANUP_SCRIPT"
|
||
|
||
############################################
|
||
# Cleanup Script Service
|
||
############################################
|
||
|
||
log "Creating cleanup systemd job..."
|
||
|
||
cat > "$CLEANUP_SERVICE" <<EOF
|
||
[Unit]
|
||
Description=Clean Gitea runner Docker and workspace leftovers
|
||
After=docker.service
|
||
Requires=docker.service
|
||
|
||
[Service]
|
||
Type=oneshot
|
||
ExecStart=$CLEANUP_SCRIPT
|
||
EOF
|
||
|
||
cat > "$CLEANUP_TIMER" <<EOF
|
||
[Unit]
|
||
Description=Run Gitea runner cleanup daily
|
||
|
||
[Timer]
|
||
OnCalendar=daily
|
||
Persistent=true
|
||
|
||
[Install]
|
||
WantedBy=timers.target
|
||
EOF
|
||
|
||
############################################
|
||
# Enable Service
|
||
############################################
|
||
|
||
log "Enabling runner service..."
|
||
|
||
systemctl daemon-reload
|
||
systemctl enable gitea-runner
|
||
systemctl start gitea-runner
|
||
|
||
systemctl is-active --quiet gitea-runner || journalctl -u gitea-runner -n 100 --no-pager
|
||
|
||
systemctl enable --now gitea-runner-cleanup.timer
|
||
|
||
############################################
|
||
# Final Checks
|
||
############################################
|
||
|
||
log "Installation complete."
|
||
|
||
echo
|
||
echo "Status:"
|
||
systemctl status gitea-runner --no-pager
|
||
|
||
echo
|
||
echo "Runner name: $RUNNER_NAME"
|
||
echo "Gitea URL: $GITEA_URL"
|
||
echo "Install dir: $INSTALL_DIR"
|
||
echo "Config: $CONFIG_PATH"
|
||
echo |