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!