traffic management

In this section, we will continue the previous task [Deploy Dubbo-go application in Istio environment].

In the previous task, we deployed a set of Dubbo-go Server and Client applications in the cluster, and verified the success of service discovery and invocation. In this section, we will create a new version of the server-side application. By configuring VirtualService and DestinationRule, routing management and traffic transfer capabilities are realized

1. Preparations

  • The dubbo-go cli tool and dependent tools have been installed, grpc_cli (for local debugging).
  • The docker, helm, and kubectl environments have been installed. (arm machines need to support docker buildx)
  • Task [Deploy Dubbo-go application in Istio environment] completed

2. Develop multi-version Dubbo-go applications.

2.1 Use dubbogo-cli to create another project template

$ dubbogo-cli newApp .

2.2 Develop and deploy client Dubbo-go application v2:

Write business logic

  • Modify the implementation method of package/service/service.go, and return the version number as v2.0.0
func (s *GreeterServerImpl) SayHello(ctx context.Context, in *api.HelloRequest) (*api.User, error) {
return &api.User{Name: "Hello " + in.Name, Id: "v2.0.0"}, nil
}
  • Modify the following configuration file, use the xds protocol as the registration center, and load the service structure named GreeterServerImpl.

    conf/dubbogo.yaml

    dubbo:
      registries:
        xds:
          protocol: xds
          address: istiod.istio-system.svc.cluster.local:15010
      protocols:
        triple:
          name: tri
          port: 20000
      provider:
        services:
          GreeterServerImpl:
            interface: "" # read from stub
    

    At this point, the application development is complete.

Configure build and deployment parameters

  • Specify the image to be built:

    Modify the following fields in the Makefile, specify the address and version of the image to be built, and change the image tag to 2.0.0.

    Specify the name that needs to be installed through helm.

    IMAGE = xxx/dubbo-go-server
    TAG = 2.0.0
    HELM_INSTALL_NAME = dubbo-go-server
    
  • Specify the application and image to be deployed:

    Modify the following fields in chart/app/Chart.yaml, and specify the current application name as dubbo-go-server. When we created the v1 version of the service, we already had the service of the application. The template will not be created during this deployment service.

    apiVersion: v1
    name: dubbo-go-server
    description: dubbo-go-server
    

    Modify the following fields in chart/app/values.yaml, specify the image to be deployed as 2.0.0, and the currently developed application version dubbogoAppVersion as v2.

    The deployed image needs to be consistent with the image built above. The current application version is used for mesh traffic rule control.

    image:
      repository: xxx/dubbo-go-server
      pullPolicy: Always
      tag: "2.0.0"
    
    # Dubbo-go-mesh version control labels
    version:
      labels:
        dubbogoAppVersion: v2
    

    At this point, the build parameters and release parameters have been specified, ready to build and deploy.

Use templates to build and deploy Dubbo-go applications

  • Build and push images

    $ make build (locally for amd64 machines)

    or

    $ make buildx-publish (Local is arm64 machine, depends on docker buildx command)

  • Publish Dubbo-go Server v2 to the cluster

    $ make deploy
    NAME: dubbo-go-server-v2
    LAST DEPLOYED: Thu Apr 7 12:29:28 2022
    NAMESPACE: default
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
    $ helm list
    NAME NAMESPACE REVISION UPDATED STATUS CHART dubbo-go-client default 1 2022-04-07 11:49:55.517898 +0800 CST deployed dubbo-go-client-0.0.1 1.16.0
    dubbo-go-server-v1 default 1 2022-04-07 11:23:18.397658 +0800 CST deployed dubbo-go-server-0.0.1 1.16.0
    dubbo-go-server-v2 default 1 2022-04-07 12:29:28.497476 +0800 CST deployed dubbo-go-client-0.0.1 1.16.0
    

    It can be seen that the deployment through helm is successful, and there is already a Client application and two versions of Server in the cluster.

2.3 Verify application

View resource deployment

Looking at the deployed deployment, the server contains two versions.

$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
dubbo-go-client-v1 1/1 1 1 40m
dubbo-go-server-v2 1/1 1 1 77s
dubbo-go-server-v1 1/1 1 1 67m

View the deployed service. Two versions of the deployment share the same service.

$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dubbo-go-client ClusterIP 192.168.8.176 <none> 20000/TCP 41m
dubbo-go-server ClusterIP 192.168.216.253 <none> 20000/TCP 67m

Check the Client application log to verify that the request is called to two versions of the application.

$ kubectl get pods | grep client | awk '{print $1}' | xargs kubectl logs
...
2022-04-07T05:06:40.384Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v2.0.0"
2022-04-07T05:06:41.386Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v2.0.0"
2022-04-07T05:06:42.388Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0"
2022-04-07T05:06:43.389Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v2.0.0"
2022-04-07T05:06:44.390Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v2.0.0"
2022-04-07T05:06:45.392Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0"
2022-04-07T05:06:46.393Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0"
2022-04-07T05:06:47.394Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0"
2022-04-07T05:06:48.396Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v2.0.0"
2022-04-07T05:06:49.397Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0"

So far, we have successfully developed and deployed multi-version applications.

3. Configure request routing

3.1 Configure target rules

Execute the following command to create a target rule that subdivides dubbo-go-server into two subsets. v1 and v2

$ kubectl apply -f destinationrule.yaml

