0
votes

I have a basic, proof-of-concept Python gRPC server.

When I run my docker container locally, I can make requests to the server and receive responses on the exposed port.

I can successfully deploy the server to Cloud Run, and I see the service running in the Cloud Run UI.

However, I am unable to access the Cloud Run version from a client.

I am looking for suggestions to help me access this server, whether it is changes to the clients or the server.

Client code:

with grpc.insecure_channel('...-uc.a.run.app:80') as channel:
  stub = tax_service_pb2_grpc.TaxServiceStub(channel)
  response = stub.GetTaxRate(tax_service_pb2.GetTaxRateRequest(zipcode='12345'))
  print("Tax client received: {}".format(response.tax_rate))

If I try to connect to port 80, I received this message:

    raise _Rendezvous(state, None, None, deadline)
grpc._channel._Rendezvous: <_Rendezvous of RPC that terminated with:
    status = StatusCode.UNAVAILABLE
    details = "Trying to connect an http1.x server"
    debug_error_string = "{"created":"@1575613033.176590200","description":"Error received from peer ipv4:216.239.36.53:80","file":"src/core/lib/surface/call.cc","file_line":1055,"grpc_message":"Trying to connect an http1.x server","grpc_status":14}"

If I try to connect to port 443, I receive

    raise _Rendezvous(state, None, None, deadline)
grpc._channel._Rendezvous: <_Rendezvous of RPC that terminated with:
    status = StatusCode.UNAVAILABLE
    details = "Trying to connect an http1.x server"
    debug_error_string = "{"created":"@1575613033.176590200","description":"Error received from peer ipv4:216.239.36.53:80","file":"src/core/lib/surface/call.cc","file_line":1055,"grpc_message":"Trying to connect an http1.x server","grpc_status":14}"

Server code:

import time
from concurrent import futures

import grpc
from grpc_reflection.v1alpha import reflection

import tax_service_pb2
import tax_service_pb2_grpc


class TaxServicer(tax_service_pb2_grpc.TaxServiceServicer):
  def GetTaxRate(self, request, context):
      return tax_service_pb2.GetTaxRateResponse(tax_rate=1.5)

  def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    tax_service_pb2_grpc.add_TaxServiceServicer_to_server(TaxServicer(), server)
    SERVICE_NAMES = (
        tax_service_pb2.DESCRIPTOR.services_by_name['TaxService'].full_name,
        reflection.SERVICE_NAME,
    )
    reflection.enable_server_reflection(SERVICE_NAMES, server)
    server.add_insecure_port('0.0.0.0:{}'.format(os.environ.get('PORT', 8080)))

    try:
        while True:
            time.sleep(_ONE_DAY_IN_SECONDS)
    except KeyboardInterrupt:
        server.stop(0)

if __name__ == '__main__':
    logging.basicConfig()
    serve()
3

3 Answers

2
votes

No changes were needed on the server side.

The insecure port is used by Cloud Run to access the gRPC service, and then the SSL is added between the edge of Google's cloud and clients.

On my client, I needed to use the system root certificate in order to access the service

with grpc.secure_channel('<app-url>-uc.a.run.app:443', grpc.ssl_channel_credentials()) as channel:
   stub = tax_service_pb2_grpc.TaxServiceStub(channel)
   response = stub.GetTaxRate(tax_service_pb2.GetTaxRateRequest(zipcode='12345'))
   print("Tax client received: {}".format(response.tax_rate))
0
votes

I think that your problem is you try to create an insecure channel on a SSL enpoint. I used this part of code to create my client channel:

with open('certificate.pem', 'rb') as f:
  creds = grpc.ssl_channel_credentials(f.read())
  channel = grpc.secure_channel('predict-<PROJECTHASH>-uc.a.run.app:443',creds)
  stub = prediction_service_pb2_grpc.PredictionServiceStub(channel)
  ...

You can download the certificate from your web browser.

0
votes

Are you running your server in the $PORT provided by Cloud Run? Maybe try setting a simple endpoint that just returns a 200 and see if you can hit that and get a response back?