Files
foxhunt/infra/modules/ci-runner/cloud-init.yaml.tpl
jgrusewski 019bc140d7 fix(ci): increase idle timeout to 60min, check act_runner children
The 15min timeout was too short for Rust builds. Also checks
for act_runner child processes (image pull, git clone phases)
not just Docker containers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 22:52:28 +01:00

178 lines
4.9 KiB
Smarty

#cloud-config
#
# Foxhunt CI Runner (act_runner for Gitea Actions)
# Tailscale-only access, native Docker (no DinD).
#
package_update: true
package_upgrade: true
packages:
- ca-certificates
- curl
- gnupg
write_files:
- path: /opt/act_runner/config.yaml
permissions: '0644'
content: |
log:
level: info
runner:
file: /opt/act_runner/.runner
capacity: ${runner_capacity}
timeout: 3h
insecure: false
fetch_timeout: 5s
fetch_interval: 2s
cache:
enabled: true
dir: /opt/act_runner/cache
container:
network: host
privileged: false
options:
valid_volumes: []
- path: /etc/systemd/system/act-runner.service
permissions: '0644'
content: |
[Unit]
Description=Gitea Actions Runner
After=docker.service tailscaled.service
Requires=docker.service
[Service]
Type=simple
WorkingDirectory=/opt/act_runner
ExecStart=/usr/local/bin/act_runner daemon --config /opt/act_runner/config.yaml
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
- path: /opt/act_runner/idle-shutdown.sh
permissions: '0755'
content: |
#!/bin/bash
# Shutdown instance after ${idle_timeout_minutes} minutes with no running CI jobs.
# Runs via systemd timer every 5 minutes.
IDLE_FILE="/tmp/ci-idle-since"
TIMEOUT_SEC=$((${idle_timeout_minutes} * 60))
# Check for running Docker containers
CONTAINERS=$(docker ps -q 2>/dev/null | wc -l)
if [ "$CONTAINERS" -gt 0 ]; then
rm -f "$IDLE_FILE"
exit 0
fi
# Check if act_runner has child processes (actively running a job)
RUNNER_PID=$(pgrep -f 'act_runner daemon' 2>/dev/null)
if [ -n "$RUNNER_PID" ]; then
CHILDREN=$(pgrep -P "$RUNNER_PID" 2>/dev/null | wc -l)
if [ "$CHILDREN" -gt 0 ]; then
rm -f "$IDLE_FILE"
exit 0
fi
fi
# No jobs running — record when idle started
if [ ! -f "$IDLE_FILE" ]; then
date +%s > "$IDLE_FILE"
logger -t idle-shutdown "CI runner idle, starting countdown"
exit 0
fi
IDLE_SINCE=$(cat "$IDLE_FILE")
NOW=$(date +%s)
IDLE_SECS=$((NOW - IDLE_SINCE))
if [ "$IDLE_SECS" -ge "$TIMEOUT_SEC" ]; then
logger -t idle-shutdown "Idle for $${IDLE_SECS}s (threshold $${TIMEOUT_SEC}s), shutting down"
# Clean up Docker to free disk space on next boot
docker system prune -af --volumes 2>/dev/null || true
rm -f "$IDLE_FILE"
poweroff
fi
- path: /etc/systemd/system/ci-idle-shutdown.service
permissions: '0644'
content: |
[Unit]
Description=Check CI runner idle state and shutdown if unused
[Service]
Type=oneshot
ExecStart=/opt/act_runner/idle-shutdown.sh
- path: /etc/systemd/system/ci-idle-shutdown.timer
permissions: '0644'
content: |
[Unit]
Description=Periodic idle check for CI runner auto-shutdown
[Timer]
OnBootSec=10min
OnUnitActiveSec=5min
AccuracySec=1min
[Install]
WantedBy=timers.target
runcmd:
# --- Docker CE ---
- install -m 0755 -d /etc/apt/keyrings
- curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
- chmod a+r /etc/apt/keyrings/docker.gpg
- |
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" > /etc/apt/sources.list.d/docker.list
- apt-get update -qq
- apt-get install -y -qq docker-ce docker-ce-cli containerd.io docker-buildx-plugin
- systemctl enable docker
- systemctl start docker
# --- Tailscale ---
- curl -fsSL https://tailscale.com/install.sh | sh
- tailscale up --authkey=${tailscale_auth_key} --hostname=${instance_name} --ssh
# Wait for Tailscale connectivity
- |
for i in $(seq 1 30); do
TS_IP=$(tailscale ip -4 2>/dev/null)
if [ -n "$TS_IP" ]; then
echo "Tailscale IP: $TS_IP"
break
fi
sleep 2
done
# --- act_runner ---
- |
ACT_RUNNER_VERSION="0.3.0"
curl -fsSL "https://dl.gitea.com/act_runner/$${ACT_RUNNER_VERSION}/act_runner-$${ACT_RUNNER_VERSION}-linux-amd64" \
-o /usr/local/bin/act_runner
chmod +x /usr/local/bin/act_runner
# Register runner with Gitea (via Tailscale)
- |
cd /opt/act_runner
act_runner register --no-interactive \
--instance "${gitea_url}" \
--token "${runner_token}" \
--name "${instance_name}" \
--labels "${runner_labels}"
# Enable and start runner service
- systemctl daemon-reload
- systemctl enable act-runner
- systemctl start act-runner
# Enable idle auto-shutdown timer
- systemctl enable --now ci-idle-shutdown.timer
- echo "PROVISIONING_COMPLETE" > /var/log/cloud-init-done