0

I'm working on a project using gRPC and have recently migrated it to have each service running in Docker containers (it might be worth adding that I am fairly new to containerisation). Today, while moving one of my Go services into a container I ran into this error and have been trying to work around it for a couple of hours now with no success. The error I'm getting is:

"rpc error: code = Unimplemented desc = unknown service PowerEstimationServicePackage"

I've looked around online and it seems that the error, while not hugely descriptive, usually means that the service call your client is making has not been registered on the port by the server. I've spent a couple of hours looking at my code now and can't for the life of me figure out why I'm getting the error - as far as I can tell I have registered it correctly!

Additionally, when I run the Go service locally, it works perfectly! This leads me to believe that the issue has to do with my port bindings when running it in Docker. I feel like I've got a reasonable understanding of how Docker deals with networks but could very well have overlooked something here.

The relevant client code (running locally) is:

const {
    addrEstimationSP = "127.0.0.1:50101"
}

// Use this to implement the power estimation service routing
type estimationServer struct {
    serverPB.UnimplementedPowerEstimationServicesServer
}

func main {
    // Create a connection over the specified tcp port
    callCounter := interceptors.ClientMetricStruct{}
    connEstimationSP := CreateInsecureServerConnection(addrEstimationSP, timeoutDuration, callCounter.ClientMetrics)

    /* Create the client and pass the connection made above to it. After the client has been
    created, we create the gRPC request */
    InfoLogger.Println("Creating clients")
    clientEstimationSP := estimationPB.NewPowerEstimationServicePackageClient(connEstimationSP)
    DebugLogger.Println("Succesfully created the clients")

    requestMessageEstimationSP := estimationPB.ServicePackageRequestMessage{
        InputFile: INPUTfilename,
        ModelType: estimationPB.ModelTypeEnum_OPENWATER,
    }

    estimationContext, _ := context.WithTimeout(context.Background(), callTimeoutDuration)
    responseEstimationSP, errEstimationSP := clientEstimationSP.PowerEstimatorService(estimationContext, &requestMessageEstimationSP)
    if errEstimationSP != nil {
        ErrorLogger.Println("Failed to make EstimationSP service call: ")
        ErrorLogger.Println(errEstimationSP)
    } else {
        DebugLogger.Println("Succesfully made service call to GoLang EstimationSP.")
        connEstimationSP.Close()
    }

    responseMessage := serverPB.PowerEstimationResponse{
        PowerEstimate: responseEstimationSP.PowerEstimate,
    }
}

, and the relevant code on the server side (this is the service that I'm trying to move into Docker) is:

var (
    // Addresses
    addrMyself = os.Getenv("POWERESTIMATIONHOST") + ":50101"
)

// server is used to implement PowerEstimationServicePackage
type server struct {
    serverPB.UnimplementedPowerEstimationServicePackageServer
}

func main() {
    InfoLogger.Println("Started GoLang Aggregator")

    // Create a listener on the specified tcp port
    listener, err := net.Listen("tcp", addrMyself)
    if err != nil {
        ErrorLogger.Fatalf("Failed to listen on port %v: \n%v", addrMyself, err)
    }
    InfoLogger.Println("Listeneing on port: ", addrMyself)

    // Create a gRPC server object
    estimationServer := grpc.NewServer()
    // Attach the power estimation service to the server
    serverPB.RegisterPowerEstimationServicePackageServer(estimationServer, &server{})
    // Start the server
    if err := estimationServer.Serve(listener); err != nil {
        ErrorLogger.Fatalf("Failed to expose service: \n%v", err)
    }
}


func (s *server) PowerEstimatorService(ctx context.Context, request *serverPB.ServicePackageRequestMessage) (*serverPB.EstimateResponseMessage, error) {
    ...
}

The client is able to create a connection to the server but is getting an error when making the clientEstimationPB.PowerEstimatorService(...) call. The service is running inside a Docker network, hence passing environment variables for its address. The Dockerfile and Docker-compose file can be seen below:

Dockerfile:

FROM golang:alpine

# Install git.
# Git is required for fetching the dependencies.
RUN apk add --no-cache git

WORKDIR $GOPATH/src/github.com/nicholasbunn/masters/

# Create a program logs folder in the service directory
RUN mkdir ./program\ logs
RUN mkdir -p $GOPATH/src/github.com/nicholasbunn/masters/src/powerEstimationSP

COPY /src/powerEstimationSP/go.mod ./src/powerEstimationSP
COPY /src/powerEstimationSP/go.sum ./src/powerEstimationSP

# Copy over contents into image
COPY src/powerEstimationSP/interceptors/ ./src/powerEstimationSP/interceptors
COPY src/powerEstimationSP/proto/ ./src/powerEstimationSP/proto
COPY certification/ certification
COPY src/powerEstimationSP/powerEstimationSP.go ./src/powerEstimationSP
COPY src/powerEstimationSP/powerEstimationSP_test.go ./src/powerEstimationSP

COPY src/fetchDataService/proto src/fetchDataService/proto
COPY src/prepareDataService/proto src/prepareDataService/proto
COPY src/estimateService/proto src/estimateService/proto

WORKDIR $GOPATH/src/github.com/nicholasbunn/masters//src/powerEstimationSP/

# Fetch the dependecies
RUN go mod tidy

# Build the binary. for grpc gateway
RUN go build -o ./powerEstimationSP .

WORKDIR $GOPATH/src/github.com/nicholasbunn/masters/

EXPOSE 50101
ENTRYPOINT ["./src/powerEstimationSP/powerEstimationSP"]

Docker-compose.yaml:

version: "3.8"

services:
...
    powerestimationsp:
        build: 
            context: .
            dockerfile: src/powerEstimationSP/Dockerfile
        environment: 
            POWERESTIMATIONHOST: powerestimationsp
            FETCHHOST: fetchservice
            PREPAREHOST: prepareservice
            ESTIMATEHOST: estimateservice
            PROMETHEUSHOST: prometheus
        image: power_estimation_sp
        networks: 
            - southernOcean
        ports: 
            - 50101:50101
networks:
    southernOcean:

I have a feeling the fix for this is really simple and probably just a small misunderstanding on my side, I've just had a bit of a cloudy-head day so hopefully a fresh pair of eyes can help out here.

Thanks!

Nicholas Bunn
  • 21
  • 1
  • 2

1 Answers1

2

I solved things this afternoon, going to throw it on here in case anyone else can't figure the issue out with other resources.

The problem was actually coming from my go module, not Docker or my code. I was working on an un-published branch of code where I had changed the proto file (I had literally just changed a lowercase letter to an uppercase one to maintain consistent semantics), but my go.mod file was pulling the older version of the proto which was not compatible with the newer one. The client was using the newer one as it was running on the local machine, and the server used the newer one when running locally which is why it worked outside of Docker. In my Dockerfile (above) I run "RUN go mod tidy" which was pulling the older proto files from my master branch and registered a differently named service which is why I was getting this error.

Anyway, glad it's all sorted now! Hopefully this can help someone else down the line.

Nicholas Bunn
  • 21
  • 1
  • 2