更新时间:2025-07-08 GMT+08:00

Jenkins自动构建并滚动升级部署到ServiceStage的组件

  • 场景一:使用Jenkins构建生成的是软件包,如Jar包,就使用脚本中的软件包部署场景,软件包部署会将构建出来的软件包上传到OBS桶中并升级ServiceStage组件。
  • 场景二:使用Jenkins构建生成的是镜像包,就使用脚本中的镜像部署场景,镜像部署会将构建出来的镜像包上传到SWR镜像仓库中并升级ServiceStage组件。

本章节以配置流水线脚本中的实例为Jar包的场景进行说明。

在执行本操作之前,您需要已经在ServiceStage上完成了待操作组件的创建及部署。创建及部署组件,请参考使用容器部署方式基于界面配置创建组件

创建GitLab凭证

使用具有GitLab代码仓库权限的账号密码在Jenkins中创建凭证,用于拉取GitLab代码。

  1. 在浏览器地址栏输入http://{安装Jenkins的Linux虚拟机IP}:8080,登录Jenkins。
  2. 选择“系统管理 > 系统配置”,在“配置”中选择“Gitlab”。
  3. 单击“Credentials”下方的“添加”,选择“Jenkins”。
  4. 配置GitLab账号密码,单击“添加”,保存配置。
  5. 选择“系统管理 > Manage Credentials”,查看配置的凭据。

    唯一标识在配置流水线脚本中会用到。

创建流水线任务

  1. 在浏览器地址栏输入http://{安装Jenkins的Linux虚拟机IP}:8080,登录Jenkins。
  2. 单击“新建任务”。
  3. 输入任务名称,示例:test-upgrade,选择“流水线”,单击“确定”。

配置构建触发器

  1. 配置Jenkins构建触发器。

    1. 勾选“Build when a change is pushed to GitLab”,保存GitLab webhook URL(配置Gitlab webhook时需使用),然后单击右下角“高级”。
    2. 选择“Filter branches by regex ”,配置指定分支变更后触发构建任务,示例中的分支名称为main,单击右下角“Generate”生成Secret token并保存,在配置GitLab webhook时需使用。

  2. 配置GitLab webhook。

    1. 登录GitLab,进入代码仓库,示例中的仓库名称是“test”,选择settings中的“Webhooks”,URL和Secret token填写1获取到的GitLab webhook URL和Secret token。
    2. 取消勾选SSL verification的“Enable SSL verification”,单击“Add webhook”。

配置流水线脚本

流水线脚本是构建时运行的构建命令。

  1. 选择“流水线”页签,在下拉框选择“Pipeline script”。
  2. 配置如下所示流水线脚本,示例中使用的是构建jar包场景。

    • 请使用您环境下的实际参数替换脚本中的参数变量。脚本参数说明,请参考表1
    • 流水线脚本运行时会调用upgrade.sh。脚本详细说明,请参考upgrade.sh脚本
    • 需要设置脚本文件upgrade.sh为可执行文件。
    node {
        // 定义代码仓库地址,例如:http://10.95.156.58:8090/zmg/test.git
        def git_url = '{代码仓库地址}'
        // GitLab凭据id
        def credentials_id = '{GitLab凭据id}'
        // git代码仓库分支名称,例如:main
        def branch_name = '{git代码仓库分支名称}'
        // maven安装的可执行文件路径,例如 :/root/app/maven/apache-maven-3.8.6/bin/mvn
        def maven = '{maven安装的可执行文件路径}'
        // upgrade.sh脚本存放路径,例如:/root/jar/upgrade.sh
        def upgrade_shell = '{upgrade.sh脚本存放路径}'
    
        stage('Clone sources') {
            git branch: branch_name, credentialsId: credentials_id, url: git_url
        }
        stage('Build') {
            // 构建jar包
            sh "'$maven' clean package -Dmaven.test.failure.ignore=true -Dmaven.wagon.http.ssl.insecure=true -Dmaven.wagon.http.ssl.allowall=true"
        }
        stage('upgrade') {
            // 执行脚本,使用构建上传到obs的jar包升级ServiceStage组件,超时时间5分钟
            sh "timeout 300s '$upgrade_shell'"
        }
    }
    表1 流水线脚本参数说明

    参数

    是否必须

    参数类型

    描述

    git_url

    String

    GitLab代码仓库地址。

    credentials_id

    String

    使用账号密码配置的GitLab凭据id,请参考创建GitLab凭证

    branch_name

    String

    GitLab代码仓库分支名称。

    maven

    String

    maven安装的可执行文件路径,例如:/root/app/maven/apache-maven-3.8.6/bin/mvn。

    upgrade_shell

    String

    upgrade.sh脚本在Jenkins所在虚拟机上存放的路径,例如:/root/jar/upgrade.sh。脚本内容,请参考upgrade.sh脚本

  3. 执行构建并验证构建结果,请参考构建验证

upgrade.sh脚本

请使用您环境下的实际参数替换脚本中的参数变量。

