英文:
Unable to build go program in multistage build with undefined error in Docker
问题
我正在尝试学习Go,并且已经在一个简单的项目上构建了我的第一个Go程序。
以下是我的目录结构:
❯ tree .
.
├── README.md
├── convert.go
├── dockerfile
├── go.mod
├── go.sum
├── main.go
├── pageindices.go
├── pageindices_test.go
├── pdf2png.go
└── pdf2png_test.go
这是我的Dockerfile内容:
ARG GOLANG_IMAGE_TAG="1.20.6-alpine"
FROM golang:${GOLANG_IMAGE_TAG} as base
ARG PDF2IMG_VERSION=dev
# 使用8.14.2版本
ARG VIPS_VERSION="8.14.2"
RUN apk update && apk add --no-cache \
automake build-base pkgconfig glib-dev expat-dev gobject-introspection \
libjpeg-turbo-dev libpng-dev libwebp-dev giflib-dev librsvg-dev libexif-dev lcms2-dev
# 添加"exit 0"是因为警告通常会导致构建以非零状态退出
RUN cd /root \
&& mkdir vips \
&& wget -q0- "https://github.com/libvips/libvips/releases/download/v${VIPS_VERSION}/vips-${VIPS_VERSION}.tar.gz" | tar -xzf - -C vips --strip-components=1 \
&& cd vips \
&& CFLAGS="-g -O3" CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0 -g -O3" ./configure \
--disable-debug \
--disable-dependency-tracking \
--disable-introspection \
--disable-static \
--enable-gtk-doc-html=no \
--enable-gtk-doc=no \
--enable-pyvips8=no && \
make && make install-strip && ldconfig; exit 0
RUN export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/vips/lib
RUN apk del automake build-base
# 在镜像中创建一个工作目录
WORKDIR /go/src/github.com/felixgao/pdf2img
# 缓存Go模块
ENV GO111MODULE=on
# 复制go.mod和go.sum文件
COPY go.mod go.sum ./
# 下载所有依赖项。如果go.mod和go.sum文件未更改,则依赖项将被缓存
RUN go mod download
# 复制所有以.go结尾的文件
COPY *.go .
# 使用ldflags构建Go应用程序
RUN CGO_ENABLED=0 GOOS=linux go build -a \
-ldflags="-s -w -h -X main.Version=${PDF2IMG_VERSION}" \
-o pdf2png
# 构建目标镜像
FROM golang:${GOLANG_IMAGE_TAG} as prod
WORKDIR /app/
RUN apk --update add --no-cache \
fftw glib expat libjpeg-turbo libpng \
libwebp giflib librsvg libgsf libexif lcms2
WORKDIR /root/
COPY --from=base /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=base /root/libs/* /root/libs/
COPY --from=base /usr/local/lib/* /usr/local/lib/
COPY --from=base /go/src/github.com/felixgao/pdf2img/pdf2png .
# 告诉Docker要暴露的端口
EXPOSE 8080
# 运行"go install"生成的二进制程序
CMD ["./pdf2png"]
我的go.mod文件内容如下:
module github.com/felixgao/pdf_to_png
go 1.20
require github.com/davidbyttow/govips/v2 v2.13.0
require (
golang.org/x/image v0.9.0 // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/text v0.11.0 // indirect
)
当我构建时,它一直告诉我所需的包不存在。我以为go mod download会为我下载它。我漏掉了什么吗?
=> CACHED [base 6/10] WORKDIR /go/src/github.com/felixgao/pdf2img 0.0s
=> CACHED [base 7/10] COPY go.mod go.sum ./ 0.0s
=> [base 8/10] RUN go mod download 6.0s
=> [base 9/10] COPY *.go . 0.0s
=> ERROR [base 10/10] RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags="-s -w - 4.5s
------
> [base 10/10] RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags="-s -w -h -X main.Version=dev" -o pdf2png:
#18 4.394 # github.com/felixgao/pdf_to_png
#18 4.394 ./pdf2png.go:29:29: undefined: vips.ImageType
#18 4.394 ./pdf2png.go:30:7: undefined: vips.ImageTypeJPEG
#18 4.394 ./pdf2png.go:31:7: undefined: vips.ImageTypePNG
#18 4.394 ./pdf2png.go:32:7: undefined: vips.ImageTypeTIFF
#18 4.394 ./pdf2png.go:35:41: undefined: vips.ImageType
#18 4.394 ./pdf2png.go:36:15: undefined: vips.ImageTypeJPEG
#18 4.394 ./pdf2png.go:37:15: undefined: vips.ImageTypePNG
#18 4.394 ./pdf2png.go:38:15: undefined: vips.ImageTypeTIFF
#18 4.394 ./pdf2png.go:41:25: undefined: vips.ImageRef
#18 4.394 ./pdf2png.go:41:86: undefined: vips.ImageMetadata
#18 4.394 ./pdf2png.go:41:86: too many errors
------
executor failed running [/bin/sh -c CGO_ENABLED=0 GOOS=linux go build -a -ldflags="-s -w -h -X main.Version=${PDF2IMG_VERSION}" -o pdf2png]: exit code: 1pdf2png]: exit code: 1
当我在本地运行构建命令时,它可以正常工作。
❯ go build -a -ldflags="-s -w -h -X main.Version=dev" -o pdf2png && echo $?
0
❯ ls -al pdf2png
-rwxr-xr-x 1 ggao staff 6334226 Jul 18 17:52 pdf2png
我期望go mod download会下载所需的包,并允许构建通过,就像在本地使用go build命令一样。
英文:
I am trying to learn go and I have build my first go program on something simple as.
❯ tree .
.
├── README.md
├── convert.go
├── dockerfile
├── go.mod
├── go.sum
├── main.go
├── pageindices.go
├── pageindices_test.go
├── pdf2png.go
└── pdf2png_test.go
what my docker file looks like the following
ARG GOLANG_IMAGE_TAG="1.20.6-alpine"
FROM golang:${GOLANG_IMAGE_TAG} as base
ARG PDF2IMG_VERSION=dev
# So using 8.14.2 for now
ARG VIPS_VERSION="8.14.2"
RUN apk update && apk add --no-cache \
automake build-base pkgconfig glib-dev expat-dev gobject-introspection \
libjpeg-turbo-dev libpng-dev libwebp-dev giflib-dev librsvg-dev libexif-dev lcms2-dev
# Exit 0 added because warnings tend to exit the build at a non-zero status
RUN cd /root \
&& mkdir vips \
&& wget -q0- "https://github.com/libvips/libvips/releases/download/v${VIPS_VERSION}/vips-${VIPS_VERSION}.tar.gz" | tar -xzf - -C vips --strip-components=1 \
&& cd vips \
&& CFLAGS="-g -O3" CXXFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0 -g -O3" ./configure \
--disable-debug \
--disable-dependency-tracking \
--disable-introspection \
--disable-static \
--enable-gtk-doc-html=no \
--enable-gtk-doc=no \
--enable-pyvips8=no && \
make && make install-strip && ldconfig; exit 0
RUN export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/vips/lib
RUN apk del automake build-base
# create a working directory inside the image
WORKDIR /go/src/github.com/felixgao/pdf2img
# Cache go modules
ENV GO111MODULE=on
# Copy go mod and sum files
COPY go.mod go.sum ./
# Download all dependencies. Dependencies will be cached if the go.mod and go.sum files are not changed
RUN go mod download
# copy directry files i.e all files ending with .go
COPY *.go .
# Build the Go app with ldflags
RUN CGO_ENABLED=0 GOOS=linux go build -a \
-ldflags="-s -w -h -X main.Version=${PDF2IMG_VERSION}" \
-o pdf2png
# build target image
FROM golang:${GOLANG_IMAGE_TAG} as prod
WORKDIR /app/
RUN apk --update add --no-cache \
fftw glib expat libjpeg-turbo libpng \
libwebp giflib librsvg libgsf libexif lcms2
WORKDIR /root/
COPY --from=base /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=base /root/libs/* /root/libs/
COPY --from=base /usr/local/lib/* /usr/local/lib/
COPY --from=base /go/src/github.com/felixgao/pdf2img/pdf2png .
#tell docker what port to expose
EXPOSE 8080
# Run the binary program produced by `go install`
CMD ["./pdf2png"]
my go.mod file looks like
module github.com/felixgao/pdf_to_png
go 1.20
require github.com/davidbyttow/govips/v2 v2.13.0
require (
golang.org/x/image v0.9.0 // indirect
golang.org/x/net v0.12.0 // indirect
golang.org/x/text v0.11.0 // indirect
)
When I built it, it kept telling me the required package is not there. I thought go mod download would pull that down for me. Am I missing something?
=> CACHED [base 6/10] WORKDIR /go/src/github.com/felixgao/pdf2img 0.0s
=> CACHED [base 7/10] COPY go.mod go.sum ./ 0.0s
=> [base 8/10] RUN go mod download 6.0s
=> [base 9/10] COPY *.go . 0.0s
=> ERROR [base 10/10] RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags="-s -w - 4.5s
------
> [base 10/10] RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags="-s -w -h -X main.Version=dev" -o pdf2png:
#18 4.394 # github.com/felixgao/pdf_to_png
#18 4.394 ./pdf2png.go:29:29: undefined: vips.ImageType
#18 4.394 ./pdf2png.go:30:7: undefined: vips.ImageTypeJPEG
#18 4.394 ./pdf2png.go:31:7: undefined: vips.ImageTypePNG
#18 4.394 ./pdf2png.go:32:7: undefined: vips.ImageTypeTIFF
#18 4.394 ./pdf2png.go:35:41: undefined: vips.ImageType
#18 4.394 ./pdf2png.go:36:15: undefined: vips.ImageTypeJPEG
#18 4.394 ./pdf2png.go:37:15: undefined: vips.ImageTypePNG
#18 4.394 ./pdf2png.go:38:15: undefined: vips.ImageTypeTIFF
#18 4.394 ./pdf2png.go:41:25: undefined: vips.ImageRef
#18 4.394 ./pdf2png.go:41:86: undefined: vips.ImageMetadata
#18 4.394 ./pdf2png.go:41:86: too many errors
------
executor failed running [/bin/sh -c CGO_ENABLED=0 GOOS=linux go build -a -ldflags="-s -w -h -X main.Version=${PDF2IMG_VERSION}" -o pdf2png]: exit code: 1pdf2png]: exit code: 1
When run the build command locally, it works fine.
❯ go build -a -ldflags="-s -w -h -X main.Version=dev" -o pdf2png && echo $?
0
❯ ls -al pdf2png
-rwxr-xr-x 1 ggao staff 6334226 Jul 18 17:52 pdf2png
I would expect the go mod download will pull down the necessary packages and allows the build to pass as it is passing in my local without using docker.
答案1
得分: 3
我认为问题出在go mod tidy
上。你的Dockerfile在将任何Go源文件复制到构建容器之前运行此命令。因此,Go会通过删除所有依赖项来积极整理go.mod。
在这种情况下,我认为你可以直接删除go mod tidy
。特别是因为这不是Dockerfile中的最终构建阶段。
英文:
I believe the issue is go mod tidy
. Your Dockerfile runs this command before any Go source files have been copied to the build container. So Go aggressively tidies go.mod by removing all dependencies.
In this case I think you can just remove the go mod tidy
. Especially since this isn't the final build stage in the Dockerfile.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论