配置Jenkins从节点(slave)进行iOS打包

踩了些坑,记录下
我的场景是一台Mac mini做master,另一台Mac mini做slave

  1. Jenkins的插件中心安装 ssh插件
  2. 节点列表中增加从节点
    • 从节点电脑需要安装和master同版本的Java环境
    • 确保从节点使用固定的内网ip,需要在系统设置->共享->打开远程登录
    • 从节点配置使用userName password登录(使用ssh公钥也行)
  3. 从节点环境变量
    我需要执行的Job都是一些shell脚本,在从节点中执行时,默认无法访问到所有环境变量,比如会出现 command not found,需要再shell中手动导出下
#从节点 .zshrc文件中 需要配置好的一些环境变量
export PATH="/opt/homebrew/bin:$PATH"
#export PATH=$PATH:/Users/flutter/bin:$PATH       
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
# Jenkins的Job命中中,先导入环境变量
source ~/.bash_profile
source ~/.zshrc
# todo ..
  1. 打包脚本遇到签名错误,如这种
    ...xxxKitExtension.appex: errSecInternalComponent Command CodeSign failed with a nonzero exit code
    解决方法是在脚本增加钥匙串登录命令(下面的判断可以不要,我是有需要才加的)
# 登录从节点钥匙串
if [ $(hostname) == "ios_slave_1.local" ]; then
    echo "登录从节点钥匙串"
    security unlock-keychain -p "password" ~/Library/Keychains/login.keychain
fi

问题1: 打包机磁盘占用很高

  1. 仅保留有限的构建日志,job配置里 -> 丢弃旧的构建 -> 保持构建的最大个数(50-100即可)
  2. 脚本定期清理构建产物, 我设置job每周执行一次 定时构建 -> 日程表(H 5 * * 6)
echo "清理7天前的内网包."
# 设置根目录  
root_dir="xxxx/itms-services"  
# 计算7天前的时间(秒)  
# $(date +%s) 获取当前时间的秒数  
threshold=$(( $(date +%s) - 7 * 24 * 60 * 60 ))  
# 递归遍历目录 (3层)
find "$root_dir" -type d -maxdepth 3 -mindepth 3 -print0 | while IFS= read -r -d '' dir; do  
    # 获取文件夹的修改时间戳(秒)  
    mtime=$(stat -f %m "$dir")  # macOS 上使用 %m 获取修改时间  
    # 检查时间戳是否大于阈值(即是否早于7天前)  
    if [ "$mtime" -lt "$threshold" ]; then  
        rm -rf "$dir"  
    else
        echo "step this dir"  
    fi  
    printf "\n"  
done  


问题2: 清理废弃job残留工作空间的磁盘目录

直接贴到 Manage Jenkins-> Script Console里点运行,查看输出;
确认删除的话,修改DRY_RUN = false后再次运行脚本

import jenkins.model.Jenkins
import hudson.FilePath

def DRY_RUN = true   // 先跑一遍只打印,确认无误后改 false

def jenkins = Jenkins.instance
def existingJobs = jenkins.getAllItems(hudson.model.AbstractItem.class)*.fullName as Set

def deleteCount = 0
def failCount = 0

def cleanWorkspace = { String nodeName, FilePath wsRoot ->
    println ""
    println "========== 节点: ${nodeName} =========="
    if (wsRoot == null || !wsRoot.exists()) {
        println "  (workspace 目录不存在,跳过)"
        return
    }
    def found = false
    wsRoot.listDirectories().each { dir ->
        def baseName = dir.name.split('@')[0]
        if (!existingJobs.contains(baseName)) {
            found = true
            println ""
            println "  ${DRY_RUN ? '[DRY-RUN] ' : ''}发现废弃 workspace:"
            println "    目录: ${dir.remote}"
            println "    对应 job: ${baseName} (已不存在)"
            if (!DRY_RUN) {
                try {
                    dir.deleteRecursive()
                    deleteCount++
                    println "    => 已删除"
                } catch (e) {
                    failCount++
                    println "    => 删除失败: ${e.message}"
                }
            } else {
                deleteCount++
            }
        }
    }
    if (!found) {
        println "  (无废弃 workspace)"
    }
}

// agents
jenkins.nodes.each { node ->
    def computer = node.toComputer()
    if (computer == null || computer.offline) {
        println ""
        println "========== 节点: ${node.displayName} =========="
        println "  (节点离线,跳过)"
        return
    }
    if (!computer.idle) {
        println ""
        println "========== 节点: ${node.displayName} =========="
        println "  (节点有构建在跑,跳过)"
        return
    }
    cleanWorkspace(node.displayName, node.rootPath?.child("workspace"))
}

// master (built-in node)
cleanWorkspace("master", jenkins.rootPath.child("workspace"))

println ""
println "===================================="
println DRY_RUN ? "DRY-RUN 完成,共发现 ${deleteCount} 个待删除目录" \
                : "执行完成: 删除 ${deleteCount} 个,失败 ${failCount} 个"
println "===================================="
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容