Harbor 高可用 (HA) 与 HTTPS 安全加固实践

Harbor 作为企业级的 Docker 镜像仓库,在生产环境中稳定可靠地运行至关重要。本文将深入探讨如何为 Harbor 配置高可用性 (HA) 方案,并启用 HTTPS 来保障数据传输安全,确保 Harbor 服务的连续性和安全性。

一、Harbor 高可用 (HA) 解决方案概述

在生产环境中,单点故障是不可接受的。为了保证 Harbor 服务的高可用,通常需要考虑以下几个层面:

  1. 接入层高可用:确保用户或 CI/CD 系统始终能通过一个稳定的入口访问 Harbor 服务,即使后端某个 Harbor 实例宕机。
  2. Harbor 服务自身高可用:运行多个 Harbor 实例,分担负载或实现故障转移。
  3. 后端存储高可用:Harbor 存储镜像数据(Registry)和元数据(Database)。这两部分都需要高可用方案。
    • Registry 存储:通常使用共享存储,如 NFS、Ceph、S3 兼容对象存储等,确保所有 Harbor 实例访问的是同一份数据。
    • Database 存储:使用高可用的数据库集群,如 PostgreSQL 主从复制或集群方案。

本文将重点关注 接入层高可用 的一种实现方式:使用 Keepalived 实现 Virtual IP (VIP) 漂移。

方案:基于 Keepalived 的 Active/Passive HA

  • 架构:部署两个(或多个)配置完全相同的 Harbor 实例。使用 Keepalived 在这两个实例之间管理一个 VIP。
  • 工作原理
    • Keepalived 通过 VRRP (Virtual Router Redundancy Protocol) 协议选举一个 Master 节点。
    • Master 节点持有 VIP,负责处理所有通过 VIP 访问 Harbor 的请求。
    • Backup 节点处于待命状态,持续监听 Master 节点的心跳。
    • Keepalived 配置健康检查脚本,用于探测本地 Harbor 服务的可用性。
    • 当 Master 节点宕机或其上的 Harbor 服务不可用(健康检查失败)时,Keepalived 会降低其优先级。
    • Backup 节点检测到 Master 故障后,如果自身健康且优先级最高,则接管 VIP,成为新的 Master。
    • 整个切换过程对客户端透明,客户端始终访问 VIP。
  • 前提条件
    • 至少两个已部署并配置相同的 Harbor 节点(假设为 10.0.0.10110.0.0.102)。
    • Harbor 的 Registry 数据必须使用 共享存储(如 NFS、S3 等)。
    • Harbor 的数据库必须使用 外部高可用数据库集群主从复制,并配置所有 Harbor 实例连接到该集群/主库(或其 VIP)。 Keepalived 只解决入口 IP 的漂移,不解决数据同步问题。
    • 网络环境支持 VRRP 协议(通常需要二层可达,注意防火墙规则)。

二、使用 Keepalived 实现 Harbor VIP 漂移

以下步骤演示如何在两个 Harbor 节点(docker101: 10.0.0.101, docker102: 10.0.0.102)上配置 Keepalived,实现 VIP 10.0.0.250 的高可用。

1. 安装 Keepalived

在两个 Harbor 节点上都执行安装命令:

# 在 docker101 和 docker102 上执行
sudo apt update
sudo apt -y install keepalived

2. 创建健康检查脚本

Keepalived 需要一个脚本来检查本地 Harbor 服务的健康状况。这里我们创建一个简单的脚本,检查 Harbor Nginx 前端(通常监听 80 或 443 端口)是否可用。

# 在 docker101 和 docker102 上创建此脚本
sudo mkdir -p /etc/keepalived/
sudo tee /etc/keepalived/check_harbor.sh > /dev/null <<'EOF'
#!/bin/bash
# 检查 Harbor Nginx 端口是否监听
# $1: 要检查的端口号 (例如 80 或 443)

PORT_TO_CHECK=${1:-80} # 默认为 80 端口
CHECK_URL="http://127.0.0.1:${PORT_TO_CHECK}/" # 检查本地 Nginx

# 尝试访问 Harbor Nginx 代理的某个路径,根据实际情况调整
# 对于较新版本 Harbor,可以直接检查 /api/v2.0/ping 或 /v2/
# 这里我们简单检查本地端口是否能建立连接
if curl --output /dev/null --silent --head --fail --max-time 2 "${CHECK_URL}"; then
  # 或者使用 nc/ss 检查端口监听:
  # if ss - Hltn sport = :${PORT_TO_CHECK} | grep LISTEN; then
  exit 0 # 端口正常,返回 0
