前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >腾讯云Windows Cloudbase-Init几千分之一的UserData代码执行异常的问题研究汇总:UserData健壮性提升

腾讯云Windows Cloudbase-Init几千分之一的UserData代码执行异常的问题研究汇总:UserData健壮性提升

原创
作者头像
Windows技术交流
修改2025-02-20 17:10:16
修改2025-02-20 17:10:16
600
举报
文章被收录于专栏:Windows技术交流Windows技术交流

Cloudbase-Init是免费开源的,但.exe主程序不开源,只是.py文件开源

OpenStackService.exe

代码语言:txt
复制
C:\Program Files\Cloudbase Solutions\Cloudbase-Init\bin\OpenStackService.exe

cloudbase-init.exe

代码语言:txt
复制
C:\Program Files\Cloudbase Solutions\Cloudbase-Init\Python\Scripts\cloudbase-init.exe

Cloudbase-Init官网:

https://cloudbase.it/cloudbase-init/

https://github.com/cloudbase/cloudbase-init/releases

初始化不单单是Cloudbase-Init的多个Plugin依次执行,还有其他的异步调用

cloudbase-init的功能主要就是自动扩展系统盘分区、api设置hostname、api利用userdata、api设置密码,如果用不上这些功能,完全可以不安装cloudbase-init,安装个tat最方便

代码语言:txt
复制
cloudbaseinit.plugins.windows.extendvolumes.ExtendVolumesPlugin
cloudbaseinit.plugins.common.networkconfig.NetworkConfigPlugin
cloudbaseinit.plugins.common.sethostname.SetHostNamePlugin
cloudbaseinit.plugins.common.setuserpassword.SetUserPasswordPlugin
cloudbaseinit.plugins.common.localscripts.LocalScriptsPlugin
cloudbaseinit.plugins.common.userdata.UserDataPlugin

从上到下,顾名思义分别是:
扩展卷:扩展C分区(后面没有其他分区阻挡的话,C分区后的空白空间在重启时会自动扩展卷,即ExtendVolumes)
网络配置:NetworkConfig
设置hostname:SetHostName
设置密码:SetUserPassword
执行脚本:LocalScripts目录的C:\Program Files\Cloudbase Solutions\Cloudbase-Init\LocalScripts\TencentCloudRun.ps1是初始化脚本起点
自定义数据:UserData

一、初始化代码有些分支逻辑是异步执行的

腾讯云Windows初始化代码入口是C:\Program Files\Cloudbase Solutions\Cloudbase-Init\LocalScripts\TencentCloudRun.ps1

禁用cloudbase-init服务后重启机器就能看到光驱config-2,双击就能看到里面的目录结构,明文代码可以记事本查看

TencentCloudRun.ps1→ autorun.ps1→qcloud_action.ps1和 qcloud_init.ps1

qcloud_init.ps1→ cvm_init.bat→ basic_windows_install_1.0.35\install.bat

二、自定义数据UserData

前端购买CVM最后几步的时候有个高级设置,里面有自定义数据

比如基于Windows公共镜像做的自定义镜像新购的实例hostname需要重启才可以生效,这点就可以通过在UserData里加重启代码实现自动化重启

代码语言:txt
复制
<powershell>
#这里添加代码,代码丰富度就看业务设计了,可以通过这里添加业务代码实现改密码、自动入域、重启、修改文本文件等动作
restart-computer -force;
</powershell>

注意:cloudbase-init userdata不是只支持powershell

如果是直接调用接口给UserData参数传值的话,需要把自定义数据代码块进行base64编码,编码后的字符串传给RunInstances接口的UserData参数。

三、批量新购场景中,较低概率出现同一个镜像在初始化阶段UserData执行异常的情况

渲染业务一般是批量场景(比如100帧买100台机器,每台机器渲1帧,最后再组装结果,以此来提升效率),在初始化时可能会一些噪点机器(一致性跟大部分机器可能有出入,比如批量买1000台机器,个别机器的UserData代码没有产生该有的效果)

UserData秒针跟路由变动秒针重合或贴近执行,执行中会有概率因为route delete 0.0.0.0遭遇网络不通的情况,在RS3t机型概率还挺高(1000台有20台左右),在SA5大概1000台出现1台(得益于AMD机器普遍在虚拟化场景中比Intel机器开机进桌面快,不太容易踩中路由变动跟UserData同时执行的情况)

