Tous les produits
Search
Centre de documentation

Alibaba Cloud Service Mesh:Routage dynamique de sous-ensembles

Dernière mise à jour :Aug 11, 2026

Avec le routage statique de sous-ensembles, chaque DestinationRule doit répertorier explicitement chaque sous-ensemble. Lorsqu'une nouvelle version est déployée ou qu'une ancienne est retirée, la règle doit être mise à jour manuellement. Le routage dynamique de sous-ensembles supprime cette charge : Service Mesh (ASM) surveille les libellés des charges de travail et regroupe automatiquement les points de terminaison en sous-ensembles, maintenant ainsi les règles de routage à jour sans intervention manuelle.

L'exemple complet ci-dessous déploie une application multiversion, achemine les requêtes vers des versions et environnements spécifiques via des en-têtes HTTP et configure le comportement de secours lorsqu'un sous-ensemble cible n'existe pas.

Fonctionnement des sous-ensembles dynamiques

Dans le routage Istio standard, une DestinationRule énumère chaque sous-ensemble avec un ensemble fixe de libellés. Lorsque les versions changent, la règle doit être mise à jour en conséquence.

Les sous-ensembles dynamiques adoptent une approche différente. Au lieu de lister chaque sous-ensemble, vous spécifiez une ou plusieurs clés de regroupement (par exemple, version et stage). ASM inspecte les libellés de chaque point de terminaison derrière un service et regroupe automatiquement les points de terminaison partageant la même combinaison clé-valeur dans le même sous-ensemble.

Une VirtualService mappe ensuite les en-têtes des requêtes entrantes à ces clés de regroupement. Par exemple, une requête contenant x-version: v2 et x-stage: prod est acheminée vers le sous-ensemble où version=v2 et stage=prod.

Prérequis

Avant de commencer, assurez-vous d'avoir :

Étape 1 : Déployer l'application exemple

Cet exemple utilise hashicorp/http-echo pour simuler un déploiement multi-environnement et multiversion :

  • Environnement dev : versions v1, v2, v3

  • Environnement prod : versions v2, v3

Chaque pod répond avec son environnement, sa version et son adresse IP. Un service helloworld sur le port 8000 sert de façade à tous les pods, et un déploiement sleep fournit un client pour les tests.

Deployment topology

Déployez toutes les ressources avec kubectl. Pour plus d'informations, consultez la rubrique Déployer une application dans un cluster ACK ajouté à une instance ASM.

Environnement dev

apiVersion: apps/v1
kind: Deployment
metadata:
  name: helloworld-dev-v1
  labels:
    app: helloworld
    version: v1
    stage: dev
spec:
  replicas: 1
  selector:
    matchLabels:
      app: helloworld
      version: v1
      stage: dev
  template:
    metadata:
      labels:
        app: helloworld
        version: v1
        stage: dev
    spec:
      containers:
      - name: helloworld
        image: hashicorp/http-echo:0.2.3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 5678
        env:
        - name: PODIP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        - name: STAGE
          valueFrom:
            fieldRef:
              fieldPath: metadata.labels['stage']
        - name: VERSION
          valueFrom:
            fieldRef:
              fieldPath: metadata.labels['version']
        command: ["/http-echo"]
        args:
          - "-text"
          - "Welcome to helloworld stage: $(STAGE), version: $(VERSION), ip: $(PODIP)"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: helloworld-dev-v2
  labels:
    app: helloworld
    version: v2
    stage: dev
spec:
  replicas: 1
  selector:
    matchLabels:
      app: helloworld
      version: v2
      stage: dev
  template:
    metadata:
      labels:
        app: helloworld
        version: v2
        stage: dev
    spec:
      containers:
      - name: helloworld
        image: hashicorp/http-echo:0.2.3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 5678
        env:
        - name: PODIP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        - name: STAGE
          valueFrom:
            fieldRef:
              fieldPath: metadata.labels['stage']
        - name: VERSION
          valueFrom:
            fieldRef:
              fieldPath: metadata.labels['version']
        command: ["/http-echo"]
        args:
          - "-text"
          - "Welcome to helloworld stage: $(STAGE), version: $(VERSION), ip: $(PODIP)"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: helloworld-dev-v3
  labels:
    app: helloworld
    version: v3
    stage: dev
