Skip to content

构建参数

原文:https://docs.docker.com/build/guide/build-args/

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

更改运行时版本

构建参数的一个实际用途是为构建阶段指定运行时版本。您的镜像使用 golang:1.21-alpine 镜像作为基础镜像。但如果有人想使用不同版本的 Go 来构建应用程序怎么办?他们可以在 Dockerfile 中更新版本号,但这种方式不便,使版本之间的切换比必要的更加繁琐。构建参数使生活变得更简单:

diff
  # 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:

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

运行此命令将使用 golang:1.19-alpine 镜像进行构建。

注入值

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

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

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

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

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

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

diff
  # 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 作为版本。

console
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 构建不仅创建容器镜像,还可以创建可执行二进制文件。