简体   繁体   English

Dockerfile COPY 和 RUN 在一层

[英]Dockerfile COPY and RUN in one layer

I have a script used in the preapration of a Docker image.我有一个用于准备 Docker 映像的脚本。 I have this in the Dockerfile:我在 Dockerfile 中有这个:

COPY my_script /
RUN bash -c "/my_script"

The my_script file contains secrets that I don't want in the image (it deletes itself when it finishes). my_script文件包含我不希望出现在图像中的秘密(完成后它会自行删除)。

The problem is that the file remains in the image despite being deleted because the COPY is a separate layer.问题是尽管被删除了文件仍然保留在图像中,因为 COPY 是一个单独的层。 What I need is for both COPY and RUN to affect the same layer.我需要的是 COPY 和 RUN 影响同一层。

How can I COPY and RUN a script so that both actions affect the same layer?如何复制和运行脚本以便两个操作都影响同一层?

take a look to multi-stage : 看一下多阶段

Use multi-stage builds 使用多阶段构建

With multi-stage builds, you use multiple FROM statements in your Dockerfile. 通过多阶段构建,您可以在Dockerfile中使用多个FROM语句。 Each FROM instruction can use a different base, and each of them begins a new stage of the build. 每个FROM指令可以使用不同的基础,并且每个都开始构建的新阶段。 You can selectively copy artifacts from one stage to another, leaving behind everything you don't want in the final image . 您可以有选择地将工件从一个阶段复制到另一个阶段, 从而在最终图像中留下不需要的所有内容 To show how this works, let's adapt the Dockerfile from the previous section to use multi-stage builds. 为了展示它是如何工作的,让我们改编上一部分中的Dockerfile以使用多阶段构建。

Dockerfile: Dockerfile:

FROM golang:1.7.3
WORKDIR /go/src/github.com/alexellis/href-counter/
RUN go get -d -v golang.org/x/net/html  
COPY app.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .

FROM alpine:latest  
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/alexellis/href-counter/app .
CMD ["./app"]  

As of 18.09 you can use docker build --secret to use secret information during the build process. 从18.09开始,您可以使用docker build --secret在构建过程中使用秘密信息。 The secrets are mounted into the build environment and aren't stored in the final image. 机密会安装到构建环境中,并且不会存储在最终映像中。

RUN --mount=type=secret,id=script,dst=/my_script \
    bash -c /my_script
$ docker build --secret id=script,src=my_script.sh

The script wouldn't need to delete itself. 该脚本不需要删除自身。

I guess you can use a workaround to do this: 我想您可以使用一种解决方法来做到这一点:

Put my_script in a local http server which for example using python -m SimpleHTTPServer , and then the file could be accessed with http://http_server_ip:8000/my_script my_script放入本地http服务器(例如,使用python -m SimpleHTTPServer ,然后可以使用http://http_server_ip:8000/my_script访问该文件

Then, in Dockerfile use next: 然后,在Dockerfile中使用next:

RUN curl http://http_server_ip:8000/my_script > /my_script && chmod +x /my_script && bash -c "/my_script"

This workaround assure file add & delete in same layer, of course, you may need to add curl install in Dockerfile . 这种解决方法确保文件在同一层中添加和删除,当然,您可能需要在Dockerfile添加curl安装。

This can be handled by BuildKit: 可以通过BuildKit处理:

# syntax=docker/dockerfile:experimental
FROM ...
RUN --mount=type=bind,target=/my_script,source=my_script,rw \
    bash -c "/my_script"

You would then build with: 然后,您将使用:

DOCKER_BUILDKIT=1 docker build -t my_image .

This also sounds like you are trying to inject secrets into the build, eg to pull from a private git repo. 这听起来也像您正在尝试向构建中注入秘密,例如从私有git repo中提取。 BuildKit also allows you to specify: BuildKit还允许您指定:

# syntax=docker/dockerfile:experimental
FROM ...
RUN --mount=type=secret,target=/creds,id=cred \
    bash -c "/my_script -i /creds"

You would then build with: 然后,您将使用:

DOCKER_BUILDKIT=1 docker build -t my_image --secret id=creds,src=./creds .

With both of the BuildKit options, the mount command never actually adds the file to your image. 使用这两个BuildKit选项时,mount命令实际上从未将文件添加到映像中。 It only makes the file available as a bind mount during that single RUN step. 它仅使文件在该单个RUN步骤中可用作绑定安装。 As long as that RUN step does not output the secret to another file in your image, the secret is never injected in the image. 只要该RUN步骤不会将密钥输出到映像中的另一个文件,该密钥就永远不会注入到映像中。

For more on the BuildKit experimental syntax, see: https://github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md 有关BuildKit实验语法的更多信息,请参见: https : //github.com/moby/buildkit/blob/master/frontend/dockerfile/docs/experimental.md

I think RUN --mount=type=bind,source=my_script,target=/my_script bash /my_script in BuildKit can solve your problem.我认为RUN --mount=type=bind,source=my_script,target=/my_script bash /my_script可以解决您的问题。

First, prepare BuildKit一、准备BuildKit

export DOCKER_CLI_EXPERIMENTAL=enabled
export DOCKER_BUILDKIT=1
docker buildx create --name mybuilder --driver docker-container
docker buildx use mybuilder

Then, write your Dockerfile.然后,编写您的 Dockerfile。

# syntax = docker/dockerfile:experimental
FORM debian
## something

RUN --mount=type=bind,source=my_script,target=/my_script bash -c /my_script 

The first lint must be # syntax = docker/dockerfile:experimental because it's experimental feature.第一个 lint 必须是# syntax = docker/dockerfile:experimental因为它是实验性功能。

And this method are not work in Play with docker, but work on my computer...而这种方法在与 docker 一起玩时不起作用,但在我的电脑上工作......

My computer us Ubuntu 20.04 with docker 19.03.12我的电脑是 Ubuntu 20.04 和 docker 19.03.12

Then, build it with然后,用

docker buildx build --platform linux/amd64 -t user/imgname -f ./Dockerfile . --push

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM