使用toolkit-maven-plugin插件分批发布应用(K8s)

本文介绍如何使用toolkit-maven-plugin插件分批发布已经部署在EDAS的Spring Cloud、Dubbo和HSF应用。

自动化部署

通过toolkit-maven-plugin插件自动化部署应用的流程为:添加插件依赖,配置插件,构建部署。

  1. 添加插件依赖

    pom.xml文件中增加如下所示的插件依赖。

    <build>
        <plugins>
            <plugin>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>toolkit-maven-plugin</artifactId>
                <version>1.1.9</version>
            </plugin>
        </plugins>
    </build>                            
    说明

    toolkit-maven-plugin建议使用最近版本。

  2. 配置插件

    配置插件主要包含账号配置,打包配置及部署配置。如果需要更多自定义配置项,请参见打包参数部署参数

    1. 账号配置

      在打包工程的根目录下创建文件格式为YAML的账号配置文件,命名为toolkit_profile.yaml并填入如下信息:

      regionId:        # 应用所在区域,如北京为"cn-beijing",上海为"cn-shanghai",杭州为"cn-hangzhou"。
      jarPath:         # 部署包路径,配置该参数可忽略Maven打包流程从而直接使用配置路径内的包部署,您可配置绝对路径和相对路径。
      accessKeyId:     # 访问阿里云资源的AccessKey ID,建议使用子账号或RAM用户的AccessKey ID,以降低安全风险。
      accessKeySecret: # 访问阿里云资源的AccessKey Secret,建议使用子账号或RAM用户的AccessKey Secret,以降低安全风险。
    2. 打包配置

      在打包工程的根目录下创建文件格式为YAML的打包配置文件。如果打包工程为Maven的子模块,则需要在子模块的目录下创建该文件,并命名为toolkit_package.yaml,填入如下信息:

      apiVersion: V1
      kind: AppPackage
      spec:
       packageType: # 应用部署包类型,支持War、FatJar、Image、url;您只有在该处配置了URL,那么packageUrl才能生效。
       packageUrl:  # 如果应用部署包类型为War或FatJar,可填入此字段,不填则使用当前Maven构建的包进行部署。
       imageUrl:    # 如果部署包类型为Image,可填入此字段;Image类型也可以在本地构建Docker镜像进行部署。
    3. 部署配置

      在打包工程的根目录下创建文件格式为YAML的部署文件,命名为toolkit_deploy.yaml,并填入如下信息:

      apiVersion: V1
      kind: AppDeployment
      spec:
        type: kubernetes
        target:
          appId:        # 部署应用的ID。如果配置了appId,则无需配置namespaceId和appName。
          namespaceId:  # 应用所属的微服务空间ID。如果不清楚appId,可使用namespaceId和appName(应用名称)进行部署。
          appName:      # 应用名称。如果不清楚appId,可使用namespaceId和appName进行部署。
        updateStrategy:
          type: GrayBatchUpdate    # 灰度分批发布。
          grayUpdate:              # 灰度设置。
            gray: x                 # 整数值,含义为灰度实例数量。
          batchUpdate:             # 分批设置。
            batch: x                # 整数值,含义为批次数量。
            releaseType: xxx        # 发布方式:auto表示自动发布,manual表示手动发布。
            batchWaitTime: x        # 整数值,含义为批次间隔时间,单位分钟。
  3. 构建部署

    进入pom.xml所在的目录(如果部署Maven子模块,则进入子模块pom.xml所在的目录),执行如下命令。

    mvn clean package toolkit:deploy -Dtoolkit_profile=toolkit_profile.yaml -Dtoolkit_package=toolkit_package.yaml -Dtoolkit_deploy=toolkit_deploy.yaml                           

    命令参数含义为:

    • toolkit:deploy:在打包完成后进行应用部署。

    • -Dtoolkit_profile:指定账号配置文件。如果账号文件跟pom.xml在同一个目录下,且名字为.toolkit_profile.yaml(注意:文件名最前面有个小数点),可不填此参数,插件会自动获取。

    • -Dtoolkit_package:指定打包文件。如果打包文件跟pom.xml在同一个目录下,且名字为.toolkit_package.yaml(注意:文件名最前面有个小数点),可不填此参数,插件会自动获取。

    • -Dtoolkit_deploy:指定部署文件。如果部署文件跟pom.xml在同一个目录下,且名字为.toolkit_deploy.yaml(注意:文件名最前面有个小数点),可不填此参数,插件会自动获取。

    • -Ddeploy_version:指定部署的版本号,优先级高于部署配置文件中的version配置。

      说明

      toolkit-maven-plugin插件1.0.6及以后版本支持配置该参数。

    执行该打包命令后,系统显示如下结果,当回显信息中显示BUILD SUCCESS表示部署成功。