下图就是路由变动跟UserData同时执行而网络异常影响UserData代码执行了,虽然路由(网络)很快恢复,但UserData代码只执行1次,如果UserData代码中涉及网络调用的部分没有加重试逻辑,就会有域名解析异常(11001或11004)、远程访问异常(10051)等问题。

批量1000台/次测试的时候,总有若干台网络异常,从理论上讲,出于健壮性考虑,userdata执行的时候,网络相关的东西就不应该再变动了

cloudbase-init userdata执行时的日志:\r\n \r\nERROR 2005 (HY000): Unknown MySQL server host \'nj-cdb-0tqfmfov.sql.tencentcdb.com\' (11004)\r\n' execute_user_data_script

cloudbase-init userdata执行时的日志:\r\n \r\nERROR 2005 (HY000): Unknown MySQL server host \'nj-cdb-0tqfmfov.sql.tencentcdb.com\' (11001)\r\n' execute_user_data_script

cloudbase-init userdata执行时的日志:\r\n \r\nERROR 2002 (HY000): Can\'t connect to MySQL server on \'101.34.180.125\' (10051)\r\n' execute_user_data_script

每次批量买1000台,一开始,有几十台调用cdb mysql上报数据失败,报错有11001和11004,我把域名解析添加到hosts文件(c:\windows\system32\drivers\etc\hosts)后再批量买1000台,只剩11004报错(1000台有20台左右),后来我干脆把cdb mysql换成我自建mysql server的IP,报错10051(1000台有20台左右)

下图是正常的情况:路由变动比UserData代码执行早几秒完成,这样等UserData代码执行时网络是稳定的

解决方案:

UserData健壮性提升

①userdata代码中涉及网络的部分加上重试逻辑,路由变动和userdata代码前后相差不会超过10秒,加重试逻辑可以规避

代码语言:txt
复制
$retryCount = 1
$maxRetries = 5
$logFile = "c:\shangbaolog.txt"
$pwd="密码"

while ($retryCount -le $maxRetries) {
    # 记录重试次数
    "$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss') - Attempt $retryCount" | Out-File -FilePath $logFile -Append

    # 执行 MySQL 插入操作
    C:\mariadb-10.2.40-win32\bin\mysql.exe -h 101.34.180.125 -uroot -p$pwd -e "
        INSERT INTO shawyang.3dsmaxdone (
            instanceid, ip, uuid, disk0id, disk0type, instancetype, 
            imageid, appid, starttime_12_1, endtime_6005_1, timediff_a, 
            starttime_3dsmax, endtime_3dsmax, timediff_b, timediff_c
        ) VALUES (
            '$instanceid', '$ip', '$uuid', '$disk0id', '$disk0type', '$instancetype', 
            '$imageid', '$appid', '$starttime_12_1', '$endtime_6005_1', '$timediff_a', 
            '$starttime_3dsmax', '$endtime_3dsmax', '$timediff_b', '$timediff_c'
        );
    " | Out-File -FilePath $logFile -Append

    # 检查上一条命令是否成功
    if (-not $?) {
        Write-Host "Try $retryCount failed"
        $retryCount++
        Start-Sleep -Seconds 2  # 等待 2 秒后重试
    } else {
        Write-Host "Data inserted successfully!"
        exit  # 成功则退出脚本
    }
}

# 如果达到最大重试次数仍未成功
Write-Host "Failed to insert data after $maxRetries attempts."
exit 1

②在_process_user_data函数这里加sleep可以达到我说的目的:在userdata代码执行前完成路由改动

整体上:

首先,针对decode那块的except分支直接赋值从url获取的内容而不是return跳出执行(我自己遇到的就是这种情形)

其次,在_process_user_data函数中等待路由完成(10秒绰绰有余),这样涉及mysql上报的部分不用加重试也可以(我自己搞的测试用例,在UserData部分用mysql客户端上报数据到我的php+mysql web服务器

结尾突然想起一个无关的点:

2016/2019/2022域机器,cloudbase-init离线重置密码,2016支持,2019/2022不支持,此差异,源于cloudbase-init本身功能,为啥这样?我也不清楚。有些时候深究不清楚,但好在见多识广,类似的其他问题,比如:mini sftp server 支持2019/2022,不支持2016,为啥不支持,得问软件开发者。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、初始化代码有些分支逻辑是异步执行的
  • 二、自定义数据UserData
  • 三、批量新购场景中,较低概率出现同一个镜像在初始化阶段UserData执行异常的情况
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档