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

bis0qfac  于 2024-01-04  发布在  Go
关注(0)|答案(1)|浏览(114)

我有以下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

字符串
(Yes我知道FROM行中的as gobuilder部分是不必要的,让我们暂时忽略它。
当我构建这个时,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扩展和引用。但是如果引用不起作用,我就不能轻易地验证这一点。

7gcisfzg

7gcisfzg1#

一个更好的解决方法是不依赖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指令的剩余时间内设置一次变量。
(You我还注意到我重构了第一个printf。我想如果你真的想的话,你可以在源文件中获得制表符缩进;但对我来说,易读性胜过完全控制。)

相关问题