为什么 golang 1.19.2-bullseye Docker 容器未在 Docker 输出中提供正确的引用?

问题描述 投票:0回答:1

我有以下 Dockerfile:

FROM golang:1.19.2-bullseye@sha256:2fddf0539591f8e364c9adb3d495d1ba2ca8a8df420ad23b58e7bcee7986ea6c as gobuilder

ARG CGO_ENABLED
ARG CGO_CFLAGS

RUN set -x && \
    printf 'package main\nimport (\n\t"fmt"\n\t"os"\n)\nfunc main(){\n\tfmt.Println(os.Getenv("CGO_CFLAGS"))\n}\n' > main.go && \
    cat main.go && \
    CGO_ENABLED="${CGO_ENABLED}" CGO_CFLAGS="${CGO_CFLAGS}" go build main.go && \
    ls && \
    CGO_CFLAGS="${CGO_CFLAGS}" ./main

(是的,我知道

as gobuilder
行中的
FROM
部分不是必需的,我们暂时忽略它。)

当我构建这个时,

set -x
输出没有正确引用构建参数:

$ docker build -t mre --build-arg CGO_ENABLED=1 --build-arg CGO_CFLAGS='-Wall -Wextra' .
Sending build context to Docker daemon  13.82kB
Step 1/4 : FROM golang:1.19.2-bullseye@sha256:2fddf0539591f8e364c9adb3d495d1ba2ca8a8df420ad23b58e7bcee7986ea6c as gobuilder
 ---> dce494d5814b
Step 2/4 : ARG CGO_ENABLED
 ---> Using cache
 ---> 39d4b3dd0c4e
Step 3/4 : ARG CGO_CFLAGS
 ---> Using cache
 ---> bfdf4834ae3b
Step 4/4 : RUN set -x &&     printf 'package main\nimport (\n\t"fmt"\n\t"os"\n)\nfunc main(){\n\tfmt.Println(os.Getenv("CGO_CFLAGS"))\n}\n' > main.go &&     cat main.go &&     CGO_ENABLED="${CGO_ENABLED}" CGO_CFLAGS="${CGO_CFLAGS}" go build main.go &&     ls &&     CGO_CFLAGS="${CGO_CFLAGS}" ./main
 ---> Running in 1936a6076a84
+ printf package main\nimport (\n\t"fmt"\n\t"os"\n)\nfunc main(){\n\tfmt.Println(os.Getenv("CGO_CFLAGS"))\n}\n
+ cat main.go
package main
import (
    "fmt"
    "os"
)
func main(){
    fmt.Println(os.Getenv("CGO_CFLAGS"))
}
+ CGO_ENABLED=1 CGO_CFLAGS=-Wall -Wextra go build main.go
+ ls
bin
main
main.go
src
+ CGO_CFLAGS=-Wall -Wextra ./main
-Wall -Wextra
Removing intermediate container 1936a6076a84
 ---> a5c293ba4ba8
Successfully built a5c293ba4ba8
Successfully tagged mre:latest

请注意,

main
二进制文件输出预期的环境变量值,但我希望看到
CGO_CFLAGS
部分像
+ CGO_CFLAGS='-Wall -Wextra' ./main
一样被引用。同样,我期望在
go build
命令中引用以下内容:

+ CGO_ENABLED=1 CGO_CFLAGS='-Wall -Wextra' go build main.go

为了进行比较,我尝试了一个使用不同 Dockerfile 和不同基础映像的示例。

Dockerfile:

FROM alpine:3.17.3

ARG ENV_VAR1

RUN set -x && ENV_VAR1="${ENV_VAR1}" ENV_VAR2='hello world' true 'minimal reproducible example'

构建输出:

$ docker build -t mre2 --build-arg ENV_VAR1='foo bar' .
Sending build context to Docker daemon  13.82kB
Step 1/3 : FROM alpine:3.17.3
 ---> 9ed4aefc74f6
Step 2/3 : ARG ENV_VAR1
 ---> Running in 182a965d4c83
Removing intermediate container 182a965d4c83
 ---> fc5f7f7f2e01
Step 3/3 : RUN set -x && ENV_VAR1="${ENV_VAR1}" ENV_VAR2='hello world' true 'minimal reproducible example'
 ---> Running in 6ebec9bed99a
+ ENV_VAR1='foo bar' ENV_VAR2='hello world' true 'minimal reproducible example'
Removing intermediate container 6ebec9bed99a
 ---> 5e1901518b51
Successfully built 5e1901518b51
Successfully tagged mre2:latest

行中注释

+ ENV_VAR1='foo bar' ENV_VAR2='hello world' true 'minimal reproducible example'

两个环境变量都按我的预期引用了。

我希望帮助理解为什么基于

golang:1.19.2-bullseye
基础镜像的 Docker 构建中不包含引号。

对于上下文,我希望能够在我的构建中看到引用,以便我可以确保我的所有命令都按照我的预期被 shell 扩展和引用。但如果引用不起作用,我无法轻易验证这一点。

bash docker shell go sh
1个回答
0
投票

更好的解决方法是不依赖

set -x
来准确显示您想要的格式。尝试类似的事情

RUN printf '%s\n' 'package main' \
        'import (' \
        '    "fmt"' \
        '    "os"' \
        ')' \
        'func main(){' \
        '    fmt.Println(os.Getenv("CGO_CFLAGS"))' \
        '}' > main.go && \
    cat main.go && \
    : basically unnecessary && \
    CGO_ENABLED="$CGO_ENABLED" && \
    CGO_FLAGS="$CGO_FLAGS" && \
    printf '%s=\042%s\042\n' \
        CGO_ENABLED "$CGO_ENABLED" \
        CGO_FLAGS "$CGO_FLAGS" && \
    go build main.go && \
    ls && \
    ./main

输出会稍微少一些(如果您真的想查看所有内容,当然可以放回

set -x
;但要了解输出格式将取决于 shell),但这样,您就可以完全控制
 printf
以明确的格式显示变量值。

ARG
变量分配回自身基本上是不必要的(正如评论中提到的);但我保留它们只是为了演示如何在当前
RUN
指令的剩余时间内设置一次变量。

(您还会注意到我重构了第一个

printf
。我想如果您真的愿意的话,您可以在源文件中获得制表符缩进;但对我来说,这里的易读性胜过完全控制。)

© www.soinside.com 2019 - 2024. All rights reserved.