Reputation: 677
I've the following docker file which is working for my application. I was able to access to the simple web app server.
FROM golang:1.14.7 AS builder
RUN go get github.com/go-delve/delve/cmd/dlv
RUN mkdir /app
ADD . /app
WORKDIR /app
RUN CGO_ENABLED=0 GOOS=linux go build -gcflags="all=-N -l" -o main ./...
FROM alpine:3.12.0 AS production
COPY --from=builder /app .
EXPOSE 8000 40000
ENV PORT=8000
CMD ["./main"]
When I adopt it like following, I am not able to deploy it successfully to Kubernetes. The container crashed with some general error, not something that I can use.
standard_init_linux.go:190: exec user process caused "no such file or directory"
This not working
FROM golang:1.14.7 AS builder
RUN go get github.com/go-delve/delve/cmd/dlv
RUN mkdir /app
ADD . /app
WORKDIR /app
RUN CGO_ENABLED=0 GOOS=linux go build -gcflags="all=-N -l" -o main ./...
FROM alpine:3.12.0 AS production
COPY --from=builder /app .
COPY --from=builder /go/bin/dlv /
EXPOSE 8000 40000
ENV PORT=8000
CMD ["/dlv", "--listen=:40000", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", "./main"]
If someone want to try it out this is the simple program (this is minimum reproducible example), if you take the first docker file it will work for you, for the second it does not.
package main
import (
"fmt"
"net/http"
"os"
)
func main() {
fmt.Println("app is starting!")
var port string
if port = os.Getenv("PORT"); len(port) == 0 {
port = "8080"
}
http.HandleFunc("/", handler)
http.ListenAndServe(":"+port, nil)
}
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hi there, %s!", r.URL.Path[1:])
}
Upvotes: 5
Views: 1598
Reputation: 264861
You need to compile dlv
itself with the static linking flags. Without that, dlv
will have dynamic links to libc which doesn't exist within an alpine image. Other options include switching your production image to be debian based (FROM debian
) or change to golang image to be alpine based (FROM golang:1.14.7-alpine
). To compile dlv
without dynamic links, the following Dockerfile works:
FROM golang:1.14.7 AS builder
RUN CGO_ENABLED=0 go get -ldflags '-s -w -extldflags -static' github.com/go-delve/delve/cmd/dlv
RUN mkdir /app
ADD . /app
WORKDIR /app
RUN CGO_ENABLED=0 GOOS=linux go build -gcflags="all=-N -l" -o main ./...
FROM alpine:3.12.0 AS production
COPY --from=builder /app .
COPY --from=builder /go/bin/dlv /
EXPOSE 8000 40000
ENV PORT=8000
CMD ["/dlv", "--listen=:40000", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", "./main"]
To see the dynamic links, build your builder image and run ldd
against the output binaries:
$ docker build --target builder -t test-63403272 .
[+] Building 4.6s (11/11) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 570B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/golang:1.14.7 0.2s
=> [builder 1/6] FROM docker.io/library/golang:1.14.7@sha256:1364cfbbcd1a5f38bdf8c814f02ebbd2170c93933415480480104834341f283e 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 591B 0.0s
=> CACHED [builder 2/6] RUN go get github.com/go-delve/delve/cmd/dlv 0.0s
=> CACHED [builder 3/6] RUN mkdir /app 0.0s
=> [builder 4/6] ADD . /app 0.1s
=> [builder 5/6] WORKDIR /app 0.0s
=> [builder 6/6] RUN CGO_ENABLED=0 GOOS=linux go build -gcflags="all=-N -l" -o main ./... 4.0s
=> exporting to image 0.2s
=> => exporting layers 0.2s
=> => writing image sha256:d2ca7bbc0bb6659d0623e1b8a3e1e87819d02d0c7f0a0762cffa02601799c35e 0.0s
=> => naming to docker.io/library/test-63403272 0.0s
$ docker run -it --rm test-63403272 ldd /go/bin/dlv
linux-vdso.so.1 (0x00007ffda66ee000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007faa4824d000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007faa4808c000)
/lib64/ld-linux-x86-64.so.2 (0x00007faa48274000)
Libc is a common missing library when switching to alpine since it uses musl by default.
Upvotes: 2