Add Gitea Actions runner workflow
This commit is contained in:
parent
7aec70640a
commit
e4f4cef272
|
|
@ -0,0 +1,75 @@
|
||||||
|
name: Homelab Main
|
||||||
|
|
||||||
|
"on":
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate-and-deploy:
|
||||||
|
runs-on: homelab-debian
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Check out repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Verify Debian runner guardrails
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
test "$(uname -s)" = "Linux"
|
||||||
|
. /etc/os-release
|
||||||
|
test "${ID}" = "debian"
|
||||||
|
sudo -n true
|
||||||
|
|
||||||
|
- name: Validate shell, Kubernetes manifests, and OpenTofu stacks
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
bash -n lab.sh
|
||||||
|
|
||||||
|
mapfile -t manifests < <(find apps -type f \( -name '*.yaml' -o -name '*.yml' \) | sort)
|
||||||
|
kubectl --kubeconfig "${KUBECONFIG:-/home/jv/.kube/config}" apply --dry-run=server -f "${manifests[@]}"
|
||||||
|
|
||||||
|
set +e
|
||||||
|
kubectl --kubeconfig "${KUBECONFIG:-/home/jv/.kube/config}" diff -f "${manifests[@]}"
|
||||||
|
diff_status="$?"
|
||||||
|
set -e
|
||||||
|
if (( diff_status > 1 )); then
|
||||||
|
exit "${diff_status}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
for stack in bootstrap/cluster bootstrap/platform bootstrap/apps bootstrap/edge; do
|
||||||
|
tofu -chdir="${stack}" init -input=false
|
||||||
|
tofu -chdir="${stack}" fmt -check
|
||||||
|
tofu -chdir="${stack}" validate
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Block automatic deploy for high-impact changes
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
event_before="$(
|
||||||
|
python3 -c 'import json, os; p = os.environ.get("GITHUB_EVENT_PATH", ""); print(json.load(open(p, encoding="utf-8")).get("before", "") if p and os.path.exists(p) else "")'
|
||||||
|
)"
|
||||||
|
|
||||||
|
if [[ -n "${event_before}" && ! "${event_before}" =~ ^0+$ ]]; then
|
||||||
|
changed_files="$(git diff --name-only "${event_before}" HEAD)"
|
||||||
|
else
|
||||||
|
changed_files="$(git diff-tree --no-commit-id --name-only -r HEAD)"
|
||||||
|
fi
|
||||||
|
printf '%s\n' "${changed_files}"
|
||||||
|
|
||||||
|
if printf '%s\n' "${changed_files}" | grep -Eq '^(bootstrap/(cluster|platform|edge)/|lab[.]sh|[.]gitea/workflows/)'; then
|
||||||
|
echo "High-impact bootstrap, runner, or workflow changes require a manual Debian run."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Deploy validated main branch
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
./lab.sh up
|
||||||
|
kubectl --kubeconfig "${KUBECONFIG:-/home/jv/.kube/config}" -n argocd get applications
|
||||||
40
README.md
40
README.md
|
|
@ -239,6 +239,46 @@ sudo systemctl start homelab-gitea-backup.service
|
||||||
sudo ls -lh /var/backups/homelab/gitea
|
sudo ls -lh /var/backups/homelab/gitea
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Gitea Actions
|
||||||
|
|
||||||
|
This repo includes a Gitea Actions workflow at
|
||||||
|
`.gitea/workflows/homelab-main.yml`. It runs only on pushes to `main` and targets
|
||||||
|
a repository-scoped Debian host runner with the label `homelab-debian`.
|
||||||
|
|
||||||
|
The workflow validates shell syntax, Kubernetes manifests, and all OpenTofu
|
||||||
|
stacks before deployment. It automatically stops when high-impact files under
|
||||||
|
`bootstrap/cluster`, `bootstrap/platform`, `bootstrap/edge`, `lab.sh`, or
|
||||||
|
`.gitea/workflows` change; those changes still require a manual Debian run.
|
||||||
|
Lower-risk app changes proceed to `./lab.sh up` after validation passes.
|
||||||
|
|
||||||
|
Enable Actions for the repository in Gitea, then create a repository-level runner
|
||||||
|
token from:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://lab2025.duckdns.org/git/jv/my-homelab-configs/settings/actions/runners
|
||||||
|
```
|
||||||
|
|
||||||
|
Register and start the Debian runner from the Debian server:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/my-homelab-configs
|
||||||
|
GITEA_RUNNER_REGISTRATION_TOKEN='<repo-runner-token>' ./lab.sh install-gitea-runner
|
||||||
|
```
|
||||||
|
|
||||||
|
The runner is installed as `homelab-gitea-runner.service`, runs as user `jv`, and
|
||||||
|
uses a host label instead of a Docker job container because deployment needs the
|
||||||
|
Debian host's Docker, OpenTofu, kubeconfig, SSH keys, and local state.
|
||||||
|
|
||||||
|
The deployment job is non-interactive. User `jv` must be able to run `sudo -n
|
||||||
|
true` on the Debian host or the workflow will fail before deployment.
|
||||||
|
|
||||||
|
Useful checks:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
systemctl status homelab-gitea-runner.service
|
||||||
|
journalctl -u homelab-gitea-runner.service -n 100 --no-pager
|
||||||
|
```
|
||||||
|
|
||||||
## Destructive Rebuilds
|
## Destructive Rebuilds
|
||||||
|
|
||||||
`./lab.sh nuke` resets kubeadm, containerd runtime state, CNI files, Calico
|
`./lab.sh nuke` resets kubeadm, containerd runtime state, CNI files, Calico
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@ spec:
|
||||||
value: "true"
|
value: "true"
|
||||||
- name: GITEA__migrations__ALLOW_LOCALNETWORKS
|
- name: GITEA__migrations__ALLOW_LOCALNETWORKS
|
||||||
value: "true"
|
value: "true"
|
||||||
|
- name: GITEA__actions__ENABLED
|
||||||
|
value: "true"
|
||||||
- name: GITEA__repository__DEFAULT_PRIVATE
|
- name: GITEA__repository__DEFAULT_PRIVATE
|
||||||
value: public
|
value: public
|
||||||
- name: GITEA__security__INSTALL_LOCK
|
- name: GITEA__security__INSTALL_LOCK
|
||||||
|
|
|
||||||
95
lab.sh
95
lab.sh
|
|
@ -467,6 +467,8 @@ cleanup() {
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
|
|
||||||
kubectl --kubeconfig "\${KUBECONFIG_PATH}" -n "\${GITEA_NAMESPACE}" exec "\${pod}" -c "\${GITEA_CONTAINER}" -- rm -f "\${REMOTE_ARCHIVE}" >/dev/null 2>&1 || true
|
kubectl --kubeconfig "\${KUBECONFIG_PATH}" -n "\${GITEA_NAMESPACE}" exec "\${pod}" -c "\${GITEA_CONTAINER}" -- rm -f "\${REMOTE_ARCHIVE}" >/dev/null 2>&1 || true
|
||||||
|
kubectl --kubeconfig "\${KUBECONFIG_PATH}" -n "\${GITEA_NAMESPACE}" exec "\${pod}" -c "\${GITEA_CONTAINER}" -- \
|
||||||
|
sh -c 'mkdir -p /data/git/repositories && chown git:git /data/git /data/git/repositories'
|
||||||
kubectl --kubeconfig "\${KUBECONFIG_PATH}" -n "\${GITEA_NAMESPACE}" exec "\${pod}" -c "\${GITEA_CONTAINER}" -- \
|
kubectl --kubeconfig "\${KUBECONFIG_PATH}" -n "\${GITEA_NAMESPACE}" exec "\${pod}" -c "\${GITEA_CONTAINER}" -- \
|
||||||
su-exec git gitea dump -c /data/gitea/conf/app.ini --file "\${REMOTE_ARCHIVE}"
|
su-exec git gitea dump -c /data/gitea/conf/app.ini --file "\${REMOTE_ARCHIVE}"
|
||||||
kubectl --kubeconfig "\${KUBECONFIG_PATH}" -n "\${GITEA_NAMESPACE}" cp -c "\${GITEA_CONTAINER}" \
|
kubectl --kubeconfig "\${KUBECONFIG_PATH}" -n "\${GITEA_NAMESPACE}" cp -c "\${GITEA_CONTAINER}" \
|
||||||
|
|
@ -516,6 +518,94 @@ backup_gitea() {
|
||||||
sudo /usr/local/sbin/homelab-gitea-backup.sh
|
sudo /usr/local/sbin/homelab-gitea-backup.sh
|
||||||
}
|
}
|
||||||
|
|
||||||
|
install_gitea_runner() {
|
||||||
|
local runner_arch
|
||||||
|
local runner_home="${GITEA_RUNNER_HOME:-/home/jv/.local/share/gitea-runner/my-homelab-configs}"
|
||||||
|
local runner_instance="${GITEA_RUNNER_INSTANCE_URL:-https://lab2025.duckdns.org/git/}"
|
||||||
|
local runner_labels="${GITEA_RUNNER_LABELS:-homelab-debian:host}"
|
||||||
|
local runner_name="${GITEA_RUNNER_NAME:-homelab-debian-my-homelab-configs}"
|
||||||
|
local runner_token="${GITEA_RUNNER_REGISTRATION_TOKEN:-${1:-}}"
|
||||||
|
local runner_user="${GITEA_RUNNER_USER:-jv}"
|
||||||
|
local runner_version="${GITEA_ACT_RUNNER_VERSION:-0.2.11}"
|
||||||
|
local missing_packages=""
|
||||||
|
|
||||||
|
require_debian_server "install-gitea-runner"
|
||||||
|
|
||||||
|
case "$(dpkg --print-architecture)" in
|
||||||
|
amd64)
|
||||||
|
runner_arch="linux-amd64"
|
||||||
|
;;
|
||||||
|
arm64)
|
||||||
|
runner_arch="linux-arm64"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unsupported Debian architecture: $(dpkg --print-architecture)" >&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
for package in ca-certificates curl git python3; do
|
||||||
|
if ! dpkg-query -W -f='${Status}' "$package" 2>/dev/null | grep -q "install ok installed"; then
|
||||||
|
missing_packages="$missing_packages $package"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [[ -n "${missing_packages}" ]]; then
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --no-install-recommends ${missing_packages}
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo curl -fsSL \
|
||||||
|
-o /usr/local/bin/act_runner \
|
||||||
|
"https://gitea.com/gitea/act_runner/releases/download/v${runner_version}/act_runner-${runner_version}-${runner_arch}"
|
||||||
|
sudo chmod 0755 /usr/local/bin/act_runner
|
||||||
|
sudo chown root:root /usr/local/bin/act_runner
|
||||||
|
|
||||||
|
sudo -u "${runner_user}" mkdir -p "${runner_home}"
|
||||||
|
|
||||||
|
if [[ ! -f "${runner_home}/.runner" ]]; then
|
||||||
|
if [[ -z "${runner_token}" ]]; then
|
||||||
|
echo "Set GITEA_RUNNER_REGISTRATION_TOKEN to the repository-level runner token from Gitea." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo -u "${runner_user}" env \
|
||||||
|
HOME="/home/${runner_user}" \
|
||||||
|
GITEA_RUNNER_HOME="${runner_home}" \
|
||||||
|
GITEA_RUNNER_INSTANCE_URL="${runner_instance}" \
|
||||||
|
GITEA_RUNNER_REGISTRATION_TOKEN="${runner_token}" \
|
||||||
|
GITEA_RUNNER_NAME="${runner_name}" \
|
||||||
|
GITEA_RUNNER_LABELS="${runner_labels}" \
|
||||||
|
bash -lc 'cd "${GITEA_RUNNER_HOME}" && /usr/local/bin/act_runner register --no-interactive --instance "${GITEA_RUNNER_INSTANCE_URL}" --token "${GITEA_RUNNER_REGISTRATION_TOKEN}" --name "${GITEA_RUNNER_NAME}" --labels "${GITEA_RUNNER_LABELS}"'
|
||||||
|
else
|
||||||
|
echo "Existing runner registration found at ${runner_home}/.runner; keeping it."
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo tee /etc/systemd/system/homelab-gitea-runner.service >/dev/null <<SERVICE_EOT
|
||||||
|
[Unit]
|
||||||
|
Description=Homelab Gitea Actions runner for my-homelab-configs
|
||||||
|
After=network-online.target docker.service
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=${runner_user}
|
||||||
|
Group=${runner_user}
|
||||||
|
WorkingDirectory=${runner_home}
|
||||||
|
Environment=HOME=/home/${runner_user}
|
||||||
|
Environment=PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||||
|
ExecStart=/usr/local/bin/act_runner daemon
|
||||||
|
Restart=always
|
||||||
|
RestartSec=5
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
SERVICE_EOT
|
||||||
|
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable --now homelab-gitea-runner.service >/dev/null
|
||||||
|
sudo systemctl status homelab-gitea-runner.service --no-pager -l
|
||||||
|
}
|
||||||
|
|
||||||
recreate_pods_for_selector() {
|
recreate_pods_for_selector() {
|
||||||
local namespace="$1"
|
local namespace="$1"
|
||||||
local selector="$2"
|
local selector="$2"
|
||||||
|
|
@ -818,11 +908,14 @@ case "${1:-}" in
|
||||||
backup-gitea)
|
backup-gitea)
|
||||||
backup_gitea
|
backup_gitea
|
||||||
;;
|
;;
|
||||||
|
install-gitea-runner)
|
||||||
|
install_gitea_runner "${2:-}"
|
||||||
|
;;
|
||||||
nuke)
|
nuke)
|
||||||
nuke
|
nuke
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Usage: $0 {up|backup-gitea|nuke}"
|
echo "Usage: $0 {up|backup-gitea|install-gitea-runner|nuke}"
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue