使用Dockerfile时找不到二进制文件

I am following Go's Docker instructions. Their example works for me. I am now trying to modify it to run a tcp server:

go get github.com/Kelindar/tcp

Add a Dockerfile:

FROM golang

ADD . /go/src/github.com/Kelindar/tcp
RUN go install github.com/Kelindar/tcp

ENTRYPOINT /go/bin/tcp

EXPOSE 8080

I then build it:

docker build --no-cache -t tcp .

build output:

Sending build context to Docker daemon    322kB
Step 1/5 : FROM golang
 ---> 9fe4cdc1f173
Step 2/5 : ADD . /go/src/github.com/Kelindar/tcp
 ---> 10abce658324
Step 3/5 : RUN go install github.com/Kelindar/tcp
 ---> Running in 59dc47b30474
Removing intermediate container 59dc47b30474
 ---> 8fab53d2882c
Step 4/5 : ENTRYPOINT /go/bin/tcp
 ---> Running in 18d4b5befccb
Removing intermediate container 18d4b5befccb
 ---> 073fdb78a481
Step 5/5 : EXPOSE 8080
 ---> Running in 8ee2b7bc0cba
Removing intermediate container 8ee2b7bc0cba
 ---> 8bf9f82d4fef
Successfully built 8bf9f82d4fef
Successfully tagged tcp:latest

Now, I run it:

docker run --name test --rm tcp

I get an error:

/bin/sh: 1: /go/bin/tcp: not found

Not really sure where to go on this.

There are two problems here:

  • The package github.com/Kelindar/tcp does not contain a main function, thus it can't produce a binary to be executed.
  • There is no main package, and every go program needs a main package with a main function

Whether you run go build or go install in this repository, you will see that nothing will happen, since your package is actually a library.

Now if you add a cmd/tcp_server folder with a tcp_server.go file like this:

package main

import (
    "fmt"
    "log"
    "net"

    "github.com/kelindar/tcp"
)

func main() {
    closingChan := make(chan bool)
    onAccept := func(c net.Conn) {
        // Do something here.
    }

    l, err := net.Listen("tcp", fmt.Sprintf(":%d", 4242))
    if err != nil {
        log.Fatalf("Unable to net.Listen: %v", err)
    }

    server := &tcp.Server{
        Closing:  closingChan,
        OnAccept: onAccept,
    }

    log.Println("Server ready...")
    if err := server.Serve(l); err != nil {
        log.Fatalf("Server crashed: %v", err)
    }

    log.Println("Server stopped")
}

And that you update your Dockerfile to use the command that uses your tcp package:

FROM golang

RUN go get github.com/Kelindar/tcp
RUN go build -o $GOPATH/bin/tcp_server $GOPATH/src/github.com/Kelindar/tcp/cmd/tcp_server/tcp_server.go

ENTRYPOINT tcp_server

EXPOSE 8080

Your server will be working properly within docker:

2019/06/16 05:23:29 Server ready...