Todos los productos
Search
Centro de documentos

Enterprise Distributed Application Service:Use toolkit-maven-plugin to perform a canary release in a Kubernetes cluster

Última actualización: Sep 03, 2026

toolkit-maven-plugin automatiza los despliegues canary para aplicaciones de Spring Cloud, Dubbo y High-speed Service Framework (HSF) implementadas en Enterprise Distributed Application Service (EDAS). En lugar de actualizar todas las instancias simultáneamente, un despliegue canary aplica los cambios primero a un subconjunto pequeño de instancias y luego promueve gradualmente la actualización al resto de las instancias por lotes.

Funcionamiento del despliegue canary

Un despliegue canary con toolkit-maven-plugin sigue un proceso de dos fases:

  1. Fase canary: Despliegue de la nueva versión en un número específico de instancias (gray). Estas instancias reciben tráfico en vivo, lo que permite validar la nueva versión antes del despliegue completo.

  2. Fase de despliegue por lotes: Distribución de la nueva versión a las instancias restantes en lotes controlados (batch), con un intervalo configurable (batchWaitTime) entre cada lote. Los lotes pueden ejecutarse automáticamente o requerir aprobación manual.

El tipo de estrategia de actualización de EDAS para este proceso es GrayBatchUpdate.

Requisitos previos

Antes de empezar, asegúrese de contar con lo siguiente:

  • Una aplicación de Spring Cloud, Dubbo o HSF desplegada en un clúster de Kubernetes de EDAS

  • Un AccessKey ID y un AccessKey secret de un usuario de Resource Access Management (RAM) (se recomienda usar estas credenciales en lugar de las de la cuenta raíz)

  • El ID de la aplicación (appId), o bien el ID del namespace de microservices (namespaceId) y el nombre de la aplicación (appName) de la aplicación destino

Configuración de un despliegue canary

Para configurar un despliegue canary, agregue la dependencia del plugin, cree los archivos de configuración y ejecute el comando de despliegue.

Paso 1: Agregar la dependencia del plugin

Agregue la siguiente dependencia a su archivo pom.xml:

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

Utilice siempre la versión más reciente de toolkit-maven-plugin.

Paso 2: Crear los archivos de configuración

Cree tres archivos YAML en el directorio raíz de su proyecto empaquetado. Si despliega un submódulo de Maven, cree el archivo de configuración del paquete en el directorio del submódulo.

Configuración de la cuenta (toolkit_profile.yaml)

regionId:        # Region where the application is deployed, for example, cn-hangzhou
accessKeyId:     # AccessKey ID of a RAM user
accessKeySecret: # AccessKey secret of a RAM user
jarPath:         # (Optional) Path to the deployment package. Skips Maven packaging if specified.

Configuración del paquete (toolkit_package.yaml)

apiVersion: V1
kind: AppPackage
spec:
  packageType:   # War, FatJar, Image, or url
  packageUrl:    # (Optional) URL of a remote deployment package. Used when packageType is url.
  imageUrl:      # (Optional) Image URL. Used when packageType is Image.

Configuración del despliegue (toolkit_deploy.yaml)

apiVersion: V1
kind: AppDeployment
spec:
  type: kubernetes
  target:
    appId:        # Application ID. If specified, namespaceId and appName are not required.
    namespaceId:  # Microservices namespace ID. Required if appId is not specified.
    appName:      # Application name. Required if appId is not specified.
  updateStrategy:
    type: GrayBatchUpdate
    grayUpdate:
      gray: 2              # Number of instances to update in the canary phase
    batchUpdate:
      batch: 3             # Number of batches for the remaining instances
      releaseType: auto     # auto or manual
      batchWaitTime: 5      # Minutes to wait between batches

La siguiente tabla describe los parámetros del despliegue canary:

Parámetro

Descripción

Ejemplo

appId

ID de la aplicación en EDAS

6bbc57a2-a2a0-4edb-****-************

namespaceId

ID del namespace de microservices

cn-hangzhou:my-namespace

gray

Número de instancias canary

2

batch

Número de lotes de despliegue

3

releaseType

auto (automático) o manual (requiere aprobación)

auto

batchWaitTime

Minutos entre lotes

5

Paso 3: Ejecutar el comando de despliegue

Vaya al directorio que contiene el archivo pom.xml (o el pom.xml del submódulo) y ejecute:

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

Cuando el despliegue se completa correctamente, la salida muestra BUILD SUCCESS.