spec:
  replicas: 1
  selector:
    matchLabels:
      app: helloworld
      version: v3
      stage: dev
  template:
    metadata:
      labels:
        app: helloworld
        version: v3
        stage: dev
    spec:
      containers:
      - name: helloworld
        image: hashicorp/http-echo:0.2.3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 5678
        env:
        - name: PODIP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        - name: STAGE
          valueFrom:
            fieldRef:
              fieldPath: metadata.labels['stage']
        - name: VERSION
          valueFrom:
            fieldRef:
              fieldPath: metadata.labels['version']
        command: ["/http-echo"]
        args:
          - "-text"
          - "Welcome to helloworld stage: $(STAGE), version: $(VERSION), ip: $(PODIP)"

Environnement prod

apiVersion: apps/v1
kind: Deployment
metadata:
  name: helloworld-prod-v2
  labels:
    app: helloworld
    version: v2
    stage: prod
spec:
  replicas: 1
  selector:
    matchLabels:
      app: helloworld
      version: v2
      stage: prod
  template:
    metadata:
      labels:
        app: helloworld
        version: v2
        stage: prod
    spec:
      containers:
      - name: helloworld
        image: hashicorp/http-echo:0.2.3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 5678
        env:
        - name: PODIP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        - name: STAGE
          valueFrom:
            fieldRef:
              fieldPath: metadata.labels['stage']
        - name: VERSION
          valueFrom:
            fieldRef:
              fieldPath: metadata.labels['version']
        command: ["/http-echo"]
        args:
          - "-text"
          - "Welcome to helloworld stage: $(STAGE), version: $(VERSION), ip: $(PODIP)"
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: helloworld-prod-v3
  labels:
    app: helloworld
    version: v3
    stage: prod
spec:
  replicas: 2
  selector:
    matchLabels:
      app: helloworld
      version: v3
      stage: prod
  template:
    metadata:
      labels:
        app: helloworld
        version: v3
        stage: prod
    spec:
      containers:
      - name: helloworld
        image: hashicorp/http-echo:0.2.3
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 5678
        env:
        - name: PODIP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        - name: STAGE
          valueFrom:
            fieldRef:
              fieldPath: metadata.labels['stage']
        - name: VERSION
          valueFrom:
            fieldRef:
              fieldPath: metadata.labels['version']
        command: ["/http-echo"]
        args:
          - "-text"
          - "Welcome to helloworld stage: $(STAGE), version: $(VERSION), ip: $(PODIP)"

Service helloworld

apiVersion: v1
kind: Service
metadata:
  name: helloworld
  labels:
    app: helloworld
    service: helloworld
spec:
  ports:
  - port: 8000
    name: http
    targetPort: 5678
  selector:
    app: helloworld

Client sleep

apiVersion: apps/v1
kind: Deployment
metadata:
  name: sleep
spec:
  replicas: 1
  selector:
    matchLabels:
      app: sleep
  template:
    metadata:
      labels:
        app: sleep
    spec:
      terminationGracePeriodSeconds: 0
      serviceAccountName: sleep
      containers:
      - name: sleep
        image: curlimages/curl
        command: ["/bin/sleep", "infinity"]
        imagePullPolicy: IfNotPresent
        volumeMounts:
        - mountPath: /etc/sleep/tls
          name: secret-volume
      volumes:
      - name: secret-volume
        secret:
          secretName: sleep-secret
          optional: true

Étape 2 : Acheminer les requêtes vers une version et un environnement spécifiques

