Todos os produtos
Search
Central de documentação

Alibaba Cloud Service Mesh:Roteamento dinâmico de subconjuntos

Última atualização: Jun 28, 2026

No roteamento estático de subconjuntos, cada DestinationRule precisa listar explicitamente todos os subconjuntos. Sempre que uma nova versão é lançada ou uma antiga descontinuada, a regra exige atualização manual. O roteamento dinâmico de subconjuntos elimina essa sobrecarga: o Service Mesh (ASM) monitora os rótulos das cargas de trabalho e agrupa os endpoints em subconjuntos automaticamente, mantendo as regras de roteamento atualizadas sem alterações manuais.

O exemplo de ponta a ponta abaixo implanta uma aplicação com múltiplas versões, direciona requisições para versões e ambientes específicos com base em cabeçalhos HTTP e configura um comportamento de fallback quando o subconjunto de destino não existe.

Como funcionam os subconjuntos dinâmicos

No roteamento padrão do Istio, uma DestinationRule enumera cada subconjunto com um conjunto fixo de rótulos. Quando as versões mudam, a regra deve ser atualizada para corresponder à nova realidade.

Os subconjuntos dinâmicos adotam uma abordagem diferente. Em vez de listar cada subconjunto, especifique uma ou mais chaves de agrupamento (por exemplo, version e stage). O ASM inspeciona os rótulos de cada endpoint associado a um serviço e agrupa automaticamente os endpoints que compartilham a mesma combinação de chave-valor no mesmo subconjunto.

Em seguida, uma VirtualService mapeia os cabeçalhos das requisições recebidas para essas chaves de agrupamento. Por exemplo, uma requisição contendo x-version: v2 e x-stage: prod é roteada para o subconjunto onde version=v2 e stage=prod.

Pré-requisitos

Antes de começar, certifique-se de ter:

Etapa 1: Implantar a aplicação de exemplo

Este exemplo utiliza hashicorp/http-echo para simular uma implantação com múltiplos ambientes e versões:

  • Ambiente dev: versões v1, v2, v3

  • Ambiente prod: versões v2, v3

Cada pod responde com seu ambiente, versão e endereço IP. Um Service helloworld na porta 8000 atua como frontend para todos os pods, e um Deployment sleep fornece um cliente para testes.

Deployment topology

Implante todos os recursos com kubectl. Para mais informações, consulte Implantar uma aplicação em um cluster ACK adicionado a uma instância do ASM.

dev environment

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)"

prod environment

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)"

helloworld Service

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

sleep client

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

Etapa 2: Roteamento de requisições para uma versão e ambiente específicos

Após a implantação, o Kubernetes balanceia a carga das requisições entre todos os pods do helloworld, independentemente da versão ou do ambiente. Para direcionar o tráfego a uma combinação específica, crie uma DestinationRule que defina as chaves de agrupamento e uma VirtualService que mapeie os cabeçalhos das requisições para essas chaves.

Criar a DestinationRule

Aplique a seguinte DestinationRule para agrupar endpoints por stage e version. Para mais informações, consulte Gerenciar regras de destino.

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

O ASM lê os rótulos stage e version de cada endpoint e gera os seguintes subconjuntos:

Subconjunto

Pod

Endereço 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

Criar a VirtualService

Aplique a seguinte VirtualService para mapear cabeçalhos HTTP nas chaves de subconjunto dinâmico. Para mais informações, consulte Gerenciar serviços virtuais.

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

Esta VirtualService estabelece dois mapeamentos:

  • Do cabeçalho x-version para a chave de agrupamento version. Padrão: v3 quando o cabeçalho estiver ausente.

  • Do cabeçalho x-stage para a chave de agrupamento stage. Padrão: prod quando o cabeçalho estiver ausente.

Verificar o roteamento

Envie uma requisição direcionada ao ambiente dev, versão v1:

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

Saída esperada:

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

A requisição atinge o pod onde stage=dev e version=v1, confirmando que o roteamento dinâmico de subconjuntos funciona corretamente.

Etapa 3: Configurar políticas de fallback

A versão v1 não existe no ambiente prod. Uma requisição direcionada a stage=prod, version=v1 não corresponde a nenhum subconjunto:

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

Para lidar com subconjuntos não correspondidos, defina uma fallbackPolicy na DestinationRule. O ASM suporta três políticas:

Política

Comportamento

Recomendada para

NO_FALLBACK

Retorna um erro no healthy upstream. Este é o comportamento padrão.

Roteamento estrito, onde requisições mal direcionadas devem falhar rapidamente

ANY_ENDPOINT

Roteia para qualquer endpoint disponível em todos os subconjuntos

Desenvolvimento ou testes, onde a disponibilidade é mais importante que a precisão

DEFAULT_SUBSET (recomendada para produção)

Roteia para um subconjunto padrão pré-configurado

Cargas de trabalho em produção, onde requisições sem correspondência devem ser direcionadas a uma versão estável conhecida

NO_FALLBACK

NO_FALLBACK é o comportamento padrão. Requisições que não correspondem a nenhum subconjunto retornam um erro. Defina-a explicitamente para deixar clara a intenção de falha rápida.

