双机房场景下,1分钟交付Nginx跨区域变更!
需求
双机房或多机房场景下会存在多套Nginx,每次配置变更需要跨多套Nginx进行修改,这无疑会存在极大的变更风险。因此我们团队内部根据此种场景进行了一次头脑风暴,在不增加复杂度的前提下,提供一种双机房场景的Nginx管理实践,满足一次提交、多机房部署的需求,既能简化操作步骤、规避变更风险,又能将交付效率提升到1分钟级别。
架构
Nginx管理规范
经过如下整改,我们将配置进行分离绑定但统一管理,以满足配置在不同区域可分别生效。
基础目录conf,所有配置相关都存在于此目录下; upstream.conf 按机房区域命名为:upstream_A.conf 、upstream_B.conf; 每个机房的proxy_pass 必须保持一致,均来源于upstream.conf; 每个机房的nginx.conf 分别绑定相应的upstream.conf; 其他区域差异配置,参考upstream.conf做相应拆分;
Git管理规范
为满足精简操作的需求,我们每套Nginx 使用一个Git仓库,不区分机房,因此既需要上述的Nginx目录规范,也需要在Git侧遵循一定的纳管规范。
配置文件以conf 为最小单元进行纳管; conf 中只保留变更相关文件,其他Ningx依赖文件均按以下规则忽略; 必须忽略nginx.conf,因为此文件绑定了upstream.conf,须在各自机房区域生效; 必须忽略Ningx依赖文件,如koi、scgi、uwsgi等conf目录下的基础文件;
流水线编排
在双机房场景下,CMDB的重要性更加凸显,尤其在金融行业下业务、网络分区等场景下Nginx可能会达几十套,我们如何快速选择资产虽然并不是本次的重点,但是这反映出有序的运维建设对后续自动化是重要的!
流水线编排方面主要包含以下几点:
CMDB 快速选择多机房下Nginx IP; pull 最新配置文件; 配置文件检查; 更新A机房第一台,等待验证; 验证通过,更新A机房剩余所有及B机房所有; 单IP、批量IP、单机房、多机房等不同情况的消息通知;
流水线中我们引入了验证等待环节,可用于团队间的二次复核,保证变更的准确性!
具体实施
Nginx配置初始化
首次Nginx配置需要使用Git进行纳管,主要操作如下:
1.备份conf,因为clone目标目录必须是空目录
cd /opt/openresty/nginx
mv conf conf.bak
git clone http://x.x.x.x/nginx/nginx.git conf
2.保存密码
git config --global credential.helper store
3.基础文件从备份中复制回conf目录
cp ../conf.bak/* .
4.由于nginx.conf未被git纳管,需要单独绑定区域upstream_A/B.conf 配置
5.检查配置文件并启动
Ngnix配置变更
每次变更操作只需在其中一台进行配置文件修改即可,剩余操作交给流水线一键更新。
#1.重要:每次变更前必须pull到最新
cd /app/openresty/nginx/conf
git pull
#2.配置文件修改
vim xxxx.conf
#3.push到远程git
git add
git status
git commit -m "增加xxx配置"
git push
流水线实现
流水线通过共享库中的原子模块对接cmdb,并通过两条子流水线在双机房场景下编排,将配置文件的变更压缩到1分钟级别交付,大大简化了中间操作步骤。
@Library('shared-library') _
pipeline {
agent any
options
timestamps()
stages {
stage('A机房发布第一台'){
steps {
script {
currentBuild.displayName = "#$(BUILD_NUMBER}-${params.ACTION}"
currentBuild.description = "${params.NGINX_NAME}"
hosts = cmdb.GetHosts("${NGINX_NAME}")
println(hosts [0])
build job: 'nginx_admin_A', parameters: [string(name: 'NGINX_NAME', value: "S{NGINX_NAME}"), string(name: "HOST", value: "${hosts[0]}"), string(name: "ACTION", value: "${ACTION}")
input message:"等待第一台${hosts[0]}验证通过",ok: 'Pass'
}
}
}
stage('A机房更新剩余所有'){
steps {
script {
hosts = cmdb.GetHosts("${NGINX_NAME}")
println(hosts.tail().join(','))
build job: 'nginx_admin_A', parameters: [string(name: 'NGINX_NAME', value: "S{NGINX_NAME}"), string(name: "HOST", value: "${hosts.tail().join(',')}"), string(name: "ACTION",value:"${ACTION}")]
}
}
}
stage('B机房更新所有'){
steps {
script {
build job: 'nginx_admin_B', parameters: [string(name:'NGINX_NAME', value: "${NGINX_NAME}"), string(name: "HOST",value: ''), string(name: 'ACTION', value: "${ACTION}")]
}
}
}
}
}
总结
也许会有小伙伴有疑问,为啥不用nginxWebUI开源项目或Nginx+Nacos的方案,但这两种方案由于会引入外部组件,在一定程度上增加架构的复杂度,适配性上也需要耗费精力去踩坑。而业务场景下Nginx作为唯一入口,我们需要更加安全、可控的解决方案!
添加好友,邀你入群,运维人的圈子,每日精彩分享,更有小伙伴们的热议!
📢 近期话题:
札记:“所有发行版都在淘汰的东西那就跟着淘汰!”
--优秀的运维小伙伴