Après le déploiement, Kubernetes répartit la charge des requêtes sur tous les pods helloworld, indépendamment de la version ou de l'environnement. Pour cibler une combinaison spécifique, créez une DestinationRule qui définit les clés de regroupement et une VirtualService qui mappe les en-têtes de requête à ces clés.

Créer la DestinationRule

Appliquez la DestinationRule suivante pour regrouper les points de terminaison par stage et version. Pour plus d'informations, consultez la rubrique Gérer les règles de destination.

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: helloworld
  namespace: default
spec:
  host: helloworld.default.svc.cluster.local
  trafficPolicy:
    loadBalancer:
      dynamicSubset:
        subsetSelectors:
          - keys:
              - stage
              - version

ASM lit les libellés stage et version de chaque point de terminaison et produit les sous-ensembles suivants :

Sous-ensemble Pod Adresse IP
stage=dev, version=v1 helloworld-dev-v1-67b6876778-nf7pz 192.168.0.5
stage=dev, version=v2 helloworld-dev-v2-68f65bbc99-v957l 192.168.0.1
stage=dev, version=v3 helloworld-dev-v3-7f6978bc56-hqzgg 192.168.0.252
stage=prod, version=v2 helloworld-prod-v2-b5745b949-p8rc4 192.168.0.103
stage=prod, version=v3 helloworld-prod-v3-6768bf56f8-6bd6h 192.168.0.104, 192.168.0.6

Créer la VirtualService

Appliquez la VirtualService suivante pour mapper les en-têtes HTTP aux clés de sous-ensemble dynamique. Pour plus d'informations, consultez la rubrique Gérer les services virtuels.

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: helloworld
  namespace: default
spec:
  hosts:
    - helloworld.default.svc.cluster.local
  http:
    - headerToDynamicSubsetKey:
        - header: x-version        # Map the x-version header to the "version" grouping key
          key: version
          defaultValue: v3          # Fall back to v3 if the header is absent
        - header: x-stage           # Map the x-stage header to the "stage" grouping key
          key: stage
          defaultValue: prod        # Fall back to prod if the header is absent
      name: default
      route:
        - destination:
            host: helloworld.default.svc.cluster.local
            port:
              number: 8000

Cette VirtualService établit deux mappages :

  • L'en-tête x-version vers la clé de regroupement version. Valeur par défaut : v3 si l'en-tête est absent.

  • L'en-tête x-stage vers la clé de regroupement stage. Valeur par défaut : prod si l'en-tête est absent.

Vérifier le routage

Envoyez une requête ciblant l'environnement dev, version v1 :

kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: dev' -H 'x-version: v1' helloworld:8000

Résultat attendu :

Welcome to helloworld stage: dev, version: v1, ip: 192.168.0.5

La requête atteint le pod où stage=dev et version=v1, ce qui confirme que le routage dynamique de sous-ensembles fonctionne correctement.

Étape 3 : Configurer les politiques de secours

La version v1 n'existe pas dans l'environnement prod. Une requête ciblant stage=prod, version=v1 ne correspond à aucun sous-ensemble :

kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' -H 'x-version: v1' helloworld:8000
# Output: no healthy upstream

Pour gérer les sous-ensembles non correspondants, définissez une fallbackPolicy dans la DestinationRule. ASM prend en charge trois politiques :

Politique Comportement Recommandé pour
NO_FALLBACK Renvoie une erreur no healthy upstream. Il s'agit de la valeur par défaut. Routage strict où les requêtes mal acheminées doivent échouer rapidement
ANY_ENDPOINT Achemine vers n'importe quel point de terminaison disponible dans tous les sous-ensembles Développement ou test où la disponibilité importe plus que la précision
DEFAULT_SUBSET (recommandé pour la production) Achemine vers un sous-ensemble par défaut préconfiguré Charges de travail de production, où les requêtes non correspondantes doivent atterrir sur une version connue et fiable

NO_FALLBACK

