如何在Jenkins全局SSH配置中自动动态更新AWS Autoscaling实例的IP地址
如何在Jenkins全局SSH配置中自动动态更新AWS Autoscaling实例的IP地址
针对你遇到的AWS自动扩缩容实例IP更新后,Jenkins全局SSH配置无法同步的问题,结合你使用Jenkins 2.414.2的场景,我给你几个实用的解决方案,按省心程度排序:
方案一:利用AWS Route53自动解析(无需修改Jenkins配置)
这是最省心的方案,完全不用改动Jenkins的任何设置,把IP动态管理交给AWS的DNS服务:
- 给你的ASG实例添加统一的自定义标签,比如
Name=ASG-Web-Servers,方便后续识别 - 在Route53创建一个私有(内网用)或公网托管区,比如
asg-servers.internal - 配置实例自动注册DNS:可以通过VPC的DHCP选项集设置域名和DNS服务器,或者在ASG的启动模板里添加一段初始化脚本,让实例启动时自动把自己的IP注册到Route53的多值路由记录(比如
web-servers.asg-servers.internal),终止时自动注销 - 最后在Jenkins全局SSH配置里,把服务器的Hostname填成这个Route53域名。Publish Over SSH插件会自动解析域名对应的所有IP,不管ASG怎么扩缩容,Jenkins都能访问到最新的实例,完全不用手动或自动更新Jenkins配置。
方案二:Jenkins API + 事件触发(主动更新全局SSH配置)
如果不想用DNS,那可以通过Jenkins的REST API主动更新全局SSH配置,步骤如下:
步骤1:准备Jenkins API访问权限
- 登录Jenkins,点击右上角头像进入「设置」页面
- 点击「添加新令牌」生成一个API令牌,务必保存好你的Jenkins用户名和这个令牌,后续调用API需要用它做身份认证。
步骤2:编写IP同步脚本
你可以用Shell或Python写脚本,核心完成两个动作:
- 获取ASG运行中实例的IP
用AWS CLI的话,执行以下命令(替换成你的ASG名称):# 获取私有IP,需要公网IP就把PrivateIpAddress换成PublicIpAddress ASG_INSTANCE_IPS=$(aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names "你的ASG名称" --query 'AutoScalingGroups[0].Instances[?LifecycleState==`InService`].PrivateIpAddress' --output text | tr '\t' ',') - 调用Jenkins API更新SSH配置
先写一个Groovy脚本update_ssh_host.groovy(替换成你在Jenkins里配置的SSH服务器名称):
然后用curl命令把脚本和IP参数传给Jenkins的远程脚本执行API:import jenkins.model.Jenkins import hudson.plugins.publish_over_ssh.BapSshHostConfiguration import hudson.plugins.publish_over_ssh.BapSshPublisherPlugin // 获取Jenkins实例和SSH插件全局配置 def jenkins = Jenkins.get() def sshPlugin = jenkins.getPlugin(BapSshPublisherPlugin.class) def globalSshConfig = sshPlugin.getGlobalConfig() def sshHosts = globalSshConfig.getHosts() // 替换成你在Jenkins全局配置里的SSH服务器名称 def targetHostName = "ASG-Servers" def targetHost = sshHosts.find { it.name == targetHostName } if (targetHost) { // 更新IP列表,newIps是外部传入的逗号分隔IP字符串 targetHost.setHostname("${newIps}") globalSshConfig.save() jenkins.save() println "SSH主机 ${targetHostName} 的IP已更新为: ${newIps}" } else { println "未找到名称为 ${targetHostName} 的SSH主机配置" }curl -u "你的Jenkins用户名:你的API令牌" -X POST \ --data-urlencode "script=$(cat update_ssh_host.groovy)" \ --data-urlencode "newIps=${ASG_INSTANCE_IPS}" \ "你的Jenkins地址/script"
步骤3:触发脚本执行
- 事件触发(推荐):用AWS CloudWatch Events监听ASG的实例启动/终止事件(事件源选
aws.autoscaling,事件类型选EC2 Instance Launch Successful和EC2 Instance Terminate Successful),触发Lambda函数执行上述脚本。注意要给Lambda配置IAM权限:允许访问ASG的描述权限,以及能访问Jenkins的网络权限。 - 定时触发:如果事件触发配置麻烦,可以在一台有AWS CLI和Jenkins访问权限的EC2实例上,用cron定时执行脚本,比如每5分钟同步一次IP。
方案三:改用Jenkins动态参数替代全局配置
如果你的declarative pipeline可以转换成Jenkinsfile管理,那可以不用依赖全局SSH配置,而是在pipeline里动态获取ASG实例IP,直接传递给Publish Over SSH步骤:
pipeline { agent any stages { stage('获取ASG实例IP') { steps { script { // 调用AWS CLI获取运行中实例的私有IP def instanceIps = sh( script: 'aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names "你的ASG名称" --query \'AutoScalingGroups[0].Instances[?LifecycleState==`InService`].PrivateIpAddress\' --output text', returnStdout: true ).trim().split('\t') // 把IP列表转为逗号分隔的字符串,存为环境变量 env.ASG_INSTANCE_IPS = instanceIps.join(',') } } } stage('发布到服务器') { steps { sshPublisher(publishers: [sshPublisherDesc( configName: '通用SSH模板', // 提前配置一个包含密钥、端口等信息的通用SSH配置 transfers: [sshTransfer(sourceFiles: 'target/*.jar', remoteDirectory: '/opt/app')], remote: remoteHost(hostname: env.ASG_INSTANCE_IPS) )]) } } } }
这个方案更灵活,不需要维护全局SSH配置的IP,但需要你把现有的pipeline迁移到Jenkinsfile管理。
备注:内容来源于stack exchange,提问作者S_H
相关产品推荐
相关产品推荐