#!/bin/bash
# 项目id
project_id='{项目id}'
# 应用id
application_id='{应用id}'
# 组件id
component_id='{组件id}'
# 分批信息
rolling_release_batches=1
# 部署类型
deploy_type="package"


### 方法简要说明:
### 1. 查找一个字符串,如下述代码里面的key所示。如果没找到,则直接返回defaultValue。
### 2. 查找最近的冒号(:),找到后则冒号后的内容即为值的内容。
### 3. 如果有多个同名key,只打印第一个value。
###
### 4. params: json, key, defaultValue
function getJsonValuesByAwk() {
    awk -v json="$1" -v key="$2" -v defaultValue="$3" 'BEGIN{
        foundKeyCount = 0
        pos = match(json, "\""key"\"[ \\t]*?:[ \\t]*");
        if (pos == 0) {if (foundKeyCount == 0) {print defaultValue;} exit 0;}

        ++foundKeyCount;
        start = 0; stop = 0; layer = 0;
        for (i = pos + length(key) + 1; i <= length(json); ++i) {
            lastChar = substr(json, i - 1, 1)
            currChar = substr(json, i, 1)

            if (start <= 0) {
                if (lastChar == ":") {
                    start = currChar == " " ? i + 1: i;
                    if (currChar == "{" || currChar == "[") {
                        layer = 1;
                    }
                }
            } else {
                if (currChar == "{" || currChar == "[") {
                    ++layer;
                }
                if (currChar == "}" || currChar == "]") {
                    --layer;
                }
                if ((currChar == "," || currChar == "}" || currChar == "]") && layer <= 0) {
                    stop = currChar == "," ? i : i + 1 + layer;
                    break;
                }
            }
        }

        if (start <= 0 || stop <= 0 || start > length(json) || stop > length(json) || start >= stop) {
            if (foundKeyCount == 0) {print defaultValue;} exit 0;
        } else {
            print substr(json, start, stop-start);
        }
    }'
}

