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:
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 }})"
|
||||
- "=========================================="
|
||||
Reference in New Issue
Block a user