Parámetros del comando:

Parámetro

Descripción

toolkit:deploy

Despliega la aplicación después de completar el empaquetado de Maven.

-Dtoolkit_profile

Ruta al archivo de configuración de la cuenta.

-Dtoolkit_package

Ruta al archivo de configuración del paquete.

-Dtoolkit_deploy

Ruta al archivo de configuración del despliegue.

-Ddeploy_version

(Opcional) Versión del despliegue. Anula la versión definida en toolkit_deploy.yaml. Requiere toolkit-maven-plugin 1.0.6 o posterior.

Nota

Para omitir los parámetros -Dtoolkit_profile, -Dtoolkit_package y -Dtoolkit_deploy, coloque los archivos de configuración en el mismo directorio que el archivo pom.xml y anteponga un punto a cada nombre de archivo (.toolkit_profile.yaml, .toolkit_package.yaml, .toolkit_deploy.yaml). El plugin los detectará automáticamente.

Escenarios de despliegue

Despliegue con un paquete WAR o FatJar local

Compile un paquete WAR o FatJar localmente y despliéguelo en una aplicación existente de EDAS.

toolkit_package.yaml:

apiVersion: V1
kind: AppPackage
spec:
  packageType: War    # Or FatJar

toolkit_deploy.yaml:

apiVersion: V1
kind: AppDeployment
spec:
  type: kubernetes
  target:
    appId:        # Application ID
    namespaceId:  # (Optional) Namespace ID, required if appId is not specified
    appName:      # (Optional) Application name, required if appId is not specified

Despliegue con una URL de imagen existente

Despliegue una aplicación mediante una imagen de contenedor que ya existe en un registro.

toolkit_package.yaml:

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

toolkit_deploy.yaml:

apiVersion: V1
kind: AppDeployment
spec:
  type: kubernetes
  target:
    appId:        # Application ID
    namespaceId:  # (Optional) Namespace ID, required if appId is not specified
    appName:      # (Optional) Application name, required if appId is not specified

Compilación y envío de una imagen Docker local

Compile una imagen Docker localmente, envíela a un repositorio de imágenes de contenedor de Alibaba Cloud y realice el despliegue.

toolkit_package.yaml:

apiVersion: V1
kind: AppPackage
spec:
  packageType: Image
  build:
    docker:
      dockerfile: Dockerfile
      imageRepoAddress:   # Image repository address
      imageTag:           # Image tag
      imageRepoUser:      # Repository username
      imageRepoPassword:  # Repository password

toolkit_deploy.yaml:

apiVersion: V1
kind: AppDeployment
spec:
  type: kubernetes
  target:
    appId:        # Application ID
    namespaceId:  # (Optional) Namespace ID, required if appId is not specified
    appName:      # (Optional) Application name, required if appId is not specified

Referencia de configuración

Parámetros del paquete

apiVersion: V1
kind: AppPackage
spec:
  packageType:         # War, FatJar, Image, or url
  imageUrl:            # Image URL. Required when deploying with an image.
  packageUrl:          # Package URL. Used when packageType is url.
  build:
    docker:
      dockerfile:        # Dockerfile path. Required for local image builds.
      imageRepoAddress:  # Alibaba Cloud image repository address
      imageTag:          # Image tag
      imageRepoUser:     # Repository username
      imageRepoPassword: # Repository password
    oss:
      bucket:            # Object Storage Service (OSS) bucket name
      key:               # OSS object path
      accessKeyId:       # AccessKey ID for OSS access
      accessKeySecret:   # AccessKey secret for OSS access

Parámetros de despliegue

Haga clic para expandir los parámetros compatibles con el archivo de configuración de despliegue.

El archivo de despliegue admite los siguientes parámetros. Todos son opcionales a menos que se indique lo contrario.

apiVersion: V1
kind: AppDeployment
spec:
  type: kubernetes
  target:
    appName:       # Application name
    namespaceId:   # Microservices namespace ID
    appId:         # Application ID. If specified, namespaceId and appName are not required.
    version:       # Deployment version. Default format: day-hour-minute-second.
    jdk:           # JDK version (Open JDK 7 or Open JDK 8). Not applicable to image deployments.
    webContainer:  # Tomcat version (apache-tomcat-7.0.91). Not applicable to image deployments.
    batchWaitTime: # Interval between batches (minutes)
    command:       # Container startup command. Overrides the default image command.
    commandArgs:   # Startup command arguments
    - 1d
  envs:            # Container environment variables
    - name: ENV_NAME
      value: 'value'

