gRPC with Istio

2023年02月12日


Prerequisites

Install CDK

% npm install aws-cdk-lib

npm WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated
npm WARN deprecated source-map-url@0.4.1: See https://github.com/lydell/source-map-url#deprecated
npm WARN deprecated source-map-resolve@0.5.3: See https://github.com/lydell/source-map-resolve#deprecated
npm WARN deprecated sane@4.1.0: some dependency vulnerabilities fixed, support for node < 10 dropped, and newer ECMAScript syntax/features added
npm WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated

added 688 packages, and audited 858 packages in 6m

30 packages are looking for funding
  run `npm fund` for details

5 vulnerabilities (1 low, 4 high)

To address issues that do not require attention, run:
  npm audit fix

To address all issues, run:
  npm audit fix --force

Run `npm audit` for details.

% cd grpc-examples
% ls
CODE_OF_CONDUCT.md	LICENSE			examples		go.sum
CONTRIBUTING.md		README.md		go.mod			walkthroughs
% cd walkthroughs/compute-options


Install Go on Linux.
sudo rm -rf /usr/local/go && tar -C /usr/local -xzf go1.20.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
go version

Here is a sample Go code to make a gRPC request to a URL:
package main

import (
	"context"
	"fmt"
	"log"

	"google.golang.org/grpc"

	pb "path/to/your/proto/file"
)

const (
	address = "localhost:50051"
)

func main() {
	// Set up a connection to the server.
	conn, err := grpc.Dial(address, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()

	// Create a client for the service.
	client := pb.NewYourServiceClient(conn)

	// Make a request to the server.
	req := &pb.YourRequest{}
	res, err := client.MakeRequest(context.Background(), req)
	if err != nil {
		log.Fatalf("could not make request: %v", err)
	}

	fmt.Println(res)
}

In this example, you need to replace path/to/your/proto/file with the path to your protobuf file, and YourService and YourRequest with the names of your gRPC service and request message.
The code establishes a connection to the gRPC server at localhost:50051, creates a client for your service, and makes a request to the server using the MakeRequest method of the client. The response from the server is printed to the console.

Here's an example protobuf file (protos.proto):
syntax = "proto3";

package example;

service YourService {
  rpc MakeRequest (YourRequest) returns (YourResponse) {}
}

message YourRequest {
  string request_field = 1;
}

message YourResponse {
  string response_field = 1;
}
In this example, the protobuf file defines a gRPC service named YourService with a single method, MakeRequest, that takes a YourRequest message as input and returns a YourResponse message.
The YourRequest message has a single field, request_field, of type string. The YourResponse message has a single field, response_field, also of type string.
You can customize this file to define the messages and service methods required for your application.

Clone the GitHub repository.
$ git clone https://github.com/xxx/sc-grpc.git

$ aws ecr create-repository --repository-name grpcdemo --region us-west-2
{
    "repository": {
        "repositoryUri": "<111122223333>.dkr.ecr.us-west-2.amazonaws.com/grpcdemo", 
        "imageScanningConfiguration": {
            "scanOnPush": false
        }, 
        "encryptionConfiguration": {
            "encryptionType": "AES256"
        }, 
        "registryId": "<111122223333>", 
        "imageTagMutability": "MUTABLE", 
        "repositoryArn": "arn:aws:ecr:us-west-2:<111122223333>:repository/grpcdemo", 
        "repositoryName": "grpcdemo", 
        "createdAt": 1676204231.0
    }
}

$ docker tag grpcdemo <111122223333>.dkr.ecr.us-west-2.amazonaws.com/grpcdemo

$ docker login -u AWS -p $(aws ecr get-login-password --region us-west-2) <111122223333>.dkr.ecr.us-west-2.amazonaws.com
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /home/ec2-user/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

$ docker push <111122223333>.dkr.ecr.us-west-2.amazonaws.com/grpcdemo
Using default tag: latest
The push refers to repository [<111122223333>.dkr.ecr.us-west-2.amazonaws.com/grpcdemo]
efc05b1694d5: Pushed 
ae1da9abcf46: Pushed 
latest: digest: sha256:2e3439f76ddcfc026a13dea9eb22e3664470a68365434293a65e3a6d96b9581e size: 739

$ cd ..
$ mkdir grpcclient
$ cd grpcclient/

greeter_client]$ go build
go: downloading google.golang.org/grpc v1.31.1
go: downloading github.com/golang/protobuf v1.4.2
go: downloading google.golang.org/protobuf v1.25.0
go: downloading golang.org/x/net v0.0.0-20200904194848-62affa334b73
go: downloading google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d
go: downloading golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f
go: downloading golang.org/x/text v0.3.3


$ vim Dockerfile
FROM golang:1.17 as builder
RUN CGO_ENABLED=0 go get github.com/aws-samples/grpc-examples/examples/helloworld/greeter_client

FROM scratch
COPY --from=builder /go/bin/greeter_client /greeter_client
CMD ["/greeter_client"]

$ vim main.go
/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

// Package main implements a client for Greeter service.
package main

import (
	"context"
	"log"
	"os"
	"time"

	pb "github.com/aws-samples/grpc-examples/examples/helloworld/helloworld"
	"google.golang.org/grpc"
)

const (
	defaultName = "world"
)

var (
	address = "grpcdemo.blog.svc.cluster.local:8051"
)

func init() {
	if ep, ok := os.LookupEnv("GREETER_ENDPOINT"); ok {
		address = ep
	}
}