else
  exit 1 # 端口异常,返回 1
fi
EOF

# 赋予执行权限
sudo chmod +x /etc/keepalived/check_harbor.sh
  • 注意:这个脚本非常基础。生产环境建议使用更健壮的检查,例如:
    • 检查 Harbor Core API 是否正常 (/api/v2.0/ping)。
    • 如果使用 HTTPS,请修改 CHECK_URLhttps://127.0.0.1:${PORT_TO_CHECK}/ 并可能需要添加 curl -k (不推荐,最好配置信任) 或检查特定 API 端点。
    • 脚本的检查目标端口 ($1) 需要与 keepalived.confvrrp_script 的参数一致。如果 Harbor 使用 HTTPS,则应检查 443 端口。

3. 配置 Keepalived (Master 节点 - docker101)

编辑 docker101 上的 Keepalived 配置文件 /etc/keepalived/keepalived.conf

# 在 docker101 上执行
sudo tee /etc/keepalived/keepalived.conf > /dev/null <<'EOF'
! Configuration File for keepalived

global_defs {
   # 标识本节点的路由器 ID,建议使用节点 IP 或唯一名称
   router_id harbor_node_101
   # 启用 VRRP 脚本日志记录 (可选, 方便调试)
   # vrrp_log_run_scripts
}

# 定义健康检查脚本
vrrp_script chk_harbor_service {
    script "/etc/keepalived/check_harbor.sh 80" # 检查 HTTP 80 端口,如果用 HTTPS 则改为 443
    interval 2                                  # 每 2 秒执行一次脚本
    timeout 1                                   # 脚本执行超时时间
    fall 2                                      # 连续 2 次失败则认为服务故障
    rise 2                                      # 连续 2 次成功则认为服务恢复
    weight -20                                  # 如果脚本失败(exit 非0),则将本节点优先级降低 20
}

# 定义 VRRP 实例
vrrp_instance VI_HARBOR {
    state MASTER                            # 初始状态为 Master
    interface ens33                         # VIP 绑定的网络接口,根据实际情况修改
    virtual_router_id 51                    # VRID,同一 VRRP 组内的节点必须相同!
    priority 101                            # 优先级,Master 节点通常设置较高值
    advert_int 1                            # VRRP 通告间隔(秒)
    # mcast_src_ip 10.0.0.101               # (可选) 指定发送 VRRP 报文的源 IP,通常自动选择接口 IP
                                            # 如果网络环境复杂或有多 IP,建议指定
    # nopreempt                             # (可选) Master 恢复后不抢占 VIP,让当前 Master 继续服务。
                                            # 如果希望 Master 恢复后立即夺回 VIP,请注释或移除此行。

    authentication {
        auth_type PASS                      # 认证方式
        auth_pass yinzhengjie_k8s_ha        # 认证密码,同一 VRRP 组内必须相同!
    }

    # 追踪健康检查脚本
    track_script {
         chk_harbor_service                 # 关联上面定义的脚本
    }

    # 定义虚拟 IP 地址 (VIP)
    virtual_ipaddress {
        10.0.0.250/32 dev ens33             # VIP 地址和子网掩码,/32 表示单主机路由
                                            # dev ens33 (可选) 明确指定 VIP 绑定的接口
    }

    # (可选) 针对单播模式 (如果组播受限)
    # unicast_src_ip 10.0.0.101             # 本机 IP
    # unicast_peer {
    #    10.0.0.102                         # 对端节点 IP
    # }
}
EOF
  • 关键配置解释
    • router_id: 节点的唯一标识。
    • vrrp_script: 定义如何执行健康检查。weight -20 表示检查失败时,优先级降低 20。
    • state MASTER: 指定此节点优先成为 Master。
    • interface: VIP 将绑定到此网络接口。
    • virtual_router_id: 极其重要,同一高可用组内的所有 Keepalived 节点必须配置 相同 的 VRID(例如 51)。
    • priority: 决定 Master 选举,值越高优先级越高。Master 应高于 Backup。
    • authentication: 确保只有密码匹配的节点才能加入 VRRP 组。
    • track_script: 将健康检查脚本与 VRRP 实例关联。当脚本失败时,根据 weight 调整优先级。
    • virtual_ipaddress: 要管理的 VIP。/32 通常用于 VIP。
    • nopreempt: (可选) 防止已恢复的原 Master 节点抢占 VIP。在 Active/Passive 模式下,如果希望故障恢复后 VIP 留在当前工作的节点上(减少不必要的切换),可以启用 nopreempt。如果希望原 Master 恢复后总是拿回 VIP,则不设置或注释掉此项。