Verificaciones de estado

Configure sondas de liveness y readiness para supervisar el estado del contenedor y de la aplicación. Especifique uno de los siguientes valores para cada sonda: exec, tcpSocket o httpGet.

Los contenedores que fallan en las verificaciones de liveness se reinician. Los contenedores que fallan repetidamente en las verificaciones de readiness se detienen y luego se reinician; además, dejan de recibir tráfico de las instancias de Server Load Balancer (SLB).

  liveness:
    exec:
      command:
        - cat
        - /tmp/healthy
    tcpSocket:
      host: "192.168.1.109"  # (Optional) Defaults to the pod IP address
      port: "8080"
    httpGet:
      path: "/health"
      port: "8080"
      host: "192.168.1.109"  # (Optional) Defaults to the pod IP address
      scheme: "HTTP"       # HTTP or HTTPS
      httpHeaders:
        - name: "Custom-Header"
          value: "value"
    initialDelaySeconds: 5   # Seconds before the first check
    timeoutSeconds: 11       # Seconds before a check times out
    periodSeconds: 5         # Seconds between checks
    successThreshold: 1      # Must be 1 for liveness probes
    failureThreshold: 3      # Consecutive failures before action

  readiness:
    exec:
      command:
        - cat
        - /tmp/healthy
    tcpSocket:
      host: "192.168.1.109"  # (Optional) Defaults to the pod IP address
      port: "8080"
    httpGet:
      path: "/health"
      port: "8080"
      host: "192.168.1.109"  # (Optional) Defaults to the pod IP address
      scheme: "HTTP"
      httpHeaders:
        - name: "Custom-Header"
          value: "value"
    initialDelaySeconds: 5
    timeoutSeconds: 11
    periodSeconds: 5
    successThreshold: 2
    failureThreshold: 3

Hooks del ciclo de vida

  preStop:          # Runs before the container is terminated
    exec:
      command:
        - /bin/bash
        - -c
        - "sleep 30"
    httpGet:
      host: "192.168.1.109"  # (Optional) Defaults to the pod IP address
      path: "/shutdown"
      port: "8080"
      scheme: "HTTP"         # HTTP or HTTPS
      httpHeaders:
        - name: "Custom-Header"
          value: "value"

  postStart:        # Runs after the container starts
    exec:
      command:
        - /bin/bash
        - -c
        - "echo started"
    httpGet:
      host: "192.168.1.109"  # (Optional) Defaults to the pod IP address
      path: "/initialize"
      port: "8080"
      scheme: "HTTP"         # HTTP or HTTPS
      httpHeaders:
        - name: "Custom-Header"
          value: "value"

Montajes de configuración

Monte recursos de ConfigMap o Secret en el contenedor.

  configMountDescs:
    - type: "ConfigMap"           # ConfigMap or Secret
      name: "my-config"
      mountPath: "/home/admin"    # Mount directory
      mountItems:                 # Mount as individual files
        - key: "config-key"
          path: "config-file"
      useSubPath: true            # true: keep existing files; false: overwrite

