Initial commit: Ansible playbook for Gitea Act Runner deployment
Some checks failed
Ansible Lint / Ansible Lint Check (push) Has been cancelled
Some checks failed
Ansible Lint / Ansible Lint Check (push) Has been cancelled
Automated deployment of act_runner on Ubuntu 20.04+ servers: - Docker CE installation (DEB822 format) - Node.js 24.x via NodeSource - act_runner binary with SHA256 verification - systemd service with security hardening - CI: ansible-lint via Gitea Actions Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
23
.ansible-lint
Normal file
23
.ansible-lint
Normal file
@@ -0,0 +1,23 @@
|
||||
# =============================================================================
|
||||
# Ansible-lint Configuration
|
||||
# =============================================================================
|
||||
# See: https://ansible.readthedocs.io/projects/lint/configuring/
|
||||
|
||||
# Use production profile (strictest)
|
||||
profile: production
|
||||
|
||||
# Exclude paths
|
||||
exclude_paths:
|
||||
- .git/
|
||||
- .gitignore
|
||||
|
||||
# Enable offline mode (don't download roles/collections)
|
||||
offline: true
|
||||
|
||||
# Warn about these rules instead of failing
|
||||
warn_list:
|
||||
- experimental
|
||||
|
||||
# Skip these rules entirely (if needed)
|
||||
# skip_list:
|
||||
# - yaml[line-length]
|
||||
139
.gitea/workflows/lint.yml
Normal file
139
.gitea/workflows/lint.yml
Normal file
@@ -0,0 +1,139 @@
|
||||
# =============================================================================
|
||||
# Gitea Actions Workflow - Ansible Lint
|
||||
# =============================================================================
|
||||
#
|
||||
# This workflow validates Ansible playbooks and roles using ansible-lint.
|
||||
# Runs automatically on push and pull request events.
|
||||
#
|
||||
# WORKFLOW LOCATION:
|
||||
# Gitea Actions requires workflow files in `.gitea/workflows/` directory.
|
||||
# This differs from GitHub Actions which uses `.github/workflows/`.
|
||||
# See: https://docs.gitea.com/usage/actions/quickstart
|
||||
#
|
||||
# RUNNER CONFIGURATION:
|
||||
# - `runs-on: ubuntu-latest` matches our runner label from act_runner config
|
||||
# - Jobs execute on self-hosted runners registered with this repository's Gitea
|
||||
# - Requires runner with `ubuntu-latest:host` label (host execution mode)
|
||||
#
|
||||
# WHAT THIS WORKFLOW DOES:
|
||||
# 1. Checks out the repository code
|
||||
# 2. Installs uv package manager
|
||||
# 3. Syncs dependencies from pyproject.toml
|
||||
# 4. Runs ansible-lint against the playbook
|
||||
#
|
||||
# MANUAL TRIGGER:
|
||||
# You can manually trigger this workflow from Gitea UI:
|
||||
# Repository > Actions > Select workflow > "Run workflow"
|
||||
#
|
||||
# DOCUMENTATION:
|
||||
# - Gitea Actions: https://docs.gitea.com/usage/actions/overview
|
||||
# - Ansible Lint: https://ansible.readthedocs.io/projects/lint/
|
||||
# - uv: https://docs.astral.sh/uv/
|
||||
# - Workflow Syntax: https://docs.gitea.com/usage/actions/workflow-syntax
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Workflow Metadata
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Human-readable name displayed in Gitea Actions UI.
|
||||
# Shown in repository's Actions tab and in commit status checks.
|
||||
name: Ansible Lint
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Trigger Events
|
||||
# -----------------------------------------------------------------------------
|
||||
# Define when this workflow should run.
|
||||
# See: https://docs.gitea.com/usage/actions/workflow-syntax#on
|
||||
|
||||
on:
|
||||
# Run on every push to any branch.
|
||||
# This catches issues before they're merged.
|
||||
push:
|
||||
# Optionally limit to specific branches:
|
||||
# branches:
|
||||
# - master
|
||||
# - main
|
||||
|
||||
# Run on pull requests targeting any branch.
|
||||
# Provides feedback before merge.
|
||||
pull_request:
|
||||
# Optionally limit to PRs targeting specific branches:
|
||||
# branches:
|
||||
# - master
|
||||
# - main
|
||||
|
||||
# Allow manual triggering from Gitea UI.
|
||||
# Useful for re-running after fixing external issues (e.g., runner problems).
|
||||
workflow_dispatch:
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Jobs
|
||||
# -----------------------------------------------------------------------------
|
||||
# A workflow consists of one or more jobs that run in parallel by default.
|
||||
# Use `needs:` to create dependencies between jobs if sequential execution
|
||||
# is required.
|
||||
|
||||
jobs:
|
||||
# ---------------------------------------------------------------------------
|
||||
# Lint Job
|
||||
# ---------------------------------------------------------------------------
|
||||
# Validates Ansible code quality and best practices.
|
||||
lint:
|
||||
# Human-readable name shown in Gitea UI for this job.
|
||||
name: Ansible Lint Check
|
||||
|
||||
# Runner label to execute this job.
|
||||
# Must match a label registered with act_runner.
|
||||
# Our runner uses: `ubuntu-latest:host` (see roles/act_runner/defaults/main.yml)
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# -------------------------------------------------------------------------
|
||||
# Job Steps
|
||||
# -------------------------------------------------------------------------
|
||||
# Steps run sequentially within a job.
|
||||
# Each step can run commands or use pre-built actions.
|
||||
steps:
|
||||
# -----------------------------------------------------------------------
|
||||
# Step 1: Checkout Repository
|
||||
# -----------------------------------------------------------------------
|
||||
# Clone the repository to the runner's workspace.
|
||||
# Uses the official checkout action maintained by GitHub/Gitea.
|
||||
# See: https://github.com/actions/checkout
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
# Default behavior:
|
||||
# - Clones the commit that triggered the workflow
|
||||
# - For PRs, clones the merge commit
|
||||
# - Shallow clone (depth=1) for faster checkout
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Step 2: Install uv
|
||||
# -----------------------------------------------------------------------
|
||||
# Install uv - a fast Python package manager from Astral.
|
||||
# Replaces pip/virtualenv with a single, faster tool.
|
||||
# See: https://docs.astral.sh/uv/
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v5
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Step 3: Sync Dependencies and Run Linter
|
||||
# -----------------------------------------------------------------------
|
||||
# uv sync reads pyproject.toml and creates a virtual environment
|
||||
# with all dependencies (ansible, ansible-lint).
|
||||
# uv run executes commands within that environment.
|
||||
- name: Run ansible-lint
|
||||
run: |
|
||||
# Install dependencies from pyproject.toml.
|
||||
uv sync
|
||||
|
||||
# Run ansible-lint on the main playbook.
|
||||
# Exit code 0 = success (no issues found)
|
||||
# Exit code non-zero = linting errors found (fails the workflow)
|
||||
#
|
||||
# The linter uses .ansible-lint config file for:
|
||||
# - Profile: production (strictest rules)
|
||||
# - Excluded paths: .git/, .gitignore
|
||||
# - Offline mode: true (no network calls)
|
||||
uv run ansible-lint playbook.yml
|
||||
46
.gitignore
vendored
Normal file
46
.gitignore
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
# =============================================================================
|
||||
# Gitignore - Gitea Act Runner Ansible Playbook
|
||||
# =============================================================================
|
||||
|
||||
# Ansible Vault - NEVER commit actual vault files
|
||||
group_vars/all/vault.yml
|
||||
group_vars/*/vault.yml
|
||||
*.vault.yml
|
||||
!*.vault.yml.example
|
||||
|
||||
# Vault password files
|
||||
.vault_pass
|
||||
.vault_password
|
||||
*.vault_pass
|
||||
|
||||
# Ansible retry files
|
||||
*.retry
|
||||
|
||||
# Python
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*.pyo
|
||||
.Python
|
||||
*.egg-info/
|
||||
.eggs/
|
||||
|
||||
# IDE
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Temp files
|
||||
*.tmp
|
||||
*.temp
|
||||
*.log
|
||||
|
||||
# SSH keys (if accidentally placed here)
|
||||
*.pem
|
||||
*.key
|
||||
id_rsa*
|
||||
21
README.md
Normal file
21
README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Gitea Act Runner - Ansible Playbook
|
||||
|
||||
Deploys [Gitea Act Runner](https://docs.gitea.com/usage/actions/act-runner) on Ubuntu 20.04+ servers.
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
uv sync
|
||||
|
||||
# Configure inventory and vault (see examples)
|
||||
ansible-vault create group_vars/all/vault.yml
|
||||
|
||||
# Deploy
|
||||
uv run ansible-playbook -i inventory/hosts.yml playbook.yml --ask-vault-pass
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [Act Runner Docs](https://docs.gitea.com/usage/actions/act-runner)
|
||||
- [Gitea Actions](https://docs.gitea.com/usage/actions/overview)
|
||||
79
group_vars/all/vars.yml
Normal file
79
group_vars/all/vars.yml
Normal file
@@ -0,0 +1,79 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Group Variables - All Hosts
|
||||
# =============================================================================
|
||||
#
|
||||
# This file maps vault secrets to role variables and sets common overrides.
|
||||
#
|
||||
# VARIABLE RESOLUTION ORDER (lowest to highest priority):
|
||||
# 1. roles/act_runner/defaults/main.yml (role defaults)
|
||||
# 2. group_vars/all.yml (this file)
|
||||
# 3. inventory host_vars (per-host overrides)
|
||||
# 4. command line --extra-vars (highest priority)
|
||||
#
|
||||
# Vault variables (prefixed with vault_) are stored encrypted in vault.yml.
|
||||
# Role variables are defined in roles/act_runner/defaults/main.yml.
|
||||
#
|
||||
# HOW TO USE:
|
||||
# 1. Create the vault: ansible-vault create group_vars/vault.yml
|
||||
# 2. Add your secrets to the vault (see vault.yml.example)
|
||||
# 3. The mappings below will reference those vault variables
|
||||
#
|
||||
# See: https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html
|
||||
# =============================================================================
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Vault Secret Mappings
|
||||
# -----------------------------------------------------------------------------
|
||||
# These map encrypted vault variables to the role's expected variable names.
|
||||
# This indirection allows vault structure to differ from role expectations.
|
||||
#
|
||||
# REQUIRED: These must be set in group_vars/vault.yml
|
||||
|
||||
# URL of your Gitea instance (e.g., "https://git.example.com")
|
||||
gitea_instance_url: "{{ vault_gitea_instance_url }}"
|
||||
|
||||
# Registration token from Gitea admin panel
|
||||
# Get it from: {{ gitea_instance_url }}/-/admin/actions/runners
|
||||
act_runner_token: "{{ vault_act_runner_token }}"
|
||||
|
||||
# Package registry hostname (usually same as Gitea host, without https://)
|
||||
gitea_registry: "{{ vault_gitea_registry }}"
|
||||
|
||||
# Service account username for package registry authentication
|
||||
gitea_actions_user: "{{ vault_gitea_actions_user }}"
|
||||
|
||||
# Personal Access Token (PAT) for package registry
|
||||
# Create at: {{ gitea_instance_url }}/user/settings/applications
|
||||
gitea_packages_token: "{{ vault_gitea_packages_token }}"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Role Variable Overrides (Optional)
|
||||
# -----------------------------------------------------------------------------
|
||||
# Uncomment and modify to override role defaults for all hosts.
|
||||
# See roles/act_runner/defaults/main.yml for all available variables.
|
||||
|
||||
# Act Runner Version
|
||||
# Check available versions: https://dl.gitea.com/act_runner/
|
||||
# act_runner_version: "0.2.13"
|
||||
|
||||
# Node.js Version
|
||||
# Valid values: "18", "20", "22", "24"
|
||||
# See: https://nodejs.org/en/about/previous-releases
|
||||
# nodejs_version: "24"
|
||||
|
||||
# Runner Labels
|
||||
# Define what jobs this runner can handle.
|
||||
# Format: "label:executor" where executor is "host" or "docker://image"
|
||||
# act_runner_labels:
|
||||
# - "ubuntu-latest:host"
|
||||
# - "self-hosted:host"
|
||||
|
||||
# Concurrent Jobs
|
||||
# How many jobs can run simultaneously on each runner.
|
||||
# Higher values = more parallelism but more resource usage.
|
||||
# runner_capacity: 1
|
||||
|
||||
# Container Settings
|
||||
# Whether to always pull images before running (recommended: true)
|
||||
# container_force_pull: true
|
||||
94
group_vars/all/vault.yml.example
Normal file
94
group_vars/all/vault.yml.example
Normal file
@@ -0,0 +1,94 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Ansible Vault - Encrypted Secrets (EXAMPLE)
|
||||
# =============================================================================
|
||||
#
|
||||
# This is an EXAMPLE file showing what should go in your encrypted vault.
|
||||
# DO NOT commit actual secrets to version control.
|
||||
#
|
||||
# HOW TO CREATE THE REAL VAULT:
|
||||
# 1. Copy this file's contents
|
||||
# 2. Run: ansible-vault create group_vars/vault.yml
|
||||
# 3. Paste and edit with your actual values
|
||||
# 4. Save and exit
|
||||
#
|
||||
# HOW TO MANAGE THE VAULT:
|
||||
# - Edit: ansible-vault edit group_vars/vault.yml
|
||||
# - View: ansible-vault view group_vars/vault.yml
|
||||
# - Rekey: ansible-vault rekey group_vars/vault.yml
|
||||
#
|
||||
# SECURITY NOTES:
|
||||
# - Never commit the vault password to version control
|
||||
# - Store vault password in a secure location (password manager, etc.)
|
||||
# - Consider using --vault-password-file for automation
|
||||
# - Add vault.yml to .gitignore (this example file is safe to commit)
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Gitea Instance Configuration
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# URL of your Gitea instance (including https://).
|
||||
# This is where the runner will connect to pick up jobs.
|
||||
# Example: "https://git.example.com"
|
||||
vault_gitea_instance_url: "https://git.karmaxplan.ru"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Runner Registration Token
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Registration token from Gitea for authenticating new runners.
|
||||
#
|
||||
# HOW TO GET THIS TOKEN:
|
||||
# 1. Log into Gitea as admin
|
||||
# 2. Go to: Site Administration > Actions > Runners
|
||||
# URL: {{ vault_gitea_instance_url }}/-/admin/actions/runners
|
||||
# 3. Click "Create new Runner"
|
||||
# 4. Copy the displayed token
|
||||
#
|
||||
# IMPORTANT:
|
||||
# - Tokens are SINGLE-USE: one token = one runner registration
|
||||
# - Generate a new token for each server you deploy to
|
||||
# - Token expires if not used within a certain time
|
||||
vault_act_runner_token: "<your-registration-token-here>"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Package Registry Configuration
|
||||
# -----------------------------------------------------------------------------
|
||||
# These values enable the runner to authenticate with Gitea's package registry.
|
||||
# This is needed if your workflows push/pull container images or packages.
|
||||
|
||||
# Hostname of the Gitea package registry.
|
||||
# Usually the same as your Gitea instance hostname (without https://).
|
||||
vault_gitea_registry: "git.karmaxplan.ru"
|
||||
|
||||
# Service account username for package registry operations.
|
||||
# Best practice: Create a dedicated "actions" user in Gitea for CI/CD.
|
||||
# This user should have appropriate permissions for your repositories.
|
||||
vault_gitea_actions_user: "actions"
|
||||
|
||||
# Personal Access Token (PAT) for package registry authentication.
|
||||
#
|
||||
# HOW TO CREATE THE PAT:
|
||||
# 1. Log into Gitea as the service account (e.g., "actions")
|
||||
# 2. Go to: User Settings > Applications
|
||||
# URL: {{ vault_gitea_instance_url }}/user/settings/applications
|
||||
# 3. Under "Generate New Token", enter a name (e.g., "act-runner-packages")
|
||||
# 4. Select scopes:
|
||||
# - read:package (required for pulling images)
|
||||
# - write:package (required for pushing images)
|
||||
# 5. Click "Generate Token"
|
||||
# 6. Copy the token immediately (it won't be shown again)
|
||||
#
|
||||
# SECURITY NOTES:
|
||||
# - This token grants package access - keep it secret
|
||||
# - Rotate tokens periodically
|
||||
# - Use the minimum required scopes
|
||||
vault_gitea_packages_token: "<your-packages-pat-here>"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Optional: Sudo Password (if using non-root user with password sudo)
|
||||
# -----------------------------------------------------------------------------
|
||||
# Uncomment if your ansible_user requires a password for sudo.
|
||||
# vault_sudo_password: "<your-sudo-password-here>"
|
||||
99
inventory/hosts.yml
Normal file
99
inventory/hosts.yml
Normal file
@@ -0,0 +1,99 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Ansible Inventory - Gitea Act Runner Servers
|
||||
# =============================================================================
|
||||
#
|
||||
# This file defines which servers the playbook will deploy to.
|
||||
# Each host should be reachable via SSH with the specified ansible_user.
|
||||
#
|
||||
# HOW TO USE:
|
||||
# 1. Replace the example hosts with your actual server IPs/hostnames
|
||||
# 2. Set the correct SSH user (ansible_user)
|
||||
# 3. Optionally override variables per-host
|
||||
#
|
||||
# Host-specific variables can override group defaults.
|
||||
# Example: Different runner names, labels, or capacity per server.
|
||||
#
|
||||
# EXAMPLE CONFIGURATIONS:
|
||||
#
|
||||
# Single server:
|
||||
# all:
|
||||
# hosts:
|
||||
# runner:
|
||||
# ansible_host: 10.0.0.50
|
||||
# vars:
|
||||
# ansible_user: root
|
||||
#
|
||||
# Multiple servers with custom names:
|
||||
# all:
|
||||
# hosts:
|
||||
# prod-runner-01:
|
||||
# ansible_host: 10.0.0.50
|
||||
# act_runner_name: "production-01"
|
||||
# prod-runner-02:
|
||||
# ansible_host: 10.0.0.51
|
||||
# act_runner_name: "production-02"
|
||||
# vars:
|
||||
# ansible_user: deploy
|
||||
# ansible_become: true
|
||||
#
|
||||
# See: https://docs.ansible.com/ansible/latest/inventory_guide/
|
||||
# =============================================================================
|
||||
|
||||
all:
|
||||
hosts:
|
||||
# -------------------------------------------------------------------------
|
||||
# Define each runner server below
|
||||
# -------------------------------------------------------------------------
|
||||
# The key (e.g., runner-01) is the inventory_hostname.
|
||||
# Replace with your actual server details.
|
||||
|
||||
tralalero-tralala:
|
||||
# IP address or hostname for SSH connection.
|
||||
# REQUIRED: Change this to your server's address.
|
||||
ansible_host: 147.45.100.33
|
||||
|
||||
# Optional: Override runner name for this specific host.
|
||||
# Default: Uses the server's actual hostname (ansible_hostname fact).
|
||||
# Uncomment and modify if you want a custom name in Gitea UI.
|
||||
# act_runner_name: "production-runner-01"
|
||||
|
||||
# Optional: Different labels for this runner.
|
||||
# Default: ["ubuntu-latest:host"] (from role defaults)
|
||||
# Uncomment to customize what jobs this runner can handle.
|
||||
# act_runner_labels:
|
||||
# - "ubuntu-latest:host"
|
||||
# - "self-hosted:host"
|
||||
|
||||
# Uncomment and configure additional servers as needed:
|
||||
# runner-02:
|
||||
# ansible_host: 192.168.1.11
|
||||
# act_runner_name: "production-runner-02"
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Variables applied to all hosts in this inventory
|
||||
# ---------------------------------------------------------------------------
|
||||
vars:
|
||||
# SSH user for connecting to servers.
|
||||
# This user must either be root, or have sudo privileges.
|
||||
# REQUIRED: Change this to match your server access.
|
||||
ansible_user: root
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Alternative: Use a non-root user with sudo
|
||||
# ---------------------------------------------------------------------------
|
||||
# If you connect as a regular user that has sudo access, uncomment these:
|
||||
# ansible_user: deploy
|
||||
# ansible_become: true
|
||||
# ansible_become_method: sudo
|
||||
# ansible_become_password: "{{ vault_sudo_password }}" # If password required
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# SSH Configuration (optional)
|
||||
# ---------------------------------------------------------------------------
|
||||
# Uncomment if you need to specify SSH key or port:
|
||||
# ansible_ssh_private_key_file: ~/.ssh/id_rsa
|
||||
# ansible_port: 22
|
||||
|
||||
# Disable host key checking for new servers (not recommended for production):
|
||||
# ansible_ssh_common_args: '-o StrictHostKeyChecking=no'
|
||||
97
playbook.yml
Normal file
97
playbook.yml
Normal file
@@ -0,0 +1,97 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Gitea Act Runner - Deployment Playbook
|
||||
# =============================================================================
|
||||
#
|
||||
# This playbook deploys and configures Gitea Act Runner on Ubuntu servers.
|
||||
#
|
||||
# USAGE:
|
||||
# # Standard deployment (interactive vault password prompt):
|
||||
# ansible-playbook -i inventory/hosts.yml playbook.yml --ask-vault-pass
|
||||
#
|
||||
# # Dry run (preview changes without applying):
|
||||
# ansible-playbook -i inventory/hosts.yml playbook.yml --check --diff --ask-vault-pass
|
||||
#
|
||||
# # Deploy to specific hosts only:
|
||||
# ansible-playbook -i inventory/hosts.yml playbook.yml --limit runner-01 --ask-vault-pass
|
||||
#
|
||||
# PREREQUISITES:
|
||||
# - Ansible 2.15+ on control machine
|
||||
# - SSH access to target servers (root or sudo user)
|
||||
# - Vault password for encrypted secrets (group_vars/vault.yml)
|
||||
# - Target servers running Ubuntu 20.04 or later
|
||||
#
|
||||
# WHAT THIS PLAYBOOK DOES:
|
||||
# 1. Validates target OS is supported (Ubuntu 20.04+)
|
||||
# 2. Updates apt package cache
|
||||
# 3. Installs Docker CE
|
||||
# 4. Installs Node.js LTS via NodeSource
|
||||
# 5. Downloads and installs act_runner binary
|
||||
# 6. Creates act_runner system user
|
||||
# 7. Deploys configuration and registers with Gitea
|
||||
# 8. Sets up systemd service for automatic startup
|
||||
# 9. Verifies all components are working
|
||||
#
|
||||
# DOCUMENTATION:
|
||||
# - Gitea Actions: https://docs.gitea.com/usage/actions/overview
|
||||
# - Act Runner: https://docs.gitea.com/usage/actions/act-runner
|
||||
# - Ansible: https://docs.ansible.com/ansible/latest/
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
- name: Deploy Gitea Act Runner
|
||||
hosts: all
|
||||
become: true
|
||||
gather_facts: true
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Pre-tasks: Validation and preparation before role execution
|
||||
# ---------------------------------------------------------------------------
|
||||
pre_tasks:
|
||||
# Fail early if the target OS is not supported.
|
||||
# This prevents confusing errors later in the playbook.
|
||||
- name: Validate target operating system
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ansible_facts['distribution'] == "Ubuntu"
|
||||
- ansible_facts['distribution_major_version'] | int >= 20
|
||||
fail_msg: >-
|
||||
This playbook requires Ubuntu 20.04 or later.
|
||||
Detected: {{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_version'] }}
|
||||
success_msg: >-
|
||||
Target OS validated: {{ ansible_facts['distribution'] }} {{ ansible_facts['distribution_version'] }}
|
||||
|
||||
# Update apt cache before installing packages.
|
||||
# cache_valid_time prevents unnecessary updates on repeated runs.
|
||||
- name: Update apt package cache
|
||||
ansible.builtin.apt:
|
||||
update_cache: true
|
||||
cache_valid_time: 3600 # Skip update if cache is less than 1 hour old
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Roles: Main installation logic
|
||||
# ---------------------------------------------------------------------------
|
||||
roles:
|
||||
- role: act_runner
|
||||
tags:
|
||||
- act_runner
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Post-tasks: Summary and verification
|
||||
# ---------------------------------------------------------------------------
|
||||
post_tasks:
|
||||
# Display deployment summary for operator confirmation.
|
||||
# Uses variables registered during verification tasks.
|
||||
- name: Display deployment summary
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "=============================================="
|
||||
- "Gitea Act Runner - Deployment Complete"
|
||||
- "=============================================="
|
||||
- "Runner name: {{ act_runner_name }}"
|
||||
- "Gitea instance: {{ gitea_instance_url }}"
|
||||
- "Service status: {{ 'RUNNING' if act_runner_service_status.status.ActiveState == 'active' else 'NOT RUNNING' }}"
|
||||
- ""
|
||||
- "Verify in Gitea UI:"
|
||||
- " {{ gitea_instance_url }}/-/admin/actions/runners"
|
||||
- "=============================================="
|
||||
20
pyproject.toml
Normal file
20
pyproject.toml
Normal file
@@ -0,0 +1,20 @@
|
||||
# =============================================================================
|
||||
# Project Configuration - Gitea Act Runner Ansible Playbook
|
||||
# =============================================================================
|
||||
# Dependency management for uv (https://docs.astral.sh/uv/)
|
||||
#
|
||||
# Usage:
|
||||
# uv sync # Install dependencies
|
||||
# uv run ansible-lint # Run linter
|
||||
# =============================================================================
|
||||
|
||||
[project]
|
||||
name = "act-runner-gitea"
|
||||
version = "0.1.0"
|
||||
description = "Ansible playbook for Gitea Act Runner deployment"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
dependencies = [
|
||||
"ansible>=2.15",
|
||||
"ansible-lint>=6.0",
|
||||
]
|
||||
99
roles/act_runner/defaults/main.yml
Normal file
99
roles/act_runner/defaults/main.yml
Normal file
@@ -0,0 +1,99 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Gitea Act Runner - Role Default Variables
|
||||
# =============================================================================
|
||||
#
|
||||
# This file defines configurable variables for the act_runner role.
|
||||
# Override these in group_vars/all.yml or inventory host_vars as needed.
|
||||
#
|
||||
# REQUIRED VARIABLES (must be set in vault - not defined here):
|
||||
# - gitea_instance_url : URL of your Gitea instance
|
||||
# - act_runner_token : Registration token from Gitea
|
||||
# - gitea_packages_token : PAT for package registry access
|
||||
# - gitea_registry : Package registry hostname
|
||||
# - gitea_actions_user : Service account username
|
||||
#
|
||||
# See group_vars/vault.yml.example for how to set these secrets.
|
||||
# See: https://docs.gitea.com/usage/actions/act-runner
|
||||
# =============================================================================
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Act Runner Binary Configuration
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Version of act_runner to install.
|
||||
# Check available versions at: https://dl.gitea.com/act_runner/
|
||||
# Format: semantic version string without 'v' prefix.
|
||||
act_runner_version: "0.2.13"
|
||||
|
||||
# Target CPU architecture for the binary download.
|
||||
# Valid values: "amd64" (x86_64), "arm64" (aarch64)
|
||||
act_runner_arch: "amd64"
|
||||
|
||||
# Whether to verify SHA256 checksum after downloading the binary.
|
||||
# STRONGLY RECOMMENDED: Leave as true for security.
|
||||
act_runner_verify_checksum: true
|
||||
|
||||
# Filesystem path where the act_runner binary will be installed.
|
||||
# /usr/local/bin is the standard FHS location for locally installed binaries.
|
||||
act_runner_bin_path: "/usr/local/bin/act_runner"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# System User Configuration
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Unix username for running the act_runner service.
|
||||
# Will be created as a system user if it doesn't exist.
|
||||
act_runner_user: "act_runner"
|
||||
|
||||
# Unix group for the act_runner user.
|
||||
act_runner_group: "act_runner"
|
||||
|
||||
# Home directory for the act_runner user.
|
||||
# Stores: .runner file, cache, working directories.
|
||||
act_runner_home: "/home/act_runner"
|
||||
|
||||
# Directory for act_runner configuration files.
|
||||
# Stores: config.yaml
|
||||
act_runner_config_dir: "/etc/act_runner"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Node.js Configuration
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Node.js major version to install via NodeSource.
|
||||
# Required for JavaScript-based GitHub Actions.
|
||||
# Valid values: "18", "20", "22", "24"
|
||||
# See: https://nodejs.org/en/about/previous-releases
|
||||
act_runner_nodejs_version: "24"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Runner Configuration
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Human-readable name for this runner instance.
|
||||
# Displayed in Gitea UI under Actions > Runners.
|
||||
# Default: server's hostname
|
||||
act_runner_name: "{{ ansible_facts['hostname'] }}"
|
||||
|
||||
# Labels determine which jobs this runner can execute.
|
||||
# Format: "label-name:executor"
|
||||
# Executors:
|
||||
# - "host" : Run directly on the host system
|
||||
# - "docker://image" : Run in Docker container
|
||||
#
|
||||
# Examples:
|
||||
# - "ubuntu-latest:host"
|
||||
# - "ubuntu-latest:docker://node:24"
|
||||
# - "self-hosted:host"
|
||||
act_runner_labels:
|
||||
- "ubuntu-latest:host"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Container Behavior
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Whether to always pull container images before running jobs.
|
||||
# true: Ensures latest image (recommended for CI/CD)
|
||||
# false: Uses cached image if available (faster)
|
||||
act_runner_container_force_pull: true
|
||||
26
roles/act_runner/handlers/main.yml
Normal file
26
roles/act_runner/handlers/main.yml
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Gitea Act Runner - Ansible Handlers
|
||||
# =============================================================================
|
||||
#
|
||||
# Handlers are triggered by 'notify' in tasks and run once at the end of play.
|
||||
# They provide a way to restart services only when configuration changes.
|
||||
#
|
||||
# Usage in tasks:
|
||||
# - name: Deploy config
|
||||
# template: ...
|
||||
# notify: restart act_runner
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
# Reload systemd configuration after unit file changes.
|
||||
# Required before systemctl can see updated unit files.
|
||||
- name: Reload systemd
|
||||
ansible.builtin.systemd:
|
||||
daemon_reload: true
|
||||
|
||||
# Restart the act_runner service to apply configuration changes.
|
||||
- name: Restart act_runner
|
||||
ansible.builtin.systemd:
|
||||
name: act_runner
|
||||
state: restarted
|
||||
88
roles/act_runner/tasks/binary.yml
Normal file
88
roles/act_runner/tasks/binary.yml
Normal file
@@ -0,0 +1,88 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Gitea Act Runner - Binary Installation
|
||||
# =============================================================================
|
||||
#
|
||||
# Downloads and installs the act_runner binary from:
|
||||
# https://dl.gitea.com/act_runner/
|
||||
#
|
||||
# Security: Binary integrity is verified via SHA256 checksum.
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
# Construct download URLs based on version and architecture.
|
||||
- name: Set act_runner download URLs
|
||||
ansible.builtin.set_fact:
|
||||
act_runner_download_url: >-
|
||||
https://dl.gitea.com/act_runner/{{ act_runner_version }}/act_runner-{{ act_runner_version }}-linux-{{ act_runner_arch }}
|
||||
act_runner_checksum_url: >-
|
||||
https://dl.gitea.com/act_runner/{{ act_runner_version }}/act_runner-{{ act_runner_version }}-linux-{{ act_runner_arch }}.sha256
|
||||
|
||||
# Download the act_runner binary to a temporary location.
|
||||
- name: Download act_runner binary
|
||||
ansible.builtin.get_url:
|
||||
url: "{{ act_runner_download_url }}"
|
||||
dest: /tmp/act_runner
|
||||
mode: '0755'
|
||||
|
||||
# Download checksum file for verification (when enabled).
|
||||
- name: Download act_runner checksum
|
||||
ansible.builtin.get_url:
|
||||
url: "{{ act_runner_checksum_url }}"
|
||||
dest: /tmp/act_runner.sha256
|
||||
mode: '0644'
|
||||
when: act_runner_verify_checksum
|
||||
|
||||
# Read the expected checksum from the downloaded file.
|
||||
- name: Read expected checksum
|
||||
ansible.builtin.slurp:
|
||||
src: /tmp/act_runner.sha256
|
||||
register: act_runner_expected_checksum_file
|
||||
when: act_runner_verify_checksum
|
||||
|
||||
# Parse the checksum (format: "checksum filename").
|
||||
- name: Parse expected checksum
|
||||
ansible.builtin.set_fact:
|
||||
act_runner_expected_checksum: "{{ (act_runner_expected_checksum_file.content | b64decode).split()[0] }}"
|
||||
when: act_runner_verify_checksum
|
||||
|
||||
# Calculate actual checksum of downloaded binary.
|
||||
- name: Calculate actual checksum
|
||||
ansible.builtin.stat:
|
||||
path: /tmp/act_runner
|
||||
checksum_algorithm: sha256
|
||||
register: act_runner_actual_checksum
|
||||
when: act_runner_verify_checksum
|
||||
|
||||
# Verify checksums match (fail if tampered).
|
||||
- name: Verify checksum matches
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- act_runner_actual_checksum.stat.checksum == act_runner_expected_checksum
|
||||
fail_msg: >-
|
||||
Checksum verification FAILED!
|
||||
Expected: {{ act_runner_expected_checksum }}
|
||||
Actual: {{ act_runner_actual_checksum.stat.checksum }}
|
||||
The downloaded binary may have been tampered with.
|
||||
success_msg: "Checksum verified: {{ act_runner_expected_checksum }}"
|
||||
when: act_runner_verify_checksum
|
||||
|
||||
# Install binary to final location.
|
||||
- name: Install act_runner binary
|
||||
ansible.builtin.copy:
|
||||
src: /tmp/act_runner
|
||||
dest: "{{ act_runner_bin_path }}"
|
||||
remote_src: true
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0755'
|
||||
notify: Restart act_runner
|
||||
|
||||
# Clean up temporary files.
|
||||
- name: Clean up temporary files
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: absent
|
||||
loop:
|
||||
- /tmp/act_runner
|
||||
- /tmp/act_runner.sha256
|
||||
56
roles/act_runner/tasks/config.yml
Normal file
56
roles/act_runner/tasks/config.yml
Normal file
@@ -0,0 +1,56 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Gitea Act Runner - Configuration and Registration
|
||||
# =============================================================================
|
||||
#
|
||||
# Deploys the runner configuration and registers with Gitea.
|
||||
# Registration is idempotent: only runs if .runner file doesn't exist.
|
||||
#
|
||||
# The .runner file contains the runner's identity after registration.
|
||||
# DO NOT DELETE this file or re-registration will be required.
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
# Deploy configuration file from template.
|
||||
- name: Deploy act_runner configuration
|
||||
ansible.builtin.template:
|
||||
src: config.yaml.j2
|
||||
dest: "{{ act_runner_config_dir }}/config.yaml"
|
||||
owner: "{{ act_runner_user }}"
|
||||
group: "{{ act_runner_group }}"
|
||||
mode: '0640' # Restrictive: contains secrets
|
||||
notify: Restart act_runner
|
||||
|
||||
# Check if runner is already registered.
|
||||
# The .runner file is created during registration and persists.
|
||||
- name: Check if runner is already registered
|
||||
ansible.builtin.stat:
|
||||
path: "{{ act_runner_home }}/.runner"
|
||||
register: act_runner_runner_file
|
||||
|
||||
# Register the runner with Gitea (only if not already registered).
|
||||
# This is a one-time operation that creates the .runner file.
|
||||
- name: Register runner with Gitea
|
||||
ansible.builtin.command:
|
||||
cmd: >-
|
||||
{{ act_runner_bin_path }} register
|
||||
--no-interactive
|
||||
--config {{ act_runner_config_dir }}/config.yaml
|
||||
--instance {{ gitea_instance_url }}
|
||||
--token {{ act_runner_token }}
|
||||
--name {{ act_runner_name }}
|
||||
--labels {{ act_runner_labels | join(',') }}
|
||||
chdir: "{{ act_runner_home }}"
|
||||
become: true
|
||||
become_user: "{{ act_runner_user }}"
|
||||
when: not act_runner_runner_file.stat.exists
|
||||
register: act_runner_registration_result
|
||||
changed_when: act_runner_registration_result.rc == 0
|
||||
# Don't show token in logs
|
||||
no_log: true
|
||||
|
||||
# Display registration result (without sensitive data).
|
||||
- name: Display registration status
|
||||
ansible.builtin.debug:
|
||||
msg: >-
|
||||
Runner registration: {{ 'NEW - registered successfully' if act_runner_registration_result.changed | default(false) else 'EXISTING - already registered' }}
|
||||
91
roles/act_runner/tasks/docker.yml
Normal file
91
roles/act_runner/tasks/docker.yml
Normal file
@@ -0,0 +1,91 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Gitea Act Runner - Docker Installation
|
||||
# =============================================================================
|
||||
#
|
||||
# Installs Docker CE following the official Docker documentation:
|
||||
# https://docs.docker.com/engine/install/ubuntu/
|
||||
#
|
||||
# Uses DEB822 format (.sources) as per current Docker documentation.
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
# Remove old/conflicting Docker packages that may interfere.
|
||||
- name: Remove conflicting Docker packages
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- docker.io
|
||||
- docker-doc
|
||||
- docker-compose
|
||||
- docker-compose-v2
|
||||
- podman-docker
|
||||
- containerd
|
||||
- runc
|
||||
state: absent
|
||||
failed_when: false
|
||||
|
||||
# Install packages required to add Docker's APT repository.
|
||||
- name: Install Docker prerequisites
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- ca-certificates
|
||||
- curl
|
||||
state: present
|
||||
|
||||
# Create directory for APT keyrings.
|
||||
- name: Create keyrings directory
|
||||
ansible.builtin.file:
|
||||
path: /etc/apt/keyrings
|
||||
state: directory
|
||||
mode: '0755'
|
||||
|
||||
# Download Docker's official GPG key.
|
||||
- name: Download Docker GPG key
|
||||
ansible.builtin.get_url:
|
||||
url: https://download.docker.com/linux/ubuntu/gpg
|
||||
dest: /etc/apt/keyrings/docker.asc
|
||||
mode: '0644'
|
||||
|
||||
# Get the dpkg architecture for the repository URL.
|
||||
- name: Get dpkg architecture
|
||||
ansible.builtin.command: dpkg --print-architecture
|
||||
register: act_runner_dpkg_arch
|
||||
changed_when: false
|
||||
|
||||
# Add Docker's APT repository using DEB822 format.
|
||||
# This is the modern format recommended by Docker documentation.
|
||||
- name: Add Docker APT repository (DEB822 format)
|
||||
ansible.builtin.copy:
|
||||
dest: /etc/apt/sources.list.d/docker.sources
|
||||
mode: '0644'
|
||||
content: |
|
||||
Types: deb
|
||||
URIs: https://download.docker.com/linux/ubuntu
|
||||
Suites: {{ ansible_facts['distribution_release'] }}
|
||||
Components: stable
|
||||
Architectures: {{ act_runner_dpkg_arch.stdout }}
|
||||
Signed-By: /etc/apt/keyrings/docker.asc
|
||||
|
||||
# Update apt cache after adding repository.
|
||||
- name: Update apt cache
|
||||
ansible.builtin.apt:
|
||||
update_cache: true
|
||||
cache_valid_time: 0 # Force update since we just added a new repo
|
||||
|
||||
# Install Docker CE and related packages.
|
||||
- name: Install Docker packages
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- docker-ce
|
||||
- docker-ce-cli
|
||||
- containerd.io
|
||||
- docker-buildx-plugin
|
||||
- docker-compose-plugin
|
||||
state: present
|
||||
|
||||
# Ensure Docker service is running and enabled on boot.
|
||||
- name: Ensure Docker service is started and enabled
|
||||
ansible.builtin.systemd:
|
||||
name: docker
|
||||
state: started
|
||||
enabled: true
|
||||
75
roles/act_runner/tasks/main.yml
Normal file
75
roles/act_runner/tasks/main.yml
Normal file
@@ -0,0 +1,75 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Gitea Act Runner - Main Task Orchestration
|
||||
# =============================================================================
|
||||
#
|
||||
# This file orchestrates the act_runner installation in the correct order.
|
||||
# Each include_tasks imports a focused task file for better maintainability.
|
||||
#
|
||||
# Execution order matters:
|
||||
# 1. Validate inputs (fail fast on missing required values)
|
||||
# 2. Install Docker (required for container operations in Actions)
|
||||
# 3. Install Node.js (required for JavaScript-based GitHub Actions)
|
||||
# 4. Download act_runner binary (the core component)
|
||||
# 5. Create system user (security: run as unprivileged user)
|
||||
# 6. Configure and register (connect to Gitea instance)
|
||||
# 7. Setup systemd service (enable automatic startup)
|
||||
# 8. Verify installation (ensure everything works)
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
# Fail early if required variables are not set.
|
||||
# This prevents partial installations that would be harder to debug.
|
||||
- name: Validate required variables are defined
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- gitea_instance_url is defined
|
||||
- gitea_instance_url | length > 0
|
||||
- act_runner_token is defined
|
||||
- act_runner_token | length > 0
|
||||
- gitea_packages_token is defined
|
||||
- gitea_packages_token | length > 0
|
||||
- gitea_registry is defined
|
||||
- gitea_registry | length > 0
|
||||
- gitea_actions_user is defined
|
||||
- gitea_actions_user | length > 0
|
||||
fail_msg: >-
|
||||
Missing required variables. Ensure these are set in vault:
|
||||
gitea_instance_url, act_runner_token, gitea_packages_token,
|
||||
gitea_registry, gitea_actions_user.
|
||||
See group_vars/vault.yml.example for details.
|
||||
success_msg: "All required variables are defined"
|
||||
|
||||
# Docker is needed even for host execution because many GitHub Actions
|
||||
# use Docker internally (e.g., actions/checkout uses node in container).
|
||||
- name: Install and configure Docker
|
||||
ansible.builtin.include_tasks: docker.yml
|
||||
|
||||
# Node.js is required for JavaScript-based GitHub Actions.
|
||||
# Many popular actions (checkout, cache, upload-artifact) need Node.js.
|
||||
- name: Install Node.js runtime
|
||||
ansible.builtin.include_tasks: nodejs.yml
|
||||
|
||||
# Download and install the act_runner binary with checksum verification.
|
||||
- name: Install act_runner binary
|
||||
ansible.builtin.include_tasks: binary.yml
|
||||
|
||||
# Create dedicated system user for security isolation.
|
||||
# The runner should not run as root.
|
||||
- name: Create act_runner system user
|
||||
ansible.builtin.include_tasks: user.yml
|
||||
|
||||
# Deploy configuration and register with Gitea instance.
|
||||
# Registration only happens if .runner file doesn't exist (idempotent).
|
||||
- name: Configure and register runner
|
||||
ansible.builtin.include_tasks: config.yml
|
||||
|
||||
# Deploy systemd unit file for service management.
|
||||
# Enables automatic startup on boot and easy service control.
|
||||
- name: Setup systemd service
|
||||
ansible.builtin.include_tasks: systemd.yml
|
||||
|
||||
# Run verification checks to ensure installation succeeded.
|
||||
# Fails the playbook if any critical component is not working.
|
||||
- name: Verify installation
|
||||
ansible.builtin.include_tasks: verify.yml
|
||||
54
roles/act_runner/tasks/nodejs.yml
Normal file
54
roles/act_runner/tasks/nodejs.yml
Normal file
@@ -0,0 +1,54 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Gitea Act Runner - Node.js Installation
|
||||
# =============================================================================
|
||||
#
|
||||
# Installs Node.js LTS via NodeSource:
|
||||
# https://github.com/nodesource/distributions
|
||||
#
|
||||
# Node.js is required because:
|
||||
# - Many GitHub Actions are written in JavaScript
|
||||
# - Popular actions like checkout, cache, upload-artifact need Node.js
|
||||
# - The runner itself may need Node.js for certain operations
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
# Install prerequisites for NodeSource setup script.
|
||||
- name: Install Node.js prerequisites
|
||||
ansible.builtin.apt:
|
||||
name:
|
||||
- ca-certificates
|
||||
- curl
|
||||
- gnupg
|
||||
state: present
|
||||
|
||||
# Download NodeSource setup script.
|
||||
# This script adds the NodeSource APT repository.
|
||||
- name: Download NodeSource setup script
|
||||
ansible.builtin.get_url:
|
||||
url: "https://deb.nodesource.com/setup_{{ act_runner_nodejs_version }}.x"
|
||||
dest: /tmp/nodesource_setup.sh
|
||||
mode: '0755'
|
||||
|
||||
# Execute the NodeSource setup script to configure APT repository.
|
||||
# Script is safe to re-run (idempotent).
|
||||
- name: Execute NodeSource setup script
|
||||
ansible.builtin.command:
|
||||
cmd: /tmp/nodesource_setup.sh
|
||||
args:
|
||||
creates: /etc/apt/sources.list.d/nodesource.list
|
||||
register: act_runner_nodesource_result
|
||||
changed_when: act_runner_nodesource_result.rc == 0
|
||||
|
||||
# Install Node.js from NodeSource repository.
|
||||
- name: Install Node.js
|
||||
ansible.builtin.apt:
|
||||
name: nodejs
|
||||
state: present
|
||||
update_cache: true
|
||||
|
||||
# Clean up setup script.
|
||||
- name: Remove NodeSource setup script
|
||||
ansible.builtin.file:
|
||||
path: /tmp/nodesource_setup.sh
|
||||
state: absent
|
||||
37
roles/act_runner/tasks/systemd.yml
Normal file
37
roles/act_runner/tasks/systemd.yml
Normal file
@@ -0,0 +1,37 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Gitea Act Runner - Systemd Service Setup
|
||||
# =============================================================================
|
||||
#
|
||||
# Creates and enables the systemd service for act_runner.
|
||||
# This ensures the runner:
|
||||
# - Starts automatically on boot
|
||||
# - Restarts if it crashes
|
||||
# - Can be controlled via systemctl
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
# Deploy systemd service unit file from template.
|
||||
- name: Deploy systemd service file
|
||||
ansible.builtin.template:
|
||||
src: act_runner.service.j2
|
||||
dest: /etc/systemd/system/act_runner.service
|
||||
owner: root
|
||||
group: root
|
||||
mode: '0644'
|
||||
notify:
|
||||
- Reload systemd
|
||||
- Restart act_runner
|
||||
|
||||
# Reload systemd to pick up the new/changed unit file.
|
||||
# This is immediate (not via handler) to ensure service can be started.
|
||||
- name: Reload systemd daemon
|
||||
ansible.builtin.systemd:
|
||||
daemon_reload: true
|
||||
|
||||
# Enable and start the act_runner service.
|
||||
- name: Enable and start act_runner service
|
||||
ansible.builtin.systemd:
|
||||
name: act_runner
|
||||
state: started
|
||||
enabled: true
|
||||
54
roles/act_runner/tasks/user.yml
Normal file
54
roles/act_runner/tasks/user.yml
Normal file
@@ -0,0 +1,54 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Gitea Act Runner - System User Setup
|
||||
# =============================================================================
|
||||
#
|
||||
# Creates a dedicated system user for running the act_runner service.
|
||||
# Running as an unprivileged user improves security by:
|
||||
# - Limiting what the service can access
|
||||
# - Isolating it from other services
|
||||
# - Following the principle of least privilege
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
# Create the act_runner system group.
|
||||
- name: Create act_runner group
|
||||
ansible.builtin.group:
|
||||
name: "{{ act_runner_group }}"
|
||||
state: present
|
||||
system: true
|
||||
|
||||
# Create the act_runner system user.
|
||||
- name: Create act_runner user
|
||||
ansible.builtin.user:
|
||||
name: "{{ act_runner_user }}"
|
||||
group: "{{ act_runner_group }}"
|
||||
# Add to docker group for container access.
|
||||
groups: docker
|
||||
append: true
|
||||
# Use bash shell for better compatibility with actions.
|
||||
shell: /bin/bash
|
||||
# Home directory for runner data.
|
||||
home: "{{ act_runner_home }}"
|
||||
create_home: true
|
||||
# System user (no login, low UID).
|
||||
system: true
|
||||
state: present
|
||||
|
||||
# Ensure home directory has correct permissions.
|
||||
- name: Set permissions on home directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ act_runner_home }}"
|
||||
state: directory
|
||||
owner: "{{ act_runner_user }}"
|
||||
group: "{{ act_runner_group }}"
|
||||
mode: '0750'
|
||||
|
||||
# Create configuration directory.
|
||||
- name: Create configuration directory
|
||||
ansible.builtin.file:
|
||||
path: "{{ act_runner_config_dir }}"
|
||||
state: directory
|
||||
owner: "{{ act_runner_user }}"
|
||||
group: "{{ act_runner_group }}"
|
||||
mode: '0750'
|
||||
80
roles/act_runner/tasks/verify.yml
Normal file
80
roles/act_runner/tasks/verify.yml
Normal file
@@ -0,0 +1,80 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# Gitea Act Runner - Installation Verification
|
||||
# =============================================================================
|
||||
#
|
||||
# Verifies that all components were installed correctly.
|
||||
# Fails the playbook if any critical check doesn't pass.
|
||||
#
|
||||
# Verification order:
|
||||
# 1. Docker daemon is running and accessible
|
||||
# 2. Node.js is installed at the expected version
|
||||
# 3. act_runner binary is executable and reports version
|
||||
# 4. act_runner systemd service is active
|
||||
#
|
||||
# =============================================================================
|
||||
|
||||
# Verify Docker daemon is running and accessible.
|
||||
- name: Verify Docker daemon is accessible
|
||||
ansible.builtin.command: docker info
|
||||
changed_when: false
|
||||
register: act_runner_docker_info_result
|
||||
|
||||
- name: Display Docker status
|
||||
ansible.builtin.debug:
|
||||
msg: "Docker is running: {{ act_runner_docker_info_result.stdout_lines[0] | default('OK') }}"
|
||||
|
||||
# Verify Node.js is installed at the expected major version.
|
||||
- name: Verify Node.js installation
|
||||
ansible.builtin.command: node --version
|
||||
changed_when: false
|
||||
register: act_runner_node_version_result
|
||||
|
||||
- name: Verify Node.js major version matches expected
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- act_runner_node_version_result.stdout is match('^v' ~ act_runner_nodejs_version ~ '\\.')
|
||||
fail_msg: >-
|
||||
Node.js version mismatch!
|
||||
Expected: v{{ act_runner_nodejs_version }}.x
|
||||
Actual: {{ act_runner_node_version_result.stdout }}
|
||||
success_msg: "Node.js {{ act_runner_node_version_result.stdout }} installed correctly"
|
||||
|
||||
# Verify act_runner binary is installed and executable.
|
||||
- name: Verify act_runner binary
|
||||
ansible.builtin.command: "{{ act_runner_bin_path }} --version"
|
||||
changed_when: false
|
||||
register: act_runner_version_result
|
||||
|
||||
- name: Display act_runner version
|
||||
ansible.builtin.debug:
|
||||
msg: "act_runner version: {{ act_runner_version_result.stdout }}"
|
||||
|
||||
# Verify the systemd service is running.
|
||||
- name: Get act_runner service status
|
||||
ansible.builtin.systemd:
|
||||
name: act_runner
|
||||
register: act_runner_service_status
|
||||
|
||||
- name: Verify act_runner service is active
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- act_runner_service_status.status.ActiveState == "active"
|
||||
fail_msg: >-
|
||||
act_runner service is NOT running!
|
||||
State: {{ act_runner_service_status.status.ActiveState }}
|
||||
Check logs: journalctl -u act_runner -n 50
|
||||
success_msg: "act_runner service is running (PID: {{ act_runner_service_status.status.MainPID }})"
|
||||
|
||||
# Final summary.
|
||||
- name: Verification complete
|
||||
ansible.builtin.debug:
|
||||
msg:
|
||||
- "=========================================="
|
||||
- "All verification checks PASSED!"
|
||||
- "=========================================="
|
||||
- "Docker: running"
|
||||
- "Node.js: {{ act_runner_node_version_result.stdout }}"
|
||||
- "act_runner: {{ act_runner_version_result.stdout }}"
|
||||
- "Service: active (PID {{ act_runner_service_status.status.MainPID }})"
|
||||
- "=========================================="
|
||||
71
roles/act_runner/templates/act_runner.service.j2
Normal file
71
roles/act_runner/templates/act_runner.service.j2
Normal file
@@ -0,0 +1,71 @@
|
||||
# =============================================================================
|
||||
# Gitea Act Runner - Systemd Service Unit
|
||||
# =============================================================================
|
||||
# Managed by Ansible - DO NOT EDIT MANUALLY
|
||||
#
|
||||
# Common commands:
|
||||
# systemctl status act_runner - Check service status
|
||||
# systemctl restart act_runner - Restart the service
|
||||
# journalctl -u act_runner -f - Follow service logs
|
||||
#
|
||||
# See: https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html
|
||||
# =============================================================================
|
||||
|
||||
[Unit]
|
||||
# Human-readable description
|
||||
Description=Gitea Actions runner
|
||||
|
||||
# Documentation link
|
||||
Documentation=https://gitea.com/gitea/act_runner
|
||||
|
||||
# Start after Docker and network are available
|
||||
After=docker.service network-online.target
|
||||
|
||||
# Request network-online.target to be started
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
# Simple type: process runs in foreground
|
||||
Type=simple
|
||||
|
||||
# Main command
|
||||
ExecStart={{ act_runner_bin_path }} daemon --config {{ act_runner_config_dir }}/config.yaml
|
||||
|
||||
# Reload command (sends HUP signal)
|
||||
ExecReload=/bin/kill -s HUP $MAINPID
|
||||
|
||||
# Working directory
|
||||
WorkingDirectory={{ act_runner_home }}
|
||||
|
||||
# No timeout for start/stop (jobs may take long)
|
||||
TimeoutSec=0
|
||||
|
||||
# Wait before restarting after failure
|
||||
RestartSec=10
|
||||
|
||||
# Always restart on any exit
|
||||
Restart=always
|
||||
|
||||
# Run as unprivileged user
|
||||
User={{ act_runner_user }}
|
||||
Group={{ act_runner_group }}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Security Hardening
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
# No new privileges via setuid/setgid
|
||||
NoNewPrivileges=true
|
||||
|
||||
# Make /usr, /boot, /efi read-only
|
||||
ProtectSystem=strict
|
||||
|
||||
# Allow writes only to these paths
|
||||
ReadWritePaths={{ act_runner_home }} {{ act_runner_config_dir }}
|
||||
|
||||
# Private /tmp directory
|
||||
PrivateTmp=true
|
||||
|
||||
[Install]
|
||||
# Start on normal boot
|
||||
WantedBy=multi-user.target
|
||||
113
roles/act_runner/templates/config.yaml.j2
Normal file
113
roles/act_runner/templates/config.yaml.j2
Normal file
@@ -0,0 +1,113 @@
|
||||
# =============================================================================
|
||||
# Gitea Act Runner - Configuration File
|
||||
# =============================================================================
|
||||
# Managed by Ansible - DO NOT EDIT MANUALLY
|
||||
#
|
||||
# To modify settings, update the role variables and re-run the playbook.
|
||||
#
|
||||
# Reference: https://docs.gitea.com/usage/actions/act-runner
|
||||
# =============================================================================
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Logging Configuration
|
||||
# -----------------------------------------------------------------------------
|
||||
log:
|
||||
# Log verbosity level.
|
||||
# Valid values: trace, debug, info, warn, error, fatal
|
||||
level: info
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Runner Core Configuration
|
||||
# -----------------------------------------------------------------------------
|
||||
runner:
|
||||
# Path to the runner registration state file.
|
||||
# Created during 'act_runner register'. DO NOT DELETE.
|
||||
file: {{ act_runner_home }}/.runner
|
||||
|
||||
# Maximum number of concurrent jobs.
|
||||
capacity: 1
|
||||
|
||||
# Environment variables injected into every job.
|
||||
envs:
|
||||
# Package registry hostname
|
||||
registry: {{ gitea_registry }}
|
||||
|
||||
# Service account username
|
||||
actions_user: {{ gitea_actions_user }}
|
||||
|
||||
# PAT for package registry authentication
|
||||
PACKAGES_TOKEN: {{ gitea_packages_token }}
|
||||
|
||||
# Optional file for additional environment variables.
|
||||
env_file: .env
|
||||
|
||||
# Maximum job duration (also limited by Gitea instance).
|
||||
timeout: 3h
|
||||
|
||||
# Grace period for jobs during shutdown.
|
||||
shutdown_timeout: 0s
|
||||
|
||||
# Skip TLS verification. WARNING: Security risk if true.
|
||||
insecure: false
|
||||
|
||||
# Job polling settings.
|
||||
fetch_timeout: 5s
|
||||
fetch_interval: 2s
|
||||
|
||||
# Labels determine which jobs this runner handles.
|
||||
labels:
|
||||
{% for label in act_runner_labels %}
|
||||
- "{{ label }}"
|
||||
{% endfor %}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Cache Server Configuration
|
||||
# -----------------------------------------------------------------------------
|
||||
cache:
|
||||
# Enable built-in cache server for actions/cache.
|
||||
enabled: true
|
||||
|
||||
# Cache storage directory (empty = default).
|
||||
dir: ""
|
||||
|
||||
# Network settings (empty = auto-detect).
|
||||
host: ""
|
||||
port: 0
|
||||
|
||||
# External cache server URL (empty = use built-in).
|
||||
external_server: ""
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Container Execution Configuration
|
||||
# -----------------------------------------------------------------------------
|
||||
container:
|
||||
# Docker network (empty = isolated per job).
|
||||
network: ""
|
||||
|
||||
# Privileged mode. WARNING: Security risk if true.
|
||||
privileged: false
|
||||
|
||||
# Additional docker run options.
|
||||
options:
|
||||
|
||||
# Working directory inside containers.
|
||||
workdir_parent:
|
||||
|
||||
# Allowed volume mounts (empty = none, ["**"] = any).
|
||||
valid_volumes: []
|
||||
|
||||
# Docker daemon (empty = auto-detect).
|
||||
docker_host: ""
|
||||
|
||||
# Always pull images before jobs.
|
||||
force_pull: {{ act_runner_container_force_pull | lower }}
|
||||
|
||||
# Rebuild images even if they exist.
|
||||
force_rebuild: false
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Host Execution Configuration
|
||||
# -----------------------------------------------------------------------------
|
||||
host:
|
||||
# Working directory for host execution.
|
||||
workdir_parent:
|
||||
Reference in New Issue
Block a user