4. 配置 Keepalived (Backup 节点 - docker102)

编辑 docker102 上的 Keepalived 配置文件 /etc/keepalived/keepalived.conf。大部分配置与 Master 相同,主要修改 state, priority, 和 router_id

# 在 docker102 上执行
sudo tee /etc/keepalived/keepalived.conf > /dev/null <<'EOF'
! Configuration File for keepalived

global_defs {
   router_id harbor_node_102 # 修改为节点 102 的唯一标识
   # vrrp_log_run_scripts
}

vrrp_script chk_harbor_service {
    script "/etc/keepalived/check_harbor.sh 80" # 与 Master 节点保持一致
    interval 2
    timeout 1
    fall 2
    rise 2
    weight -20
}

vrrp_instance VI_HARBOR {
    state BACKUP                            # 初始状态为 Backup
    interface ens33                         # 与 Master 节点保持一致
    virtual_router_id 51                    # !! 必须与 Master 节点相同 !!
    priority 100                            # !! 优先级必须低于 Master 节点 (例如 100) !!
    advert_int 1
    # mcast_src_ip 10.0.0.102               # (可选) 指定源 IP
    # nopreempt                             # (可选) 通常 Backup 节点也建议设置 nopreempt

    authentication {
        auth_type PASS
        auth_pass yinzhengjie_k8s_ha        # !! 必须与 Master 节点相同 !!
    }

    track_script {
         chk_harbor_service                 # 与 Master 节点保持一致
    }

    virtual_ipaddress {
        10.0.0.250/32 dev ens33             # 与 Master 节点保持一致
    }

    # (可选) 针对单播模式
    # unicast_src_ip 10.0.0.102             # 本机 IP
    # unicast_peer {
    #    10.0.0.101                         # 对端节点 IP
    # }
}
EOF
  • 主要区别
    • router_id: 更改为 harbor_node_102
    • state: 设置为 BACKUP
    • priority: 设置为 100低于 Master 节点的 101
    • virtual_router_idauth_pass: 必须 与 Master 节点完全一致。

5. 启动并设置 Keepalived 开机自启

在两个 Harbor 节点上都执行:

# 在 docker101 和 docker102 上执行
sudo systemctl restart keepalived
sudo systemctl enable keepalived

6. 验证初始状态

  • 查看 VIP:在 docker101 (Master) 上执行 ip addr show ens33,应该能看到 10.0.0.250 这个 VIP。

    # 在 docker101 上执行
    ip addr show ens33
    # ... 输出应包含类似行 ...
    # inet 10.0.0.101/24 brd 10.0.0.255 scope global ens33
    #    valid_lft forever preferred_lft forever
    # inet 10.0.0.250/32 scope global ens33  <--- VIP 存在
    #    valid_lft forever preferred_lft forever
    # ...
    
  • docker102 (Backup) 上执行 ip addr show ens33不应该 看到 10.0.0.250 这个 VIP。

  • 查看 Keepalived 日志:检查 Keepalived 服务状态和日志,确认 VRRP 状态。

    # 在 docker101 和 docker102 上查看
    sudo systemctl status keepalived
    sudo journalctl -u keepalived -f  # 实时查看日志
    # 或者查看日志文件 (如果配置了)
    # sudo tail -f /var/log/syslog | grep Keepalived
    

    在 Master (docker101) 日志中应该看到类似 Entering MASTER STATE 的信息。在 Backup (docker102) 日志中应该看到类似 Entering BACKUP STATE 的信息。

  • 访问 Harbor:尝试通过 VIP http://10.0.0.250 (或 https:// 如果已配置 HTTPS) 访问 Harbor Web UI,应该可以正常访问。

