1

I am trying to get a simple client/server RPC example running between two docker containers using Golang.

When I run them on my local machine, both build and run flawlessly. I know that building them into docker containers would probably have some communication errors that I would need to work out, but I can't even get to that stage as I am getting a segmentation fault when trying to run my client.

When I run the master (server) container, it works, no problems. But when I run the worker (client) I get this:

panic: runtime error: invalid memory address or nil pointer `   `dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x10 
pc=0x72425d]

goroutine 1 [running]:
net/rpc.(*Client).send(0x0, 0xc0000d61e0)
        /usr/local/go/src/net/rpc/client.go:72 +0x3d
net/rpc.(*Client).Go(0x0, 0x7e062d, 0xa, 0x7887e0, 
0xc0000b04a8, 0x788860, 0xb0c440, 0xc0000aa300, 
0xc0000d6190)
        /usr/local/go/src/net/rpc/client.go:316 +0xcc
net/rpc.(*Client).Call(...)
        /usr/local/go/src/net/rpc/client.go:322
main.main()
        /app/worker.go:20 +0x11c
exit status 2

My master.go:

package main

import (
    "fmt"
    "net"
    "net/http"
    "net/rpc"
)

type Args struct {
    Addthis int
}

type Reply struct {
    Ret int
}
type Api int

func (master *Api) Add(args Args, reply *Reply) error {
    out := args.Addthis + 10
    reply.Ret = out
    return nil
}

func main() {
    var master = new(Api)
    rpc.Register(master)
    rpc.HandleHTTP()
    listener, _ := net.Listen("tcp", ":4040")
    fmt.Printf("\nServing on %d\n", 4040)
    http.Serve(listener, nil)
}

My Master Dockerfile:

FROM golang:latest

WORKDIR /app

COPY ./ /app

EXPOSE 4040

ENTRYPOINT go run master.go

I build and run master with:

docker build -t master
docker run --net=testnet --name=master master

This works fine.

My worker.go

package main

import (
    "fmt"
    "net/rpc"
)

type Args struct {
    Addthis int
}

type Reply struct {
    Ret int
}

func main() {
    var reply Reply
    client, _ := rpc.DialHTTP("tcp", ":4040")
    num := Args{215}
    client.Call("master.Add", num, &reply)
    fmt.Println("Here")
    fmt.Printf("\nGot back: %d\n", reply.Ret) 
}

My worker Dockerfile:

FROM golang:latest

WORKDIR /app

COPY ./ /app

EXPOSE 4040

ENTRYPOINT go run worker.go

I build and run the worker with:

docker build -t worker .
docker run --net=testnet --name=worker worker

THAT'S when I get the above error.

Googling for three hours and nothing helpful seems to come up. I guess I don't know what search to use.

I know that this probably won't actually communicate as-is, but I would like to debug the communication issues, not deal with segmentation faults. The code was supplied by my professor, not as part of an assignment, but just because I asked for it. He claims this works without issue for him, and wasn't helpful with my troubleshooting (I don't think he actually tried deploying it in a container, but I'm not gonna call him out on it. He's "touchy"). "Try stack exchange!" was all he said, really.

  • 3
    Don't ignore the error returned by `rpc.DialHTTP` (or other errors for that matter). – Marc May 30 '20 at 16:10
  • 1
    Evidence points to client being null. There's probably a non-nill error from HTTP dial. – Burak Serdar May 30 '20 at 16:11
  • Quite right! I am catching the error and now I'm getting "dial tcp :4040: connect: connection refused" Then I get the seg fault. I assume this is related to the fact that I am not actually putting in an ip? – timbitsaregood May 30 '20 at 16:40
  • 2
    It means there's nothing listening on localhost on port :4040. If you are running two separate containers, you need to setup the appropriate networking, it won't be on localhost. You should also handle the error correctly, not just proceed to try using the client. – Marc May 30 '20 at 16:45

1 Answers1

1
client, _ := rpc.DialHTTP("tcp", ":4040")

This basically means you are trying to connect to port 4040 on the same container however, your master is running in a different container. To connect to your master container you need to connect to {ip that docker has assigned automatically:4040} (for testing) or setup your docker network for proper usage of containers.

vishal ashank
  • 43
  • 1
  • 6