対象の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
という変数を指定している。
docs.docker.com
CGO_ENABLEについて公式のDocumentに書いてある。
golang.org
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
ref
qiita.com
docs.docker.com
golang.org
github.com