docker 多阶段构建 Go 映像 - x509:未知权威机构签署的证书
docker multi-stage build Go image - x509: certificate signed by unknown authority
我尝试构建 go images in private corp network use docker-multi-stage-build:
FROM golang:latest as builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN GO111MODULE="on" CGO_ENABLED=0 GOOS=linux go build -o main ${MAIN_PATH}
FROM alpine:latest
LABEL maintainer="Kozmo"
RUN apk add --no-cache bash
WORKDIR /app
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]
并得到x509: certificate signed by unknown authority
错误
Step 1/13 : FROM golang:latest as builder
---> 2421885b04da
Step 2/13 : WORKDIR /app
---> Using cache
---> 6555644dbd16
Step 3/13 : COPY go.mod go.sum ./
---> 55d45a30f492
Step 4/13 : RUN go mod download
---> Running in 88c21c6b4fab
go: github.com/dgrijalva/jwt-go/v4@v4.0.0-preview1: Get "https://proxy.golang.org/github.com/dgrijalva/jwt-go/v4/@v/v4.0.0-preview1.mod": x509: certificate signed by unknown authority
The command '/bin/sh -c go mod download' returned a non-zero code: 1
make: *** [docker] Error 1
我试图在
中找到答案
X509: Certificate Signed by Unknown Authority (Running a Go App
Inside a Docker Container)
和
docker build: cannot get the github public repository, x509:
certificate signed by unknown authority
和
,但结果是一样的。
❗️如果加-insecure
标志
...
RUN go env -w GOPROXY=direct GOFLAGS="-insecure"
COPY go.mod go.sum ./
...
到Dockerfile
unrecognized import path
错误wrap之前的x509
错误和无法访问 包更改为 golang.org/x/crypto
go: golang.org/x/crypto@v0.0.0-20200622213623-75b288015ac9: unrecognized import path "golang.org/x/crypto": https fetch: Get "https://golang.org/x/crypto?go-get=1": x509: certificate signed by unknown authority
有什么问题❓
(我知道问题出在 git
获取依赖项时的证书和身份验证中,但我尝试使构建映像的过程更常见)
应对自我证书 (.crt
) 有帮助
1️⃣ 将 .crt
添加到所需的 dir
.
└── backend
├── Dockerfile
├── Makefile
├── cmd
│ └── main.go
├── etc
│ ├── ssl
│ │ └── github.crt #❗️a copy of the self certificate
2️⃣ COPY
证书到 'builder'-容器
FROM golang:latest as builder
COPY etc/ssl/ /etc/ssl/certs/ #❗️add certificates to the container
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
我会提出一些建议:
- 在与最终代码映像相同的 OS 发行版中构建您的代码,以便您确定您的代码将 运行 在该特定发行版中。此外,某些发行版要求证书位于不同的文件夹中,因此请注意这一点。
- 对第一个图像使用 alpine 将大大减少您的构建时间。你可以看到 here
latest
大小是~260M,但是 alpine
是~100M。
- 最好使用特定版本的 alpine,这样你就可以确定你的代码 运行 在那个版本中(我让你自行决定)
- Golang 的一个非常强大的地方是你可以 运行 它在一个名为
scratch
的空 docker 图像中,这意味着你的最终 docker 图像不包含不仅仅是你自己的可执行文件。
- 如果您需要自己的证书,您必须在代码中包含它们并在执行之前复制它们
update-ca-certificates
以便它们包含在最终文件中
这是一个 docker 文件的示例,其中包含我上面解释的内容
FROM golang:alpine as builder
WORKDIR /app
# This will download all certificates (ca-certificates) and builds it in a
# single file under /etc/ssl/certs/ca-certificates.crt (update-ca-certificates)
# I also add git so that we can download with `go mod download` and
# tzdata to configure timezone in final image
RUN apk --update add --no-cache ca-certificates openssl git tzdata && \
update-ca-certificates
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN GO111MODULE="on" CGO_ENABLED=0 GOOS=linux go build -o main ${MAIN_PATH}
# Golang can run in a scratch image, so that, the only thing that your docker
# image contains is your executable
FROM scratch
LABEL maintainer="Kozmo"
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
# This line will copy all certificates to final image
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
WORKDIR /app
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]
如果自己的证书将第一个 docker 阶段替换为:
FROM golang:alpine as builder
WORKDIR /app
RUN apk --update add --no-cache ca-certificates openssl git tzdata
COPY your/cert/path /usr/local/share/ca-certificates/your-cert-name
RUN update-ca-certificates
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN GO111MODULE="on" CGO_ENABLED=0 GOOS=linux go build -o main ${MAIN_PATH}
因为您使用自己的证书,所以您的最终 Dockerfile
将如下所示:
FROM golang:alpine as builder
WORKDIR /app
RUN apk --update add --no-cache ca-certificates openssl git tzdata
COPY your/cert/path /usr/local/share/ca-certificates/your-cert-name
RUN update-ca-certificates
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN GO111MODULE="on" CGO_ENABLED=0 GOOS=linux go build -o main ${MAIN_PATH}
FROM scratch
LABEL maintainer="Kozmo"
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
# This line will copy all certificates to final image
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
WORKDIR /app
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]
如有任何疑问,请随时问我:)
来自您的错误信息
Get
"https://proxy.golang.org/github.com/dgrijalva/jwt-go/v4/@v/v4.0.0-preview1.mod":
x509: certificate signed by unknown authority
proxy.golang.org 的 CA 根似乎不是您私人公司 docker 环境中受信任的根 CA 的一部分。
我会尝试安装它:
1 - 从 proxy.golang.org 获取证书:
echo -n | openssl s_client -connect proxy.golang.org:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ./golang.cer
如果您打开 golang.cer,您应该会看到证书链
2 - 将其安装在您信任的根 CA 中:
certutil.exe -addstore root golang.cer
...或在 Mac 上:
2a - 双击证书文件(扩展名为“.cer”)
2b - 从钥匙串选项中选择“系统”。然后按“确定”
2c - 当出现以下window pops-up时,点击“始终信任”按钮。
git
使用curl
访问https
服务器,因此您需要将证书导入系统CA store
。
解决方法是在您的 Agent 环境变量上定义环境变量 GIT_SSL_NO_VERIFY=1
,但是在使用 go get
或 go mod download
.
要在您的系统 CA 存储上导入证书,过程取决于您的 OS 您必须使用 openssl
。
例如
FROM golang:latest as builder
RUN apt-get update && apt-get install -y ca-certificates openssl
ARG cert_location=/usr/local/share/ca-certificates
# Get certificate from "github.com"
RUN openssl s_client -showcerts -connect github.com:443 </dev/null 2>/dev/null|openssl x509 -outform PEM > ${cert_location}/github.crt
# Get certificate from "proxy.golang.org"
RUN openssl s_client -showcerts -connect proxy.golang.org:443 </dev/null 2>/dev/null|openssl x509 -outform PEM > ${cert_location}/proxy.golang.crt
# Update certificates
RUN update-ca-certificates
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN GO111MODULE="on" CGO_ENABLED=0 GOOS=linux go build -o main ${MAIN_PATH}
FROM alpine:latest
LABEL maintainer="Kozmo"
RUN apk add --no-cache bash
WORKDIR /app
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]
docker image build
输出
...
Step 5/19 : RUN openssl s_client -showcerts -connect github.com:443 </dev/null 2>/dev/null|openssl x509 -outform PEM > ${cert_location}/github.crt
---> Running in bb797e26d4b4
Removing intermediate container bb797e26d4b4
---> 6c68ddafd884
Step 6/19 : RUN openssl s_client -showcerts -connect proxy.golang.org:443 </dev/null 2>/dev/null|openssl x509 -outform PEM > ${cert_location}/proxy.golang.crt
---> Running in 61f59939d75e
Removing intermediate container 61f59939d75e
---> 72d2b03b11e6
Step 7/19 : RUN update-ca-certificates
---> Running in 6cf9aa248776
Updating certificates in /etc/ssl/certs...
2 added, 0 removed; done. 'certificates updated'
...
Step 8/18 : COPY go.mod go.sum ./
---> 436263b76050
Step 9/18 : RUN go mod download 'works fine'
---> Running in 2387c78147db
Removing intermediate container 2387c78147db
---> a37c05c2b531
Step 10/18 : COPY . .
---> 01b49c388f59
...
我尝试构建 go images in private corp network use docker-multi-stage-build:
FROM golang:latest as builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN GO111MODULE="on" CGO_ENABLED=0 GOOS=linux go build -o main ${MAIN_PATH}
FROM alpine:latest
LABEL maintainer="Kozmo"
RUN apk add --no-cache bash
WORKDIR /app
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]
并得到x509: certificate signed by unknown authority
错误
Step 1/13 : FROM golang:latest as builder
---> 2421885b04da
Step 2/13 : WORKDIR /app
---> Using cache
---> 6555644dbd16
Step 3/13 : COPY go.mod go.sum ./
---> 55d45a30f492
Step 4/13 : RUN go mod download
---> Running in 88c21c6b4fab
go: github.com/dgrijalva/jwt-go/v4@v4.0.0-preview1: Get "https://proxy.golang.org/github.com/dgrijalva/jwt-go/v4/@v/v4.0.0-preview1.mod": x509: certificate signed by unknown authority
The command '/bin/sh -c go mod download' returned a non-zero code: 1
make: *** [docker] Error 1
我试图在
中找到答案X509: Certificate Signed by Unknown Authority (Running a Go App Inside a Docker Container)
和
docker build: cannot get the github public repository, x509: certificate signed by unknown authority
和
,但结果是一样的。
❗️如果加-insecure
标志
...
RUN go env -w GOPROXY=direct GOFLAGS="-insecure"
COPY go.mod go.sum ./
...
到Dockerfile
unrecognized import path
错误wrap之前的x509
错误和无法访问 包更改为 golang.org/x/crypto
go: golang.org/x/crypto@v0.0.0-20200622213623-75b288015ac9: unrecognized import path "golang.org/x/crypto": https fetch: Get "https://golang.org/x/crypto?go-get=1": x509: certificate signed by unknown authority
有什么问题❓
(我知道问题出在 git
获取依赖项时的证书和身份验证中,但我尝试使构建映像的过程更常见)
应对自我证书 (.crt
) 有帮助
1️⃣ 将 .crt
添加到所需的 dir
.
└── backend
├── Dockerfile
├── Makefile
├── cmd
│ └── main.go
├── etc
│ ├── ssl
│ │ └── github.crt #❗️a copy of the self certificate
2️⃣ COPY
证书到 'builder'-容器
FROM golang:latest as builder
COPY etc/ssl/ /etc/ssl/certs/ #❗️add certificates to the container
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
我会提出一些建议:
- 在与最终代码映像相同的 OS 发行版中构建您的代码,以便您确定您的代码将 运行 在该特定发行版中。此外,某些发行版要求证书位于不同的文件夹中,因此请注意这一点。
- 对第一个图像使用 alpine 将大大减少您的构建时间。你可以看到 here
latest
大小是~260M,但是alpine
是~100M。 - 最好使用特定版本的 alpine,这样你就可以确定你的代码 运行 在那个版本中(我让你自行决定)
- Golang 的一个非常强大的地方是你可以 运行 它在一个名为
scratch
的空 docker 图像中,这意味着你的最终 docker 图像不包含不仅仅是你自己的可执行文件。 - 如果您需要自己的证书,您必须在代码中包含它们并在执行之前复制它们
update-ca-certificates
以便它们包含在最终文件中
这是一个 docker 文件的示例,其中包含我上面解释的内容
FROM golang:alpine as builder
WORKDIR /app
# This will download all certificates (ca-certificates) and builds it in a
# single file under /etc/ssl/certs/ca-certificates.crt (update-ca-certificates)
# I also add git so that we can download with `go mod download` and
# tzdata to configure timezone in final image
RUN apk --update add --no-cache ca-certificates openssl git tzdata && \
update-ca-certificates
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN GO111MODULE="on" CGO_ENABLED=0 GOOS=linux go build -o main ${MAIN_PATH}
# Golang can run in a scratch image, so that, the only thing that your docker
# image contains is your executable
FROM scratch
LABEL maintainer="Kozmo"
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
# This line will copy all certificates to final image
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
WORKDIR /app
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]
如果自己的证书将第一个 docker 阶段替换为:
FROM golang:alpine as builder
WORKDIR /app
RUN apk --update add --no-cache ca-certificates openssl git tzdata
COPY your/cert/path /usr/local/share/ca-certificates/your-cert-name
RUN update-ca-certificates
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN GO111MODULE="on" CGO_ENABLED=0 GOOS=linux go build -o main ${MAIN_PATH}
因为您使用自己的证书,所以您的最终 Dockerfile
将如下所示:
FROM golang:alpine as builder
WORKDIR /app
RUN apk --update add --no-cache ca-certificates openssl git tzdata
COPY your/cert/path /usr/local/share/ca-certificates/your-cert-name
RUN update-ca-certificates
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN GO111MODULE="on" CGO_ENABLED=0 GOOS=linux go build -o main ${MAIN_PATH}
FROM scratch
LABEL maintainer="Kozmo"
COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo
# This line will copy all certificates to final image
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
WORKDIR /app
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]
如有任何疑问,请随时问我:)
来自您的错误信息
Get "https://proxy.golang.org/github.com/dgrijalva/jwt-go/v4/@v/v4.0.0-preview1.mod": x509: certificate signed by unknown authority
proxy.golang.org 的 CA 根似乎不是您私人公司 docker 环境中受信任的根 CA 的一部分。
我会尝试安装它:
1 - 从 proxy.golang.org 获取证书:
echo -n | openssl s_client -connect proxy.golang.org:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > ./golang.cer
如果您打开 golang.cer,您应该会看到证书链
2 - 将其安装在您信任的根 CA 中:
certutil.exe -addstore root golang.cer
...或在 Mac 上:
2a - 双击证书文件(扩展名为“.cer”)
2b - 从钥匙串选项中选择“系统”。然后按“确定”
2c - 当出现以下window pops-up时,点击“始终信任”按钮。
git
使用curl
访问https
服务器,因此您需要将证书导入系统CA store
。
解决方法是在您的 Agent 环境变量上定义环境变量 GIT_SSL_NO_VERIFY=1
,但是在使用 go get
或 go mod download
.
要在您的系统 CA 存储上导入证书,过程取决于您的 OS 您必须使用 openssl
。
例如
FROM golang:latest as builder
RUN apt-get update && apt-get install -y ca-certificates openssl
ARG cert_location=/usr/local/share/ca-certificates
# Get certificate from "github.com"
RUN openssl s_client -showcerts -connect github.com:443 </dev/null 2>/dev/null|openssl x509 -outform PEM > ${cert_location}/github.crt
# Get certificate from "proxy.golang.org"
RUN openssl s_client -showcerts -connect proxy.golang.org:443 </dev/null 2>/dev/null|openssl x509 -outform PEM > ${cert_location}/proxy.golang.crt
# Update certificates
RUN update-ca-certificates
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN GO111MODULE="on" CGO_ENABLED=0 GOOS=linux go build -o main ${MAIN_PATH}
FROM alpine:latest
LABEL maintainer="Kozmo"
RUN apk add --no-cache bash
WORKDIR /app
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]
docker image build
输出
...
Step 5/19 : RUN openssl s_client -showcerts -connect github.com:443 </dev/null 2>/dev/null|openssl x509 -outform PEM > ${cert_location}/github.crt
---> Running in bb797e26d4b4
Removing intermediate container bb797e26d4b4
---> 6c68ddafd884
Step 6/19 : RUN openssl s_client -showcerts -connect proxy.golang.org:443 </dev/null 2>/dev/null|openssl x509 -outform PEM > ${cert_location}/proxy.golang.crt
---> Running in 61f59939d75e
Removing intermediate container 61f59939d75e
---> 72d2b03b11e6
Step 7/19 : RUN update-ca-certificates
---> Running in 6cf9aa248776
Updating certificates in /etc/ssl/certs...
2 added, 0 removed; done. 'certificates updated'
...
Step 8/18 : COPY go.mod go.sum ./
---> 436263b76050
Step 9/18 : RUN go mod download 'works fine'
---> Running in 2387c78147db
Removing intermediate container 2387c78147db
---> a37c05c2b531
Step 10/18 : COPY . .
---> 01b49c388f59
...