构建参数

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

更改运行时版本

构建参数的实际用例是为构建阶段指定运行时版本。您的镜像使用 `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)
	}

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

以下示例向 `build-server` 阶段添加了 `APP_VERSION` 构建参数。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 构建不仅创建容器镜像,还可以创建可执行二进制文件。