## Summary - Add 2G swap on runner to prevent OOM crashes - Limit job container memory to 1536MB - Restrict runner concurrency to 1 job at a time - Disable cache to avoid Docker network connectivity issues (`ETIMEDOUT 172.17.0.2`) - Configure job containers with `--add-host` for private network gitea resolution ## Test plan - [x] Runner survives Go builds that previously OOM-killed the server - [ ] Verify swap is active after fresh provision (`swapon --show`) - [ ] Confirm job containers respect memory limit 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: #8 Co-authored-by: M.V. Hutz <git@maximhutz.me> Co-committed-by: M.V. Hutz <git@maximhutz.me>
179 lines
4.8 KiB
YAML
179 lines
4.8 KiB
YAML
- name: Set up runner host via jumphost.
|
|
gather_facts: false
|
|
hosts: localhost
|
|
vars_files:
|
|
- ../vault.yml
|
|
- ../dist/terraform_outputs.yml
|
|
tasks:
|
|
- name: Add gitea server as jumphost.
|
|
ansible.builtin.add_host:
|
|
name: server
|
|
ansible_ssh_host: "{{ server_ip.value }}"
|
|
ansible_user: root
|
|
ansible_port: 2222
|
|
ansible_private_key_file: "{{ secret.private_ssh_key_path }}"
|
|
|
|
- name: Add runner host (via jumphost).
|
|
ansible.builtin.add_host:
|
|
name: runner
|
|
ansible_ssh_host: "{{ runner_ip.value }}"
|
|
ansible_user: root
|
|
ansible_private_key_file: "{{ secret.private_ssh_key_path }}"
|
|
ansible_ssh_common_args: >-
|
|
-o ProxyCommand="ssh -i {{ secret.private_ssh_key_path }} -p 2222 -W %h:%p root@{{ server_ip.value }}"
|
|
|
|
- name: Install Docker on runner.
|
|
gather_facts: true
|
|
hosts: runner
|
|
vars_files:
|
|
- ../vault.yml
|
|
- ../dist/terraform_outputs.yml
|
|
tasks:
|
|
- name: Set DNS resolver.
|
|
ansible.builtin.copy:
|
|
content: "nameserver 185.12.64.2\n"
|
|
dest: /etc/resolv.conf
|
|
mode: "0644"
|
|
|
|
- name: Install PIP.
|
|
ansible.builtin.apt:
|
|
state: present
|
|
update_cache: true
|
|
name:
|
|
- python3-pip
|
|
|
|
- name: Install needed packages.
|
|
ansible.builtin.pip:
|
|
name:
|
|
- packaging
|
|
state: present
|
|
break_system_packages: true
|
|
|
|
- name: Download Docker repository key.
|
|
ansible.builtin.apt_key:
|
|
url: https://download.docker.com/linux/debian/gpg
|
|
state: present
|
|
|
|
- name: Download Docker repository.
|
|
ansible.builtin.apt_repository:
|
|
repo: "deb https://download.docker.com/linux/debian {{ ansible_distribution_release }} stable"
|
|
state: present
|
|
|
|
- name: Remove bad packages.
|
|
ansible.builtin.apt:
|
|
state: absent
|
|
package:
|
|
- docker.io
|
|
- docker-doc
|
|
- docker-compose
|
|
- podman-docker
|
|
- containerd
|
|
- runc
|
|
|
|
- name: Download Docker dependencies.
|
|
ansible.builtin.apt:
|
|
state: present
|
|
package:
|
|
- ca-certificates
|
|
- curl
|
|
- jq
|
|
|
|
- name: Download Docker packages.
|
|
ansible.builtin.apt:
|
|
state: present
|
|
update_cache: true
|
|
package:
|
|
- docker-ce
|
|
- docker-ce-cli
|
|
- containerd.io
|
|
- docker-buildx-plugin
|
|
- docker-compose-plugin
|
|
|
|
- name: Configure swap on runner.
|
|
hosts: runner
|
|
gather_facts: false
|
|
tasks:
|
|
- name: Create swapfile.
|
|
ansible.builtin.command:
|
|
cmd: fallocate -l 2G /swapfile
|
|
creates: /swapfile
|
|
|
|
- name: Set swapfile permissions.
|
|
ansible.builtin.file:
|
|
path: /swapfile
|
|
mode: "0600"
|
|
|
|
- name: Check if swap is active.
|
|
ansible.builtin.command:
|
|
cmd: swapon --show=NAME --noheadings
|
|
register: swap_status
|
|
changed_when: false
|
|
|
|
- name: Format swapfile.
|
|
ansible.builtin.command:
|
|
cmd: mkswap /swapfile
|
|
when: "'/swapfile' not in swap_status.stdout"
|
|
changed_when: true
|
|
|
|
- name: Enable swapfile.
|
|
ansible.builtin.command:
|
|
cmd: swapon /swapfile
|
|
when: "'/swapfile' not in swap_status.stdout"
|
|
changed_when: true
|
|
|
|
- name: Add swapfile to fstab.
|
|
ansible.posix.mount:
|
|
path: none
|
|
src: /swapfile
|
|
fstype: swap
|
|
opts: sw
|
|
state: present
|
|
|
|
- name: Register and start Gitea runner.
|
|
hosts: runner
|
|
gather_facts: false
|
|
vars_files:
|
|
- ../vault.yml
|
|
- ../dist/terraform_outputs.yml
|
|
vars:
|
|
gitea_hostname: "{{ server_fqdn.value }}"
|
|
gitea_internal_url: "https://{{ gitea_hostname }}"
|
|
tasks:
|
|
- name: Create runner data volume.
|
|
community.docker.docker_volume:
|
|
name: runner-data
|
|
state: present
|
|
|
|
- name: Generate runner config.
|
|
ansible.builtin.copy:
|
|
dest: /root/runner-config.yaml
|
|
mode: "0644"
|
|
content: |
|
|
runner:
|
|
insecure: true
|
|
capacity: 1
|
|
cache:
|
|
enabled: false
|
|
container:
|
|
options: "--add-host {{ gitea_hostname }}:10.0.1.2 --memory=1536m"
|
|
valid_volumes:
|
|
- /var/run/docker.sock
|
|
|
|
- name: Start Gitea runner container.
|
|
community.docker.docker_container:
|
|
name: gitea-runner
|
|
image: gitea/act_runner:latest
|
|
state: started
|
|
recreate: true
|
|
restart_policy: unless-stopped
|
|
etc_hosts: "{{ {gitea_hostname: '10.0.1.2'} }}"
|
|
volumes:
|
|
- runner-data:/data
|
|
- /var/run/docker.sock:/var/run/docker.sock
|
|
- /root/runner-config.yaml:/config.yaml:ro
|
|
env:
|
|
GITEA_INSTANCE_URL: "{{ gitea_internal_url }}"
|
|
GITEA_RUNNER_REGISTRATION_TOKEN: "{{ secret.runner_registration_token }}"
|
|
GITEA_RUNNER_NAME: "runner-01"
|
|
CONFIG_FILE: "/config.yaml"
|