Cloud Native 20 min read

How to Build a Minimal‑Cost HA Harbor Registry with PostgreSQL Replication on Alibaba Cloud

This guide details a low‑overhead, highly available Harbor deployment on Alibaba Cloud, covering preparation of SLB, ECS, NFS storage, installation of Docker‑Compose, configuration of image mirrors, installation of Harbor 2.3, setup of PostgreSQL 13 master‑slave replication, Redis integration, backup procedures, failover handling, and disaster‑recovery strategies.

Ops Development Stories
Ops Development Stories
Ops Development Stories
How to Build a Minimal‑Cost HA Harbor Registry with PostgreSQL Replication on Alibaba Cloud

Introduction

Because of resource cost constraints, this Harbor high‑availability architecture uses the minimal‑overhead solution; if resources are abundant, PG and Redis can be switched to cloud‑provider managed clusters. To keep configuration simple, keepalived and heartbeat are not used.

Preparation

Required Alibaba Cloud resources: minimal‑instance SLB, two ECS instances (2 CPU 4 GB), NFS storage, and Alibaba Cloud Redis.

Operating system: Ubuntu 18.04. Two ECS machines will host PostgreSQL master‑slave; Redis can also be deployed on ECS if not using Alibaba Cloud Redis.

Install Docker‑Compose

curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo add-apt-repository "deb [arch=amd64] http://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
# Add Alibaba Cloud mirror
curl -fsSL http://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
# Update
sudo apt-get update
# View Docker version
apt-cache madison docker-ce
# Install latest version
sudo apt-get install -y docker-ce
# Install specific version 19.03.6
sudo apt-get install -y docker-ce=5:19.03.6~3-0~ubuntu-bionic

Configure Docker Image Mirrors

