4
votes

The very basic web app is created in Go

package main

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

func hostHandler(w http.ResponseWriter, r *http.Request){
    name, err :=os.Hostname()

    if err != nil {
           panic(err)
        }

        fmt.Fprintf(w, "<h1>HOSTNAME: %s</h1><br>",name)
        fmt.Fprintf(w, "<h1>ENVIRONMENT VARS: </h1><br>")
        fmt.Fprintf(w, "<ul>")

        for _, evar := range os.Environ(){
            fmt.Fprintf(w, "<li>%s</li>",evar)
        }
        fmt.Fprintf(w, "</ul>")

}

func rootHandler(w http.ResponseWriter, r *http.Request){

    fmt.Fprintf(w, "<h1>Awesome site in Go!</h1><br>")
    fmt.Fprintf(w, "<a href='/host/'>Host info</a><br>")

}

func main() {

        http.HandleFunc("/", rootHandler)
        http.HandleFunc("/host/", hostHandler)
        http.ListenAndServe(":8080", nil)


}

Docker File for it

FROM scratch
WORKDIR /home/ubuntu/go
COPY webapp /
EXPOSE 8080
CMD ["/webapp"]

The image is built successfully

ubuntu@ip-172-31-32-125:~/go/src/hello$ docker build -t "webapp" .
Sending build context to Docker daemon  6.152MB
Step 1/5 : FROM scratch
 --->
Step 2/5 : WORKDIR /home/ubuntu/go
 ---> Using cache
 ---> 8810a06c58c7
Step 3/5 : COPY webapp /
 ---> Using cache
 ---> d75222363d3a
Step 4/5 : EXPOSE 8080
 ---> Using cache
 ---> 45de0853de8e
Step 5/5 : CMD ["/webapp"]
 ---> Using cache
 ---> e9f9031f3632
Successfully built e9f9031f3632
Successfully tagged webapp:latest

But when i run the docker its show error.

ubuntu@ip:~/go/src/hello$ docker run webapp
standard_init_linux.go:190: exec user process caused "no such file or directory"

Please guide what is the issue, I am new to docker and go.

Environment-related information

ubuntu@ip:~/go/src/hello$ ls
Dockerfile  webapp
ubuntu@ip:~/go/src/hello$ echo $GOPATH
/home/ubuntu/go

Code was compiled with go build webapp.go command

7
Please include your compile command. - BMitch
BMitch code was compiled with go build webapp.go command - Ajay yadav

7 Answers

13
votes

File not found can mean the file is missing, a script missing the interpreter, or an executable missing a library. In this case, the net import brings in libc by default, as a dynamic linked binary. You should be able to see that with ldd on your binary.

To fix it, you'll need to pass some extra flags:

CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -tags netgo -ldflags '-w' -o mybin *.go

The above is from: https://medium.com/@diogok/on-golang-static-binaries-cross-compiling-and-plugins-1aed33499671

6
votes

In my case CGO_ENABLED=0 was the key to fix this problem.

Cgo allows to use inline C code in Go sources, see more: https://golang.org/cmd/cgo/

I reckon by default Cgo links your application dynamically to libc, even if you don't use any inline C.
And libc is missing when you package your application to Docker image FROM scratch

Here is my working Dockerfile:

FROM golang:1.9.2-alpine AS builder
WORKDIR /go/src/app
COPY . .
RUN CGO_ENABLED=0 go install


FROM scratch
WORKDIR /opt
COPY --from=builder /go/bin/app .
ENTRYPOINT ["/opt/app"]
1
votes

build:

# build
CGO_ENABLED=0 go build -o myapp main.go

dockerfile:

#FROM alpine:3.10
FROM scratch
COPY . /

EXPOSE 8080

CMD ["/myapp", "-c", "app.ini"]
1
votes

In case you might need CGO_ENABLED because of a dependency like mattn/go-sqlite3, you can pass static compilation down the chain using this:

RUN go build -ldflags '-extldflags "-static"'
  • go build tells go link (-ldflags)
  • to tell the external linker (-extldflags) clang or gcc
  • to link it's libraries statically, i.e. not in separate files

Then when the executable is run, it won't try to load an external library like libc.so, or libpthread.so and be unable to find the file "no such file or directory" as soon as it loads.

Before

RUN go build -o myapp
$ ldd myapp
    /lib64/ld-linux-x86-64.so.2 (0x7ff635fb9000)
    libpthread.so.0 => /lib64/ld-linux-x86-64.so.2 (0x7ff635fb9000)
    libdl.so.2 => /lib64/ld-linux-x86-64.so.2 (0x7ff635fb9000)
    libc.so.6 => /lib64/ld-linux-x86-64.so.2 (0x7ff635fb9000)

After

RUN go build -ldflags '-extldflags "-static"' -o myapp
$ ldd myapp
/lib/ld-musl-x86_64.so.1: /usr/bin/walnutcube-api: Not a valid dynamic program

That is good, we don't want it to be a "dynamic program" we want it to be one of the only files on the system in a scratch container.

0
votes

Try change line in your Dockerfile

COPY webapp /webapp

0
votes

I used this and it works

env GOARCH=386 GOOS=linux go build webapp.go
0
votes

In my case en env was not enough: RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64

I had to add as well in the build the tags and ldflags: RUN go build -a -tags netgo -ldflags '-w' -o /go/bin/myService *.go