Skip to content

About

PostgreSQL Active/Passive Replication with Load Balancer & DNS. Simulates 2 data centers with Vagrant.

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

Β 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

⚑ 2 Data Centers High Availability Lab

PostgreSQL Active/Passive Replication with Load Balancer & DNS

GitHub stars GitHub forks GitHub issues License Vagrant PostgreSQL


Simulate. Automate. Failover.


πŸ“‹ Table of Contents


✨ Features

  • 🏒 2 Data Centers – Simulated with Vagrant (DC1 and DC2)
  • πŸ—„οΈ PostgreSQL 16 – Active/Passive with Streaming Replication
  • 🌐 Flask Application – Deployed on both DCs
  • βš–οΈ HAProxy – Load balancer with round-robin distribution
  • πŸ“‘ Bind9 – DNS server for dynamic failover
  • πŸ€– Fully Automated – Single command deployment (vagrant up)
  • πŸ”„ Replication – Real-time data synchronization
  • πŸ§ͺ Optional Tests – Switchover and Disaster Recovery scenarios

πŸ—οΈ Infrastructure as Code (IaC)

This project is built on Infrastructure as Code principles:

  • Vagrant defines the entire infrastructure (VMs, networks, resources) in a single Vagrantfile.
  • Provisioning scripts automate the installation and configuration of all software (PostgreSQL, Flask, HAProxy, Bind9).

With a single command (vagrant up), you can recreate the entire 2-data-center environment from scratch. This is the power of IaC: consistent, repeatable, and automated infrastructure.

πŸ’‘ Infrastructure as Code is a core practice in DevOps and SRE (Site Reliability Engineering). It enables teams to manage infrastructure with the same rigor as application code.


πŸ§ͺ Safe Playground for Real-World Scenarios

One of the greatest benefits of this lab is that it provides a safe, isolated environment to test and learn from real-world infrastructure scenarios without any risk to production systems.

Scenario What you can test
πŸ”„ Switchover Promote a replica to primary and reconfigure the old primary as a replica β€” all without downtime.
🧯 Disaster Recovery (DR) Simulate the complete loss of a data center (DC1) and verify that the system continues to work using DC2.
πŸ› οΈ Failover Testing Test how the system behaves when a database or application server goes down.
πŸ“‘ DNS Failover Update DNS records dynamically to point to a new primary database.
βš–οΈ Load Balancing Test HAProxy's round-robin distribution and see how it handles traffic.
πŸ”§ Configuration Changes Modify PostgreSQL, Flask, or HAProxy settings and observe the impact in real time.
πŸ§ͺ Rollback Simulations Practice reincorporating a failed node back into the cluster after recovery.

⚑ Key advantage: All of these tests can be performed safely and repeatedly in your local environment. Break things, learn from the failures, and rebuild everything with vagrant destroy -f && vagrant up β€” it's that simple.

This approach helps build the confidence and skills needed to manage real production environments, where mistakes are costly and downtime is unacceptable.


πŸ—οΈ Architecture

2DC-HA Architecture
Architecture diagram of the 2 Data Centers High Availability Lab
Component Description
πŸ—„οΈ PostgreSQL Primary (db1) Handles all write operations
πŸ—„οΈ PostgreSQL Replica (db2) Real-time replication from db1
🌐 Flask App (app1 & app2) API endpoints connected to local DB
βš–οΈ HAProxy (lb) Distributes traffic between apps
πŸ“‘ Bind9 (dns) Resolves db.lab.local and lb.lab.local


🌐 Network Topology

Machine DC IP (Host-Only) Role RAM CPU
db1 1 10.10.1.20 PostgreSQL Primary 2048 MB 2
app1 1 10.10.1.10 Flask App DC1 1024 MB 1
db2 2 10.10.2.20 PostgreSQL Replica 2048 MB 2
app2 2 10.10.2.10 Flask App DC2 1024 MB 1
lb - 10.10.1.100 HAProxy Load Balancer 512 MB 1
dns - 10.10.1.200 Bind9 DNS Server 512 MB 1

πŸ“¦ Requirements

Requirement Minimum Recommended
Vagrant 2.4+ Latest
VirtualBox 7.0+ Latest
RAM 8 GB 16 GB+
Disk Space 20 GB 40 GB+
OS Windows 10/11, macOS, Linux Any with VirtualBox support

βœ… Tested on: Windows 11 Pro with VirtualBox 7.2.12 and Vagrant 2.4.9. Compatible with macOS and Linux (may require minor adjustments).


⚑ Quick Start

πŸ’‘ For a detailed step-by-step guide, see Installation below.

# 1. Clone the repository
git clone https://github.com/rafajimenezdev/2dc-ha-lab.git
cd 2dc-ha-lab

# 2. Start the environment (this will create 6 VMs)
vagrant up

# 3. Test the application
curl http://10.10.1.100/items

# 4. Insert data
curl -X POST http://10.10.1.100/items -H "Content-Type: application/json" -d '{"id": 42}'

