构建论点

构建参数是增加构建灵活性的好方法。您可以在构建时传递构建参数,并且可以设置构建器用作后备的默认值。

更改运行时版本

构建参数的一个实际用例是为构建阶段指定运行时版本。您的图像使用该golang:1.21-alpine 图像作为基础图像。但是,如果有人想使用不同版本的 Go 来构建应用程序怎么办?他们可以更新 Dockerfile 内的版本号,但这很不方便,它使得版本之间的切换变得更加繁琐。建立论点让生活更轻松:

  # syntax=docker/dockerfile:1
- FROM golang:1.21-alpine AS base
+ ARG GO_VERSION=1.21
+ FROM golang:${GO_VERSION}-alpine AS base
  WORKDIR /src
  RUN --mount=type=cache,target=/go/pkg/mod/ \
      --mount=type=bind,source=go.sum,target=go.sum \
      --mount=type=bind,source=go.mod,target=go.mod \
      go mod download -x

  FROM base AS build-client
  RUN --mount=type=cache,target=/go/pkg/mod/ \
      --mount=type=bind,target=. \
      go build -o /bin/client ./cmd/client

  FROM base AS build-server
  RUN --mount=type=cache,target=/go/pkg/mod/ \
      --mount=type=bind,target=. \
      go build -o /bin/server ./cmd/server

  FROM scratch AS client
  COPY --from=build-client /bin/client /bin/
  ENTRYPOINT [ "/bin/client" ]

  FROM scratch AS server
  COPY --from=build-server /bin/server /bin/
  ENTRYPOINT [ "/bin/server" ]

关键字ARG插入FROM指令中的图像名称中。构建参数的默认值GO_VERSION设置为1.21。如果构建未收到GO_VERSION构建参数,则FROM指令解析为golang:1.21-alpine.

--build-arg尝试使用构建命令的标志来设置用于构建的不同版本的 Go :

$ docker build --build-arg="GO_VERSION=1.19" .

运行此命令会导致使用该映像进行构建golang:1.19-alpine

注入值

您还可以在构建时使用构建参数来修改程序源代码中的值。这对于动态注入信息非常有用,避免硬编码值。对于 Go,在构建时使用外部值是使用链接器标志或-ldflags.

应用程序的服务器部分包含一个条件语句,用于打印应用程序版本(如果指定了版本):

// cmd/server/main.go
var version string

func main() {
	if version != "" {
		log.Printf("Version: %s", version)
	}

您可以直接在代码中声明版本字符串值。但是,更新版本以与应用程序的发布版本保持一致需要在每次发布之前更新代码。这既乏味又容易出错。更好的解决方案是将版本字符串作为构建参数传递,并将构建参数注入到代码中。

以下示例将APP_VERSION构建参数添加到build-server 阶段。 Go 编译器使用构建参数的值来设置代码中变量的值。

  # syntax=docker/dockerfile:1
  ARG GO_VERSION=1.21
  FROM golang:${GO_VERSION}-alpine AS base
  WORKDIR /src
  RUN --mount=type=cache,target=/go/pkg/mod/ \
      --mount=type=bind,source=go.sum,target=go.sum \
      --mount=type=bind,source=go.mod,target=go.mod \
      go mod download -x

  FROM base AS build-client
  RUN --mount=type=cache,target=/go/pkg/mod/ \
      --mount=type=bind,target=. \
      go build -o /bin/client ./cmd/client

  FROM base AS build-server
+ ARG APP_VERSION="v0.0.0+unknown"
  RUN --mount=type=cache,target=/go/pkg/mod/ \
      --mount=type=bind,target=. \
-     go build -o /bin/server ./cmd/server
+     go build -ldflags "-X main.version=$APP_VERSION" -o /bin/server ./cmd/server

  FROM scratch AS client
  COPY --from=build-client /bin/client /bin/
  ENTRYPOINT [ "/bin/client" ]

  FROM scratch AS server
  COPY --from=build-server /bin/server /bin/
  ENTRYPOINT [ "/bin/server" ]

现在,在构建二进制文件时会注入服务器的版本,而无需更新源代码。要验证这一点,您可以构建server目标并使用 启动容器docker run。服务器v0.0.1在启动时输出版本。

$ docker build --target=server --build-arg="APP_VERSION=v0.0.1" --tag=buildme-server .
$ docker run buildme-server
2023/04/06 08:54:27 Version: v0.0.1
2023/04/06 08:54:27 Starting server...
2023/04/06 08:54:27 Listening on HTTP port 3000

概括

本节展示了如何使用构建参数来使构建更加可配置,并在构建时注入值。

相关信息:

下一步

本指南的下一部分将介绍如何使用 Docker 构建来创建容器映像和可执行二进制文件。