This article provides step-by-step instructions on configuring a gRPC backend on Cloud Run and an Apigee X Proxy by updating an existing Envoy based Load Balancer. We’ll show how to create unique URLs / routing urls on the GCP Load Balancer that will only work for gRPC / http2 services. This walkthrough compliments the instructions published here:
https://cloud.google.com/apigee/docs/api-platform/fundamentals/build-simple-api-proxy#creating-grpc-api-proxies
All the commands / instructions should be run in a GCP Cloud Shell (https://shell.cloud.google.com) session in the GCP project where Apigee is installed.
Create gRPC backend on Cloud Run
We’ll use Docker containers and Cloud Run for the gRPC backend
-
In Cloud Shell, clone the gRPC repo
export PROJECT=$GOOGLE_CLOUD_PROJECT mkdir grpc-backend cd grpc-backend git clone https://github.com/grpc/grpc.git cd $HOME/grpc-backend/grpc/examples/python/helloworld -
Create Dockerfile for the Hello World example
touch Dockerfile cloudshell edit Dockerfile -
Add the following code to the Dockerfile
FROM python:3.7 WORKDIR /app COPY . . RUN pip install grpcio protobuf EXPOSE 50051 CMD ["python", "greeter_server.py"] -
Build the Docker image and then list the images created
docker build . docker images -a
-
Save the imageid from above to an environment variable and run the Docker image locally
export DOCKER_IMAGE=<imageid> docker run -p 8080:50051 -it $DOCKER_IMAGE -
Use grpcurl to ensure the service is working. grpcurl expects to send Service.Method to gRPC endpoints and validates that against the proto file. If you look at the protofile referenced, you’ll see that the package keyword is used to specify the package name for the service. The package name is used to uniquely identify the service. In this case, the fully qualified name of the service is helloworld.Greeter
grpcurl -plaintext -import-path $HOME/grpc-backend/grpc/examples/protos \ -proto helloworld.proto -d '{"name":"Guest"}' \ localhost:8080 helloworld.Greeter/SayHello -
If you get a response like the one below, the Docker image is working!

-
Once the image is working, create an global Artifact Registry and configure Docker to use the Artifact Registry
gcloud artifacts repositories create grpcdemo \ --repository-format=Docker \ --location=us \ --description="gRPC Demo repo" gcloud auth configure-docker us-docker.pkg.dev -
Tag the Docker image, Push the Docker image, and create a Cloud Run service from the Docker image. Optional: Change REGION= to a region closest to your Apigee instance
export REGION=us-east1 docker tag $DOCKER_IMAGE us-docker.pkg.dev/$PROJECT/grpcdemo/my-grpc-service docker push us-docker.pkg.dev/$PROJECT/grpcdemo/my-grpc-service gcloud run deploy my-grpc-service \ --image us-docker.pkg.dev/$PROJECT/grpcdemo/my-grpc-service \ --platform managed --use-http2 --allow-unauthenticated \ --region $REGION --port 50051 -
Once the deployment completes, grab the service URL (omitting https://) and update the command below to test your gRPC backend
grpcurl -import-path $HOME/grpc-backend/grpc/examples/protos -proto helloworld.proto \
-d '{"name":"Guest"}' <serviceurl>:443 helloworld.Greeter/SayHello
If you get a successful response you’re ready to update the GCP LB to support gRPC!

Update Load Balancer
For this step, we’ll create a unique path for gRPC traffic. We’ll use a unique ssl certificate and a route rule for the domain name using the nip.io service. This assumes that your backend is using a PSC NEG connected to Apigee. If you’re using MIGs, you can follow the public documentation for these steps.
-
Identify the IP and forwarding rule of your load balancer
gcloud compute forwarding-rules list -
Create environment variables from the output above
export FORWARDING_RULE=<NAME from above> export IP_ADDRESS=<IP_ADDRESS from above> export TARGET_PROXY=<TARGET from above> -
Identify the URL Map and SSL certificate names by getting the details of the Target Proxy
gcloud compute target-https-proxies describe $TARGET_PROXY -
Use the output to create environment variables for use later
export URL_MAP=<url map name from above> export SSL_CERT=<certificate name from above> -
Identify your current SSL certificate domain names
gcloud compute ssl-certificates describe $SSL_CERT --format json | jq .managed.domains -
Create a new certificate that includes grpc specific nip.io dns name. Adding your existing domain names is not required.
export DOMAINS="<existing domain name>","grpc.$IP_ADDRESS.nip.io" gcloud compute ssl-certificates create apigee-ssl-grpc \ --domains $DOMAINS -
Update the target proxy to use the new certificate
gcloud compute target-https-proxies update $TARGET_PROXY \ --ssl-certificates apigee-ssl-grpc -
Create a Backend service that supports HTTP2
gcloud compute backend-services create apigee-grpc \ --load-balancing-scheme=EXTERNAL_MANAGED \ --protocol=HTTP2 \ --global --project=$PROJECT -
Find the name of the Apigee NEG
gcloud compute network-endpoint-groups list
-
Add the backend service to the Apigee (NEG)
export APIGEE_NEG=<NAME from above> gcloud compute backend-services add-backend apigee-grpc \ --network-endpoint-group=$APIGEE_NEG \ --network-endpoint-group-region=<LOCATION from above> \ --global --project=$PROJECT -
Edit the URL map
gcloud compute url-maps edit $URL_MAP -
Edit the values for and <PROJECT_ID> below and paste them under the defaultService so it matches the screenshot. Do not modify / remove defaultService as it will break any existing routing rules. Note that you’re in vi so press ‘i’ to begin insert mode. When you’re done type “:” to enter command mode and type wq to write and quit (:wq to save and exit).
defaultService:<DO NOT REMOVE/MODIFY THE ORIGINAL OUTPUT. COPY AND PASTE ONLY THE hostRules THE BELOW> hostRules: - hosts: - grpc.<IP-ADDRESS>.nip.io pathMatcher: grpc-domain name: apigee-lb pathMatchers: - defaultService: https://www.googleapis.com/compute/v1/projects/<PROJECT_ID>/global/backendServices/apigee-grpc name: grpc-domain
Create API Proxy
-
Update your environment group to support grpc..nip.io
-
In the GCP Cloud Console, create a Target Server that uses the gRPC Protocol. Note: you must use the GCP console and not the classic Apigee admin console. Choose gRPC - Target preview for the protocol
-
Create a Reverse proxy and use a fictitious Target. For the Base path, specify the service name/method from the proto file the API clients use
-
Edit the proxy and change the Target Endpoint configuration using the code below. Save and Deploy.
<TargetEndpoint name="default"> <Description/> <FaultRules/> <HTTPTargetConnection> <LoadBalancer> <Server name="grpc-server"/> </LoadBalancer> <Path>/helloworld.Greeter/SayHello</Path> </HTTPTargetConnection> </TargetEndpoint> -
Test by updating the command below to include the grpc domain name created earlier
grpcurl -import-path $HOME/grpc-backend/grpc/examples/protos -proto helloworld.proto -d '{"name":"Guest"}'grpc.<IP Address>.nip.io:443 helloworld.Greeter/SayHello
Optional: Add a verify API Key policy
-
Add a Verify API Key policy that looks at headers for the API Key
<VerifyAPIKey continueOnError="false" enabled="true" name="VA-VerifyKey"> <DisplayName>VA-VerifyKey</DisplayName> <Properties/> <APIKey ref="request.header.apikey"/> </VerifyAPIKey> -
Create a product that specifies the supported gRPC Service Name and Methods. Note: gRPC proxies require that they exist in their own products. gRPC proxies that are combine with REST or GraphQL proxies will not respond.
-
Create an app registration that is only subscribed to the gRPC product. The app registration must not contain any non-gRPC products or the gRPC proxy will not work.
-
Test by passing the apikey as a header
grpcurl -import-path $HOME/grpc/examples/protos -proto helloworld.proto -H "apikey":"<api key>" -d '{"name":"Guest"}' grpc.<IP Address>nip.io:443 helloworld.Greeter/SayHello