更多配置项

  1. 打包参数

    打包文件支持的参数如下所示。

    apiVersion: V1
    kind: AppPackage
    spec:
      packageType:  # 应用部署包类型,支持War、FatJar、Image、url;您只有在该处配置了URL,那么packageUrl才能生效。
      imageUrl:     # 镜像地址,Image包类型应用可填入。
      packageUrl:   # 包地址,War、FatJar类型应用可填入。
    build:
        docker:
           dockerfile:        # Docker镜像构建文件。如您希望在本地构建镜像部署,需填入此字段。
           imageRepoAddress:  # 阿里云镜像仓库地址。如您希望在本地构建镜像部署,需填入此字段。
           imageTag:          # 镜像Tag。如您希望在本地构建镜像部署,需填入此字段。
           imageRepoUser:     # 阿里云镜像仓库用户名。如您希望在本地构建镜像部署,需填入此字段。
           imageRepoPassword: # 阿里云镜像仓库密码。如您希望在本地构建镜像部署,需填入此字段。
         oss:
           bucket:          # 目标存储桶名称。如您希望使用自定义的OSS仓库存储部署包,需填入此字段。
           key:             # OSS自定义路径。如您希望使用自定义的OSS仓库存储部署包,需填入此字段。
           accessKeyId:     # OSS账号。如您希望使用自定义的OSS仓库存储包,需填入此字段。
           accessKeySecret: # OSS密码。如您希望使用自定义的OSS仓库存储包,可填入此字段。
  2. 部署参数

    单击此处展开部署文件支持的参数。

    apiVersion: V1
    kind: AppDeployment
    spec:
      type: kubernetes
      target:
        appName:     # 应用名称。
        namespaceId: # 应用所在微服务空间。
        appId:       # 应用ID。插件会使用此应用进行部署,如未填入则使用namespaceId和appName来查找应用进行部署。
        version:     # 部署版本号,默认使用日时分秒格式。
        jdk:         # 部署的包依赖的JDK版本,JDK支持版本为Open JDK 7和Open JDK 8。镜像不支持。
        webContainer:  # 部署的包依赖的Tomcat版本,WebContainer支持apache-tomcat-7.0.91。镜像不支持。
        batchWaitTime: # 分批等待时间。
        command:       # 镜像启动命令。该命令必须为容器内存在的可执行的对象。例如: sleep。设置该命令将导致镜像原本的启动命令失效。
        commandArgs:   # 镜像启动命令参数。上述启动命令所需参数。
        - 1d
      envs:       # 容器环境变量参数。
        - name: envtmp0
          value: '0'
        - name: envtmp1
          value: '1'
      liveness:   # 容器健康检查,健康检查失败的容器将停止运行并恢复。
        exec:    # exec、tcpSocket和httpGet三者选其一配置
          command:
            - sleep
            - 1s
        tcpSocket: # exec、tcpSocket和httpGet三者选其一配置
          host: "192.168.1.109"  # 此配置项可选,如未设置则默认为Pod IP
          port: "18081"  # 端口(注意,此处为字符串类型)
        httpGet:  # exec、tcpSocket和httpGet三者选其一配置
          host: "192.168.1.109"  # 此配置项可选,如未设置则默认为Pod IP
          port: "18081"  # 端口(注意,此处为字符串类型)
          path: "/health"
          scheme: "HTTP"  # 可选值为HTTP、HTTPS
          httpHeaders:
           - name: "color"
             value: "blue"
        initialDelaySeconds: 5
        timeoutSeconds: 11
        periodSeconds: 5
        successThreshold: 1   # 固定为1,不可修改
        failureThreshold: 3
      readiness:   # 应用启动状态检查,多次健康检查失败的容器将停止运行并重启。不通过健康检查的容器将不会有SLB流量进入。
        exec:    # exec、tcpSocket和httpGet三者选其一配置
          command:
            - sleep
            - 1s
        tcpSocket: #exec、tcpSocket和httpGet三者选其一配置
          host: "192.168.1.109"  # 此配置项可选,如未设置则默认为Pod IP
          port: "18081"  # 端口(注意,此处为字符串类型)
        httpGet:  #exec、tcpSocket和httpGet三者选其一配置
          host: "192.168.1.109"  # 此配置项可选,如未设置则默认为Pod IP
          port: "18081"  # 端口(注意,此处为字符串类型)
          path: "/health"
          scheme: "HTTP"  # 可选值为HTTP、HTTPS
          httpHeaders:
           - name: "color"
             value: "blue"
        initialDelaySeconds: 5
        timeoutSeconds: 11
        periodSeconds: 5
        successThreshold: 2
        failureThreshold: 3
      preStop:   # 生命周期挂钩,在容器删除前触发执行
        exec:
          command:
            - /bin/bash
            - -c
            - ls /tmp
        httpGet:
          host: "192.168.1.109"  # 此配置项可选,如未设置则默认为Pod IP
          port: "18081"  # 端口(注意,此处为字符串类型)
          path: "/health"
          scheme: "HTTP"  # 可选值为HTTP、HTTPS
          httpHeaders:
           - name: "color"
             value: "blue"
      postStart:   # 生命周期挂钩,在容器创建后立即执行
        exec:
          command:
           - /bin/bash
           - -c
           - ls /tmp
        httpGet:
          host: "192.168.1.109"  # 此配置项可选,如未设置则默认为Pod IP
          port: "18081"  # 端口(注意,此处为字符串类型)
          path: "/health"
          scheme: "HTTP"  # 可选值为HTTP、HTTPS
          httpHeaders:
           - name: "color"
             value: "blue"
      configMountDescs:   # 配置管理
        - type: "ConfigMap"  # 可选值为 ConfigMap、Secret
          name: "configtest"
          mountPath: "/home/admin"  # 如此值为目录,则需配置mountItems来挂载到文件
          mountItems:   # 挂载到文件
            - key: "test-name"
              path: "test"
          useSubPath: true   # 当挂载到文件时,此值为true表示保留源文件,为false表示覆盖源文件
      javaStartUpConfig:   # Java启动参数配置,根据实际情况设置相应值
        initialHeapSize:  # 初始堆内存
          original: 1000
          startup: "-Xms1000m"
        maxHeapSize:  # 最大堆内存
          original: 1000
          startup: "-Xmx1000m"
        newSize:   # 初始新生代
          original: 200
          startup: "-XX:NewSize=200m"
        maxNewSize:  # 最大新生代
          original: 200
          startup: "-XX:MaxNewSize=200m"
        survivorRatio:  # Eden/Survivor比例
          original: 2
          startup: "-XX:SurvivorRatio=2"
        newRatio:   # 老年代/新生代比例
          original: 8
          startup: "-XX:NewRatio=8"
        permSize:  # 持久代内存
          original: 512
          startup: "-XX:PermSize=512m"
        maxPermSize:  # 最大持久代内存
          original: 512
          startup: "-XX:MaxPermSize=200m"
        maxDirectMemorySize:  # 直接内存
          original: 100
          startup: "-XX:MaxDirectMemorySize=100m"
        threadStackSize:  # 栈大小
          original: 500
          startup: "-XX:ThreadStackSize=500"
        hsfserverPort:  # HSF端口
          original: 12200
          startup: "-Dhsf.server.port=12200"
        hsfserverMinPoolSize:  # HSF最小线程池
          original: 50
          startup: "-Dhsf.server.min.poolsize=50"
        hsfserverMaxPoolSize:  # HSF最大线程池
          original: 720
          startup: "-Dhsf.server.max.poolsize=720"
        youngGarbageCollector:   # 年轻代GC策略
          original: "UseSerialGC"  #可选值为 UseSerialGC、UseG1GC、UseParNewGC、UseParallelGC
          startup: "-XX:+UseSerialGC"  # 当值为UseG1GC、UseParNewGC 或 UseParallelGC 时,此值为空字符串
        oldGarbageCollector:   # 老年代GC策略
          original: "UseConcMarkSweepGC"  # 可选值为 UseConcMarkSweepGC、UseSerialGC、UseG1GC、UseConcMarkSweepGC、UseParNewGC、UseParallelOldGC、UseParallelGC
          startup: "-XX:+UseConcMarkSweepGC"  # 格式为-XX:+<GC策略>
        concGCThreads:   # 并发GC线程数
          original: 5
          startup: "-XX:ConcGCThreads=5"
        parallelGCThreads:   # 并行GC线程数
          original: 5
          startup: "-XX:ParallelGCThreads=5"
        g1HeapRegionSize:    # G1 Region文件大小
          original: 50
          startup: "-XX:G1HeapRegionSize=50m"
        gclogFilePath:  # gc日志目录
          original: "/tmp/"
          startup: "-Xloggc:/tmp/"
        useGCLogFileRotation:  # GC日志滚动
          original: true
          startup: "-XX:+UseGCLogFileRotation"
        numberOfGCLogFiles:  # GC日志数量
          original: 5
          startup: "-XX:NumberOfGCLogFiles=5"
        gclogFileSize:  # GC日志大小
          original: 100
          startup: "-XX:GCLogFileSize=100m"
        heapDumpOnOutOfMemoryError:  # 打开OOM Dump
          original: true
          startup: "-XX:+HeapDumpOnOutOfMemoryError"
        heapDumpPath: #OOM Dump文件路径
          original: "/tmp/dumpfile"
          startup: "-XX:HeapDumpPath=/tmp/dumpfile"
        customParams:  # 自定义参数
          original: "-Dtest=true"
          startup: "-Dtest=true"
      deployAcrossZones: "true"  # 尽量多可用区部署(注意,此值为字符串类型)
      deployAcrossNodes: "true"  # 尽量多节点部署(注意,此值为字符串类型)
      customTolerations:  # 调度容忍
        - key: aa
          operator: Exists
          effect: NoSchedule
        - key: bb
          operator: Equal
          value: "111"
          effect: "NoExecute"
          tolerationSeconds: 111
      customAffinity:  # 自定义调度规则
        nodeAffinity:  # 节点亲和性规则
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: "beta.kubernetes.io/arch"
                operator: "Gt"
                values:
                - "11"
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            preference:
              matchExpressions:
              - key: "beta.kubernetes.io/arch"
                operator: "Gt"
                values:
                - "11"
        podAffinity:  # 应用(Pod)亲和性规则
          requiredDuringSchedulingIgnoredDuringExecution:
          - namespaces:
            - "default"
            topologyKey: "failure-domain.beta.kubernetes.io/zone"
            labelSelector:
              matchExpressions:
              - key: "beta.kubernetes.io/arch"
                operator: "In"
                values:
                - "11"
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 1
            podAffinityTerm:
              namespaces:
              - "default"
              topologyKey: "failure-domain.beta.kubernetes.io/region"
              labelSelector:
                matchExpressions:
                - key: "beta.kubernetes.io/arch"
                  operator: "Exists"
                  values: []
        podAntiAffinity:   # 应用(Pod)反亲和性规则
          requiredDuringSchedulingIgnoredDuringExecution:
          - namespaces:
            - "default"
            topologyKey: "kubernetes.io/hostname"
            labelSelector:
              matchExpressions:
              - key: "beta.kubernetes.io/arch"
                operator: "In"
                values:
                - "11"
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 2
            podAffinityTerm:
              namespaces:
              - "default"
              topologyKey: "kubernetes.io/hostname"
              labelSelector:
                matchExpressions:
                - key: "beta.kubernetes.io/arch"
                  operator: "In"
                  values:
                  - "11"
                            