NO_FALLBACK est le comportement par défaut. Les requêtes qui ne correspondent à aucun sous-ensemble renvoient une erreur. Définissez-la explicitement pour clarifier l'intention d'échec rapide.

Appliquez la DestinationRule suivante. Pour plus d'informations, consultez la rubrique Gérer les règles de destination.

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: helloworld
  namespace: default
spec:
  host: helloworld.default.svc.cluster.local
  trafficPolicy:
    loadBalancer:
      dynamicSubset:
        subsetSelectors:
          - fallbackPolicy: NO_FALLBACK
            keys:
              - stage
              - version

Vérification :

kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' -H 'x-version: v1' helloworld:8000

Résultat attendu :

no healthy upstream

ANY_ENDPOINT

Lorsqu'aucun sous-ensemble ne correspond, les requêtes sont acheminées vers n'importe quel point de terminaison disponible, indépendamment des libellés.

Appliquez la DestinationRule suivante. Pour plus d'informations, consultez la rubrique Gérer les règles de destination.

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: helloworld
  namespace: default
spec:
  host: helloworld.default.svc.cluster.local
  trafficPolicy:
    loadBalancer:
      dynamicSubset:
        subsetSelectors:
          - fallbackPolicy: ANY_ENDPOINT
            keys:
              - stage
              - version

Vérifiez en envoyant deux requêtes. Chacune peut atterrir sur un pod différent :

# First request
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' helloworld:8000

Exemple de résultat :

Welcome to helloworld stage: prod, version: v2, ip: 192.168.0.103
# Second request -- targets a non-existent subset
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' -H 'x-version: v1' helloworld:8000

Exemple de résultat :

Welcome to helloworld stage: dev, version: v2, ip: 192.168.0.1

Étant donné qu'aucun sous-ensemble prod/v1 n'existe, la requête se rabat sur un point de terminaison aléatoire.

DEFAULT_SUBSET

Lorsqu'aucun sous-ensemble ne correspond, les requêtes sont acheminées vers le sous-ensemble défini dans defaultSubset. Cette politique est recommandée pour les charges de travail de production, car les requêtes non correspondantes atterrissent sur une version fiable plutôt que d'échouer ou d'être dispersées aléatoirement.

Appliquez la DestinationRule suivante. Dans cet exemple, defaultSubset pointe vers stage=prod, version=v3. Pour plus d'informations, consultez la rubrique Gérer les règles de destination.

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: helloworld
  namespace: default
spec:
  host: helloworld.default.svc.cluster.local
  trafficPolicy:
    loadBalancer:
      dynamicSubset:
        defaultSubset:
          stage: prod
          version: v3
        subsetSelectors:
          - fallbackPolicy: DEFAULT_SUBSET
            keys:
              - stage
              - version

Vérifiez en envoyant deux requêtes vers le sous-ensemble inexistant prod/v1 :

kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' -H 'x-version: v1' helloworld:8000

Résultat attendu :

Welcome to helloworld stage: prod, version: v3, ip: 192.168.0.6
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' -H 'x-version: v1' helloworld:8000

Résultat attendu :

Welcome to helloworld stage: prod, version: v3, ip: 192.168.0.104

Les deux requêtes atterrissent sur le sous-ensemble par défaut prod/v3. Les deux adresses IP différentes (192.168.0.6 et 192.168.0.104) reflètent la répartition de charge entre les deux réplicas prod-v3.

Étape 4 : Acheminer vers un pod spécifique par adresse IP

Pour épingler les requêtes à un pod individuel, utilisez l'attribut intégré %ip% comme clé de regroupement. Chaque pod devient son propre sous-ensemble à membre unique.

Créer la DestinationRule

Appliquez la DestinationRule suivante pour regrouper les pods par adresse IP. Pour plus d'informations, consultez la rubrique Gérer les règles de destination.

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: helloworld
  namespace: default
