Adding gitea act_runner roles
This commit is contained in:
@@ -75,6 +75,16 @@ The mail role deploys four containers on `mail_internal`: `mail-db` (PostgreSQL
|
|||||||
- Fetchmail 6.6.x rcfile syntax: `ssl` is a user-level option (inline after `password`), port is `smtphost dovecot/24` (slash-separated), `smtpport` keyword does not exist
|
- Fetchmail 6.6.x rcfile syntax: `ssl` is a user-level option (inline after `password`), port is `smtphost dovecot/24` (slash-separated), `smtpport` keyword does not exist
|
||||||
- `mail.ladkau.de` is the Roundcube webmail client, not an MTA — no outgoing SMTP server is configured
|
- `mail.ladkau.de` is the Roundcube webmail client, not an MTA — no outgoing SMTP server is configured
|
||||||
|
|
||||||
|
### Gitea Actions runners
|
||||||
|
|
||||||
|
The `act_runner` role deploys three `gitea/act_runner` containers (Docker executor). Each runner handles one concurrent job. Key details:
|
||||||
|
|
||||||
|
- Runners connect to Gitea via the public HTTPS URL — no internal Docker network needed
|
||||||
|
- Each runner gets its own data dir (`/opt/act_runner/runner-N/`) for its `.runner` registration file
|
||||||
|
- All runners share a single `config.yml` at `/opt/act_runner/config.yml`
|
||||||
|
- `/var/run/docker.sock` is mounted — job containers are spawned directly on the host
|
||||||
|
- `gitea_runner_registration_token` is obtained from Gitea admin UI **after** Gitea is running; add it to the vault and then deploy with `--tags act_runner`
|
||||||
|
|
||||||
### SSO
|
### SSO
|
||||||
|
|
||||||
Keycloak at `sso.ladkau.de` is the identity provider. Gitea and Nextcloud are configured post-provisioning to use it (see `docs/runbook-configuration.md`).
|
Keycloak at `sso.ladkau.de` is the identity provider. Gitea and Nextcloud are configured post-provisioning to use it (see `docs/runbook-configuration.md`).
|
||||||
|
|||||||
@@ -89,6 +89,13 @@ roundcube_smtp_port: "587"
|
|||||||
# ssl: true # default: true
|
# ssl: true # default: true
|
||||||
# keep: true # default: true — set false to delete from source after fetch
|
# keep: true # default: true — set false to delete from source after fetch
|
||||||
|
|
||||||
|
# Gitea Actions runners (act_runner with Docker executor)
|
||||||
|
act_runner_version: "latest"
|
||||||
|
act_runner_data_dir: /opt/act_runner
|
||||||
|
act_runner_count: 3
|
||||||
|
# Secrets — store values in ansible/group_vars/all/vault.yml (Ansible Vault)
|
||||||
|
# gitea_runner_registration_token: "" # Gitea admin → Site Administration → Runners → Create runner token
|
||||||
|
|
||||||
# Container registry (Docker Registry v2)
|
# Container registry (Docker Registry v2)
|
||||||
registry_data_dir: /opt/registry
|
registry_data_dir: /opt/registry
|
||||||
# Registry users — plaintext passwords, Ansible generates bcrypt hashes at deploy time
|
# Registry users — plaintext passwords, Ansible generates bcrypt hashes at deploy time
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
- name: Restart act_runner
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ act_runner_data_dir }}"
|
||||||
|
state: present
|
||||||
|
pull: missing
|
||||||
|
recreate: always
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
---
|
||||||
|
- name: Create act_runner base directory
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ act_runner_data_dir }}"
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0755"
|
||||||
|
tags: act_runner
|
||||||
|
|
||||||
|
- name: Create per-runner data directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ act_runner_data_dir }}/runner-{{ item }}"
|
||||||
|
state: directory
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0755"
|
||||||
|
loop: "{{ range(1, act_runner_count + 1) | list }}"
|
||||||
|
tags: act_runner
|
||||||
|
|
||||||
|
- name: Deploy act_runner config
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: config.yml.j2
|
||||||
|
dest: "{{ act_runner_data_dir }}/config.yml"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
notify: Restart act_runner
|
||||||
|
tags: act_runner
|
||||||
|
|
||||||
|
- name: Deploy Docker Compose file
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: docker-compose.yml.j2
|
||||||
|
dest: "{{ act_runner_data_dir }}/docker-compose.yml"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0644"
|
||||||
|
notify: Restart act_runner
|
||||||
|
tags: act_runner
|
||||||
|
|
||||||
|
- name: Start act_runner
|
||||||
|
community.docker.docker_compose_v2:
|
||||||
|
project_src: "{{ act_runner_data_dir }}"
|
||||||
|
state: present
|
||||||
|
pull: missing
|
||||||
|
tags: act_runner
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Managed by Ansible — do not edit manually
|
||||||
|
log:
|
||||||
|
level: info
|
||||||
|
|
||||||
|
runner:
|
||||||
|
file: .runner # stored in each runner's /data volume
|
||||||
|
capacity: 1 # one concurrent job per runner container
|
||||||
|
timeout: 3h
|
||||||
|
fetch_timeout: 5s
|
||||||
|
fetch_interval: 2s
|
||||||
|
|
||||||
|
cache:
|
||||||
|
enabled: false # disable built-in cache server; use actions/cache if needed
|
||||||
|
|
||||||
|
container:
|
||||||
|
network: bridge # job containers get default bridge network with internet access
|
||||||
|
privileged: false
|
||||||
|
valid_volumes:
|
||||||
|
- /tmp
|
||||||
|
force_pull: false
|
||||||
|
force_rebuild: false
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# Managed by Ansible — do not edit manually
|
||||||
|
services:
|
||||||
|
{% for i in range(1, act_runner_count + 1) %}
|
||||||
|
runner-{{ i }}:
|
||||||
|
image: gitea/act_runner:{{ act_runner_version }}
|
||||||
|
container_name: act-runner-{{ i }}
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
- GITEA_INSTANCE_URL=https://{{ domain_gitea }}
|
||||||
|
- GITEA_RUNNER_REGISTRATION_TOKEN={{ gitea_runner_registration_token }}
|
||||||
|
- GITEA_RUNNER_NAME=runner-{{ i }}
|
||||||
|
- CONFIG_FILE=/config.yml
|
||||||
|
volumes:
|
||||||
|
- {{ act_runner_data_dir }}/runner-{{ i }}:/data
|
||||||
|
- {{ act_runner_data_dir }}/config.yml:/config.yml:ro
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
{% endfor %}
|
||||||
@@ -20,7 +20,7 @@ services:
|
|||||||
- "traefik.http.routers.registry.entrypoints=websecure"
|
- "traefik.http.routers.registry.entrypoints=websecure"
|
||||||
- "traefik.http.routers.registry.tls.certresolver=letsencrypt"
|
- "traefik.http.routers.registry.tls.certresolver=letsencrypt"
|
||||||
- "traefik.http.services.registry.loadbalancer.server.port=5000"
|
- "traefik.http.services.registry.loadbalancer.server.port=5000"
|
||||||
- "traefik.http.routers.registry.middlewares=registry-buffering,rate-limit@docker"
|
- "traefik.http.routers.registry.middlewares=registry-buffering"
|
||||||
# Remove body size limit so large image layers can be pushed
|
# Remove body size limit so large image layers can be pushed
|
||||||
- "traefik.http.middlewares.registry-buffering.buffering.maxRequestBodyBytes=0"
|
- "traefik.http.middlewares.registry-buffering.buffering.maxRequestBodyBytes=0"
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
- docker
|
- docker
|
||||||
- traefik
|
- traefik
|
||||||
- gitea
|
- gitea
|
||||||
|
- act_runner
|
||||||
- nextcloud
|
- nextcloud
|
||||||
- sso
|
- sso
|
||||||
- mail
|
- mail
|
||||||
|
|||||||
@@ -209,6 +209,55 @@ With the alias in place you can use the shorter SCP-like URL:
|
|||||||
git clone git@gitea.ladkau.de:<username>/myrepo.git
|
git clone git@gitea.ladkau.de:<username>/myrepo.git
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 3.4 Deploy Gitea Actions runners
|
||||||
|
|
||||||
|
Three `act_runner` containers (Docker executor) are provisioned by the
|
||||||
|
`act_runner` Ansible role. Each runner handles one concurrent job; together
|
||||||
|
they allow up to three parallel workflow jobs.
|
||||||
|
|
||||||
|
**This step requires Gitea to be running and the admin account to exist
|
||||||
|
(step 3.1). Runners cannot register until a token is obtained from Gitea.**
|
||||||
|
|
||||||
|
**Step 1 — Get a runner registration token**
|
||||||
|
|
||||||
|
1. Go to `https://gitea.ladkau.de` → sign in as admin.
|
||||||
|
2. Navigate to **Site Administration** (top-right menu) →
|
||||||
|
**Actions** → **Runners**.
|
||||||
|
3. Click **Create runner token** and copy the token.
|
||||||
|
|
||||||
|
**Step 2 — Add the token to the vault**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ansible-vault edit ansible/group_vars/all/vault.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
Add the key:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
gitea_runner_registration_token: "<token-from-step-1>"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Step 3 — Deploy the runners**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ansible-playbook -i ansible/inventory.ini ansible/site.yml \
|
||||||
|
--tags act_runner --ask-vault-pass
|
||||||
|
```
|
||||||
|
|
||||||
|
Ansible creates `/opt/act_runner/` with a shared `config.yml` and three
|
||||||
|
per-runner data directories (`runner-1/`, `runner-2/`, `runner-3/`). On first
|
||||||
|
start each container auto-registers with Gitea and writes a `.runner` file to
|
||||||
|
its data directory. Subsequent restarts reuse the saved registration.
|
||||||
|
|
||||||
|
**Verify**
|
||||||
|
|
||||||
|
Back in Gitea **Site Administration → Actions → Runners**, all three runners
|
||||||
|
should appear as **Online** within a few seconds.
|
||||||
|
|
||||||
|
> **Security note:** Each runner container mounts `/var/run/docker.sock`.
|
||||||
|
> This gives workflow jobs root-equivalent access to the host Docker daemon.
|
||||||
|
> Only run workflows from trusted repositories.
|
||||||
|
|
||||||
## 4. Nextcloud
|
## 4. Nextcloud
|
||||||
|
|
||||||
The admin credentials are set via `nextcloud_admin_user` and
|
The admin credentials are set via `nextcloud_admin_user` and
|
||||||
|
|||||||
@@ -121,6 +121,10 @@ registry_users:
|
|||||||
- username: alice
|
- username: alice
|
||||||
password: "your-password"
|
password: "your-password"
|
||||||
|
|
||||||
|
# Gitea Actions runners — token obtained after Gitea is running
|
||||||
|
# See step 3.4 of runbook-configuration.md; replace after Gitea admin account is created
|
||||||
|
gitea_runner_registration_token: "placeholder"
|
||||||
|
|
||||||
# Vaultwarden password vault
|
# Vaultwarden password vault
|
||||||
vaultwarden_admin_token: "" # generate: openssl rand -hex 32
|
vaultwarden_admin_token: "" # generate: openssl rand -hex 32
|
||||||
# vaultwarden_sso_client_secret is added after Keycloak is configured — see
|
# vaultwarden_sso_client_secret is added after Keycloak is configured — see
|
||||||
@@ -204,19 +208,27 @@ ansible-playbook -i ansible/inventory.ini ansible/site.yml --ask-vault-pass
|
|||||||
This runs all roles in order:
|
This runs all roles in order:
|
||||||
|
|
||||||
| # | Role | What it does |
|
| # | Role | What it does |
|
||||||
|---|------------|--------------|
|
|----|---------------|--------------|
|
||||||
| 1 | `base` | OS hardening, deploy user, SSH config, ufw firewall, fail2ban |
|
| 1 | `base` | OS hardening, deploy user, SSH config, ufw firewall, fail2ban |
|
||||||
| 2 | `docker` | Docker Engine + Compose plugin, shared Traefik network |
|
| 2 | `docker` | Docker Engine + Compose plugin, shared Traefik network |
|
||||||
| 3 | `traefik` | Reverse proxy, automatic TLS via Let's Encrypt |
|
| 3 | `traefik` | Reverse proxy, automatic TLS via Let's Encrypt |
|
||||||
| 4 | `gitea` | Self-hosted Git with PostgreSQL |
|
| 4 | `gitea` | Self-hosted Git with PostgreSQL |
|
||||||
| 5 | `nextcloud`| File storage with PostgreSQL, Redis, cron sidecar |
|
| 5 | `act_runner` | Three Gitea Actions runners with Docker executor |
|
||||||
| 6 | `sso` | Keycloak single sign-on with PostgreSQL |
|
| 6 | `nextcloud` | File storage with PostgreSQL, Redis, cron sidecar |
|
||||||
| 7 | `mail` | Roundcube webmail client with PostgreSQL |
|
| 7 | `sso` | Keycloak single sign-on with PostgreSQL |
|
||||||
| 8 | `registry` | Docker Registry v2 with htpasswd auth |
|
| 8 | `mail` | Roundcube webmail client with PostgreSQL |
|
||||||
| 9 | `k8s` | Placeholder page at k8s.ladkau.de |
|
| 9 | `registry` | Docker Registry v2 with htpasswd auth |
|
||||||
| 10 | `vaultwarden` | Vaultwarden password vault at vault.ladkau.de |
|
| 10 | `k8s` | Placeholder page at k8s.ladkau.de |
|
||||||
| 11 | `dl` | Public download server at dl.ladkau.de — nginx HTTPS + SFTP upload |
|
| 11 | `vaultwarden` | Vaultwarden password vault at vault.ladkau.de |
|
||||||
| 12 | `dashboard` | Public status dashboard at cloud.ladkau.de — service health and server stats |
|
| 12 | `dl` | Public download server at dl.ladkau.de — nginx HTTPS + SFTP upload |
|
||||||
|
| 13 | `dashboard` | Public status dashboard at cloud.ladkau.de — service health and server stats |
|
||||||
|
|
||||||
|
> **Note:** The `act_runner` role requires `gitea_runner_registration_token` in the
|
||||||
|
> vault, which can only be obtained after Gitea is running and an admin account has
|
||||||
|
> been created. On a fresh provisioning run the role will fail if the token is
|
||||||
|
> absent. Either add a placeholder and redeploy with `--tags act_runner` after
|
||||||
|
> Gitea is configured (see step 3.4 of `runbook-configuration.md`), or skip the
|
||||||
|
> role on first run: `--skip-tags act_runner`.
|
||||||
|
|
||||||
To apply a single role:
|
To apply a single role:
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user