From 0af23425f930255a763f7accc2a5e3147b248e8e Mon Sep 17 00:00:00 2001 From: Sergei Poljanski Date: Mon, 12 Oct 2026 05:31:32 +0400 Subject: [PATCH] swap: add a swapfile role, 2 GB on asxpio-ops The ops server has 3.7 GB RAM and no swap. Forgejo, MinIO and the apps fit with room to spare, but a spike (a big push, git gc, parallel image pulls) would OOM-kill a service instead of paging out. swappiness 10, so it only swaps under real pressure. Assisted-by: Claude:opus-5 --- ansible/playbooks/05-swap.yaml | 12 +++++++ ansible/roles/swap/defaults/main.yaml | 6 ++++ ansible/roles/swap/tasks/main.yaml | 49 +++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) create mode 100644 ansible/playbooks/05-swap.yaml create mode 100644 ansible/roles/swap/defaults/main.yaml create mode 100644 ansible/roles/swap/tasks/main.yaml diff --git a/ansible/playbooks/05-swap.yaml b/ansible/playbooks/05-swap.yaml new file mode 100644 index 0000000..cb514e2 --- /dev/null +++ b/ansible/playbooks/05-swap.yaml @@ -0,0 +1,12 @@ +--- +# Swapfile on the ops server (3.7 GB RAM, no swap): Forgejo, MinIO and the +# apps fit, but a spike would OOM-kill one of them instead of paging out. +# +# Usage: +# ansible-playbook playbooks/05-swap.yaml + +- name: Configure swap + hosts: ops_servers + become: true + roles: + - swap diff --git a/ansible/roles/swap/defaults/main.yaml b/ansible/roles/swap/defaults/main.yaml new file mode 100644 index 0000000..00936a2 --- /dev/null +++ b/ansible/roles/swap/defaults/main.yaml @@ -0,0 +1,6 @@ +--- +# Swapfile so a memory spike pages out instead of OOM-killing a service. +swap_file: /swapfile +swap_size_mb: 2048 +# Low: only swap under real pressure, keep the page cache for the apps. +swap_swappiness: 10 diff --git a/ansible/roles/swap/tasks/main.yaml b/ansible/roles/swap/tasks/main.yaml new file mode 100644 index 0000000..fcb84f4 --- /dev/null +++ b/ansible/roles/swap/tasks/main.yaml @@ -0,0 +1,49 @@ +--- +- name: Check for an existing swapfile + ansible.builtin.stat: + path: "{{ swap_file }}" + register: swap_stat + +- name: Create swapfile + ansible.builtin.command: + cmd: "dd if=/dev/zero of={{ swap_file }} bs=1M count={{ swap_size_mb }} status=none" + when: not swap_stat.stat.exists or (swap_stat.stat.size != swap_size_mb * 1024 * 1024) + register: swap_created + +- name: Restrict swapfile permissions + ansible.builtin.file: + path: "{{ swap_file }}" + mode: '0600' + owner: root + group: root + when: not ansible_check_mode or swap_stat.stat.exists + +- name: Format swapfile + ansible.builtin.command: + cmd: "mkswap {{ swap_file }}" + when: swap_created is changed + +- name: Add swapfile to /etc/fstab + ansible.builtin.lineinfile: + path: /etc/fstab + regexp: "^{{ swap_file }}\\s" + line: "{{ swap_file }} none swap sw 0 0" + +- name: Enable swap + ansible.builtin.command: + cmd: "swapon {{ swap_file }}" + register: swapon_result + changed_when: swapon_result.rc == 0 + failed_when: swapon_result.rc != 0 and 'busy' not in swapon_result.stderr + +- name: Set swappiness + ansible.builtin.copy: + dest: /etc/sysctl.d/90-swap.conf + content: "vm.swappiness = {{ swap_swappiness }}\n" + mode: '0644' + register: swappiness_conf + +- name: Apply swappiness + ansible.builtin.command: + cmd: sysctl -p /etc/sysctl.d/90-swap.conf + when: swappiness_conf is changed