spec:
  host: helloworld.default.svc.cluster.local
  trafficPolicy:
    loadBalancer:
      dynamicSubset:
        defaultSubset:
          stage: prod
          version: v3
        subsetSelectors:
          - keys:
              - '%ip%'

Créer la VirtualService

Mappez l'en-tête x-ip à la clé %ip% afin que la valeur de l'en-tête spécifie l'adresse IP du pod cible. Pour plus d'informations, consultez la rubrique Gérer les services virtuels.

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: helloworld
  namespace: default
spec:
  hosts:
    - helloworld.default.svc.cluster.local
  http:
    - headerToDynamicSubsetKey:
        - header: x-ip
          key: '%ip%'
      name: default
      route:
        - destination:
            host: helloworld.default.svc.cluster.local
            port:
              number: 8000

Vérifier le routage

Envoyez plusieurs requêtes ciblant l'adresse IP du pod 192.168.0.6 :

kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-ip: 192.168.0.6' helloworld:8000

Résultat attendu (cohérent lors des appels répétés) :

Welcome to helloworld stage: prod, version: v3, ip: 192.168.0.6

Chaque requête atteint le même pod, confirmant l'épinglage basé sur l'adresse IP.

Référence des champs CRD

VirtualService

HTTPRoute

ASM étend la ressource HTTPRoute avec le champ headerToDynamicSubsetKey.

Champ Type Description
headerToDynamicSubsetKey HeaderToMetadataSubsetKey[] Mappe les en-têtes de requête aux clés de regroupement de sous-ensembles dynamiques. Chaque élément définit un mappage en-tête-vers-clé.

HeaderToMetadataSubsetKey

Champ Type Description
header string Nom de l'en-tête de requête.
key string Nom de la clé de regroupement de sous-ensemble dynamique. Une valeur entourée de signes de pourcentage (par exemple, %ip%) fait référence à un attribut de charge de travail intégré.
defaultValue string Valeur utilisée lorsque la requête ne contient pas l'en-tête spécifié. Si omis et que l'en-tête est absent, la clé reste non définie et est exclue de la correspondance de sous-ensemble.

DestinationRule

ASM étend la structure trafficPolicy avec le champ dynamicSubset.

TrafficPolicy

Champ Type Description
dynamicSubset DynamicSubsetLB Configure les règles de regroupement de sous-ensembles dynamiques.

DynamicSubsetLB

Champ Type Description
defaultSubset map[string]string Sous-ensemble par défaut utilisé lorsque fallbackPolicy est DEFAULT_SUBSET et qu'aucun sous-ensemble ne correspond à la requête.
subsetSelectors SubsetSelector[] Liste des règles de regroupement. Chaque élément définit une dimension de regroupement distincte.
fallbackPolicy DynamicSubsetLB_FallbackPolicy Politique de secours globale lorsqu'aucun sous-ensemble ne correspond. La valeur par défaut est NO_FALLBACK.

SubsetSelector

Champ Type Description
keys string[] Dimensions de regroupement mappées aux libellés de charge de travail. Par exemple, version regroupe les points de terminaison par le libellé version. Les attributs de charge de travail intégrés tels que %ip% sont également pris en charge.
fallbackPolicy DynamicSubsetLB_FallbackPolicy Politique de secours pour cette règle de regroupement spécifique. Remplace la politique définie dans DynamicSubsetLB.

DynamicSubsetLB_FallbackPolicy

Valeur Description
NO_FALLBACK Renvoie une erreur lorsqu'aucun sous-ensemble ne correspond. Il s'agit de la valeur par défaut.
ANY_ENDPOINT Achemine vers n'importe quel point de terminaison du service lorsqu'aucun sous-ensemble ne correspond.
DEFAULT_SUBSET Achemine vers le sous-ensemble défini dans defaultSubset lorsqu'aucun sous-ensemble ne correspond.

Attributs de charge de travail intégrés

Attribut Type Description
%ip% string Adresse IP du pod où s'exécute la charge de travail.

Voir aussi