#查询组件信息
function getComponentInfo() {
    # 查询组件信息
    component_details=`hcloud ServiceStage ShowComponentInfo/v3 --project_id="$project_id" --application_id="$application_id" --component_id="$component_id"`

    # 打印组件信息
    echo "$component_details"

    # 获取组件当前的名称
    test_name=`getJsonValuesByAwk  "$component_details" "name" "defaultValue"`
    lenj=${#test_name}
    component_name=${test_name:1:lenj-2}
    echo "name : $component_name"


    data_time=$(date +%Y.%m%d.%H%M)
    seconds=$(date +%S)
    component_version="${data_time}${seconds:1:1}"
    echo "version: $component_version"
}

# 镜像部署使用场景
function swr_image_upgrade() {

      # 项目打包后生成的镜像:镜像名称:版本名称
      machine_image_name='java-test:v1'
      # 上传到swr的镜像仓库路径
      swr_image_url='{镜像仓库地址}/{组织名称}/{镜像名称}:{版本}'
      # AK 用于登录swr镜像仓库
      AK='BMCKUPO9HZMI6BRDJGBD'
      #SWR登录密钥,用于登录SWR镜像仓库
      SK='{SWR登录密钥}'
      # SWR镜像仓库地址
      swr_url='{SWR镜像仓库地址}'
      #region名称
      region="{region名称}"

      echo "upload image to swr"
      docker tag "$machine_image_name" "$swr_image_url"

      login_secret=`printf "$AK" | openssl dgst -binary -sha256 -hmac "$SK" | od -An -vtx1 | sed 's/[ \n]//g' | sed 'N;s/\n//'`

      login_result=`docker login -u "$region"@"$AK" -p "$login_secret" "$swr_url"`
      # 打印登录swr镜像仓库结果
      echo "$login_result"
      push_result=`docker push "$swr_image_url"`
      # 打印推送镜像结果
      #echo "$push_result"
      logout_result=`docker logout "$swr_url"`
      # 打印退出登录swr镜像仓库的结果
      echo "$logout_result"
      # 清除所有的历史记录,历史记录中可能会存在swr登录密钥信息,可以使用该命令清理所有的历史记录
      #history -c

    echo "upgrade component"

    action_result=`hcloud ServiceStage ModifyComponent/v3 --project_id="$project_id" --application_id="$application_id" --component_id="$component_id" --version="$component_version" --runtime_stack.name="Docker" --runtime_stack.type="Docker" --source.kind="image" --source.storage="swr" --source.url="$swr_image_url" --name="$component_name" --deploy_strategy.rolling_release.batches=$rolling_release_batches --deploy_strategy.type="RollingRelease" `

}

# jar包部署使用场景
function obs_jar_upgrade() {

    # obsutil安装的可执行文件绝对路径
    obsutil='/root/tools/obsutil/obsutil_linux_amd64_5.4.6/obsutil'
    # obs桶名
    bucket='obs://{obs桶名}'
    echo "upload jar to obs"
    # 将项目下构建生成的jar包上传到obs
    obs_result=`"$obsutil" cp ./target/*.jar "$bucket"`
    # 打印上传结果
    echo "$obs_result"
    # 上传到obs的jar包链接
    obs_jar_url='obs://{obs桶名}/{Jar包名称}'

    echo "upgrade component"

    action_result=`hcloud ServiceStage ModifyComponent/v3 --project_id="$project_id" --application_id="$application_id" --component_id="$component_id" --version="$component_version" --runtime_stack.name="OpenJDK8" --runtime_stack.type="Java" --source.kind="package" --source.storage="obs" --source.url="$obs_jar_url" --name="$component_name" --deploy_strategy.rolling_release.batches=$rolling_release_batches --deploy_strategy.type="RollingRelease" `

}

# 每隔15秒查询一次job状态,直到job完成
function waitDeployFinish() {
    sleep 10s
    id="$1"
    leni=${#id}
    id=${id:1:leni-2}
    echo "job_id= $id"
    job_status=""
    while [[ "$job_status" != "SUCCEEDED" ]]; do
        job_status_result=`hcloud ServiceStage ShowJobDetail/v2 --project_id="$project_id" --job_id="$id"`
        job_status=`getJsonValuesByAwk  "$job_status_result" "EXECUTION_STATUS" "defaultValue"`
        lenj=${#job_status}
        job_status=${job_status:1:lenj-2}
        echo "$job_status"
        if [[ "$job_status" != "RUNNING" && "$job_status" != "SUCCEEDED" ]]; then
            echo '部署失败'
            echo "$job_status_result"
            return
        fi
        sleep 15s
    done
    echo '部署成功'
}

function upgradeTask() {

    if [[ "$deploy_type" == "package" ]]; then
        obs_jar_upgrade
    elif [[ "$deploy_type" == "image" ]]; then
        swr_image_upgrade
    else
        return
    fi
    # 打印升级组件的结果
    echo "$action_result"
    # 获取结果中的job_id
    job_id=`getJsonValuesByAwk  "$action_result" "job_id" "defaultValue"`
    echo "$job_id"
    # 等待升级完成
    waitDeployFinish "$job_id"
}
function main() {
    getComponentInfo
    upgradeTask
}
main

脚本参数说明

参数

是否必须

参数类型

描述

region

String

Region名称。获取方法,请参考参数值获取

project_id

String

项目ID。获取方法,请参考参数值获取

application_id

String

应用ID。获取方法,请参考参数值获取

component_id

String

组件ID。获取方法,请参考参数值获取

rolling_release_batches

int

分批部署批次。

deploy_type

String

部署类型。

  • package表示软件包部署。
  • image表示镜像部署。

obsutil

String

当使用软件包部署如jar包部署时为必选参数,上传jar包到obs的工具安装的绝对路径。例如:/root/tools/obsutil/obsutil_linux_amd64_5.4.6/obsutil。

bucket

String

当使用软件包部署时为必选参数,上传到obs的桶路径,格式为obs://{桶名称},例如:obs://obs-mzc。

obs_jar_url

String

当使用软件包部署时为必选参数。软件包上传obs后的链接,格式为obs://{桶名}/{软件包名}。例如,obs://obs-mzc/spring-demo-0.0.1-SNAPSHOT.jar。

machine_image_name

String

当使用镜像部署时为必选参数,Jenkins打包构建后生成的镜像,格式为:{镜像名称}:{版本},例如:java-test:v1。

swr_image_url

String

当使用镜像部署时为必选参数,上传到SWR镜像仓库的镜像包路径,格式为:{镜像仓库地址}/{组织名称}/{镜像包名称}:{版本},其中SWR镜像仓库地址格式为:swr.{区域所属项目名称}.myhuaweicloud.com。

AK

String

当使用镜像部署时为必选参数。访问密钥ID,即AK,用于登录SWR镜像仓库。获取方法,请参考访问密钥

SK

String

当使用镜像部署时为必选参数。与访问密钥ID(AK)结合使用的密钥,即SK,用于登录SWR镜像仓库。获取方法,请参考访问密钥

login_secret

String

当使用镜像部署时为必选参数。SWR镜像仓库的登录密钥,用于登录SWR镜像仓库。执行如下命令,返回的结果就是登录密钥:

printf "{AK}" | openssl dgst -binary -sha256 -hmac "{SK}" | od -An -vtx1 | sed 's/[ \n]//g' | sed 'N;s/\n//'

{AK}、{SK}请替换为已获取到的AK、SK的值。

swr_url

String

当使用镜像部署时为必选参数。SWR镜像仓库地址,格式为:swr.{区域所属项目名称}.myhuaweicloud.com

参数值获取

  • 获取region、project_id
    1. 登录ServiceStage控制台。
    2. 鼠标移动到右上角登录用户名上,在下拉菜单选择“我的凭证”。
    3. 查看所属区域的项目和项目ID,即为对应的region和project_id值。
  • 获取application_id、component_id
    1. 登录ServiceStage控制台。
    2. 单击“组件管理”。
    3. 单击对应的组件名称。
    4. “概览”界面的“配置详情”区域,选择“容器配置 > 环境变量”。

      查看CAS_APPLICATION_ID、CAS_COMPONENT_ID的值,即为application_id、component_id。