7. 测试故障切换

  • 模拟 Master 故障:在 docker101 上停止 Keepalived 服务。

    # 在 docker101 上执行
    sudo systemctl stop keepalived
    
  • 观察 VIP 漂移

    • docker101 上再次执行 ip addr show ens33,确认 VIP 10.0.0.250 已经消失。
    • docker102 上执行 ip addr show ens33现在应该能看到 VIP 10.0.0.250
    # 在 docker102 上执行
    ip addr show ens33
    # ... 输出现在应包含 VIP ...
    # inet 10.0.0.102/24 brd 10.0.0.255 scope global ens33
    #    valid_lft forever preferred_lft forever
    # inet 10.0.0.250/32 scope global ens33  <--- VIP 已漂移至此
    #    valid_lft forever preferred_lft forever
    # ...
    
    • 查看 docker102 的 Keepalived 日志,应该看到类似 Entering MASTER STATE 的信息。
  • 再次访问 Harbor:继续通过 VIP http://10.0.0.250 访问 Harbor Web UI。由于 VIP 已经切换到 docker102,并且 docker102 上的 Harbor 服务正常运行(且连接到共享存储和数据库),访问应该仍然成功。

8. 测试故障恢复 (Failback)

  • docker101 上重新启动 Keepalived 服务。

    # 在 docker101 上执行
    sudo systemctl start keepalived
    
  • 观察 VIP 行为

    • 如果未设置 nopreemptdocker101 的优先级 (101) 高于 docker102 (100),docker101 会重新抢占 VIP。VIP 将从 docker102 消失,并重新出现在 docker101 上。
    • 如果设置了 nopreempt:即使 docker101 恢复且优先级更高,它也不会主动抢占。VIP 将 继续保留docker102 上,直到 docker102 发生故障。

根据你的配置(包含了 nopreempt),VIP 应该会留在 docker102 上。

三、Harbor 部署基于官方认证的 HTTPS

为 Harbor 启用 HTTPS 是生产环境的基本要求,可以加密客户端与 Harbor 之间的数据传输,防止中间人攻击。

