In the following example, we'll show you how to use HTTP path-based routing to direct traffic between two versions of a service. For example, /v1 will route traffic to the A service, while /v2 will route traffic to the B service. Let's get started:
- Delete the previous deployments of web and api:
$ kubectl -n consul delete -f 11-web-deployment.yaml
$ kubectl -n consul delete -f 12-api-v1-deployment.yaml
$ kubectl -n consul delete -f 13-api-v2-deployment.yaml
- We created service-defaults for web and api in the L7 configuration management section. Check the service-defaults list:
$ consul config list -kind service-defaults
api
counting
dashboard
web
- Read the web configuration:
$ consul config read -kind service-defaults -name web
{
"Kind": "service-defaults",
"Name": "web",
"Protocol": "http",
"MeshGateway": {
"Mode": "local"
},
"CreateIndex": 186,
"ModifyIndex": 1750
}
- Read the api configuration:
$ consul config read -kind service-defaults -name api
{
"Kind": "service-defaults",
"Name": "api",
"Protocol": "http",
"MeshGateway": {
"Mode": "local"
},
"CreateIndex": 218,
"ModifyIndex": 218
}
- Define a service-router for the api, which will allow us to accomplish path-based routing to a specific service:
# Script: 17-service-router.hcl
...
match {
http {
path_prefix="/v1"
}
}
destination {
service = "api"
service_subset = "v1"
}
...
- Create an api called service-router:
$ consul config write 17-service-router.hcl
- Create a Kubernetes web service and deployment:
$ kubectl apply -f 18-web-deployment.yaml
service/web created
deployment.apps/web created
- Create an api-v1 service and deployment:
$ kubectl apply -f 19-api-v1-deployment.yaml
service/api-v1 created
deployment.apps/api-v1 created
- Similarly, create an api-v2 service and deployment:
$ kubectl apply -f 20-api-v2-deployment.yaml
service/api-v2 created
deployment.apps/api-v2 created
# Check status of pods. Must show Ready 2/2
$ kubectl -n consul get pods -l 'app in (web, api-v1, api-v2)'
Nicholas Jackson of Hashicorp formulated the path-based example. You can find out more at https://github.com/nicholasjackson/demo-consul-service-mesh/tree/master/kubernetes/traffic_routing.
Through the preceding example, we have created a frontend web service that receives traffic from the internet through an Ingress definition. There are two upstream deployments, api-v1 and api-v2, that we call through a virtual upstream service defined in the 18-web-deployment.yaml web development script, as shown in the following code:
annotations:
"consul.hashicorp.com/connect-inject": "true"
"consul.hashicorp.com/connect-service-upstreams": "api:8081"
...
- name: "LISTEN_ADDR"
value: "0.0.0.0:8080"
- name: "UPSTREAM_URIS"
value: "http://localhost:8091"
- We can run the web service using curl at node port 30145 without using any path. Notice that it will always call the api-v2 upstream service since we shifted 100% traffic to this service in the Shifting traffic permanently section:
$ curl -s http://localhost:30145
{
"name": "web",
...
"body": "Hello World",
"upstream_calls": [
{
"name": "api-v2",
"uri": "http://localhost:8081",
...
"body": "Response from API v2",
"code": 200
}
],
"code": 200
}
- Run the same curl command by using the /v1 path. Note that traffic shifts to the api-v1 service due to the service-router implementation:
$ curl -s http://localhost:30145/v1
{
"name": "web",
...
"body": "Hello World",
"upstream_calls": [
{
"name": "api-v1",
"uri": "http://localhost:8081",
...
"body": "Response from API v1",
"code": 200
}
],
"code": 200
}
Though not shown in the preceding code, traffic routing can also be based upon headers, query parameters, and so on. The following example shows that, if the x-debug header is set to 1, the traffic will be routed to another service web using the service-resolver canary:
match {
http {
header = [
{
name = "x-debug"
exact = "1"
},
]
}
}
destination {
service = "web"
service_subset = "canary"
}
Next, we will use the Consul dashboard to check services and explore, sidecar proxies and upstream services.