Keepalived Installation using Ansible
Component Description
Purpose Provides seamless failover using a floating Virtual IP (VIP)
Role in Cluster Ensures clients always connect to the active primary node
Failover Trigger Monitors node health via scripts (e.g., pg_isready, replication lag)
VIP Management Automatically assigns VIP to a standby when the primary fails
Works With Tools like repmgr, Patroni, or pg_auto_failover for node promotion
Client Impact No change in connection strings; failover is transparent
Failover Speed Near-instant switch of VIP to standby after detection
Health Check Custom scripts or PostgreSQL-native commands used to verify status
Use Case Production environments needing high availability without downtime
Step 1: Create Project Directory Structure
mkdir -p ~/keepalived-ansible/roles/keepalived/{tasks,templates,files}
mkdir -p ~/keepalived-ansible/inventory
cd ~/keepalived-ansible
Step 2: Create Inventory File
vi ~/keepalived-ansible/inventory/hosts.ini
[keepalived_nodes]
pgm1 ansible_host=70.80.90.10 ansible_user=root priority=101 state=MASTER
pgm2 ansible_host=70.80.90.11 ansible_user=root priority=90 state=BACKUP
pgm3 ansible_host=70.80.90.12 ansible_user=root priority=80 state=BACKUP
Step 3: Create the Role Task File
mkdir -p /root/keepalived-ansible/keepalived-rpms
cd /root/keepalived-ansible/keepalived-rpms
--This will download keepalived and all dependencies into the current directory.
dnf download --resolve keepalived
vi ~/keepalived-ansible/roles/keepalived/tasks/main.yml
- name: Ensure keepalived config directory exists
file:
path: /etc/keepalived
state: directory
owner: root
group: root
mode: '0755'
- name: Ensure directory in the /tmp exists
file:
path: /tmp/keepalived-rpms/
state: directory
owner: root
group: root
mode: '0777'
- name: Copy keepalived RPMs to remote hosts
copy:
src: "{{ item }}"
dest: /tmp/keepalived-rpms/
mode: '0644'
loop: "{{ lookup('fileglob', 'keepalived-rpms/*.rpm', wantlist=True) }}"
- name: Get list of RPM files copied to the remote host
find:
paths: /tmp/keepalived-rpms/
patterns: "*.rpm"
register: keepalived_rpm_files
- name: Install keepalived and dependencies from RPMs
dnf:
name: "{{ keepalived_rpm_files.files | map(attribute='path') | list }}"
state: present
- name: Reload systemd
ansible.builtin.systemd:
daemon_reload: yes
- name: Enable sysctl settings
sysctl:
name: "{{ item.name }}"
value: "{{ item.value }}"
sysctl_set: yes
state: present
reload: yes
loop:
- { name: "net.ipv4.ip_nonlocal_bind", value: "1" }
- { name: "net.ipv4.ip_forward", value: "1" }
- name: Configure keepalived.conf
template:
src: keepalived.conf.j2
dest: /etc/keepalived/keepalived.conf
owner: root
group: root
mode: 0644
- name: Verify keepalived is installed
command: rpm -q keepalived
register: keepalived_check
ignore_errors: yes
- name: Print keepalived installation result
debug:
msg: "{{ keepalived_check.stdout }}"
- name: Reload systemd
ansible.builtin.systemd:
daemon_reload: yes
- name: Start Keepalived
systemd:
name: keepalived
enabled: yes
state: started
-------------------------------------------------------------------
Create defaults/main.yml to Define Variables
mkdir -p ~/keepalived-ansible/roles/keepalived/defaults
vi ~/keepalived-ansible/roles/keepalived/defaults/main.yml
vip_address: "70.80.90.221"
interface_name: "ens224"
router_id: 51
Step 4: Create Template File
vi ~/keepalived-ansible/roles/keepalived/templates/keepalived.conf.j2
vrrp_instance VI_1 {
state {{ state }}
interface {{ interface_name }}
virtual_router_id {{ router_id }}
priority {{ priority }}
advert_int 1
virtual_ipaddress {
{{ vip_address }}
}
Step 5: Create Main Playbook
vi ~/keepalived-ansible/playbook.yml
- name: Setup Keepalived on PostgreSQL nodes
hosts: keepalived_nodes
become: yes
roles:
- keepalived
Step 6: Run the Playbook
ansible-playbook -i inventory/hosts.ini playbook.yml
---------------------------------------------------------------------------------------------