sudo tee /etc/docker/daemon.json <<'EOF'
{
  "registry-mirrors": ["https://8sab4djv.mirror.aliyuncs.com", "https://registry.docker-cn.com"],
  "insecure-registries": ["https://harbor.unixsre.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

Install Harbor 2.3

# Download Harbor
wget -P /usr/local https://github.com/goharbor/harbor/releases/download/v2.3.2/harbor-online-installer-v2.3.2.tgz

# Extract
tar zxf /usr/local/harbor-online-installer-v2.3.2.tgz -C /data/harbor

# Modify configuration file
cd /data/harbor
cp harbor.yml.tmpl harbor.yml
# Edit harbor.yml as needed, e.g.:
hostname: harbor.unixsre.com
http:
  port: 80
https:
  port: 443
  certificate: /data/harbor/ssl/unixsre.com.cer
  private_key: /data/harbor/ssl/unixsre.com.key
harbor_admin_password: 1234567
data_volume: /data/harbor
self_registration: off
project_creation_restriction: adminonly
# Install
bash /data/harbor/install.sh
./prepare
docker-compose restart

Common Docker Commands for Harbor

# Login
docker login https://harbor.unixsre.com
# Pull image
docker pull busybox
# Build image
docker build -t busybox:v1 .
# Tag image
docker tag busybox:latest harbor.unixsre.com/ops/busybox:latest
# Push image
docker push harbor.unixsre.com/library/busybox:latest
# k3s pull
k3s crictl pull harbor.unixsre.com/library/busybox

Backup Harbor Databases

# Enter container
docker container exec -it harbor-db /bin/bash
# Export PostgreSQL databases
pg_dump -U postgres registry > /tmp/registry.sql
pg_dump -U postgres notarysigner > /tmp/notarysigner.sql
pg_dump -U postgres notaryserver > /tmp/notaryserver.sql
# Copy to host
docker container cp harbor-db:/tmp/registry.sql /data/harbor/backup_sql/
docker container cp harbor-db:/tmp/notarysigner.sql /data/harbor/backup_sql/
docker container cp harbor-db:/tmp/notaryserver.sql /data/harbor/backup_sql/

Install PostgreSQL Master‑Slave Cluster

PostgreSQL logical replication provides high availability, read/write separation, and real‑time backup based on WAL (xlog).

PG Master‑Slave Replication Notes

Before starting the standby, ensure no initialization data exists; delete if present.

Synchronize configuration and data from the primary using base_backup.

Adjust the generated standby.signal file after sync.

The standby can only read, not write.

Step 1 – Install PostgreSQL 13 on Each ECS

# Add PG apt source
sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list'
wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
# Update and install
apt-get update
apt -y install postgresql-13 postgresql-client-13 postgresql-contrib
# Verify service
systemctl status [email protected]
# Set password for postgres user
sudo -i -u postgres psql -p 5432 -c "ALTER USER postgres WITH PASSWORD '1234567.com';"
# Test login
psql -h localhost -p 5432 -U postgres

Step 2 – Create Data Directories

# Create data directory
mkdir -p /data/harbor_nas/pgsql/data && chown postgres:postgres /data/harbor_nas/pgsql/data
# Create archive directory
mkdir -p /data/harbor_nas/pgsql/pg_archive && chown postgres:postgres /data/harbor_nas/pgsql/pg_archive
# Set permissions
chmod 700 /data/harbor_nas/pgsql/pg_archive/ && chmod 700 /data/harbor_nas/pgsql/data/

Step 3 – Configure systemd Service

vim /lib/systemd/system/[email protected]
Environment=PGDATA=/data/harbor_nas/pgsql/data
systemctl daemon-reload
pg_dropcluster --stop 13 main
pg_createcluster -d /data/harbor_nas/pgsql/data 13 main
systemctl restart [email protected]
systemctl enable [email protected]
# Allow external connections in pg_hba.conf
vim /etc/postgresql/13/main/pg_hba.conf
# Example entries:
local   all             postgres                                peer
local   all             all                                     peer
host    all             all             0.0.0.0/0               md5
host    all             all             ::1/128                 md5
host    replication     all             127.0.0.1/32            md5
host    replication     all             ::1/128                 md5
# Listen on all addresses
vim /etc/postgresql/13/main/postgresql.conf
listen_addresses = '*'
systemctl restart [email protected]

Step 4 – Configure Primary Server

# Create replication user
CREATE ROLE replica LOGIN REPLICATION ENCRYPTED PASSWORD 'Deniss_12PRO@@@';
# Allow replica password‑less login from standby
vim /etc/postgresql/13/main/pg_hba.conf
host    replication    replica 172.19.48.254/20    trust
# Primary postgresql.conf additions
listen_addresses = '*'
max_connections = 100
archive_mode = on
archive_command = 'test ! -f /data/harbor_nas/pgsql/pg_archive/%f && cp %p /data/harbor_nas/pgsql/pg_archive/%f'
wal_level = replica
# Restart
systemctl restart [email protected]

Step 5 – Configure Standby Server

# Create standby data and archive directories
mkdir -p /data/harbor_nas/pgsql_replica/data && chown postgres:postgres /data/harbor_nas/pgsql_replica/data
mkdir -p /data/harbor_nas/pgsql_replica/pg_archive && chown postgres:postgres /data/harbor_nas/pgsql_replica/pg_archive
chmod 700 /data/harbor_nas/pgsql_replica/pg_archive/ && chmod 700 /data/harbor_nas/pgsql_replica/data/
# Adjust systemd service for standby
vim /lib/systemd/system/[email protected]
Environment=PGDATA=/data/harbor_nas/pgsql_replica/data/
systemctl daemon-reload
pg_dropcluster --stop 13 main
pg_createcluster -d /data/harbor_nas/pgsql_replica/data 13 main
systemctl restart [email protected]
# Base backup from primary
su - postgres
rm -rf /data/harbor_nas/pgsql_replica/data/*
pg_basebackup -h 172.19.48.253 -p 5432 -U replica -Fp -Xs -Pv -R -D /data/harbor_nas/pgsql_replica/data
echo "standby_mode = 'on'" > /data/harbor_nas/pgsql_replica/data/standby.signal
# Standby postgresql.conf additions
primary_conninfo = 'host=172.19.48.253 port=5432 user=replica password=Deniss_12PRO@@@'
recovery_target_timeline = latest
max_connections = 100
hot_standby = on
max_standby_streaming_delay = 30s
wal_receiver_status_interval = 10s
hot_standby_feedback = on
# Start standby
systemctl start [email protected]
# Verify replication
psql -h 172.19.48.253 -p 5432 -U postgres -c "SELECT client_addr, sync_state FROM pg_stat_replication;"

Configure Harbor to Use External PostgreSQL

# Create Harbor DB user and schema
CREATE USER harbor LOGIN PASSWORD 'Deniss1112s';
CREATE SCHEMA harbor;
GRANT harbor TO postgres;
GRANT USAGE ON SCHEMA harbor TO postgres;
ALTER SCHEMA harbor OWNER TO postgres;
# Create databases
CREATE DATABASE registry OWNER harbor;
CREATE DATABASE notarysigner OWNER harbor;
CREATE DATABASE notaryserver OWNER harbor;
# Grant privileges
GRANT ALL PRIVILEGES ON DATABASE registry TO harbor;
GRANT ALL PRIVILEGES ON DATABASE notarysigner TO harbor;
GRANT ALL PRIVILEGES ON DATABASE notaryserver TO harbor;
# Restore data
psql -h localhost -U harbor registry < /data/harbor/backup_sql/registry.sql
psql -h localhost -U harbor notarysigner < /data/harbor/backup_sql/notarysigner.sql
psql -h localhost -U harbor notaryserver < /data/harbor/backup_sql/notaryserver.sql

Adjust harbor.yml for External DB and Redis

hostname: harbor.unixsre.com

http:
  port: 80

https:
  port: 443
  certificate: /data/harbor/ssl/unixsre.com.cer
  private_key: /data/harbor/ssl/unixsre.com.key

harbor_admin_password: 1234567
data_volume: /data/harbor_nas/harbor_data

external_database:
  harbor:
    host: 172.19.48.253
    port: 5432
    db_name: registry
    username: harbor
    password: Deniss1112s
    ssl_mode: disable
  notary_signer:
    host: 172.19.48.253
    port: 5432
    db_name: notarysigner
    username: harbor
    password: Deniss1112s
    ssl_mode: disable
  notary_server:
    host: 172.19.48.253
    port: 5432
    db_name: notaryserver
    username: harbor
    password: Deniss1112s
    ssl_mode: disable

external_redis:
  host: 172.19.48.253:6379
  password: Deniss1589s
  registry_db_index: 1
  jobservice_db_index: 2
  chartmuseum_db_index: 3
  trivy_db_index: 5
  idle_timeout_seconds: 30

Regenerate Configuration and Restart

cd /data/harbor/
./prepare
docker-compose down && docker-compose up -d

Create Alibaba Cloud SLB (TCP 443)

PostgreSQL Master‑Slave Failover

# Simulate primary failure
service postgresql@13-main stop
# Promote standby to primary
psql -h 172.19.48.254 -p 5432 -U postgres -c "SELECT pg_promote(true,60);"
# Verify promotion
/usr/lib/postgresql/13/bin/pg_controldata -D /data/harbor_nas/pgsql_replica/data/ | grep cluster
# Update Harbor configuration to point to new primary
sed -i 's/172.19.48.253/172.19.48.254/' ./prepare
docker-compose down && docker-compose up -d

Disaster Recovery

In extreme cases where the cloud provider becomes unavailable, ensure two prerequisites: a full PostgreSQL backup (accepting data loss between backup start and failure) and accessible Harbor image data stored on Alibaba Cloud NFS or OSS.

Recovery steps: provision a single‑node PostgreSQL instance, import the full backup, configure Harbor to use this single node and a local or container‑embedded Redis, then start Harbor with docker‑compose up -d. More advanced cloud‑native solutions can be explored, but this manual approach provides a baseline for discussion.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Dockerhigh availabilityReplicationpostgresqlAlibaba CloudHarbor
Ops Development Stories
Written by

Ops Development Stories

Maintained by a like‑minded team, covering both operations and development. Topics span Linux ops, DevOps toolchain, Kubernetes containerization, monitoring, log collection, network security, and Python or Go development. Team members: Qiao Ke, wanger, Dong Ge, Su Xin, Hua Zai, Zheng Ge, Teacher Xia.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.