DRBD + Pacemaker + Corosync 实现 GitLab 高可用

发布时间: 更新时间: 总字数:2391 阅读时间:5m 作者:IP:上海 网址

本文介绍基于 DRBD + Pacemaker + Corosync 实现 GitLab 高可用(High Availability, HA)的经典架构。该架构通常是一个 Active/Passive (主/备) 架构。只有一台机器(主节点)运行 GitLab 服务并挂载存储,另一台机器(备节点)实时同步数据。当主节点宕机,备节点会自动接管 VIP(虚拟IP)、挂载存储并启动服务。

介绍

DRBD

DRBD (Distributed Replicated Block Device) 是 Linux 平台下一种基于软件的、无共享(Shared-Nothing)的存储复制解决方案。可以把它理解为 “通过网络实现的 RAID 1(镜像)”。

DRBD 作为一个 内核模块 工作在 Linux 的 I/O 栈中。它位于 文件系统(如 XFS, ext4)和 物理磁盘(如 /dev/sdb)之间。

  • 正常流程: 应用写数据 -> 文件系统 -> 物理硬盘。

  • DRBD 流程: 应用写数据 -> 文件系统 -> DRBD -> (同时写入:本地物理硬盘 + 通过网络发给对端 DRBD)。

  • RAID 1: 两块硬盘插在同一台电脑上,数据同时写两份。

  • DRBD: 两块硬盘插在两台不同的电脑上,通过网线连接,数据同时写两份。

DRBD 支持三种复制协议 (Replication Protocols),决定了数据的一致性和性能平衡。在高可用(HA)场景中,绝大多数情况使用协议 C。

  1. Protocol C (同步复制 - Synchronous):

    • 机制: 当本地磁盘写入成功,收到远程节点的写入确认后,才告诉应用程序写操作完成
    • 特点: 数据绝对安全(两边数据时刻一致)。但写入速度受网络延迟影响(写速度 = 磁盘速度 + 网络往返时间)。
    • 场景: 高可用集群(如 GitLab HA, MySQL HA)。
  2. Protocol A (异步复制 - Asynchronous):

    • 机制: 数据写入本地磁盘并发送到发送缓冲区后,立即告诉应用程序完成。不等待对方确认。
    • 特点: 写入速度快(接近本地磁盘),但如果主节点突然断电,可能丢失最近几秒的数据。
    • 场景: 跨长距离的异地容灾(网络延迟大)。
  3. Protocol B (内存同步 - Memory Synchronous):

    • 机制: 数据到达远程节点的内存后,即视为完成。
    • 特点: 介于 A 和 C 之间,风险在于远程节点如果断电且数据未落盘,数据会丢失。
    • 场景: 极少使用。

架构规划

本文是基于 CentOS 7/Rocky Linux 8 或 Ubuntu 20.04/22.04 通用的完整实施指南。

  • Node1 (Primary): 192.168.1.101 (gitlab-node1)
  • Node2 (Secondary): 192.168.1.102 (gitlab-node2)
  • VIP (Virtual IP): 192.168.1.100 (用户访问此IP)
  • 专用磁盘/分区: /dev/sdb1 (用于 DRBD 数据同步,两台机器需大小一致)

环境准备 (两台节点执行)

  1. 修改主机名与 Hosts

    bash
    # /etc/hosts
    192.168.1.101 gitlab-node1
    192.168.1.102 gitlab-node2
  2. 关闭防火墙和 SELinux (生产环境建议配置规则)

    bash
    systemctl stop firewalld && systemctl disable firewalld
    setenforce 0
    sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
  3. 时间同步 (非常重要)

    bash
    yum install -y chrony
    systemctl enable --now chronyd
  4. 配置 SSH 互信 确保 Node1 可以无密码 SSH 登录 Node2,反之亦然(用于文件拷贝和集群通信)。

部署 DRBD (数据镜像)

我们需要将 /var/opt/gitlab(GitLab 数据目录)放在 DRBD 设备上。

  1. 安装 DRBD CentOS: yum install -y elrepo-release && yum install -y kmod-drbd90 drbd90-utils Ubuntu: apt install -y drbd-utils

  2. 配置资源文件 在两台节点创建 /etc/drbd.d/gitlab.res:

    text
    resource gitlab {
        protocol C; # 同步复制协议,最安全
    
        on gitlab-node1 {
            device /dev/drbd0;
            disk /dev/sdb1;       # 你的实际物理分区
            address 192.168.1.101:7788;
            meta-disk internal;
        }
    
        on gitlab-node2 {
            device /dev/drbd0;
            disk /dev/sdb1;       # 你的实际物理分区
            address 192.168.1.102:7788;
            meta-disk internal;
        }
    }
  3. 初始化 DRBD (两台节点执行)

    bash
    drbdadm create-md gitlab
    drbdadm up gitlab
  4. 设置主节点 (仅在 Node1 执行)

    bash
    drbdadm primary --force gitlab
    mkfs.xfs /dev/drbd0  # 格式化 DRBD 设备