destinationrule.yaml content:

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: dubbo-go-server
spec:
  host: dubbo-go-server
  subsets:
    - name: v1
      labels:
        dubbogoAppVersion: v1 # corresponds to the version label specified in chart/app/values.yaml in the application template
    - name: v2
      labels:
        dubbogoAppVersion: v2

3.2 Apply Virtual Service

Execute the following command to create a route that routes all traffic to the v1 application.

$ kubectl apply -f virtualservice.yaml

virtualservice.yaml content

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: dubbo-go-server
spec:
  hosts:
    - dubbo-go-server
  http:
  - route:
    -destination:
        host: dubbo-go-server
        subset: v1

3.3 Verify that the routing takes effect

All traffic will go to the v1 app.

$ kubectl get pods | grep client | awk '{print $1}' | xargs kubectl logs
...
2022-04-07T05:40:44.353Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0"
2022-04-07T05:40:45.354Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0"
2022-04-07T05:40:46.356Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0"
2022-04-07T05:40:47.357Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0"
2022-04-07T05:40:48.359Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0"
2022-04-07T05:40:49.361Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0"

4. Routing based on user identity

With the above foundation of multi-version application routing, we can implement flexible traffic management through some strategies.

4.1 Add user identity for client application

We hope that traffic with the user: admin identifier can experience the new v2 version of the application.

Go back to the previously created dubbo-go-client project, modify the main function of cmd/app.go, and add the calling identifier: user: admin.

func main() {
client := &api. GreeterClientImpl{}
config. SetConsumerService(client)
if err := config.Load(); err != nil {
panic(err)
}
request := &api.HelloRequest{
Name: "Laurence",
}

for {
ctx := context. Background()
ctx = context.WithValue(ctx, constant.AttachmentKey, map[string]string{
"user":"admin", // Use the context context to add identity to the call
})

if rsp, err := client.SayHello(ctx, request); err != nil{
logger.Errorf("call server error = %s", err)
}else{
logger.Infof("call server response = %+v", rsp)
}
time. Sleep(time. Second)
}
}
  • Build and push mirrors, overwriting previous commits. You can also upgrade the released image version.

    $ make build (locally for amd64 machines)

    or

    $ make buildx-publish (Local is arm64 machine, depends on docker buildx command)

  • Remove dubbo-go-client application

    $ make remove
    helm uninstall dubbo-go-client
    release "dubbo-go-client" uninstalled
    
  • Republish the app.

    $ make deploy

    After publishing, the verification call is successful because of the previous routing configuration. All traffic goes to the v1 version.

    $ kubectl get pods | grep client | awk '{print $1}' | xargs kubectl logs
    ...
    2022-04-07T05:40:44.353Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0"
    2022-04-07T05:40:45.354Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0"
    2022-04-07T05:40:46.356Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0"
    2022-04-07T05:40:47.357Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0"
    2022-04-07T05:40:48.359Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0"
    2022-04-07T05:40:49.361Z INFO cmd/app.go:29 call server response = name:"Hello laurence" id:"v1.0.0"
    

4.2 Create a route based on user identity

Execute the following command to modify/create a route that routes all traffic with the user: admin identifier in the request header to the v2 version.

$ kubectl apply -f virtualservice.yaml

virtualservice.yaml content

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: dubbo-go-server
spec:
  hosts:
    - dubbo-go-server
  http:
  - match:
    - headers:
        user:
          exact: admin
    route:
      -destination:
          host: dubbo-go-server
          subset: v2
  - route:
    -destination:
        host: dubbo-go-server
        subset: v1

4.3 Verify that the routing takes effect

All traffic will go to the v2 app.

$ kubectl get pods | grep client | awk '{print $1}' | xargs kubectl logs
...
2022-04-07T05:52:18.714Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0"
2022-04-07T05:52:19.716Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0"
2022-04-07T05:52:20.717Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0"
2022-04-07T05:52:21.718Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0"
2022-04-07T05:52:22.720Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0"
2022-04-07T05:52:23.722Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0"
2022-04-07T05:52:24.723Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0"

5. Weight-based routing

5.1 Create weight-based routing

Continuing the above tasks, we execute the following commands to modify/create a route that imports 10% of the traffic into the new version of the application for grayscale testing.

$ kubectl apply -f virtualservice.yaml

virtualservice.yaml content

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: dubbo-go-server
spec:
  hosts:
    - dubbo-go-server
  http:
    - route:
      -destination:
          host: dubbo-go-server
          subset: v1
        weight: 90
      -destination:
          host: dubbo-go-server
          subset: v2
        weight: 10

5.2 Verify that the routing takes effect

A small amount of traffic will go to the v2 release.

$ kubectl get pods | grep client | awk '{print $1}' | xargs kubectl logs
...
2022-04-07T05:55:52.035Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0"
2022-04-07T05:55:53.036Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0"
2022-04-07T05:55:54.037Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0"
2022-04-07T05:55:55.039Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0"
2022-04-07T05:55:56.041Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0"
2022-04-07T05:55:57.043Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0"
2022-04-07T05:55:58.045Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0"
2022-04-07T05:55:59.047Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0"
2022-04-07T05:56:00.049Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0"
2022-04-07T05:56:01.050Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v2.0.0"
2022-04-07T05:56:02.053Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0"
2022-04-07T05:56:03.055Z INFO cmd/app.go:35 call server response = name:"Hello laurence" id:"v1.0.0"
Last modified January 2, 2023: Enhance Dubbogo docs (#1800) (71c8e722740)