Harbor 高可用生产搭建阶段一(dns高可用+ssl证书申请)
本文介绍了基于高可用架构的DNS与Keepalived部署方案。系统采用PostgreSQL主从复制、Redis主从架构、MinIO分布式存储等组件构建数据层和存储层。接入层使用HAProxy+Keepalived双节点实现负载均衡,应用层部署Harbor双节点。重点阐述了内部DNS集群的部署流程,包括: 在104/105节点部署Bind9主从DNS服务器,配置区域同步 通过健康检查脚本管理DNS
·
架构总览
-
数据层:PostgreSQL (1 主 1 从 1 选举) + Redis (1 主 2 从)
-
存储层:MinIO 分布式集群 (4 节点)
-
接入层:HAProxy + Keepalived (2 节点,多 VIP)
-
应用层:Harbor 双节点
-
DNS 层:内部 DNS 主从 (用于服务发现)
第一阶段:内部 DNS 集群 (可选,建议部署)不部署的话可以使用hosts
- 在 104/105 上部署 CoreDNS 或 Bind9。
- 配置主从同步。
- 将域名 (如
harbor.zz520.online) 解析指向 VIP_Harbor。 - 将所有节点的 DNS resolver 指向 VIP_DNS。
一、部署dns服务器
1.部署主服务器
1.1准备工作(关闭防火墙)104/105执行
systemctl disable ufw --now
优化53端口
root@ha1:~# cat fix_port_53.sh
#!/bin/bash
# 解决 Ubuntu systemd-resolved 占用 53 端口的问题
echo "正在检查 53 端口占用情况..."
ss -tulpn | grep :53
echo ""
echo "1. 停止并禁用 systemd-resolved 服务..."
systemctl stop systemd-resolved
systemctl disable systemd-resolved
echo ""
echo "2. 修改 /etc/systemd/resolved.conf 关闭 Stub..."
# 备份
cp /etc/systemd/resolved.conf /etc/systemd/resolved.conf.bak
# 写入配置
cat > /etc/systemd/resolved.conf << 'EOF'
[Resolve]
DNS=223.5.5.5 114.114.114.114
FallbackDNS=8.8.8.8
#Domains=
LLMNR=no
MulticastDNS=no
DNSSEC=no
DNSOverTLS=no
Cache=no
DNSStubListener=no
#ReadEtcHosts=yes
EOF
echo ""
echo "3. 重建 resolv.conf (非常重要)..."
# 删除旧的软链接
rm -f /etc/resolv.conf
# 创建新的静态 resolv.conf
cat > /etc/resolv.conf << 'EOF'
nameserver 223.5.5.5
nameserver 114.114.114.114
EOF
echo ""
echo "4. 重新加载 systemd 配置 (可选)..."
systemctl daemon-reload
echo ""
echo "5. 再次检查 53 端口..."
sleep 1
ss -tulpn | grep :53
if [ $? -eq 0 ]; then
echo ""
echo "⚠️ 警告: 53 端口仍被占用,请检查上面的输出!"
else
echo ""
echo "✅ 成功!53 端口已释放。"
echo "现在可以安装 Bind9 了。"
fi
1.2开始部署104
cat deploy_bind_master.sh
#!/bin/bash
# Ubuntu Bind9 主服务器一键部署脚本
echo "1. 更新软件源并安装 Bind9..."
apt update && apt install -y bind9 bind9-utils dnsutils
echo "2. 备份原始配置..."
cd /etc/bind
cp named.conf.options named.conf.options.bak
cp named.conf.local named.conf.local.bak
echo "3. 写入主配置文件 named.conf.options..."
cat > named.conf.options << 'EOF'
options {
directory "/var/cache/bind";
// 允许查询的网段 (你的内网)
allow-query { localhost; 10.0.0.0/24; };
// 允许递归查询
recursion yes;
// 转发到公网DNS
forwarders {
223.5.5.5;
114.114.114.114;
};
dnssec-validation auto;
listen-on-v6 { any; };
};
EOF
echo "4. 写入区域配置 named.conf.local..."
cat > named.conf.local << 'EOF'
// 定义正向区域
zone "zz520.online" {
type master;
file "/etc/bind/db.zz520.online";
// 允许从服务器传输区域文件
allow-transfer { 10.0.0.105; };
// 主动通知从服务器更新
also-notify { 10.0.0.105; };
};
EOF
echo "5. 创建区域数据库文件 db.zz520.online..."
cat > db.zz520.online << 'EOF'
$TTL 604800
@ IN SOA ns1.zz520.online. admin.zz520.online. (
2 ; Serial
604800 ; Refresh
86400 ; Retry
2419200 ; Expire
604800 ) ; Negative Cache TTL
;
@ IN NS ns1.zz520.online.
@ IN NS ns2.zz520.online.
; 定义 NS 记录
ns1 IN A 10.0.0.104
ns2 IN A 10.0.0.105
; 预定义你的 Harbor VIP (示例,后续可通过脚本修改)
harbor IN A 10.0.0.204
EOF
echo "6. 修复权限..."
chown root:bind /etc/bind/db.zz520.online
chmod 644 /etc/bind/db.zz520.online
echo "7. 检查配置语法..."
named-checkconf
if [ $? -ne 0 ]; then
echo "配置语法错误,请检查!"
exit 1
fi
echo "8. 重启 Bind9 服务..."
systemctl daemon-reload
systemctl restart named
systemctl enable named
echo "===== Master 部署完成 ====="
echo "请确保防火墙允许 10.0.0.105 访问本机的 53 端口 (TCP/UDP)"
2.部署从服务器105
2.1准备工作
关闭防火墙
systemctl disable ufw --now
优化53端口
root@ha1:~# cat fix_port_53.sh
#!/bin/bash
# 解决 Ubuntu systemd-resolved 占用 53 端口的问题
echo "正在检查 53 端口占用情况..."
ss -tulpn | grep :53
echo ""
echo "1. 停止并禁用 systemd-resolved 服务..."
systemctl stop systemd-resolved
systemctl disable systemd-resolved
echo ""
echo "2. 修改 /etc/systemd/resolved.conf 关闭 Stub..."
# 备份
cp /etc/systemd/resolved.conf /etc/systemd/resolved.conf.bak
# 写入配置
cat > /etc/systemd/resolved.conf << 'EOF'
[Resolve]
DNS=223.5.5.5 114.114.114.114
FallbackDNS=8.8.8.8
#Domains=
LLMNR=no
MulticastDNS=no
DNSSEC=no
DNSOverTLS=no
Cache=no
DNSStubListener=no
#ReadEtcHosts=yes
EOF
echo ""
echo "3. 重建 resolv.conf (非常重要)..."
# 删除旧的软链接
rm -f /etc/resolv.conf
# 创建新的静态 resolv.conf
cat > /etc/resolv.conf << 'EOF'
nameserver 223.5.5.5
nameserver 114.114.114.114
EOF
echo ""
echo "4. 重新加载 systemd 配置 (可选)..."
systemctl daemon-reload
echo ""
echo "5. 再次检查 53 端口..."
sleep 1
ss -tulpn | grep :53
if [ $? -eq 0 ]; then
echo ""
echo "⚠️ 警告: 53 端口仍被占用,请检查上面的输出!"
else
echo ""
echo "✅ 成功!53 端口已释放。"
echo "现在可以安装 Bind9 了。"
fi
2.2部署从节点dns服务器
root@ha2:~# cat deploy_bind_slave.sh
#!/bin/bash
# Ubuntu Bind9 从服务器一键部署脚本
echo "1. 更新软件源并安装 Bind9..."
apt update && apt install -y bind9 bind9-utils dnsutils
echo "2. 备份原始配置..."
cd /etc/bind
cp named.conf.options named.conf.options.bak
cp named.conf.local named.conf.local.bak
echo "3. 写入配置文件 named.conf.options..."
cat > named.conf.options << 'EOF'
options {
directory "/var/cache/bind";
allow-query { localhost; 10.0.0.0/24; };
recursion yes;
forwarders {
223.5.5.5;
114.114.114.114;
};
dnssec-validation auto;
listen-on-v6 { any; };
};
EOF
echo "4. 写入区域配置 named.conf.local (Slave模式)..."
cat > named.conf.local << 'EOF'
zone "zz520.online" {
type slave;
masters { 10.0.0.104; };
file "/var/cache/bind/db.zz520.online";
// 只允许主服务器通知
allow-notify { 10.0.0.104; };
};
EOF
echo "5. 检查配置语法..."
named-checkconf
if [ $? -ne 0 ]; then
echo "配置语法错误,请检查!"
exit 1
fi
echo "6. 重启 Bind9 服务..."
systemctl daemon-reload
systemctl restart named
systemctl enable named
echo "===== Slave 部署完成 ====="
echo "正在尝试从 Master 同步区域文件..."
sleep 3
ls -la /var/cache/bind/ | grep db.zz520
3.添加解析104执行
root@ha1:~# cat manage_bind_records.sh
#!/bin/bash
# Bind9 记录管理脚本 (仅在 Master 上运行)
ZONE_FILE="/etc/bind/db.zz520.online"
ZONE_NAME="zz520.online"
# 颜色
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
function increment_serial {
echo "正在更新 SOA 序列号..."
# 获取当前序列号
CURRENT_SERIAL=$(grep -Eo '^[[:space:]]*[0-9]+[[:space:]]*;[[:space:]]*Serial' $ZONE_FILE | awk '{print $1}')
if [ -z "$CURRENT_SERIAL" ]; then
echo -e "${RED}无法读取序列号!${NC}"
exit 1
fi
# 生成新序列号 (YYYYMMDD + 01,或者简单的+1)
# 这里使用简单的 +1 策略,最稳妥
NEW_SERIAL=$((CURRENT_SERIAL + 1))
# 替换文件中的序列号
sed -i "s/^[[:space:]]*${CURRENT_SERIAL}[[:space:]]*;[[:space:]]*Serial/ ${NEW_SERIAL} ; Serial/" $ZONE_FILE
echo -e "${GREEN}序列号已更新: ${CURRENT_SERIAL} -> ${NEW_SERIAL}${NC}"
}
function add_record {
echo "--- 添加新的 A 记录 ---"
read -p "请输入主机名 (例如 harbor, 不带域名): " HOST
read -p "请输入 IP 地址: " IP
# 检查是否已存在
if grep -q "^${HOST}[[:space:]]" $ZONE_FILE; then
echo -e "${YELLOW}警告: 记录 ${HOST} 似乎已存在。${NC}"
read -p "确定要继续添加吗?(y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
return
fi
fi
# 追加到文件末尾
echo "${HOST} IN A ${IP}" >> $ZONE_FILE
echo -e "${GREEN}记录已添加。${NC}"
increment_serial
echo "正在检查配置..."
named-checkzone $ZONE_NAME $ZONE_FILE
if [ $? -eq 0 ]; then
echo "正在重载 Bind9..."
rndc reload
echo -e "${GREEN}完成!Slave 节点将在几分钟内自动同步。${NC}"
else
echo -e "${RED}配置检查失败,请手动检查文件!${NC}"
fi
}
function view_records {
echo "--- 当前 DNS 记录 ---"
echo "Host IP"
echo "--------------------------------"
grep 'IN[[:space:]]*A' $ZONE_FILE | awk '{printf "%-20s %s\n", $1, $NF}'
}
# 主菜单
while true; do
echo ""
echo "=============================="
echo " Bind9 DNS 管理工具"
echo " 操作节点: $(hostname)"
echo "=============================="
echo "1. 查看当前记录"
echo "2. 添加 A 记录"
echo "3. 退出"
read -p "请选择 [1-3]: " choice
case $choice in
1)
view_records
;;
2)
add_record
;;
3)
echo "再见。"
break
;;
*)
echo "无效输入"
;;
esac
done
二、部署keepalived实现高可用
我们将在 10.0.0.104 (ha1) 和 10.0.0.105 (ha2) 上配置 Keepalived,创建 5 个独立的虚拟 IP (VIP)。
1.系统优化104/105执行
vim optimize_ubuntu_for_harbor_ha.sh
#!/bin/bash
# ============================================================
# Harbor HA 集群生产环境优化脚本 (Ubuntu 24.04+)
# 功能:
# 1. 内核参数优化 (Keepalived/ARP/网络性能)
# 2. 系统资源限制优化 (文件句柄/进程数)
# ============================================================
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# 检查是否为 root 用户
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}请使用 root 权限运行此脚本 (sudo su)${NC}"
exit 1
fi
# 网卡名称配置 (请根据实际情况修改)
TARGET_INTERFACE="ens33"
echo "============================================================"
echo " Harbor HA 生产环境优化脚本"
echo " 目标系统: Ubuntu 24.04"
echo " 检测网卡: ${TARGET_INTERFACE}"
echo "============================================================"
echo ""
# -------------------------- 1. 内核参数优化 --------------------------
echo -e "${YELLOW}[1/3] 正在配置内核参数 (/etc/sysctl.d/99-harbor-ha.conf)...${NC}"
SYSCTL_FILE="/etc/sysctl.d/99-harbor-ha.conf"
# 备份旧配置
if [ -f "$SYSCTL_FILE" ]; then
cp "$SYSCTL_FILE" "${SYSCTL_FILE}.bak.$(date +%s)"
fi
cat > "$SYSCTL_FILE" << EOF
# ==================================================
# Keepalived & LVS 核心优化
# ==================================================
net.ipv4.ip_nonlocal_bind = 1
net.ipv4.ip_forward = 1
# ARP 抑制
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.default.arp_ignore = 1
net.ipv4.conf.${TARGET_INTERFACE}.arp_ignore = 1
# ARP 通告
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.${TARGET_INTERFACE}.arp_announce = 2
# ==================================================
# 网络并发与性能优化
# ==================================================
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
EOF
echo -e "${GREEN}内核参数文件写入完成。${NC}"
echo ""
# -------------------------- 2. 资源限制优化 --------------------------
echo -e "${YELLOW}[2/3] 正在配置系统资源限制 (/etc/security/limits.d/99-harbor-ha.conf)...${NC}"
LIMITS_FILE="/etc/security/limits.d/99-harbor-ha.conf"
if [ -f "$LIMITS_FILE" ]; then
cp "$LIMITS_FILE" "${LIMITS_FILE}.bak.$(date +%s)"
fi
cat > "$LIMITS_FILE" << EOF
# ==================================================
# Harbor HA 集群资源限制
# ==================================================
# 针对 root 用户
root soft nofile 1048576
root hard nofile 1048576
root soft nproc 1048576
root hard nproc 1048576
# 针对所有用户
* soft nofile 1048576
* hard nofile 1048576
* soft nproc 1048576
* hard nproc 1048576
EOF
echo -e "${GREEN}资源限制文件写入完成。${NC}"
echo ""
# -------------------------- 3. 应用配置 --------------------------
echo -e "${YELLOW}[3/3] 正在应用内核参数...${NC}"
sysctl --system > /dev/null 2>&1
echo ""
echo "============================================================"
echo -e "${GREEN}✅ 所有优化配置已完成!${NC}"
echo "============================================================"
echo ""
echo "⚠️ 重要提示:"
echo "1. 内核参数已即时生效。"
echo "2. 资源限制 (ulimit) ${RED}必须重启服务器${NC}后才能完全生效。"
echo "3. 请确认脚本中的网卡名 (${TARGET_INTERFACE}) 是否正确。"
echo ""
read -p "是否现在重启服务器? (y/n): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
echo "正在重启..."
reboot
fi
2.安装keepalived(104/105均执行)
apt update && apt install -y keepalived
3.部署健康检查脚本 (deploy_health_checks.sh)
#!/bin/bash
# ============================================================
# 脚本功能:部署 Harbor HA 集群 Keepalived 健康检查脚本
# Repmgr 路径: /apps/repmgr/etc/repmgr.conf
# ============================================================
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}请使用 root 权限运行${NC}"
exit 1
fi
SCRIPT_DIR="/etc/keepalived/scripts"
echo -e "${YELLOW}正在创建脚本目录: ${SCRIPT_DIR}${NC}"
mkdir -p $SCRIPT_DIR
cd $SCRIPT_DIR
# ----------------------------------------------------
# 1. chk_haproxy.sh
# ----------------------------------------------------
echo "正在生成 chk_haproxy.sh..."
cat > chk_haproxy.sh << 'EOF'
#!/bin/bash
/usr/bin/pgrep haproxy > /dev/null 2>&1
exit $?
EOF
# ----------------------------------------------------
# 2. chk_port.sh
# ----------------------------------------------------
echo "正在生成 chk_port.sh..."
cat > chk_port.sh << 'EOF'
#!/bin/bash
PORT=$1
if [ -z "$PORT" ]; then exit 1; fi
/usr/bin/ss -tulpn | grep -q ":${PORT}" > /dev/null 2>&1
exit $?
EOF
# ----------------------------------------------------
# 3. chk_dns.sh
# ----------------------------------------------------
echo "正在生成 chk_dns.sh..."
cat > chk_dns.sh << 'EOF'
#!/bin/bash
/usr/bin/pgrep named > /dev/null 2>&1
exit $?
EOF
# ----------------------------------------------------
# 4. chk_minio.sh (需要用户后续手动改 IP)
# ----------------------------------------------------
echo "正在生成 chk_minio.sh..."
cat > chk_minio.sh << 'EOF'
#!/bin/bash
# 请修改为当前机器的物理 IP (10.0.0.104 或 10.0.0.105)
LOCAL_IP="10.0.0.104"
MINIO_PORT="9000"
/usr/bin/ss -tulpn | grep -q ":${MINIO_PORT}" > /dev/null 2>&1
exit $?
EOF
# ----------------------------------------------------
# 5. chk_pgsql_repmgr.sh (核心,已修正路径)
# ----------------------------------------------------
echo "正在生成 chk_pgsql_repmgr.sh..."
cat > chk_pgsql_repmgr.sh << 'EOF'
#!/bin/bash
# repmgr 角色检查脚本
# 配置项
PG_USER="postgres"
REPMGR_BIN="/usr/local/bin/repmgr" # 如 repmgr 不在标准 PATH,请修改此处
REPMGR_CONF="/apps/repmgr/etc/repmgr.conf"
# 尝试获取角色
# 方法:通过 repmgr node status 解析
ROLE=$(su - ${PG_USER} -c "${REPMGR_BIN} -f ${REPMGR_CONF} node status 2>/dev/null | grep 'Role' | awk '{print \$NF}'")
# 如果上面的方法失败,尝试直接查数据库 (备用方案)
if [ -z "$ROLE" ]; then
SQL="SELECT pg_is_in_recovery();"
IN_RECOVERY=$(su - ${PG_USER} -c "psql -t -c \"${SQL}\" 2>/dev/null | xargs")
if [ "$IN_RECOVERY" == "f" ]; then
ROLE="primary"
else
ROLE="standby"
fi
fi
# 逻辑判断
if [ "$ROLE" == "primary" ]; then
exit 0
else
exit 1
fi
EOF
# ----------------------------------------------------
# 6. chk_redis.sh
# ----------------------------------------------------
echo "正在生成 chk_redis.sh..."
cat > chk_redis.sh << 'EOF'
#!/bin/bash
/usr/bin/pgrep redis-server > /dev/null 2>&1
exit $?
EOF
# ----------------------------------------------------
# 收尾:赋权
# ----------------------------------------------------
echo "正在赋予执行权限..."
chmod +x $SCRIPT_DIR/*.sh
chown -R root:root $SCRIPT_DIR/
echo ""
echo -e "${GREEN}============================================================"
echo -e "✅ 所有健康检查脚本部署完成!"
echo -e "============================================================${NC}"
echo ""
echo -e "${YELLOW}⚠️ 请记得手动编辑以下文件:${NC}"
echo -e " 1. ${SCRIPT_DIR}/chk_minio.sh"
echo -e " -> 修改 LOCAL_IP 为本机物理 IP"
echo -e " 2. 请确认 repmgr 二进制文件路径是否正确"
echo ""
4.生成 Keepalived 配置 (setup_keepalived_conf.sh)
#!/bin/bash
# ============================================================
# 脚本功能:交互式生成 Keepalived 配置文件
# ============================================================
set -e
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}请使用 root 权限运行${NC}"
exit 1
fi
echo "============================================================"
echo " Keepalived 配置生成器"
echo "============================================================"
# 1. 询问节点类型
echo ""
PS3="请选择当前节点类型: "
options=("ha1 (10.0.0.104 - Master)" "ha2 (10.0.0.105 - Backup)")
select opt in "${options[@]}"
do
case $opt in
"ha1 (10.0.0.104 - Master)")
NODE_TYPE="ha1"
ROUTER_ID="LVS_HA1"
STATELESS_STATE="MASTER"
STATELESS_PRIO="150"
break
;;
"ha2 (10.0.0.105 - Backup)")
NODE_TYPE="ha2"
ROUTER_ID="LVS_HA2"
STATELESS_STATE="BACKUP"
STATELESS_PRIO="100"
break
;;
*) echo "无效选项 $REPLY";;
esac
done
# 2. 询问网卡名
echo ""
read -p "请输入网卡名称 (默认 ens33): " IFACE
IFACE=${IFACE:-ens33}
# 3. 确认 IP 前缀 (假设是 10.0.0.x)
NETWORK_PREFIX="10.0.0"
# ----------------------------------------------------
# 生成配置
# ----------------------------------------------------
CONF_FILE="/etc/keepalived/keepalived.conf"
echo ""
echo -e "${YELLOW}正在生成配置文件: ${CONF_FILE}${NC}"
# 备份旧配置
if [ -f "$CONF_FILE" ]; then
cp "$CONF_FILE" "${CONF_FILE}.bak.$(date +%s)"
fi
cat > $CONF_FILE << EOF
! /etc/keepalived/keepalived.conf
! Auto-generated for Node: ${NODE_TYPE}
global_defs {
router_id ${ROUTER_ID}
script_user root
enable_script_security
}
# -------------------------- 脚本定义区 --------------------------
vrrp_script chk_haproxy {
script "/etc/keepalived/scripts/chk_haproxy.sh"
interval 2
weight -20
fall 2
rise 2
}
vrrp_script chk_dns {
script "/etc/keepalived/scripts/chk_dns.sh"
interval 2
weight -20
}
vrrp_script chk_minio {
script "/etc/keepalived/scripts/chk_minio.sh"
interval 3
weight -20
}
vrrp_script chk_harbor {
script "/etc/keepalived/scripts/chk_port.sh 443"
interval 3
weight -20
}
vrrp_script chk_pgsql {
script "/etc/keepalived/scripts/chk_pgsql_repmgr.sh"
interval 2
weight -30
fall 1
rise 2
}
vrrp_script chk_redis {
script "/etc/keepalived/scripts/chk_redis.sh"
interval 2
weight -20
}
# -------------------------- VIP 实例区 --------------------------
# ==================================================
# Group A: 无状态服务 (抢占模式)
# ==================================================
vrrp_instance VI_DNS {
state ${STATELESS_STATE}
interface ${IFACE}
virtual_router_id 51
priority ${STATELESS_PRIO}
advert_int 1
authentication { auth_type PASS; auth_pass dnsvip1; }
virtual_ipaddress { ${NETWORK_PREFIX}.205/32 dev ${IFACE} label ${IFACE}:dns; }
track_script { chk_dns; chk_haproxy; }
}
vrrp_instance VI_MINIO {
state ${STATELESS_STATE}
interface ${IFACE}
virtual_router_id 54
priority ${STATELESS_PRIO}
advert_int 1
authentication { auth_type PASS; auth_pass minivip1; }
virtual_ipaddress { ${NETWORK_PREFIX}.203/32 dev ${IFACE} label ${IFACE}:minio; }
track_script { chk_minio; }
}
vrrp_instance VI_HARBOR {
state ${STATELESS_STATE}
interface ${IFACE}
virtual_router_id 55
priority ${STATELESS_PRIO}
advert_int 1
authentication { auth_type PASS; auth_pass harborvip1; }
virtual_ipaddress { ${NETWORK_PREFIX}.204/32 dev ${IFACE} label ${IFACE}:harbor; }
track_script { chk_harbor; chk_haproxy; }
}
# ==================================================
# Group B: 有状态服务 (非抢占模式)
# ==================================================
vrrp_instance VI_PG {
state BACKUP
interface ${IFACE}
virtual_router_id 52
priority 100
advert_int 1
nopreempt
authentication { auth_type PASS; auth_pass pgvip1; }
virtual_ipaddress { ${NETWORK_PREFIX}.201/32 dev ${IFACE} label ${IFACE}:pg; }
track_script { chk_pgsql; }
}
vrrp_instance VI_REDIS {
state BACKUP
interface ${IFACE}
virtual_router_id 53
priority 100
advert_int 1
nopreempt
authentication { auth_type PASS; auth_pass redisvip1; }
virtual_ipaddress { ${NETWORK_PREFIX}.202/32 dev ${IFACE} label ${IFACE}:redis; }
track_script { chk_redis; }
}
EOF
echo ""
echo -e "${GREEN}============================================================"
echo -e "✅ Keepalived 配置生成完成!"
echo -e "============================================================${NC}"
echo ""
echo "配置文件路径: $CONF_FILE"
echo ""
echo "下一步操作:"
echo "1. 检查配置文件内容是否正确"
echo "2. 启动并设置开机自启 Keepalived: systemctl enable keepalived --now"
echo ""
5.测试keepalived是否生效
root@ha1:~# ip addr show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:50:56:37:b7:41 brd ff:ff:ff:ff:ff:ff
altname enp2s1
inet 10.0.0.104/24 brd 10.0.0.255 scope global ens33
valid_lft forever preferred_lft forever
inet 10.0.0.205/32 scope global ens33:dns;
valid_lft forever preferred_lft forever
inet 10.0.0.203/32 scope global ens33:minio;
valid_lft forever preferred_lft forever
inet 10.0.0.204/32 scope global ens33:harbor;
valid_lft forever preferred_lft forever
inet 10.0.0.201/32 scope global ens33:pg;
valid_lft forever preferred_lft forever
inet 10.0.0.202/32 scope global ens33:redis;
valid_lft forever preferred_lft forever
inet6 fe80::250:56ff:fe37:b741/64 scope link
valid_lft forever preferred_lft forever
6. 模拟故障转移测试 (可选但推荐)
在 ha1 上手动停止 Keepalived,观察 VIP 是否飘向 ha2:
root@ha1:~# systemctl stop keepalived
root@ha1:~# ip addr show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:50:56:37:b7:41 brd ff:ff:ff:ff:ff:ff
altname enp2s1
inet 10.0.0.104/24 brd 10.0.0.255 scope global ens33
valid_lft forever preferred_lft forever
inet6 fe80::250:56ff:fe37:b741/64 scope link
valid_lft forever preferred_lft forever
root@ha2:~# ip addr show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:50:56:2b:bc:18 brd ff:ff:ff:ff:ff:ff
altname enp2s1
inet 10.0.0.105/24 brd 10.0.0.255 scope global ens33
valid_lft forever preferred_lft forever
inet 10.0.0.205/32 scope global ens33:dns;
valid_lft forever preferred_lft forever
inet 10.0.0.203/32 scope global ens33:minio;
valid_lft forever preferred_lft forever
inet 10.0.0.204/32 scope global ens33:harbor;
valid_lft forever preferred_lft forever
inet 10.0.0.201/32 scope global ens33:pg;
valid_lft forever preferred_lft forever
inet 10.0.0.202/32 scope global ens33:redis;
valid_lft forever preferred_lft forever
inet6 fe80::250:56ff:fe2b:bc18/64 scope link
valid_lft forever preferred_lft forever
7.ha1重启keepalived
# 在 ha1 上重新启动,VIP 会自动抢回来 (无状态服务)
root@ha1:~# ip addr show ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:50:56:37:b7:41 brd ff:ff:ff:ff:ff:ff
altname enp2s1
inet 10.0.0.104/24 brd 10.0.0.255 scope global ens33
valid_lft forever preferred_lft forever
inet 10.0.0.205/32 scope global ens33:dns;
valid_lft forever preferred_lft forever
inet 10.0.0.204/32 scope global ens33:harbor;
valid_lft forever preferred_lft forever
inet 10.0.0.203/32 scope global ens33:minio;
valid_lft forever preferred_lft forever
inet6 fe80::250:56ff:fe37:b741/64 scope link
valid_lft forever preferred_lft forever
root@ha2:~# ip a s ens33
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 00:50:56:2b:bc:18 brd ff:ff:ff:ff:ff:ff
altname enp2s1
inet 10.0.0.105/24 brd 10.0.0.255 scope global ens33
valid_lft forever preferred_lft forever
inet 10.0.0.201/32 scope global ens33:pg;
valid_lft forever preferred_lft forever
inet 10.0.0.202/32 scope global ens33:redis;
valid_lft forever preferred_lft forever
inet6 fe80::250:56ff:fe2b:bc18/64 scope link
valid_lft forever preferred_lft forever
三、申请ssl证书待用
1.1查看dns api
https://console.dnspod.cn/account/token/token
1.2添加dns api
cat setup-secrets.sh
#!/usr/bin/env bash
#==============================================================
# 一次性执行:安全初始化 DNSPod API 密钥
#==============================================================
set -euo pipefail
SECRET_DIR="/etc/acme-secrets"
mkdir -p "${SECRET_DIR}"
chmod 700 "${SECRET_DIR}"
echo "🔐 请输入 DNSPod API 凭据"
read -p "DNSPod ID: " dp_id
read -s -p "DNSPod API Key: " dp_key
echo
# 保存密钥
echo "${dp_id}" > "${SECRET_DIR}/dp_id"
echo "${dp_key}" > "${SECRET_DIR}/dp_key"
# 严格权限
chmod 600 "${SECRET_DIR}/dp_id" "${SECRET_DIR}/dp_key"
chown root:root "${SECRET_DIR}/dp_id" "${SECRET_DIR}/dp_key"
echo "✅ 凭据已安全存储至 ${SECRET_DIR}"
2.申请证书
cat acme_tencent_issue.sh
#!/usr/bin/env bash
set -euo pipefail
# ==========================================
# acme.sh + 腾讯云 DNSPod 通配符证书申请
# ==========================================
# -------------------------- 请在此处配置 --------------------------
# 1. 你的主域名 (将同时申请 domain.com 和 *.domain.com)
MAIN_DOMAIN="zz520.online"
# 2. 用于注册 Let's Encrypt 账户的邮箱 (用于接收过期通知)
ACCOUNT_EMAIL="admin@${MAIN_DOMAIN}"
# 3. 密钥存储路径 (与你的初始化脚本保持一致)
SECRET_DIR="/etc/acme-secrets"
# 4. 证书最终部署位置
TARGET_DIR="/etc/ssl/acme/${MAIN_DOMAIN}"
# -------------------------- 配置区域结束 --------------------------
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
log() { echo -e "${GREEN}[✅]${NC} $1"; }
err() { echo -e "${RED}[❌]${NC} $1"; }
warn() { echo -e "${YELLOW}[⚠️]${NC} $1"; }
# ==========================================
# 1. 安全检查与环境加载
# ==========================================
if [ ! -d "${SECRET_DIR}" ]; then
err "密钥目录不存在: ${SECRET_DIR}"
exit 1
fi
# 读取 DNSPod 密钥并去除首尾空白
DP_Id=$(cat "${SECRET_DIR}/dp_id" | tr -d '[:space:]')
DP_Key=$(cat "${SECRET_DIR}/dp_key" | tr -d '[:space:]')
if [ -z "${DP_Id}" ] || [ -z "${DP_Key}" ]; then
err "DNSPod 密钥为空,请检查 ${SECRET_DIR} 下的文件"
exit 1
fi
# 导出环境变量 (acme.sh 官方要求的变量名)
export DP_Id="${DP_Id}"
export DP_Key="${DP_Key}"
log "已加载 DNSPod API 凭据 (ID: ${DP_Id})"
# ==========================================
# 2. 安装/初始化 acme.sh
# ==========================================
ACME_BIN="$HOME/.acme.sh/acme.sh"
if [ ! -f "${ACME_BIN}" ]; then
log "正在安装 acme.sh ..."
# 官方推荐的在线安装方式
curl https://get.acme.sh | sh -s email="${ACCOUNT_EMAIL}"
# 重新加载环境变量,确保当前会话可用
export PATH="$HOME/.acme.sh:$PATH"
if [ -f "$HOME/.acme.sh/acme.sh.env" ]; then
# shellcheck source=/dev/null
source "$HOME/.acme.sh/acme.sh.env"
fi
else
log "acme.sh 已安装 (${ACME_BIN})"
fi
# 强制切换默认 CA 为 Let's Encrypt (官方默认现在是 ZeroSSL)
"${ACME_BIN}" --set-default-ca --server letsencrypt > /dev/null
log "已设置默认 CA 为 Let's Encrypt"
# ==========================================
# 3. 申请证书 (ECC 算法)
# ==========================================
log "正在申请证书 (ECC/EC-256) ..."
log "域名列表: ${MAIN_DOMAIN}, *.${MAIN_DOMAIN}"
# 官方文档标准命令: --dns dns_dp (对应 DNSPod.cn)
# 注意: 首次运行不要加 --force,以免触发速率限制
"${ACME_BIN}" --issue \
--dns dns_dp \
-d "${MAIN_DOMAIN}" \
-d "*.${MAIN_DOMAIN}" \
--keylength ec-256
# ==========================================
# 4. 部署证书到生产目录
# ==========================================
log "正在部署证书到 ${TARGET_DIR} ..."
mkdir -p "${TARGET_DIR}"
# 官方文档强调: 必须使用 --install-cert 安装到目标路径
# 不要直接使用 ~/.acme.sh 下的文件
"${ACME_BIN}" --install-cert \
-d "${MAIN_DOMAIN}" \
-d "*.${MAIN_DOMAIN}" \
--ecc \
--key-file "${TARGET_DIR}/privkey.pem" \
--fullchain-file "${TARGET_DIR}/fullchain.pem" \
--reloadcmd "echo '证书文件已更新,请根据需要手动重启服务 (如: systemctl reload nginx/postgresql)'"
# ==========================================
# 5. 安全权限加固
# ==========================================
chmod 700 "${TARGET_DIR}"
chmod 600 "${TARGET_DIR}/privkey.pem"
chmod 644 "${TARGET_DIR}/fullchain.pem"
# 尝试锁定文件所有者为 root (仅当以 root 运行时)
chown -R root:root "${TARGET_DIR}" 2>/dev/null || true
# ==========================================
# 6. 自动续期确认
# ==========================================
# acme.sh 安装时已自动配置 crontab,这里仅做提示
log "检查自动续期任务..."
if crontab -l | grep -q acme.sh; then
log "自动续期任务已存在 (crontab)"
else
warn "未在 crontab 中找到 acme.sh 任务,建议检查安装日志"
fi
# 开启自动升级 acme.sh (官方推荐)
"${ACME_BIN}" --upgrade --auto-upgrade > /dev/null 2>&1
# ==========================================
# 输出总结
# ==========================================
log " "
log "=============================================="
log " 🎉 通配符证书部署完成 🎉"
log "=============================================="
log -e " 主域名: \033[1;34m${MAIN_DOMAIN}\033[0m"
log -e " 泛域名: \033[1;34m*.${MAIN_DOMAIN}\033[0m"
log " "
log " 🔐 证书路径 (请在您的服务配置中使用):"
log " - Full Chain: ${TARGET_DIR}/fullchain.pem"
log " - Private Key: ${TARGET_DIR}/privkey.pem"
log " "
log " 🛠️ 维护命令:"
log " - 手动续期测试: ${ACME_BIN} --cron --home $HOME/.acme.sh --force"
log " - 查看证书信息: openssl x509 -in ${TARGET_DIR}/fullchain.pem -noout -text"
log "=============================================="
附:vim缩进错乱解决办法
vim ~/.vimrc
" 自动切换 paste 模式
augroup pastetoggle
autocmd!
au InsertEnter * set paste
au InsertLeave * set nopaste
augroup END
更多推荐
所有评论(0)