Aplique a seguinte DestinationRule. Para mais informações, consulte Gerenciar regras de destino.

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

Verifique:

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

Saída esperada:

no healthy upstream

ANY_ENDPOINT

Quando nenhum subconjunto corresponde, as requisições são roteadas para qualquer endpoint disponível, independentemente dos rótulos.

Aplique a seguinte DestinationRule. Para mais informações, consulte Gerenciar regras de destino.

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

Verifique enviando duas requisições. Cada uma pode atingir um pod diferente:

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

Exemplo de saída:

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

Exemplo de saída:

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

Como não existe nenhum subconjunto prod/v1, a requisição recorre a um endpoint aleatório.

DEFAULT_SUBSET

Quando nenhum subconjunto corresponde, as requisições são roteadas para o subconjunto definido em defaultSubset. Esta é a política recomendada para cargas de trabalho em produção, pois requisições sem correspondência são direcionadas a uma versão estável conhecida, em vez de falhar ou ser distribuídas aleatoriamente.

Aplique a seguinte DestinationRule. Neste exemplo, defaultSubset aponta para stage=prod, version=v3. Para mais informações, consulte Gerenciar regras de destino.

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

Verifique enviando duas requisições para o subconjunto inexistente prod/v1:

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

Saída esperada:

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

Saída esperada:

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

Ambas as requisições atingem o subconjunto padrão prod/v3. Os dois IPs diferentes (192.168.0.6 e 192.168.0.104) refletem o balanceamento de carga entre as duas réplicas prod-v3.

Etapa 4: Roteamento para um pod específico por endereço IP

Para fixar requisições em um pod individual, use o atributo integrado %ip% como chave de agrupamento. Cada pod se torna seu próprio subconjunto de membro único.

Criar a DestinationRule

Aplique a seguinte DestinationRule para agrupar pods por endereço IP. Para mais informações, consulte Gerenciar regras de destino.

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%'

Criar a VirtualService

Mapeie o cabeçalho x-ip para a chave %ip% para que o valor do cabeçalho especifique o IP do pod de destino. Para mais informações, consulte Gerenciar serviços virtuais.

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

Verificar o roteamento

Envie múltiplas requisições direcionadas ao IP do pod 192.168.0.6:

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

Saída esperada (consistente em chamadas repetidas):

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

Todas as requisições atingem o mesmo pod, confirmando a fixação baseada em IP.

Referência de campos CRD

VirtualService

HTTPRoute

O ASM estende o recurso HTTPRoute com o campo headerToDynamicSubsetKey.

Campo

Tipo

Descrição

headerToDynamicSubsetKey

HeaderToMetadataSubsetKey[]

Mapeia cabeçalhos de requisição para chaves de agrupamento de subconjuntos dinâmicos. Cada elemento define um mapeamento de cabeçalho para chave.

HeaderToMetadataSubsetKey

Campo

Tipo

Descrição

header

string

Nome do cabeçalho da requisição.

key

string

Nome da chave de agrupamento do subconjunto dinâmico. Um valor entre sinais de porcentagem (por exemplo, %ip%) refere-se a um atributo integrado da carga de trabalho.

defaultValue

string

Valor usado quando a requisição não contém o cabeçalho especificado. Se omitido e o cabeçalho estiver ausente, a chave fica indefinida e é excluída da correspondência de subconjuntos.

DestinationRule

O ASM estende a estrutura trafficPolicy com o campo dynamicSubset.

TrafficPolicy

Campo

Tipo

Descrição

dynamicSubset

DynamicSubsetLB

Configura regras de agrupamento de subconjuntos dinâmicos.

DynamicSubsetLB

Campo

Tipo

Descrição

defaultSubset

map[string]string

Subconjunto padrão usado quando fallbackPolicy é DEFAULT_SUBSET e nenhum subconjunto corresponde à requisição.

subsetSelectors

SubsetSelector[]

Lista de regras de agrupamento. Cada elemento define uma dimensão de agrupamento separada.

fallbackPolicy

DynamicSubsetLB_FallbackPolicy

Política de fallback global quando nenhum subconjunto corresponde. O padrão é NO_FALLBACK.

SubsetSelector

Campo

Tipo

Descrição

keys

string[]

Dimensões de agrupamento mapeadas para rótulos de carga de trabalho. Por exemplo, version agrupa endpoints pelo rótulo version. Atributos integrados da carga de trabalho, como %ip%, também são suportados.

fallbackPolicy

DynamicSubsetLB_FallbackPolicy

Política de fallback para esta regra de agrupamento específica. Substitui a política definida em DynamicSubsetLB.

DynamicSubsetLB_FallbackPolicy

Valor

Descrição

NO_FALLBACK

Retorna um erro quando nenhum subconjunto corresponde. Este é o padrão.

ANY_ENDPOINT

Roteia para qualquer endpoint do serviço quando nenhum subconjunto corresponde.

DEFAULT_SUBSET

Roteia para o subconjunto definido em defaultSubset quando nenhum subconjunto corresponde.

Atributos integrados da carga de trabalho

Atributo

Tipo

Descrição

%ip%

string

Endereço IP do pod onde a carga de trabalho está em execução.

Veja também