典型场景示例

典型部署场景及相关配置示例。

  • 场景一:本地构建War(或FatJar)包进行部署

    假设您在北京环境有WAR(或FatJar)类型的EDAS应用,期望本地构建WAR(或FatJar)进行部署。打包配置和部署配置如下所示:

    • 打包文件:

      apiVersion: V1
      kind: AppPackage
      spec:
        packageType: War                                    
    • 部署文件:

      apiVersion: V1
      kind: AppDeployment
      spec:
        type: kubernetes
        target:
          appId:        # 应用ID。插件会使用此应用进行部署,如未填入则使用namespaceId和appName来查找应用进行部署。
          namespaceId:  # 【可选】微服务空间,如不清楚appId,可使用此微服务空间及应用名称进行部署。
          appName:      # 【可选】应用名称,如不清楚appId,可使用此微服务空间及应用名称进行部署。
  • 场景二:使用已有镜像地址部署镜像类型应用

    假设您在北京环境有一个镜像类型应用,期望使用已有的镜像(registry.cn-beijing.aliyuncs.com/test/gateway:latest )部署应用。打包配置和部署配置如下所示:

    • 打包文件:

      apiVersion: V1
      kind: AppPackage
      spec:
        packageType: Image
        imageUrl: registry.cn-beijing.aliyuncs.com/test/gateway:latest                                    
    • 部署文件:

      apiVersion: V1
      kind: AppDeployment
      spec:
        type: kubernetes
        target:
          appId:        # 应用ID。插件会使用此应用进行部署,如未填入则使用namespaceId和appName来查找应用进行部署。
          namespaceId:  # 【可选】微服务空间,如不清楚appId,可使用此微服务空间及应用名称进行部署。
          appName:      # 【可选】应用名称,如不清楚appId,可使用此微服务空间及应用名称进行部署。
  • 场景三:本地构建镜像上传至仓库并部署应用

    假设您在北京环境有镜像类型应用,期望在本地编译并构建为镜像,并上传到阿里云镜像仓库进行部署,打包配置和部署配置如下所示:

    • 打包文件:

      apiVersion: V1
      kind: AppPackage
      spec:
        packageType: Image
        build:
          docker:
             dockerfile: Dockerfile # 指定Dockerfile。
             imageRepoAddress:      # 镜像仓库地址。
             imageTag:              # 镜像Tag。
             imageRepoUser:         # 镜像仓库用户名。
             imageRepoPassword:     # 镜像仓库密码。
    • 部署文件:

      apiVersion: V1
      kind: AppDeployment
      spec:
        type: kubernetes
        target:
          appId:        # 应用ID。插件会使用此应用进行部署,如未填入则使用namespaceId和appName来查找应用进行部署。
          namespaceId:  # 【可选】微服务空间,如不清楚appId,可使用此微服务空间及应用名称进行部署。
          appName:      # 【可选】应用名称,如不清楚appId,可使用此微服务空间及应用名称进行部署。