安装 GitLab

  1. 安装依赖与软件包 (两台节点) 按照 GitLab 官网安装社区版 (CE) 或企业版 (EE)。

    bash
    curl -s https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.rpm.sh | sudo bash
    yum install -y gitlab-ce
  2. 挂载数据并迁移 (仅在 Node1 执行) 先将 DRBD 挂载到临时目录,把初始数据放进去。

    bash
    mkdir -p /var/opt/gitlab
    mount /dev/drbd0 /var/opt/gitlab
    
    # 初次配置,生成配置文件
    gitlab-ctl reconfigure
    gitlab-ctl stop
    
    # 此时 /var/opt/gitlab 中已有数据
    umount /var/opt/gitlab
  3. 同步配置文件 (重要) 将 Node1 的 /etc/gitlab/gitlab.rb/etc/gitlab/gitlab-secrets.json 拷贝到 Node2。注意:gitlab-secrets.json 必须一致,否则加密数据无法在 Node2 解密。

    bash
    # 在 Node1 执行
    scp /etc/gitlab/gitlab.rb root@gitlab-node2:/etc/gitlab/
    scp /etc/gitlab/gitlab-secrets.json root@gitlab-node2:/etc/gitlab/
  4. 修改 GitLab 配置 (两台节点) 编辑 /etc/gitlab/gitlab.rb:

    ruby
    # 设置为 VIP
    external_url 'http://192.168.1.100'
    
    # 禁用开机自启 (交由 HA 集群管理)
    # 注意:GitLab 的 systemd 服务名通常是 gitlab-runsvdir

    在两台机器上执行命令禁用自启:

    bash
    systemctl disable gitlab-runsvdir

部署 Pacemaker 集群

使用 Pacemaker 来管理 VIP、挂载 DRBD 和启动 GitLab 服务。

  1. 安装集群软件 (两台节点)

    bash
    yum install -y pcs pacemaker corosync fence-agents-all
    systemctl enable --now pcsd
    passwd hacluster # 设置集群用户密码,两台需一致
  2. 创建集群 (仅在 Node1 执行)

    bash
    # 认证
    pcs cluster auth gitlab-node1 gitlab-node2 -u hacluster -p <你的密码>
    
    # 创建并启动集群
    pcs cluster setup --name gitlab_cluster gitlab-node1 gitlab-node2
    pcs cluster start --all
    pcs cluster enable --all
    
    # 禁用 STONITH (仅测试环境,生产环境强烈建议配置 STONITH/Fencing 设备以防脑裂)
    pcs property set stonith-enabled=false
    
    # 设置忽略 Quorum (因为只有2个节点,防止单节点无法工作)
    pcs property set no-quorum-policy=ignore

配置集群资源

我们需要定义三个资源:

  1. DRBD 数据资源 (Master/Slave 模式)
  2. 文件系统挂载
  3. GitLab 服务
  4. VIP

在 Node1 执行以下 PCS 命令:

  1. 配置 DRBD 资源

    bash
    pcs resource create DrbdData ocf:linbit:drbd \
      drbd_resource=gitlab op monitor interval=60s
    
    # 设置为主从克隆资源
    pcs resource master DrbdDataClone DrbdData \
      master-max=1 master-node-max=1 clone-max=2 clone-node-max=1 notify=true
  2. 配置文件系统资源

    bash
    pcs resource create FsData Filesystem \
      device="/dev/drbd0" directory="/var/opt/gitlab" fstype="xfs"
  3. 配置 GitLab 服务资源 GitLab 启动较慢,需调大超时时间。

    bash
    pcs resource create GitlabService systemd:gitlab-runsvdir \
      op monitor interval=60s timeout=100s \
      op start timeout=300s \
      op stop timeout=300s
  4. 配置 VIP 资源

    bash
    pcs resource create VirtualIP IPaddr2 ip=192.168.1.100 cidr_netmask=24
  5. 配置资源约束 (顺序和组合) 必须按照顺序启动:DRBD主 -> 挂载文件系统 -> 绑定VIP -> 启动GitLab。

    bash
    # 组合约束:FS、VIP、GitLab 必须在同一台机器运行
    pcs constraint colocation add FsData with DrbdDataClone INFINITY with-rsc-role=Master
    pcs constraint colocation add VirtualIP with FsData INFINITY
    pcs constraint colocation add GitlabService with VirtualIP INFINITY
    
    # 顺序约束:先 Promote DRBD,再 Mount,再 VIP,最后 Start GitLab
    pcs constraint order promote DrbdDataClone then start FsData
    pcs constraint order start FsData then start VirtualIP
    pcs constraint order start VirtualIP then start GitlabService

验证与测试

  1. 查看状态

    bash
    pcs status

    正常情况下,所有资源应该都在 Node1 上运行,Node2 为 Standby/Slave。

  2. 访问测试 浏览器访问 http://192.168.1.100,应能看到 GitLab 登录页。

  3. 故障模拟 (手动切换)

    bash
    # 将 Node1 设为待机
    pcs node standby gitlab-node1

    观察 pcs status,你会看到资源依次停止,DRBD 在 Node2 变为 Primary,服务在 Node2 启动。这通常需要几分钟时间(GitLab 启动较慢)。

  4. 脑裂恢复 (DRBD Split Brain) 如果两个节点都变成 Standalone 或数据不一致,需要手动恢复:

    • 从节点 (数据不要的那个) 执行:
      bash
      drbdadm secondary gitlab
      drbdadm connect --discard-my-data gitlab
    • 主节点 (数据保留的那个) 执行:
      bash
      drbdadm connect gitlab

关键注意事项

  1. GitLab 版本一致性: 升级 GitLab 时,必须先冻结集群,在两台机器升级相同版本,再恢复集群。
  2. GitLab 启动慢: GitLab 包含 Postgres、Redis、Unicorn 等多个组件,gitlab-runsvdir 启动后,内部服务还需要时间初始化。Pacemaker 的 timeout 设置一定要足够长。
  3. Fencing (STONITH): 在生产环境中,必须配置 Fencing 设备(如 IPMI 卡或 VMware 接口)。如果没有 Fencing,当心跳网络中断时,两台机器可能同时抢占 VIP 和 DRBD Primary,导致数据损坏(脑裂)。
  4. 日志: 故障排查查看 /var/log/messages/var/log/cluster/corosync.log