構建引數

構建引數是為您的構建新增靈活性的好方法。您可以在構建時傳遞構建引數,並且可以設定構建器用作回退的預設值。

更改執行時版本

構建引數的實際用例是為構建階段指定執行時版本。您的映象使用 `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 構建不僅建立容器映象,還可以建立可執行二進位制檔案。