Istio Virtual Service - can I route traffic based on the calling service - istio

Say I've got three services, ServiceA, ServiceB, and ServiceC. ServiceA and ServiceB both call ServiceC. I want to deploy a new version of ServiceC, but only want to send it traffic from ServiceB for testing. Is there a Route configuration that takes "calling service" into account?

Based on istio documentation
You can do it with virtual service, or virtual service and destination rule.
With labels, example here
Deployments with app and version labels: We recommend adding an explicit app label and version label to deployments. Add the labels to the deployment specification of pods deployed using the Kubernetes Deployment. The app and version labels add contextual information to the metrics and telemetry Istio collects.
The app label: Each deployment specification should have a distinct app label with a meaningful value. The app label is used to add contextual information in distributed tracing.
The version label: This label indicates the version of the application corresponding to the particular deployment.
Each routing rule is associated with one or more service versions (see glossary in beginning of document). Weights associated with the version determine the proportion of traffic it receives. For example, the following rule will route 25% of traffic for the “reviews” service to instances with the “v2” tag and the remaining traffic (i.e., 75%) to “v1”.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews-route
spec:
hosts:
- reviews.prod.svc.cluster.local
http:
- route:
- destination:
host: reviews.prod.svc.cluster.local
subset: v2
weight: 25
- destination:
host: reviews.prod.svc.cluster.local
subset: v1
weight: 75
And the associated DestinationRule
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews-destination
spec:
host: reviews.prod.svc.cluster.local
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
OR
Traffic can also be split across two entirely different services without having to define new subsets. For example, the following rule forwards 25% of traffic to reviews.com and 75% to dev.reviews.com
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews-route-two-domains
spec:
hosts:
- reviews.com
http:
- route:
- destination:
host: dev.reviews.com
weight: 25
- destination:
host: reviews.com
weight: 75
EDIT
So actually you would have to add labels to your serviceC 1.0 and 2.0 and virtual service would look like this.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews-route-two-domains
spec:
hosts:
- reviews.com
http:
- match:
- sourceLabels:
svc: A
- route:
- destination:
host: serviceC
label: v1
- match:
- sourceLabels:
svc: B
- route:
- destination:
host: serviceC
label: v2
Check my another answer where I used sourceLabels here
Let me know if you have any more questions.

Related

AWS cross account Loki promtail setup in EKS