前提

  • 你已经从受信任的证书颁发机构 (CA) 获取了 SSL/TLS 证书(例如,Let's Encrypt 或商业 CA)。
  • 证书通常包含至少两个文件:证书文件 (.crt.pem,可能包含证书链) 和私钥文件 (.key)。
  • 证书的通用名称 (Common Name, CN) 或主题备用名称 (Subject Alternative Name, SAN) 必须与你打算用于访问 Harbor 的域名完全匹配(例如 www.yinzhengjie.com)。

步骤

1. 准备证书文件

  • 在部署 Harbor 的节点上创建一个用于存放证书的目录(如果使用 HA,请在 所有 Harbor 节点上执行此操作)。

    # 假设在 docker102 上操作 (HA 环境下,docker101 也需要)
    # 使用你实际的 Harbor 安装路径
    HARBOR_BASE_DIR="/path/to/your/harbor" # 例如 /opt/harbor
    mkdir -p ${HARBOR_BASE_DIR}/certs
    cd ${HARBOR_BASE_DIR}/certs
    
  • 将你的证书文件(例如 yourdomain.crt)和私钥文件(例如 yourdomain.key)上传或复制到这个 certs 目录。

    • 示例中使用的是 yinzhengjie.com_bundle.crtyinzhengjie.com.key。请替换为你自己的文件名。
    • 确保证书文件权限安全,私钥文件尤其重要,通常设置为 chmod 600 yourdomain.key
    # 示例:假设证书已下载并解压到当前目录的 yinzhengjie.com_nginx 子目录
    # 实际操作中,直接将 .crt 和 .key 文件放入 ${HARBOR_BASE_DIR}/certs 即可
    # 例如:
    # cp /path/from/download/www.yinzhengjie.com_bundle.crt ${HARBOR_BASE_DIR}/certs/
    # cp /path/from/download/www.yinzhengjie.com.key ${HARBOR_BASE_DIR}/certs/
    # sudo chmod 600 ${HARBOR_BASE_DIR}/certs/www.yinzhengjie.com.key
    

2. 修改 Harbor 配置文件 (harbor.yml)

  • 编辑 Harbor 的主配置文件 harbor.yml

    # 假设在 docker102 上操作 (HA 环境下,docker101 的 harbor.yml 也需要同步修改)
    cd ${HARBOR_BASE_DIR}
    vim harbor.yml
    
  • 找到并修改以下配置项:

    • hostname: 必须 设置为你的证书匹配的域名。

      # hostname 是外部访问 Harbor 的地址,必须与证书 CN/SAN 匹配
      hostname: www.yinzhengjie.com
      
    • http: (可选) 如果只想允许 HTTPS 访问,可以注释掉 http 部分或只保留 https 部分。

      # http:
      #   # port for http, default is 80
      #   port: 80
      
    • https: 配置 HTTPS 相关参数。

      # https configuration
      https:
        # https port for harbor, default is 443
        port: 443
        # The path of cert and key files for nginx
        # !! 使用你实际存放证书的绝对路径 !!
        certificate: /path/to/your/harbor/certs/www.yinzhengjie.com_bundle.crt
        private_key: /path/to/your/harbor/certs/www.yinzhengjie.com.key
      

      确保 certificateprivate_key 的路径指向你在步骤 1 中放置的实际文件。

3. 应用配置并重新安装/更新 Harbor

修改 harbor.yml 后,需要重新运行 Harbor 的安装脚本来应用更改。这通常会重新生成 Nginx 等组件的配置并重启容器。

  • 停止当前运行的 Harbor (如果正在运行)

    # 在 Harbor 安装目录下执行 (docker101 和 docker102 都需要,如果 HA)
    sudo docker-compose down -v # -v 会移除关联的数据卷,如果需要保留旧数据,请谨慎操作或备份
    
  • 运行 prepare 脚本 (重要):此脚本会根据 harbor.yml 生成所需的配置文件。

    # 在 Harbor 安装目录下执行 (docker101 和 docker102 都需要,如果 HA)
    sudo ./prepare
    
  • 运行 install.sh 脚本:完成安装或更新过程。

    # 在 Harbor 安装目录下执行 (docker101 和 docker102 都需要,如果 HA)
    # 根据需要添加其他模块,如 --with-notary, --with-trivy, --with-chartmuseum
    sudo ./install.sh --with-chartmuseum
    

    --with-chartmuseum 是用于启用 Helm Chart 仓库功能,根据你的需求添加。

4. 验证 HTTPS 访问

  • DNS 配置 (生产环境):确保你的域名 (www.yinzhengjie.com) 的 DNS 解析指向 Harbor 的 VIP (10.0.0.250)。

  • 本地 Hosts 文件 (测试环境):如果在测试环境或 DNS 未配置,可以临时修改操作系统的 hosts 文件,将域名指向 VIP。

    • Windows: C:\Windows\System32\drivers\etc\hosts
    • Linux/macOS: /etc/hosts
    • 添加一行:10.0.0.250 www.yinzhengjie.com
  • 访问 Web UI:打开浏览器,访问 https://www.yinzhengjie.com (或者你配置的 hostnamehttps.port,默认是 443)。

    • 浏览器应该显示安全的锁图标,表示连接已通过 HTTPS 加密并且证书受信任。
    • 登录 Harbor 并进行基本操作,确认功能正常。
  • Docker/kubectl 客户端配置:如果客户端(如 Docker daemon 或 Kubernetes 节点)需要信任此 Harbor 仓库,并且使用的是官方 CA 签发的证书,通常不需要额外配置。如果使用自签名证书或私有 CA 证书,则需要在客户端配置信任该证书。

四、总结与后续

通过结合 Keepalived 实现的 VIP 漂移和标准的 HTTPS 配置,我们为 Harbor 构建了一个更健壮、更安全的运行环境。

关键要点回顾

  • Harbor HA 基础:Keepalived 解决了入口 IP 的高可用,但 必须 配合共享存储 (Registry) 和高可用数据库 (Database) 才能实现完整的 Harbor 服务高可用。
  • Keepalived 配置:注意 virtual_router_id, priority, authentication, track_script 等关键参数的正确设置,确保 Master 和 Backup 节点配置协调一致。健康检查脚本 (check_harbor.sh) 对及时发现服务故障至关重要。
  • HTTPS 配置harbor.yml 中的 hostname 必须与证书匹配,certificateprivate_key 路径必须正确。修改配置后需运行 ./prepare./install.sh 生效。
  • 生产环境:使用 DNS 解析 VIP,而非修改 hosts 文件。确保证书由受信任的 CA 签发。

后续考虑

  • 监控:对 Keepalived 服务本身、VIP 状态以及 Harbor 各组件进行监控。
  • 数据库 HA:详细规划并实施 PostgreSQL 或其他数据库的高可用方案。
  • 存储冗余:确保共享存储(NFS、S3 等)本身具有高可用性和数据冗余。
  • 备份策略:定期备份 Harbor 数据库和 Registry 存储。
  • 负载均衡:对于更高负载的场景,可以考虑使用负载均衡器(如 Nginx, HAProxy, F5 等)配合多个 Active 的 Harbor 实例,但这需要更复杂的配置来处理会话和状态。

希望这篇详细的指南能帮助你成功部署高可用且安全的 Harbor 服务!


posted on 2025-04-15 09:42  Leo-Yide  阅读(100)  评论(0)    收藏  举报