背景
在公司接手处理 单点Gitlab 服务高可用改造需求,前期也测试过基于NFS/NAS的双主架构,但由于NFS/NAS的架构访问体验非常的差,其中的网络消耗成本太高。官方虽然有提供基于AWS的双主架构,但官方也强烈不建议这样。所以采用了主备方案,主备模式中,最重要的是保证两端的数据一致性,且能够实现自动的故障转移,数据实时同步方案这里我简单提一下。
- Pacemaker Cluster + DRBD
这是Gitlab官方主备数据同步方案 ,但实施复杂度高,配置较为复杂,后续我再补充此方案过程。 - Keepalived + Rsync + Inotify-tools
实施起来比较灵活,可控性高,所以这里我用此方法实现数据高可用。
如果大家有好的Gitlab双活高可用方案,希望可以交流一下。
说明
Gitlab的部署比较简单,所以本文主要分享数据的实时同步,虽然目前网上已经有很多基于rsync+inotify
的资料,但是存在很多的问题。 例如双活架构的双向实时同步场景,当一端机器down
机了,此时数据是同步不过去的,等该机器up
恢复后,这期间就发生了部分数据不一致,那么怎么保证两端数据一致?而且大部分资料还是只要监听到数据变动就进行全量同步,这太不合理了。
本文的应用场景是主备环境下的数据实时同步,双活的数据实时同步场景,个人觉得rsync+inotify
方案存在很多的缺陷,所以不建议大家使用。
部署过程
环境 | 说明 |
---|---|
系统版本 | Centos 6.x,x86_64 |
主节点 | IP:10.1.1.1,主机名:1-1-1 |
备节点 | IP:10.1.1.2,主机名:1-1-2 |
VIP | 10.1.1.10 |
一、安装必备软件
yum install keepalived rsync xinetd inotify-tools -y
#
# 注:Centos7.x 不用安装 xinetd
二、配置 rsync daemon
主备节点均需配置
,这里配置了认证,也可以不加auth users、secrets file 选项,以匿名的方式进行数据传输。具体的路径,请根据实际情况做调整。
首先,配置 rsync 服务的主配置
# cat /etc/rsyncd.conf
# 创建配置文件,写入以下内容。
-------------------以下为文件内容-------------------
# /etc/rsyncd: configuration file for rsync daemon mode
uid = root
gid = root
# use chroot = yes
max connections = 4
pid file = /var/run/rsyncd.pid
exclude = lost+found/
# transfer logging = yes
# timeout = 900
# ignore nonreadable = yes
# dont compress = *.gz *.tgz *.zip *.z *.Z *.rpm *.deb *.bz2
[gitlab_data]
path = /var/opt/gitlab
comment = Gitlab Data Directory.
read only = no
auth users = gitlab
secrets file = /etc/rsyncd/gitlab_rsyncd.pass
创建认证文件
# 创建存放密码认证文件目录
mkdir /etc/rsyncd
# 创建服务端认证文件
echo "gitlab:yourpass" > /etc/rsyncd/gitlab_rsyncd.pass
# 创建客户端认证文件
echo "yourpass" > /etc/rsyncd/gitlab_client.pass
接下来,配置xinetd
服务
注:Centos 7.x 不需此步骤,如要自定义配置文件路径,可编辑
/usr/lib/systemd/system/rsyncd.service
# cat /etc/xinetd.d/rsync
# 编辑此文件,启用 rsync,并指定配置文件路径。
-------------------以下为文件内容-------------------
# default: off
# description: The rsync server is a good addition to an ftp server, as it \
# allows crc checksumming etc.
service rsync
{
disable = no # yes ---> no
flags = IPv6
socket_type = stream
wait = no
user = root
server = /usr/bin/rsync
server_args = --daemon
# 可自定义了配置文件路径,默认是 /etc/rsyncd.conf
# server_args = --daemon --config=/your/path/rsyncd.conf
log_on_failure += USERID
}
最后,启动服务并设置开机启动
# Centos6.x
service xinetd start
chkconfig xinetd on
# Centos7.x
systemctl start rsyncd.service
systemctl enable rsyncd.service
三、编写inotifywait脚本
脚本无需手动运行,会由后面的Keepalived程序根据主备角色变化情况,自动的运行和关闭。文件名和文件路径,请根据自己情况调整。
#!/bin/bash
# File name:job_gitlab_data_realtime_sync.sh
# File path: /opt/script/job_gitlab_data_realtime_sync.sh
src_dir="/var/opt/gitlab-data"
rsync_module_name="gitlab_data"
# 如需多个节点同步,可以填写多个IP
# 用这种判断主机名的方法,实现通用的脚本
# 就无需每个节点都得单独修改脚本的 dest_ip 变量内容了。
if [[ $(hostname) =~ 1-1-1 ]];then
dest_ip="10.1.1.2"
else
dest_ip="10.1.1.1"
fi
rsync_user="gitlab"
rsync_pass="/etc/rsyncd/gitlab_client.pass"
#
. /etc/init.d/functions
# 开启inotifywait文件监控,当文件发生变化进行文件同步
cd ${src_dir}
inotifywait -mrq -e modify,attrib,close_write,move,create,delete --format '%e %w%f' ./ |
while read file;do
INO_EVENT=$(echo $file | awk '{print $1}') # 把inotify输出切割 把事件类型部分赋值给INO_EVENT
INO_FILE=$(echo $file | awk '{print $2}') # 把inotify输出切割 把文件路径部分赋值给INO_FILE
# 判断事件类型
#增加、修改、写入完成、移动进事件
#增、改放在同一个判断,因为他们都肯定是针对文件的操作,即使是新建目录,要同步的也只是一个空目录,不会影响速度。
if [[ $INO_EVENT =~ 'CREATE' ]] || [[ $INO_EVENT =~ 'MODIFY' ]] || [[ $INO_EVENT =~ 'CLOSE_WRITE' ]] || [[ $INO_EVENT =~ 'MOVED_TO' ]];then
for ip in ${dest_ip};do
rsync -azcR --password-file=${rsync_pass} $(dirname ${INO_FILE}) ${rsync_user}@${ip}::${rsync_module_name}
# INO_FILE变量代表文件路径 -c校验文件内容
#仔细看 上面的rsync同步命令 源是用了$(dirname ${INO_FILE})变量 即每次只针对性的同步发生改变的文件的目录
# (只同步目标文件的方法在生产环境的某些极端环境下会漏文件 现在可以在不漏文件下也有不错的速度 做到平衡)
# 然后用-R参数把源的目录结构递归到目标后面 保证目录结构一致性
done
fi
#修改属性事件(指 touch chgrp chmod chown等操作)
if [[ $INO_EVENT =~ 'ATTRIB' ]];then
# 如果修改属性的是目录 则不同步,因为同步目录会发生递归扫描,等此目录下的文件发生同步时,rsync会顺带更新此目录。
if [ ! -d "$INO_FILE" ];then
for ip in ${dest_ip};do
rsync -azcR --password-file=${rsync_pass} $(dirname ${INO_FILE}) ${rsync_user}@${ip}::${rsync_module_name}
done
fi
fi
#删除、移动出事件
if [[ $INO_EVENT =~ 'DELETE' ]] || [[ $INO_EVENT =~ 'MOVED_FROM' ]];then
for ip in ${dest_ip};do
rsync -azcR --delete --password-file=${rsync_pass} $(dirname ${INO_FILE}) ${rsync_user}@${ip}::${rsync_module_name}
#看rsync命令 如果直接同步已删除的路径${INO_FILE}会报no such or directory错误 所以这里同步的源是被删文件或目录的上一级路径,并加上--delete来删除目标上有而源中没有的文件,这里不能做到指定文件删除,如果删除的路径越靠近根,则同步的目录月多,同步删除的操作就越花时间。这里有更好方法的同学,欢迎交流。
done
fi
done
优化 inotify
如果不进行优化,遇到瓶颈会有如下错误提示
Failed to watch /your/path; upper limit on inotify watches reached!
Please increase the amount of inotify watches allowed per user via `/proc/sys/fs/inotify/max_user_watches'.
查看当前参数值
# cat /proc/sys/fs/inotify/max_*
# max_queued_events max_user_instances max_user_watches
16384
128
8192
主要优化 max_user_watches 及 max_queued_events ,具体大小可以等于当前数据盘的 inode最大值(我这里是1T数据盘设定的大小)
echo "67108864" > /proc/sys/fs/inotify/max_user_watches
echo "67108864" > /proc/sys/fs/inotify/max_queued_events
# 将下面参数写入 /etc/sysctl.conf,永久生效
fs.inotify.max_user_watches = 67108864
fs.inotify.max_queued_events = 67108864
四、配置 Keepalived
编辑主配置文件
不同的节点内容需根据实际情况稍作修改。
# cat /etc/keepalived/keepalived.conf
# 编辑配置文件,写入以下内容。
-------------------以下为文件内容-------------------
# ! Configuration File for keepalived
global_defs {
notification_email {
opsarno@qq.com
}
notification_email_from 1-1-1@opsarno.com # 其它的节点需稍作修改
smtp_server 127.0.0.1
smtp_connect_timeout 30
router_id 1-1-1 # 其它的节点需稍作修改
}
# 当 gitlab 服务不可用时,关闭Keepalived服务。
vrrp_script check_gitlab_service {
script "/etc/keepalived/script/check_gitlab_service.sh"
interval 1
}
vrrp_instance gitlab_v1 {
state BACKUP # 两个节点都要配置为BACKUP
interface eth0
virtual_router_id 51
priority 100 # 其它的节点需稍作修改
nopreempt # 启用此选项
advert_int 1
unicast_src_ip 10.1.1.1
unicast_peer {
10.1.1.2
}
authentication {
auth_type PASS
auth_pass gitlab_pass
}
virtual_ipaddress {
10.1.1.10
}
track_script {
check_gitlab_service
}
# 当前角色为主时,启动实时同步脚本
notify_master "/etc/keepalived/script/start_gitlab_data_realtime_sync.sh"
# 当前角色为备时,关闭实时同步脚本
notify_backup "/etc/keepalived/script/stop_gitlab_data_realtime_sync.sh"
# 当Keepalived被关闭时,发送邮件通知
notify_stop "/etc/keepalived/script/email_to_admin.sh"
}
nopreempt 说明:
通常如果 MASTER 服务死掉后,BACKUP 会提权变成 MASTER;但是当 MASTER 服务又好了的时候,MASTER 此时会重新抢占VIP,这样就会发生两次VIP切换。
对于我们当前的数据实时同步场景,这种切换会导致数据异常问题,即当 MASTER 主机down,BACKUP会提为MASTER并启用实时同步,但是主节点网络不通,会有部分数据同步不过去,如果此时主节点up恢复后,启用数据同步,会有数据断层发生。
所以我们要在配置文件中启用 nopreempt ,但是这个参数只能用于state为 BACKUP 的配置中,故这里主备节点的state都设置成 BACKUP 。
服务检查、启动、关闭的同步脚本及邮件通知,大家根据自己情况编写即可。
启动 keepalived 服务
# 启动Keepalived服务
service keepalived start
#
# 设置开机启动
chkconfig keepalived on
全量同步场景
当机器某些原因导致重启时,另一个节点变成主角色并接管VIP,但是数据同步尽管启动着,由于本端机器down掉了,数据就传不过来,所以需要在各个节点的 rc.local 中增加数据全量同步命令。
既只要机器发生重启现象,就执行一次从对端(说明:此时对端肯定是主角色)拉取全量数据的动作。
# 在 rc.local 文件最后面,追加如下内容。
# tail -2 /etc/rc.local
# 如果机器发生重启,全量拉取 gitlab_data 数据
/opt/script/rc_local_pull_gitlab_data.sh
# 实际调用脚本中的执行命令如下
# cat /opt/script/rc_local_pull_gitlab_data.sh
#!/bin/bash
# 如果机器发生重启,全量从对端(此时对端一定是主)拉取gitlab_data数据
#
if [[ $(hostname) =~ 1-1-1 ]];then
dest_ip='10.1.1.2'
else
dest_ip='10.1.1.1'
fi
rsync -az gitlab@${dest_ip}::gitlab_data --password-file=/etc/rsync/gitlab_client.pass /var/opt/gitlab-data/
至此,数据同步相关的配置完成。
Comments