Here is my setup.
I have 2 AWS accounts.
Applications account
Monitoring account
Application account has EKS + Istio + Application related microservices + promtail agents.
Monitoring account has centralized logging system within EKS + Istio + (Grafana & Prometheus & loki pods running)
From Applications account, I want to push logs to Loki on Monitoring a/c. I tried exposing Loki service outside monitoring a/c but I am facing issues to set loki url as https://<DNS_URL>/loki. This change I tried by using suggestions at here and here, but that is not working for me. I have installed the loki-stack from this url
The question is how can I access loki URL from applications account so that it can be configured in promtail in applications a/c?
Please note both accounts are using pods within EKS and not standalone loki or promtail.
Thanks and regards.
apiVersion: v1
kind: Service
metadata:
annotations:
meta.helm.sh/release-name: loki
meta.helm.sh/release-namespace: monitoring
creationTimestamp: "2021-10-25T14:59:20Z"
labels:
app: loki
app.kubernetes.io/managed-by: Helm
chart: loki-2.5.0
heritage: Helm
release: loki
name: loki
namespace: monitoring
resourceVersion: "18279654"
uid: 7eba14cb-41c9-445d-bedb-4b88647f1ebc
spec:
clusterIP: 172.20.217.122
clusterIPs:
- 172.20.217.122
ports:
- name: metrics
port: 80
protocol: TCP
targetPort: 3100
selector:
app: loki
release: loki
sessionAffinity: None
type: ClusterIP
status:
loadBalancer: {}
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
generation: 14
name: grafana-vs
namespace: monitoring
resourceVersion: "18256422"
uid: e8969da7-062c-49d6-9152-af8362c08016
spec:
gateways:
- my-gateway
hosts:
- '*'
http:
- match:
- uri:
prefix: /grafana/
name: grafana-ui
rewrite:
uri: /
route:
- destination:
host: prometheus-operator-grafana.monitoring.svc.cluster.local
port:
number: 80
- match:
- uri:
prefix: /loki
name: loki-ui
rewrite:
uri: /loki
route:
- destination:
host: loki.monitoring.svc.cluster.local
port:
number: 80
---
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
annotations:
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"networking.istio.io/v1alpha3","kind":"Gateway","metadata":{"annotations":{},"name":"my-gateway","namespace":"monitoring"},"spec":{"selector":{"istio":"ingressgateway"},"servers":[{"hosts":["*"],"port":{"name":"http","number":80,"protocol":"HTTP"}}]}}
creationTimestamp: "2021-10-18T12:28:05Z"
generation: 1
name: my-gateway
namespace: monitoring
resourceVersion: "16618724"
uid: 9b254a22-958c-4cc4-b426-4e7447c03b87
spec:
selector:
istio: ingressgateway
servers:
- hosts:
- '*'
port:
name: http
number: 80
protocol: HTTP
---
apiVersion: v1
items:
- apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
alb.ingress.kubernetes.io/scheme: internal
alb.ingress.kubernetes.io/target-type: ip
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"networking.k8s.io/v1beta1","kind":"Ingress","metadata":{"annotations":{"alb.ingress.kubernetes.io/scheme":"internal","alb.ingress.kubernetes.io/target-type":"ip","kubernetes.io/ingress.class":"alb"},"name":"ingress-alb","namespace":"istio-system"},"spec":{"rules":[{"http":{"paths":[{"backend":{"serviceName":"istio-ingressgateway","servicePort":80},"path":"/*"}]}}]}}
kubernetes.io/ingress.class: alb
finalizers:
- ingress.k8s.aws/resources
generation: 1
name: ingress-alb
namespace: istio-system
resourceVersion: "4447931"
uid: 74b31fba-0f03-41c6-a63f-6a10dee8780c
spec:
rules:
- http:
paths:
- backend:
service:
name: istio-ingressgateway
port:
number: 80
path: /*
pathType: ImplementationSpecific
status:
loadBalancer:
ingress:
- hostname: internal-k8s-istiosys-ingressa-25a256ef4d-1368971909.us-east-1.elb.amazonaws.com
kind: List
metadata:
resourceVersion: ""
selfLink: ""
The ingress is associated with AWS ALB.
I want to access Loki from ALB URL like http(s)://my-alb-url/loki
I hope I have provided the required details now.
Let me know. Thanks.
...how can I access loki URL from applications account so that it can be configured in promtail in applications a/c?
You didn't describe what issue when you use external LB above which should work, anyway, since this method will go thru Internet, the security risk is higher with egress cost consider the volume of logging. You can use Privatelink in this case, see page 16 Shared Services. Your promtail will use the ENI DNS name as the loki target.

Is it possible to apply virtualService and Destination to the specified version of the POD

I have two http services A and B, and each service has two versions v1 and v2.
If A(v1) calls B, eg. use http://b:8080, both B(v1) and B(v2) can answer the call.
When A (v2) calls B, only B (v2) gets the call.
How should I define virtualService and Destination rules in this scenario?
You would need to match the pod from where the traffic is coming from with sourceLabels and the route it to the specific subsets. Here's an example of how that might look like:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: route-av1-bv1-2
spec:
hosts:
- service-b
http:
#Match the traffic from App-A-version-1 towards App-B versions 1 & 2
- match:
- sourceLabels:
app: av1
- route:
- destination:
host: service-b
subset: v1
- route:
- destination:
host: service-b
subset: v2
#Match the traffic from App-A-version-2 towards only App-B-version-2
- match:
- sourceLabels:
app: av2
- route:
- destination:
host: service-b
subset: v2
And the DestinationRule:
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: route-av1-bv1-2
spec:
host: service-b
subsets:
- name: v1
labels:
app: bv1
- name: v2
labels:
app: bv2
Istio traffic management sections describes the VirtualService and DestinationRule very well along with some good examples.

Istio VirtualService delegate with mesh gateway

I am implementing some routing logic for a set of internal services where a delegate VirtualService looks like a good solution:
https://istio.io/latest/docs/reference/config/networking/virtual-service/#Delegate
I created some test setup similar to the one in the documentation with only one difference. In my case, the "root" VirtualService bound to the "mesh" Gateway and the "host" is then some internal service name. Is this supposed to work or does delegation only work with non-mesh Gateways?
This is the root VirtualService (the idea is that all requests are sent to worker-pool.default.svc.cluster.local and depending on some HTTP headers they are then forwarded to other VirtualServices):
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-pool
spec:
hosts:
- worker-pool.default.svc.cluster.local
http:
- name: "route 1"
match:
- headers:
customer-id:
exact: alice
delegate:
name: worker-for-alice
- name: "route 2"
match:
- headers:
customer-id:
exact: bob
delegate:
name: worker-for-bob
And here the other VirtualService (only showing one, both look the same):
apiVersion: v1
kind: Service
metadata:
name: worker-for-alice
labels:
app: worker-for-alice
service: worker-for-alice
spec:
...
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: worker-for-alice
spec:
http:
- route:
- destination:
host: worker-for-alice
I guess there are some points to consider:
As far as I am concerned, Delegate will only work for Gateways. So, you should need something like this:
spec:
gateways:
- mesh
hosts:
- worker-pool.default.svc.cluster.local
http:
...
It is always a good idea to use namespaces. Once you have the items defined in namespaces, add "namespace" element to delegate definition:
delegate:
name: worker-for-bob
namespace: <some-namespace>
Last, but not least, it may be necessary to setup variable PILOT_ENABLE_VIRTUAL_SERVICE_DELEGATE to "true" on istiod configuration:
kubectl edit deployment istiod -n istio-system
And then add this env variable in spec.template.spec.container.env

Can one Virtual service fan out the request to multiple services

You will have request for (say /test ) , and that request has to be redirected to multiple services
kind of multitasking behavior
I tried below things , but it didn't work
- route:
- destination:
host: details
subset: v1
- destination:
host: preview
subset: v1
I have code for matching the test prefix and added only that part where actual redirection is happening.
In simpler way . I want to know , how to achieve fan out in istio
You haven't shared a full VirtualService manifest, however in the similar scenario I used the following configuration in order to distinguish HTTP requests to the same prefix path by applying specific custom headers:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- example
gateways:
- example-gateway
http:
- match:
- headers:
test:
exact: details
- uri:
prefix: /test
route:
- destination:
host: details
subset: v1
- match:
- headers:
test:
exact: preview
- uri:
prefix: /test
route:
- destination:
host: preview
subset: v1
Of course don't forget to accomplish appropriate DestinationRule's
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: details
spec:
host: details
subsets:
- name: v1
labels:
version: v1
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: preview
spec:
host: preview
subsets:
- name: v1
labels:
version: v1
You can find more relevant information in the official Istio traffic management documentation.
Try to use mirror option in Istio https://istio.io/docs/tasks/traffic-management/mirroring/

Istio VirtualService HTTP header match issue

The following Istio 0.8 VirtualService fails to match the HTTP header.
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- match:
- headers:
foo:
exact: bar
route:
- destination:
host: reviews
subset: v2
- route:
- destination:
host: reviews
subset: v3
I have followed https://github.com/istio/issues/issues/38 and Istio RouteRule based on headers user-agent doesn't work. However am unable to get it to function.
Pointers would be really helpful as the sleep service returns the product page similar to POSTMAN with no implication of the match condition!
This VirtualService by itself won't work if you don't have a DestinationRule to define your subsets (versions).
I will demonstrate how it should be done with the HelloWorld sample that is packed with the 0.8 release:
Step 1: Deploy the samples/helloworld/helloworld.yaml
Step 2: Define a DestinationRule for the two available versions:
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: helloworld
spec:
host: helloworld
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
Step 3: Replace the default VirtualService with the one that matches header attribute for routing:
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: helloworld
spec:
hosts:
- "*"
gateways:
- helloworld-gateway
http:
- match:
- headers:
foo:
exact: bar
route:
- destination:
host: helloworld
subset: v2
- route:
- destination:
host: helloworld
subset: v1
Step 4: Test it:
Without header: curl http://$INGRESS_GATEWAY/hello
Output:
Hello version: v1, instance: helloworld-v1-fd9b784bb-wcnj9
With header: curl -H "foo: bar" http://$INGRESS_GATEWAY/hello
Output:
Hello version: v2, instance: helloworld-v2-56694b7d6d-gbhqb
You need to call the reviews service through the ingressgateway. If you aren't doing that, there are two ways you could be hitting a problem:
If you are calling productpage (curl <ingress url>/productpage -H "foo: bar"), there is not any logic to propagate the foo: bar header from productpage to the reviews service. The example with the user-agent works because the user-agent is automatically propagated (a special case). If you want to use foo: bar, you would have to add logic to the productpage service to grab the foo header and send it on to the reviews service.
You are calling the reviews service directly (for instance, you gave the reviews service a node port). This would fail because your request is not being routed by an Istio proxy --instead it is being handled by the k8s service load balancer. You need to call an Istio proxy, like the ingressgateway.