无法在 Docker 的多阶段构建中构建 Go 程序,出现未定义的错误。

huangapple go评论84阅读模式
英文:

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.

huangapple
  • 本文由 发表于 2023年7月18日 08:32:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/76708854.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定