title: How to get an Istio VirtualService to vary routes by header along with uri
body: <p>I'm still experimenting with Istio in a dev cluster, along with a couple of other people.  We have a sample virtualservice, deployment, and destinationrule, and requests to the specified uri are going to the pod associated with the deployment.  This is working fine.</p>
  
  <p>I am attempting a variation of this that goes to an alternate deployment if a particular header and value are present.  If the header is not set, or the specified header value is not present, it will go to the original deployment, otherwise to the alternate deployment.  I eventually intend for it to check for several different values of the specified header, each going to different deployments.</p>
  
  <p>I've created a deployment and destination rule that are copies of the original, with consistent variations.  I attempted to modify the virtualservice with this alternate routing.  Thus far, it isn't working properly.  I determine which deployment a request goes to by tailing the container log of the container associated with each deployment.  When I sent a request with the specified header and value, it does go to the alternate deployment.  However, when I send the request without the specified header, or without the matching value, it ALSO goes to the alternate deployment. In fact, I can't get it to reach the main deployment at all.</p>
  
  <p>Note that I understand that another way to do this is to have one virtualservice for the "default" route, and an additional virtualservice for each alternate route, specifying a different header value.  I've seen something basically like that working.  However, that seems like a lot of duplication to get something that should be simpler to set up in a single VirtualService.</p>
  
  <p>The following is the current state of the virtualservice, with some elisions:</p>
  
  <pre><code>apiVersion: networking.istio.io/v1alpha3
  kind: VirtualService
  metadata:
    annotations: {}
    name: fooms-vs-ingress
    namespace: com-example
  spec:
    gateways:
    - ingress-gateway
    hosts:
    - '*'
    http:
    - match:
      - uri:
          prefix: /msapi/foo
      - headers:
          ctx-debug-route-fooms:
            exact: myuid-1
      route:
      - destination:
          host: fooms.com-example.svc.cluster.local
          port:
            number: 80
          subset: myuid-1
    - route:
      - destination:
          host: fooms.com-example.svc.cluster.local
          port:
            number: 80
          subset: blue
  </code></pre>
  
  <p>I could show the deployments and destinationrules, but I don't know if that will be helpful.</p>
  
  <p><strong>Update</strong>:</p>
  
  <p>Since I wrote this, I discovered that in order to make two conditions AND in a route match, I have to have both conditions in a single match rule. I'm still getting used to how YAML works.  I'm going to provide here an updated version of the virtualservice, along with the gateway, destination rule, and much of the deployment.  There's a lot of stuff in the deployment that probably isn't helpful.</p>
  
  <p>When I sent a request to the service from Postman, with or without the routing header, I get a 503 back.  Before I made these changes to check for the routing header, it was properly routing requests to the "blue" instance (I am tailing the logs for both pods).  When I first tried making these changes, I inadvertently defined two match blocks, one with the uri condition, and one with the header match condition.  When I did that, all of the requests were going to the alternate pod.</p>
  
  <p>Here are elided versions of the objects that might be relevant, with some transient properties removed.</p>
  
  <pre><code>apiVersion: networking.istio.io/v1alpha3
  kind: VirtualService
  metadata:
    annotations: {}
    name: fooms-vs-ingress
    namespace: com-example
  spec:
    gateways:
    - comp-ingress-gateway
    hosts:
    - '*'
    http:
    - match:
      - headers:
          compctx-debug-route-fooms:
            exact: myuid-1
        name: match-myuid-1
        uri:
          prefix: /msapi/foo
      route:
      - destination:
          host: fooms.com-example.svc.cluster.local
          port:
            number: 80
          subset: myuid-1
    - name: default
      route:
      - destination:
          host: fooms.com-example.svc.cluster.local
          port:
            number: 80
          subset: blue
  
  apiVersion: networking.istio.io/v1alpha3
  kind: Gateway
  metadata:
    annotations: {}
    name: comp-ingress-gateway
    namespace: com-example
  spec:
    selector:
      istio: ingressgateway
    servers:
    - hosts:
      - '*'
      port:
        name: http
        number: 80
        protocol: HTTP
    - hosts:
      - '*'
      port:
        name: https
        number: 443
        protocol: HTTPS
      tls:
        mode: SIMPLE
        privateKey: /etc/istio/ingressgateway-certs/tls.key
        serverCertificate: /etc/istio/ingressgateway-certs/tls.crt
  
  apiVersion: extensions/v1beta1
  kind: Deployment
  metadata:
    annotations:
      deployment.kubernetes.io/revision: "1"
    labels:
      app: FooMS
      role: blue
      routeoffer: DEFAULT
      seed: COMPv2.2.0
      version: 2.2.0-myuid-1
    name: fooms-myuid-1
    namespace: com-example
  spec:
    replicas: 1
    revisionHistoryLimit: 2
    selector:
      matchLabels:
        app: FooMS
        role: blue
    strategy:
      rollingUpdate:
        maxSurge: 1
        maxUnavailable: 1
      type: RollingUpdate
    template:
      metadata:
        annotations:
          sidecar.istio.io/inject: "true"
        creationTimestamp: null
        labels:
          app: FooMS
          role: blue
          routeoffer: DEFAULT
          seed: COMPv2.2.0
          version: 2.2.0-myuid-1
      spec:
        containers:
        - env:
          - name: SERVICE_NAME
            value: fooms
          - name: NODE_NAME
            valueFrom:
              fieldRef:
                apiVersion: v1
                fieldPath: spec.nodeName
          envFrom:
          - configMapRef:
              name: global-config
          - secretRef:
              name: global-secrets
          image: dockercentral.it....
          imagePullPolicy: Always
          name: fooms
          ports:
          - containerPort: 8080
            name: http
            protocol: TCP
        - image: ...
          imagePullPolicy: IfNotPresent
          name: info
        dnsPolicy: ClusterFirst
        restartPolicy: Always
        schedulerName: default-scheduler
        securityContext: {}
        serviceAccount: default
        serviceAccountName: default
        terminationGracePeriodSeconds: 30
  
  apiVersion: networking.istio.io/v1alpha3
  kind: DestinationRule
  metadata:
    annotations: {}
    name: fooms-destination-myuid-1
    namespace: com-example
  spec:
    host: fooms.com-example.svc.cluster.local
    subsets:
    - labels:
        version: 2.2.0-myuid-1
      name: myuid-1
    trafficPolicy:
      tls:
        mode: ISTIO_MUTUAL
  </code></pre>