Search code examples
google-cloud-platformportgoogle-cloud-run

Unable to reach service running in Cloud Run


I'm using a workflow to push my image in the Artifact Registry.

I deploy a service from that image.

The service is running. The port defined in GCP is getting picked up in the environment.

As per the log, my service is running and listening on that port.

enter image description here enter image description here enter image description here

I am unable to reach my container on that port. Port checker tool report this port as closed. Making call from my local machine to the endpoint times out.

What am I missing here?

Deploying the test container hello is working and I'm able to reach the port 8080. But no other ports are working.

Update

This is how I start the service with Go:

    port := os.Getenv("PORT")

    fmt.Println("PORT:" + port)

    listener, err := net.Listen("tcp", fmt.Sprintf("0.0.0.0:%s", port))
    if err != nil {
        fmt.Println("error on listen")
        panic(err)
    }

    srv := grpc.NewServer()
    pb.RegisterWallApiServer(srv, &server{})
    reflection.Register(srv)

    fmt.Println("Starting server on port " + port)
    if err = srv.Serve(listener); err != nil {
        fmt.Println("error on serve")
        panic(err)
    }

After using the default port 8080, Exposing it in the image, and sent my request to port 443. I'm getting this error;

rpc error: code = Unavailable desc = connection closed before server preface received.

This is how I make the call

    func main() {
    creds := insecure.NewCredentials()
    address := "idfi-api-w2b5dfqtlq-uc.a.run.app:443"
    conn, err := grpc.Dial(address, grpc.WithTransportCredentials(creds))

    if err != nil {
        log.Fatalf("Failed to connect: %v", err)
    }
    defer conn.Close()

    client := pb.NewWallApiClient(conn)
    res, err := client.SetWallSignature(context.Background(), &pb.WallSignatureRequest{Address: "0x"})
    if err != nil {
        log.Fatalf("Failed to post message: %v", err)
    }
    log.Println(res.Success)
}

Solution

  • The GCP documentation, when describing how to listen on requests in the correct port, states:

    For Cloud Run services, the container must listen for requests on 0.0.0.0 on the port to which requests are sent. By default, requests are sent to 8080, but you can configure Cloud Run to send requests to the port of your choice. Cloud Run injects the PORT environment variable into the container. Inside Cloud Run container instances, the value of the PORT environment variable always reflects the port to which requests are sent. It defaults to 8080.

    According to your screenshot it seems you already configured a different port for your application.

    If your application is starting successfully then, as indicated in my comment, the error could be related to the fact that your application is not listening in all the network interfaces, is not listening for requests on 0.0.0.0. To confirm that point, please, try running your container in the default 8080 port and see if it works properly.

    If it doesn't, please, try configuring your application to listen for requests on 0.0.0.0.

    The way in which you should configure the application to listen for requests on 0.0.0.0 depends on the actual underlying language/technology you are using (Python, NodeJS, etc): I will be glad to expand the answer to provide you guidance about this point if you include further information about what technology you are using in the question.

    As an update, sorry, because I missed an important detail that you mention in your question: of course, the configured port is not directly available, you should use port 443 to access your application; Cloud Run will provide the necessary infrastructure to access your service through an HTTPS endpoint, it acts as a "proxy", placed in front of your application, and that "proxy" redirects the traffic to the configured PORT.

    Thank you for your new update. As indicated in my answer comments, I think the new connectivity issue has to do with the way your client is interacting with your server, probably because you are establishing an insecure connection:

    creds := insecure.NewCredentials()
    address := "idfi-api-w2b5dfqtlq-uc.a.run.app:443"
    conn, err := grpc.Dial(address, grpc.WithTransportCredentials(creds))
    

    I am not still very fluent with go, but as I tried explaining in the comments as well, please, consider review this post and the answer provided by Dustin Decker. He mentions:

    I encountered this while testing with:

    grpc.WithTransportCredentials(grpc.WithInsecure()) This does not work because it causes gRPC to make the request using H2C (HTTP/2 without TLS), which fails at the Cloud Run ingress with a 503, never reaching the application.

    It means that you need to provide an appropriate certificate trust configuration for your client.

    For instance, the mentioned post propose the following solution:

    Make sure you're running Cloud Run with HTTP/2 end to end if you require gRPC streaming (and better performance in general), and make sure you're providing some certificates. Either pinned or importing your CA store. Example:

      systemRoots, err := x509.SystemCertPool()
      if err != nil {
          panic(errors.Wrap(err, "cannot load root CA certs"))
      }
      creds := credentials.NewTLS(&tls.Config{
          RootCAs: systemRoots,
      })
    
      conn, err := grpc.DialContext(ctx, addr,
          grpc.WithTransportCredentials(creds),
      )
      if err != nil {
          panic(err)
      }