Parámetros de inicio de Java

  javaStartUpConfig:
    initialHeapSize:             # -Xms (initial heap size, MB)
      original: 1000
      startup: "-Xms1000m"
    maxHeapSize:                 # -Xmx (max heap size, MB)
      original: 1000
      startup: "-Xmx1000m"
    newSize:                     # -XX:NewSize (initial young generation, MB)
      original: 200
      startup: "-XX:NewSize=200m"
    maxNewSize:                  # -XX:MaxNewSize (max young generation, MB)
      original: 200
      startup: "-XX:MaxNewSize=200m"
    survivorRatio:               # -XX:SurvivorRatio (Eden to Survivor ratio)
      original: 2
      startup: "-XX:SurvivorRatio=2"
    newRatio:                    # -XX:NewRatio (old to young generation ratio)
      original: 8
      startup: "-XX:NewRatio=8"
    permSize:                    # -XX:PermSize (permanent generation, MB)
      original: 512
      startup: "-XX:PermSize=512m"
    maxPermSize:                 # -XX:MaxPermSize (max permanent generation, MB)
      original: 512
      startup: "-XX:MaxPermSize=200m"
    maxDirectMemorySize:         # -XX:MaxDirectMemorySize (MB)
      original: 100
      startup: "-XX:MaxDirectMemorySize=100m"
    threadStackSize:             # -XX:ThreadStackSize
      original: 500
      startup: "-XX:ThreadStackSize=500"
    hsfserverPort:               # HSF server port
      original: 12200
      startup: "-Dhsf.server.port=12200"
    hsfserverMinPoolSize:        # HSF minimum thread pool size
      original: 50
      startup: "-Dhsf.server.min.poolsize=50"
    hsfserverMaxPoolSize:        # HSF maximum thread pool size
      original: 720
      startup: "-Dhsf.server.max.poolsize=720"
    youngGarbageCollector:       # Young generation GC policy
      original: "UseSerialGC"   # UseSerialGC, UseG1GC, UseParNewGC, or UseParallelGC
      startup: "-XX:+UseSerialGC"
    oldGarbageCollector:         # Old generation GC policy
      original: "UseConcMarkSweepGC"   # UseConcMarkSweepGC, UseSerialGC, UseG1GC, UseParNewGC, UseParallelOldGC, or UseParallelGC
      startup: "-XX:+UseConcMarkSweepGC"
    concGCThreads:               # Concurrent GC threads
      original: 5
      startup: "-XX:ConcGCThreads=5"
    parallelGCThreads:           # Parallel GC threads
      original: 5
      startup: "-XX:ParallelGCThreads=5"
    g1HeapRegionSize:            # G1 region size (MB)
      original: 50
      startup: "-XX:G1HeapRegionSize=50m"
    gclogFilePath:               # GC log directory
      original: "/tmp/"
      startup: "-Xloggc:/tmp/"
    useGCLogFileRotation:        # Enable GC log rotation
      original: true
      startup: "-XX:+UseGCLogFileRotation"
    numberOfGCLogFiles:          # Number of GC log files
      original: 5
      startup: "-XX:NumberOfGCLogFiles=5"
    gclogFileSize:               # GC log file size (MB)
      original: 100
      startup: "-XX:GCLogFileSize=100m"
    heapDumpOnOutOfMemoryError:  # Enable out-of-memory (OOM) heap dumps
      original: true
      startup: "-XX:+HeapDumpOnOutOfMemoryError"
    heapDumpPath:                # OOM dump file path
      original: "/tmp/dumpfile"
      startup: "-XX:HeapDumpPath=/tmp/dumpfile"
    customParams:                # Custom JVM parameters
      original: "-Dtest=true"
      startup: "-Dtest=true"

Reglas de programación

  deployAcrossZones: "true"    # Deploy pods across availability zones (recommended)
  deployAcrossNodes: "true"    # Deploy pods across nodes (recommended)

  customTolerations:           # Kubernetes scheduling tolerations
    - key: my-key
      operator: Exists         # Exists or Equal
      effect: NoSchedule       # NoSchedule or NoExecute
    - key: another-key
      operator: Equal
      value: "my-value"
      effect: "NoExecute"
      tolerationSeconds: 300

  customAffinity:
    nodeAffinity:              # Schedule pods based on node labels
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
          - matchExpressions:
              - key: "topology.kubernetes.io/zone"
                operator: "In"
                values:
                  - "cn-hangzhou-a"
      preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 1
          preference:
            matchExpressions:
              - key: "topology.kubernetes.io/zone"
                operator: "In"
                values:
                  - "cn-hangzhou-b"
    podAffinity:               # Co-locate pods with matching pods
      requiredDuringSchedulingIgnoredDuringExecution:
        - namespaces:
            - "default"
          topologyKey: "topology.kubernetes.io/zone"
          labelSelector:
            matchExpressions:
              - key: "app"
                operator: "In"
                values:
                  - "my-app"
    podAntiAffinity:           # Spread pods away from matching pods
      requiredDuringSchedulingIgnoredDuringExecution:
        - namespaces:
            - "default"
          topologyKey: "kubernetes.io/hostname"
          labelSelector:
            matchExpressions:
              - key: "app"
                operator: "In"
                values:
                  - "my-app"
      preferredDuringSchedulingIgnoredDuringExecution:
        - weight: 2
          podAffinityTerm:
            namespaces:
              - "default"
            topologyKey: "kubernetes.io/hostname"
            labelSelector:
              matchExpressions:
                - key: "app"
                  operator: "In"
                  values:
                    - "my-app"