func main() {
	// Set up a connection to the server.
	conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
	if err != nil {
		log.Fatalf("did not connect: %v", err)
	}
	defer conn.Close()
	c := pb.NewGreeterClient(conn)

	// Contact the server and print out its response.
	name := defaultName
	if len(os.Args) > 1 {
		name = os.Args[1]
	}
	ctx, cancel := context.WithTimeout(context.Background(), time.Second)
	defer cancel()
	r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
	if err != nil {
		log.Fatalf("could not greet: %v", err)
	}
	log.Printf("Greeting: %s", r.GetMessage())
}

$ docker build --tag grpcclient --file Dockerfile .
Sending build context to Docker daemon  4.608kB
Step 1/5 : FROM golang:1.17 as builder
 ---> 742df529b073
Step 2/5 : RUN CGO_ENABLED=0 go get github.com/aws-samples/grpc-examples/examples/helloworld/greeter_client
 ---> Running in bbffe5865e5b
go: downloading github.com/aws-samples/grpc-examples v0.0.0-20220627155707-8da33f5fbe7c
go: downloading google.golang.org/grpc v1.31.1
go: downloading github.com/golang/protobuf v1.4.2
go: downloading google.golang.org/protobuf v1.25.0
go: downloading google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d
go: downloading golang.org/x/net v0.0.0-20200904194848-62affa334b73
go: downloading golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f
go: downloading golang.org/x/text v0.3.3
go get: installing executables with 'go get' in module mode is deprecated.
	Use 'go install pkg@version' instead.
	For more information, see https://golang.org/doc/go-get-install-deprecation
	or run 'go help get' or 'go help install'.
Removing intermediate container bbffe5865e5b
 ---> a97c94dd438f
Step 3/5 : FROM scratch
 ---> 
Step 4/5 : COPY --from=builder /go/bin/greeter_client /greeter_client
 ---> 14a2293b22dd
Step 5/5 : CMD ["/greeter_client"]
 ---> Running in 69a6142e7be1
Removing intermediate container 69a6142e7be1
 ---> 7e6f4805f17a
Successfully built 7e6f4805f17a
Successfully tagged grpcclient:latest

$ aws ecr create-repository --repository-name grpcdemoclient --region us-west-2
{
    "repository": {
        "repositoryUri": "<111122223333>.dkr.ecr.us-west-2.amazonaws.com/grpcdemoclient", 
        "imageScanningConfiguration": {
            "scanOnPush": false
        }, 
        "encryptionConfiguration": {
            "encryptionType": "AES256"
        }, 
        "registryId": "<111122223333>", 
        "imageTagMutability": "MUTABLE", 
        "repositoryArn": "arn:aws:ecr:us-west-2:<111122223333>:repository/grpcdemoclient", 
        "repositoryName": "grpcdemoclient", 
        "createdAt": 1676212221.0
    }
}

$ docker tag grpcclient <111122223333>.dkr.ecr.us-west-2.amazonaws.com/grpcdemoclient

$ docker login -u AWS -p $(aws ecr get-login-password --region us-west-2) <111122223333>.dkr.ecr.us-west-2.amazonaws.com
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /home/ec2-user/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

$ docker push <111122223333>.dkr.ecr.us-west-2.amazonaws.com/grpcdemoclient:latest
The push refers to repository [<111122223333>.dkr.ecr.us-west-2.amazonaws.com/grpcdemoclient]
0a375004c404: Pushed 
latest: digest: sha256:fce32c53e1b8c4f3f6afe2302a97fadd1a238064129071fd46c6ca9a4c01154e size: 528

创建Virtual Service
grpc_vs.yaml文件内容:
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: grpc
  namespace: blog
spec:
  hosts:
  - tianzhui.cloud
  http:
  - match:
    - port: 50051
    route:
    - destination:
        host: backend.blog.svc.cluster.local
        subset: v0
      weight: 50
    - destination:
        host: backend.blog.svc.cluster.local
        subset: v1
      weight: 50

% k apply -f grpc_vs.yaml
virtualservice.networking.istio.io/grpc created


创建Destination Rule
grpc_dr.yaml文件内容:
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: backend
  namespace: blog
spec:
  host: backend.blog.svc.cluster.local
  subsets:
  - labels:
      version: "0"
    name: v0
  - labels:
      version: "1"
    name: v1

% k apply -f grpc_dr.yaml
destinationrule.networking.istio.io/backend created


创建Service
grpc_svc.yaml文件内容:
apiVersion: v1
kind: Service
metadata:
  labels:
    app: backend
    service: backend
  name: backend
  namespace: blog
spec:
  ports:
  - port: 50051
    protocol: TCP
    targetPort: 9090
  selector:
    app: backend
  type: ClusterIP


% k apply -f grpc_svc.yaml
service/backend created


% kubectl logs -f client-0-59f6fdf7bb-kpq8f -c python
...
-------------------------------------------------------------
Name Kana Asumi, Age: 35
Name Ayane Sakura, Age: 25
Name Aoi Yuuki, Age: 26
Name Yukari Tamura, Age: 42
Name Kana Hanazawa, Age: 29
Name Yuka Iguchi, Age: 30
Name Yoko Hikasa, Age: 33
-------------------------------------------------------------
Name Kana Asumi, Age: 35
Name Ayane Sakura, Age: 25
Name Aoi Yuuki, Age: 26
Name Yukari Tamura, Age: 42
Name Kana Hanazawa, Age: 29
Name Yuka Iguchi, Age: 30
Name Yoko Hikasa, Age: 33
-------------------------------------------------------------
...




Make sure WAF is not preventing the Uri suffix.

Category: Go Tags: public

Upvote


Downvote