対象のDockerfile。特に特殊なことは行っていない素朴なDockerfile。
FROM golang:1.14.4 as builder WORKDIR /app COPY . . RUN go mod download RUN go build path/to/main.go FROM alpine RUN apk add --no-cache ca-certificates COPY --from=builder /app/path/to/main /app/main EXPOSE 5000 ENTRYPOINT [ "/app/main" ]
build log
$ docker build . Sending build context to Docker daemon 24.16MB Step 1/10 : FROM golang:1.14.4 as builder ---> 00d970a31ef2 Step 2/10 : WORKDIR /app ---> Using cache ---> 290d933fcd92 Step 3/10 : COPY . . ---> 5c338d20e119 Step 4/10 : RUN go mod download ---> Running in fa40233a9ad4 Removing intermediate container fa40233a9ad4 ---> 32ededdd590c Step 5/10 : RUN go build cmd/app/main.go ---> Running in 715374ae5931 Removing intermediate container 715374ae5931 ---> 0df4e6ac142b Step 6/10 : FROM alpine ---> a24bb4013296 Step 7/10 : RUN apk add --no-cache ca-certificates ---> Using cache ---> 63a365fab492 Step 8/10 : COPY --from=builder /app/main /app/main ---> 262cef1fcd0f Step 9/10 : EXPOSE 5000 ---> Running in d2cc58f47b7f Removing intermediate container d2cc58f47b7f ---> 49e6a57ba3bd Step 10/10 : ENTRYPOINT [ "/app/main" ] ---> Running in 887cc0dbb3a8 Removing intermediate container 887cc0dbb3a8 ---> d5c6b638a8a7 Successfully built d5c6b638a8a7
buildしたimageを実行すると exec user process caused "no such file or directory" と出て実行が出来ない。
$ docker run -it d5c6b638a8a7 standard_init_linux.go:211: exec user process caused "no such file or directory"
Docker公式のDocumentを眺めると CGO_ENABLED=0
という変数を指定している。
CGO_ENABLEについて公式のDocumentに書いてある。
The cgo tool is enabled by default for native builds on systems where it is expected to work. It is disabled by default when cross-compiling. > You can control this by setting the CGO_ENABLED environment variable when running the go tool: set it to 1 to enable the use of cgo, and to > 0 to disable it. The go tool will set the build constraint "cgo" if cgo is enabled. The special import "C" implies the "cgo" build constraint, as > > though the file also said "// +build cgo". Therefore, if cgo is disabled, files that import "C" will not be built by the go tool. (For more about >build constraints see https://golang.org/pkg/go/build/#hdr-Build_Constraints).
今回のMulti Stage Buildのようなビルド環境と実行環境が違うクロスコンパイル時には CGO_ENABLE=0
にする必要があるとのこと。go envで見てみると案の定 CGO_ENABLE=1
となっている。
Step 6/11 : RUN go env ---> Running in f2d4bf833350 GO111MODULE="" GOARCH="amd64" GOBIN="" GOCACHE="/root/.cache/go-build" GOENV="/root/.config/go/env" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOINSECURE="" GONOPROXY="" GONOSUMDB="" GOOS="linux" GOPATH="/go" GOPRIVATE="" GOPROXY="https://proxy.golang.org,direct" GOROOT="/usr/local/go" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64" GCCGO="gccgo" AR="ar" CC="gcc" CXX="g++" CGO_ENABLED="1" GOMOD="/app/go.mod" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build835780014=/tmp/go-build -gno-record-gcc-switches"
Dockerfileのbuild箇所に CGO_ENABLE=0
を指定することで正常にビルドが出来ました。
FROM golang:1.14.4 as builder WORKDIR /app COPY . . RUN go mod download RUN CGO_ENABLED=0 go build path/to/main.go RUN go env FROM alpine RUN apk add --no-cache ca-certificates COPY --from=builder /app/path/to/main /app/main EXPOSE 5000 ENTRYPOINT [ "/app/main" ]
$ docker build . Sending build context to Docker daemon 24.16MB Step 1/11 : FROM golang:1.14.4 as builder ---> 00d970a31ef2 Step 2/11 : WORKDIR /app ---> Using cache ---> 290d933fcd92 Step 3/11 : COPY . . ---> 1e985aa7595b Step 4/11 : RUN go mod download ---> Running in 4f47920a2f07 Removing intermediate container 4f47920a2f07 ---> b3af89cc0fae Step 5/11 : RUN CGO_ENABLED=0 go build cmd/app/main.go ---> Running in 5418122649bb Removing intermediate container 5418122649bb ---> a22ffab8bc7c Step 6/11 : RUN go env ---> Running in f2d4bf833350 GO111MODULE="" GOARCH="amd64" GOBIN="" GOCACHE="/root/.cache/go-build" GOENV="/root/.config/go/env" GOEXE="" GOFLAGS="" GOHOSTARCH="amd64" GOHOSTOS="linux" GOINSECURE="" GONOPROXY="" GONOSUMDB="" GOOS="linux" GOPATH="/go" GOPRIVATE="" GOPROXY="https://proxy.golang.org,direct" GOROOT="/usr/local/go" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64" GCCGO="gccgo" AR="ar" CC="gcc" CXX="g++" CGO_ENABLED="1" GOMOD="/app/go.mod" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build835780014=/tmp/go-build -gno-record-gcc-switches" Removing intermediate container f2d4bf833350 ---> 658a897f518b Step 7/11 : FROM alpine ---> a24bb4013296 Step 8/11 : RUN apk add --no-cache ca-certificates ---> Using cache ---> 63a365fab492 Step 9/11 : COPY --from=builder /app/main /app/main ---> 4aea7dfd10cd Step 10/11 : EXPOSE 5000 ---> Running in 17d50b507678 Removing intermediate container 17d50b507678 ---> e35b39616e48 Step 11/11 : ENTRYPOINT [ "/app/main" ] ---> Running in 2a03dd0d5636 Removing intermediate container 2a03dd0d5636 ---> 7f1b74a479da Successfully built 7f1b74a479da $ docker run -it 7f1b74a479da ____ __ / __/___/ / ___ / _// __/ _ \/ _ \ /___/\__/_//_/\___/ v4.1.16 High performance, minimalist Go web framework https://echo.labstack.com ____________________________________O/_______ O\ ⇨ http server started on 127.0.0.1:5000