user1606191
user1606191

Reputation: 551

My gRPC client could not connect to my Containerised gRPC Server hosted on the same machine

I am implementing a gRPC client and server application where my gRPC server is containerised. The idea is to use Unix domain sockets to communicate between the client and the server. My application was working fine until I had my server was not containerised.

The issue arises when I containerise my gRPC server. In this case, my client is unable to reach the gRPC server. The following is the error message that I received.

   raise _InactiveRpcError(state)
grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with:
        status = StatusCode.UNAVAILABLE
        details = "failed to connect to all addresses"
        debug_error_string = "{"created":"@1655378324.763238318","description":"Failed to pick subchannel","file":"src/core/ext/filters/client_channel/client_channel.cc","file_line":3217,"referenced_errors":[{"created":"@1655378324.763237121","description":"failed to connect to all addresses","file":"src/core/lib/transport/error_utils.cc","file_line":165,"grpc_status":14}]}"

I am seeking some help to understand what the modifications I need in my gRPC client or server code to make this work.

gRPC Client Code:

    import grpc
    import greeting_pb2 as pb2
    import greeting_pb2_grpc as pb2_grpc

class HelloWorldClient(object):
def __init__(self):
    self.host = 'localhost'
    self.server_port = 50051

    #self.channel = grpc.insecure_channel('{}:{}'.format(self.host, self.server_port), options=(('grpc.enable_http_proxy', 0),))
    #self.channel = grpc.insecure_channel('unix:///var/run/test.sock', options=(('grpc.enable_http_proxy', 0),))
    self.channel = grpc.insecure_channel('unix:///service/test.sock', options=(('grpc.enable_http_proxy', 0),))
    self.stub = pb2_grpc.GreeterStub(self.channel)

def get_url(self, message):
    message = pb2.Request(name=message)
    return self.stub.SayHello(message)

if __name__ == '__main__':
    client = HelloWorldClient()
    result = client.get_url(message="Billi")
    print(f'{result}')

gRPC Server Code:

import grpc
from concurrent import futures
import time
import greeting_pb2_grpc as pb2_grpc
import greeting_pb2 as pb2


import sys
print("Python version")
print (sys.version)

class HelloWorldService(pb2_grpc.GreeterServicer):
    def __init__(self, *args, **kwargs):
        pass

    def SayHello(self, request, context):
        message = request.name
        print("Python version")
        result = f'Hello {message}! Glad to hear from you!'
        result = {'message':result}

        return pb2.Response(**result)

def serve():
    server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
    pb2_grpc.add_GreeterServicer_to_server(HelloWorldService(), server)
    server.add_insecure_port('unix:///service//test.sock')
    print("Ready To Start")
    server.start()
    print("Server Started")
    server.wait_for_termination()


if __name__ == '__main__':
    serve()
    

The client and the server are both running on the same host, but the server is running inside a Docker container. I have created a folder named "service" in the host as well as the docker container and I am mounting this path to the socket when running the Docker container

docker run -v /service/test.sock:/service/test.sock:rw grpc_sock_new

As per my understanding, the key to fixing the issue is the following line of code.

server.add_insecure_port('unix:///service//test.sock')

Please advice.

Upvotes: 0

Views: 1949

Answers (1)

pythonguy
pythonguy

Reputation: 64

You may be using more number of slashes than required in this line in gRPC Server Code: server.add_insecure_port('unix:///service//test.sock')

Try Using this instead : server.add_insecure_port('unix:///service/test.sock')

Edit : 1

  1. The client, server code you presented above should work fine when you run it locally in your system because both are essentially running on same machine and can reach to the referred socket file easily.
  2. If both the Server and client are packed to run in a single container, there is a good chance that it will work, as both can access a socket that is local to the container scope.
  3. If you are running the server and client in 2 different containers --> trying to refer to a socket from client / server refers to their respective local sockets scoped to container environment, but not to the socket in remote container.

You should share a socket in your docker host to both containers using docker bind mounts. Refer Sharing Host Sockets between containers.

Ex: docker run -d --name "server" -v /var/run/test.sock:/var/run/test.sock server_image:version

References :

  1. Name resolution in gRPC.
  2. This Answer in StackOverflow
  3. Sharing Host Sockets between containers.
  4. Docker Bind Mounts Official Documentation

Upvotes: 1

Related Questions