# 5. Verify replication
curl http://10.10.1.100/items

πŸ”§ Installation

1. Clone the repository

git clone https://github.com/rafajimenezdev/2dc-ha-lab.git
cd 2dc-ha-lab

2. Install system dependencies

Windows

# 1. Install VirtualBox: https://www.virtualbox.org/
# 2. Install Vagrant: https://www.vagrantup.com/
# 3. Ensure Hyper-V is disabled (if using VirtualBox)

Linux (Ubuntu/Debian)

# Install VirtualBox and Vagrant
sudo apt update
sudo apt install virtualbox vagrant -y

macOS

brew install --cask virtualbox
brew install vagrant

3. Verify the installation

vagrant --version
virtualbox --help

πŸ§ͺ Testing the Application

Access the Load Balancer

curl http://10.10.1.100/

Expected output:

Flask App is running! (DC1)

or

Flask App is running! (DC2)

Insert Data

curl -X POST http://10.10.1.100/items \
  -H "Content-Type: application/json" \
  -d '{"id": 42}'

Expected output:

{"status":"inserted","id":42}

Get Data

curl http://10.10.1.100/items

Expected output:

[42]

Β‘ME HA ENCANTADO TU ENTORNO, RAFAEL! πŸ”₯

Β‘Me alegra un montΓ³n que haya funcionado todo a la primera! πŸš€

Y sΓ­, claro que podemos integrar esta baterΓ­a de pruebas en el README. Es exactamente lo que un usuario necesita para validar que su laboratorio estΓ‘ funcionando correctamente. Y que lo hayas disfrutado es la mejor seΓ±al de que el proyecto estΓ‘ bien hecho.

Te voy a dar la secciΓ³n exacta para que la pegues en tu README, dentro de la secciΓ³n de "Testing the Application". He mantenido el estilo profesional y los emojis que te gustan.


πŸ§ͺ Validation Tests

After a successful vagrant up, run these tests to ensure the entire lab is functioning correctly.

1. Check VM Status

vagrant status

All machines should show running (virtualbox).

2. Test Connectivity from Host

ping 10.10.1.10   # app1
ping 10.10.1.20   # db1
ping 10.10.2.10   # app2
ping 10.10.2.20   # db2
ping 10.10.1.100  # lb
ping 10.10.1.200  # dns

All should respond successfully.

3. Test Flask Applications

Invoke-RestMethod -Uri http://10.10.1.10:5000/ -Method GET

Expected output:

Flask App is running! (DC1)
Invoke-RestMethod -Uri http://10.10.2.10:5000/ -Method GET

Expected output:

Flask App is running! (DC2)

4. Test Load Balancer (HAProxy)

Invoke-RestMethod -Uri http://10.10.1.100/ -Method GET

Run this multiple times to see the round-robin distribution:

for ($i=0; $i -lt 5; $i++) { Invoke-RestMethod -Uri http://10.10.1.100/ -Method GET }

Expected output: A mix of DC1 and DC2 responses.

5. Test API Endpoints

Invoke-RestMethod -Uri http://10.10.1.100/items -Method GET

Expected output: [] (empty array, no data yet).

6. Insert Data

Invoke-RestMethod -Uri http://10.10.1.100/items -Method POST -Headers @{"Content-Type"="application/json"} -Body '{"id": 42}'

Expected output:

{"status":"inserted","id":42}
Invoke-RestMethod -Uri http://10.10.1.100/items -Method GET

Expected output: [42]

7. Verify Replication

Invoke-RestMethod -Uri http://10.10.2.10:5000/items -Method GET

Expected output: [42] (data is replicated to db2).


πŸ§ͺ Advanced Tests (Optional)

1. Switchover (Controlled Role Swap)

This test promotes the replica (db2) to primary and reconfigures db1 as the new replica.

vagrant ssh db1
sudo -u postgres psql -c "SELECT pg_switch_wal();"
sudo systemctl stop postgresql
exit

vagrant ssh db2
sudo pg_ctl promote -D /var/lib/postgresql/16/main
exit

# Reconfigure db1 as replica of db2
vagrant ssh db1
sudo rm -rf /var/lib/postgresql/16/main/*
sudo -u postgres PGPASSWORD='replicator_password' pg_basebackup \
  -h 10.10.2.20 -U replicator \
  -D /var/lib/postgresql/16/main -Fp -Xs -R -v
sudo -u postgres touch /var/lib/postgresql/16/main/standby.signal
sudo systemctl start postgresql

2. Disaster Recovery (Simulate DC1 Failure)

This test simulates the complete loss of DC1 and verifies that the system continues to work using DC2.

# Shut down DC1
vagrant halt db1 app1

# Promote db2 to primary
vagrant ssh db2
sudo pg_ctl promote -D /var/lib/postgresql/16/main
exit

# Verify application still works
curl http://10.10.2.10:5000/items

# To recover DC1, reincorporate it as a replica of db2
vagrant up db1
vagrant ssh db1
sudo systemctl stop postgresql
sudo rm -rf /var/lib/postgresql/16/main/*
sudo -u postgres PGPASSWORD='replicator_password' pg_basebackup \
  -h 10.10.2.20 -U replicator \
  -D /var/lib/postgresql/16/main -Fp -Xs -R -v
sudo -u postgres touch /var/lib/postgresql/16/main/standby.signal
sudo systemctl start postgresql

🌐 Access from Host Machine

To access services from your host, add these entries to your hosts file:

Windows: C:\Windows\System32\drivers\etc\hosts

macOS / Linux: /etc/hosts

10.10.1.100 lb.lab.local
10.10.1.20  db.lab.local

After adding the entries:

curl http://lb.lab.local/items

πŸ“ Project Structure

2dc-ha-lab/
β”œβ”€β”€ README.md                 # This file
β”œβ”€β”€ LICENSE                   # MIT License
β”œβ”€β”€ .gitignore                # Git ignore rules
β”œβ”€β”€ Vagrantfile               # VM definitions
β”œβ”€β”€ images/
β”‚   └── arch_whitebg.png      # Architecture diagram (white background)
β”œβ”€β”€ provision/
β”‚   β”œβ”€β”€ db1.sh                # Primary DB setup
β”‚   β”œβ”€β”€ db2.sh                # Replica DB setup
β”‚   β”œβ”€β”€ app.sh                # Flask app setup
β”‚   β”œβ”€β”€ lb.sh                 # HAProxy setup
β”‚   └── dns.sh                # Bind9 DNS setup
└── app/
    β”œβ”€β”€ app.py                # Flask application
    └── requirements.txt      # Python dependencies

πŸ› Common Issues and Fixes

SSH Timeouts During Boot

Problem: Vagrant gets stuck at SSH auth method: private key.

Solution: Add this to your Vagrantfile:

vb.customize ["modifyvm", :id, "--cableconnected1", "on"]
  • Workaround during vagrant up: If the VM gets stuck, open the VirtualBox GUI and bring the VM window to the foreground (click on it). This often "wakes up" the boot process and allows Vagrant to continue.

VirtualBox Host-Only Adapter Conflicts

Problem: Error VERR_INTNET_FLT_IF_NOT_FOUND.

Solution:

  1. Open VirtualBox β†’ File β†’ Tools β†’ Network Manager.
  2. Go to Host-only Networks.
  3. Ensure you have two adapters:
    • 10.10.1.1/24 (DC1)
    • 10.10.2.1/24 (DC2)
  4. Disable DHCP on both.

Hyper-V Conflict

Problem: VirtualBox fails to start VMs.

Solution: Disable Hyper-V:

bcdedit /set hypervisorlaunchtype off

PostgreSQL Connection Refused

Problem: psycopg2.OperationalError: connection refused.

Solution: Ensure PostgreSQL is listening on all interfaces:

sudo sed -i "s/#listen_addresses = 'localhost'/listen_addresses = '*'/" /etc/postgresql/16/main/postgresql.conf
sudo systemctl restart postgresql

❓ Frequently Asked Questions

1. Why does vagrant up take so long?

The first run downloads the Ubuntu base box (~700 MB) and installs all dependencies. Subsequent runs are much faster.


2. Can I use this lab on a laptop with 8GB RAM?

Yes, but you may need to reduce the memory allocated to each VM in the Vagrantfile. Edit vb.memory values to lower values (e.g., 1024 for databases, 512 for apps).


3. How do I stop all VMs?

vagrant halt

To destroy them completely:

vagrant destroy -f

4. What if I want to use a different PostgreSQL version?

Edit the version in provision/db1.sh and provision/db2.sh. Change postgresql-16 to postgresql-15 or postgresql-14.


5. How do I access app2 directly?

You can access it directly via http://10.10.2.10:5000, provided your host has a route to the 10.10.2.0/24 network.


6. Can I run this on macOS?

Yes. Vagrant and VirtualBox work on macOS. The scripts are Bash-compatible.


7. How do I reset the lab to a clean state?

vagrant destroy -f
vagrant up

🀝 Contributing

This project is a personal learning lab and is not currently open to external contributions. However, you are welcome to:

  • ⭐ Star the repository if you find it useful.
  • 🍴 Fork it and use it for your own learning.
  • πŸ› Report issues if you find any bugs or problems.
  • πŸ“ Suggest improvements via GitHub Issues.

πŸ’‘ Note: This lab is designed to be a reproducible environment for learning high availability concepts. If you have ideas for improvements, feel free to open an issue to discuss them.


πŸ“ License

This project is licensed under the MIT License - see the LICENSE file for details.


πŸ‘€ Author

Rafael JimΓ©nez PΓ©rez


Built with ❀️ for the infrastructure community

About

PostgreSQL Active/Passive Replication with Load Balancer & DNS. Simulates 2 data centers with Vagrant.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages