Dockerfile的ADD和COPY

文章目录

  • 环境
  • ADD
    • 规则
    • 校验远程文件checksum
    • 添加Git仓库
    • 添加私有Git仓库
    • `ADD --link`
  • COPY
    • `COPY --parent`
  • 使用ADD还是COPY?
  • 参考

环境

  • RHEL 9.3
  • Docker Community 24.0.7

ADD

ADD 指令把 <src> 的文件、目录、或URL链接的文件复制到 <dest>

ADD 有两种写法:

  • ADD [--chown=<user>:<group>] [--chmod=<perms>] [--checksum=<checksum>] <src>... <dest>

例如:

ADD a.txt /mydir/
  • ADD [--chown=<user>:<group>] [--chmod=<perms>] ["<src>",... "<dest>"]

例如:

ADD ["a b.txt", "/mydir/"]

如果路径里包含空格,则必须用第二种写法。

一条ADD 指令里可以有多个 <src>

ADD a.txt b.txt /mydir/

<src> 可以使用通配符:

  • * :匹配任意0个、1个、或多个字符

例如:

ADD hom* /mydir/
  • ? :匹配任意1个字符

例如:

ADD hom?.txt /mydir/

<dest> 可以是绝对路径或相对路径。相对路径是建立在 <WORKDIR> 基础上的。

例如:

WORKDIR /dir1
ADD a.txt dir2/

则目标路径是 /dir1/dir2/

<src> 里包含特殊字符(比如 [] )时,需要按照Golang的规则转义,以避免被当作匹配模式。

比如,源文件名为 arr[0].txt ,则写法如下:

ADD arr[[]0].txt /mydir/

注:这一段话有点费解,参见我另一篇文档( https://blog.csdn.net/duke_ding2/article/details/135519942 )。

新创建的文件和目录,其UID和GID默认值都是0。可以通过 --chown 指定username/groupname(字符串)或者UID/GID(整数)。如果指定的是username/groupname字符串,则使用 /etc/passwd/etc/group 来转换为对应的UID和GID。若只指定username或只指定UID,则GID与UID相同。

例如:

ADD --chown=55:mygroup files* /somedir/
ADD --chown=bin files* /somedir/
ADD --chown=1 files* /somedir/
ADD --chown=10:11 files* /somedir/
ADD --chown=myuser:mygroup --chmod=655 files* /somedir/
  • 如果指定的username或groupname在 /etc/passwd/etc/group 里查找不到,则使用默认值0。

例如:

ADD --chown=xxx:yyy a.txt dir2/

结果为:

docker run kai0111_2 ls -l dir2
total 4
-rw-r--r--    1 root     root            12 Jan 11 07:20 a.txt
  • 如果指定的是整数,则不查看 /etc/passwd/etc/group ,指定的什么值就是什么值。

例如:

ADD --chown=111:222 a.txt dir2/

结果为:

docker run kai0111_2 ls -l dir2
total 4
-rw-r--r--    1 111      222             12 Jan 11 07:20 a.txt
  • 如果文件系统不包含 /etc/passwd/etc/group 文件,而在 ADD 指令里指定了username/groupname字符串,则构建会失败。

  • 如果 <src> 是远程的文件或URL,则目标文件的权限是“600”。

例如:

ADD https://github.com/dockersamples/buildme/blob/main/README.md dir1/

构建后,结果为:

docker run kai0111_3 ls -l dir1
total 136
-rw-------    1 root     root        137739 Jan  1  1970 README.md
  • 在获取远程文件时,如果response里有HTTP last-modified header,则该值会被用来指定目标文件的mtime。

在上一个例子中,response里没有HTTP last-modified header,所以mtime被指定为1970年1月1日。

下面是一个有HTTP last-modified header的例子:

在这里插入图片描述

添加该URL:

ADD https://docs.docker.com/guides/get-started/ dir1/

构建后,结果为:

docker run kai0111_4 ls -l dir1
total 68
-rw-------    1 root     root         68424 Jan 10 15:29 get-started

可见,修改时间时间和response里 last-modified header的值是一致的。

注意:mtime不会用来判断文件是否有修改以及是否要更新缓存。

  • 如果URL的文件受验证保护,则需要使用 RUN wgetRUN curl 或者其它方法,因为 ADD 指令不支持身份验证。

  • 如果 <src> 的内容有变化,则 ADD 指令的cache失效,随后的指令的cache也都失效,包括 RUN 指令。显然,应该合理放置 ADD 指令,使其只影响与源文件变化相关的步骤。

规则

ADD 指令有如下规则:

  • <src> 必须在build context里。不能使用 ../xxx ,也不能使用绝对路径。
  • 如果 <src> 是目录,则目录的所有内容都会复制,包括文件系统元数据。(注意:目录本身并不复制,只复制目录里面的内容。)
  • 如果 <src> 是URL,且 <dest>/ 结尾,则文件名由URL推断,下载到 <dest>/<filename> 。例如, ADD http://example.com/foobar / 会复制文件到 /foobar 。URL必须能推断出文件名,像 http://example.com 这样的URL是不行的。
  • 如果 <src> 是本地的压缩的tar包(比如 identitygzipbzip2xz ),则会被解压为一个目录。但如果 <src> 是远程文件,则不会解压。当目录被复制或解压时,其行为和 tar -x 是相同的。结果是以下的结合:
    1. Whatever existed at the destination path and
    2. The contents of the source tree, with conflicts resolved in favor of “2.” on a file-by-file basis.

注:这段话我没看懂是什么意思……我猜测意思是:目标路径下可能已经存在一些文件和目录,现在把tar包解压到目标路径时,可能会产生冲突,会按照“favor of “2.””逐个文件的解决冲突,但是不清楚“favor of “2.””是什么意思。

我测试了一下,如果遇到同名文件,解压的文件会覆盖原有的文件。

a.txt 文件内容如下:

hello

a.tar.gz 文件打包了以下目录结构:

.
├── a
│   ├── a.txt
│   └── b.txt
└── a.tar.gz

其中 a.txt 文件内容如下:

hi

创建 Dockerfile 文件如下:

FROM alpineADD a.txt a/a.txtADD a.tar.gz .

构建:

docker build -t kai0111_5 .

查看

docker run kai0111_5 sh -c "tree a && cat a/a.txt"
a
├── a.txt
└── b.txt0 directories, 2 files
hi

可见, a.txt 文件内容是tar包里的文件内容。

注:不能写成 docker run kai0111_5 tree a && cat a/a.txt ,否则会被识别为 docker run kai0111_5 tree acat a/a.txt 两条命令的组合。

  • 文件是否被看做压缩文件并自动解压,是由文件内容决定的,而不是由文件的后缀名决定的。
FROM alpineADD a.tar.gz .

其中, a.tar.gz 是一个空文件。

构建:

docker build -t kai0111_6 .

查看:

docker run kai0111_6 ls -l
total 12
-rw-r--r--    1 root     root             0 Jan 11 10:48 a.tar.gz
......

可见,仍然是 a.tar.gz ,没有解压。

  • 对于其它类型的文件,则连同元数据一起复制到目标路径。如果 <dest>/ 结尾,则被当作是一个目录, <src> 的内容会被写入该目录。

  • 如果有多个 <src> ,或者使用了通配符,则 <dest> 必须是目录,并以 / 结尾。

  • 如果 <dest> 不是以 / 结尾,则会看作文件名。

  • 如果 <dest> 路径里的目录不存在,则会自动创建。

校验远程文件checksum

语法:

--checksum=<checksum>

例如:

ADD --checksum=sha256:24454f830cdb571e2c4ad15481119c43b3cafd48dd869a9b2945d1036d1dc68d https://mirrors.edge.kernel.org/pub/linux/kernel/Historic/linux-0.01.tar.gz /

注:可用 sha256sum 命令生成checksum:

sha256sum linux-0.01.tar.gz
24454f830cdb571e2c4ad15481119c43b3cafd48dd869a9b2945d1036d1dc68d  linux-0.01.tar.gz

这样,如果文件发生变化,checksum对不上,就会及时报错。

创建 Dockerfile 文件如下:

# syntax=docker/dockerfile:1FROM alpineADD --checksum=sha256:24454f830cdb571e2c4ad15481119c43b3cafd48dd869a9b2945d1036d1dc68d https://mirrors.edge.kernel.org/pub/linux/kernel/Historic/linux-0.01.tar.gz /

注意: # syntax=docker/dockerfile:1 这一行不能缺少,否则会报错:

ERROR: failed to solve: instruction 'ADD --checksum=<CHECKSUM>' requires the labs channel

构建:

docker build -t kai0111_7 .

查看:

docker run kai0111_7 ls -l    
-rw-------    1 root     root         73091 Oct 30  1993 linux-0.01.tar.gz
......

如果文件发生了变化(此处用checksum变化来模拟文件变化,总之都是二者不匹配),构建时报错:

docker build -t kai0111_8 .
......
ERROR: failed to solve: digest mismatch sha256:24454f830cdb571e2c4ad15481119c43b3cafd48dd869a9b2945d1036d1dc68d: sha256:e97d6191145d306c052bb0205e66ad507e934f189edd1b7f58f17ab1a7387fd0

--checksum 只支持HTTP来源的文件。若是本地文件,则会报错。

创建 Dockerfile 文件如下:

# syntax=docker/dockerfile:1FROM alpineADD --checksum=sha256:24454f830cdb571e2c4ad15481119c43b3cafd48dd869a9b2945d1036d1dc68d linux-0.01.tar.gz /

构建,报错如下:

docker build -t kai0111_9 .
......
ERROR: failed to solve: checksum can't be specified for non-HTTP sources

添加Git仓库

语法:

ADD [--keep-git-dir=<boolean>] <git ref> <dir>

例如:

# syntax=docker/dockerfile:1
FROM alpine
ADD --keep-git-dir=true https://github.com/moby/buildkit.git#v0.10.1 /buildkit

注意: # syntax=docker/dockerfile:1 这一行不能缺少,否则会报错:

ERROR: failed to solve: instruction ADD <git ref> requires the labs channel

构建:

docker build -t kai0111_10 .

查看:

docker run kai0111_10 tree -L 1 /buildkit

注:结果很长,不在这里展示了。tree 命令的 -L 1 选项(只显示一层结构)无效,可能是因为alpine image里的 tree 命令做了简化。

--keep-git-dir=true 选项表示是否添加 .git 目录,其默认值是false。

添加私有Git仓库

语法:

ADD git@git.example.com:foo/bar.git /bar

git.weixin.qq.com 为例。

首先在网站上配置好ssh key,确认git clone没有问题:

git clone git@git.weixin.qq.com:dukeding/test0522.git
Cloning into 'test0522'...
sign_and_send_pubkey: signing failed for RSA "/home/ding/.ssh/id_rsa" from agent: agent refused operation
remote: Total 101 (delta 0), reused 101 (delta 0)
Receiving objects: 100% (101/101), 617.38 KiB | 666.00 KiB/s, done.
Resolving deltas: 100% (33/33), done.

创建 Dockerfile 文件如下:

# syntax=docker/dockerfile:1FROM alpineADD git@git.weixin.qq.com:dukeding/test0522.git /dir1

构建:

docker build --ssh default -t kai0111_11 .

注意:多了 --ssh default 选项,如果不加该选项,会报错:

ERROR: failed to solve: failed to load cache key: unset ssh forward key default

查看:

docker run kai0111_11 ls -l dir1
total 16
-rw-r--r--    1 root     root           583 Jan 11 13:41 README.md
drwxr-xr-x    4 root     root            52 Jan 11 13:41 cloudfunctions
drwxr-xr-x    5 root     root           135 Jan 11 13:41 miniprogram
-rw-r--r--    1 root     root          1847 Jan 11 13:41 project.config.json
-rw-r--r--    1 root     root          1722 Jan 11 13:41 project.private.config.json
-rw-r--r--    1 root     root           223 Jan 11 13:41 uploadCloudFunction.bat

注:在RedHat 9.3中,遇到问题:

问题1:

Unable to negotiate with **** port 22: no matching host key type found. Their offer: ssh-rsa

解决方法:

创建 ~/.ssh/config 文件,权限是600。

Host *
HostkeyAlgorithms +ssh-rsa
PubkeyAcceptedKeyTypes +ssh-rsa

参考:

  • https://www.jianshu.com/p/764249229bc4

问题2:

ssh_dispatch_run_fatal: Connection to 212.64.118.180 port 22: error in libcrypto

解决办法:

sudo update-crypto-policies --show
sudo update-crypto-policies --set DEFAULT:SHA1

参考:

  • https://zhuanlan.zhihu.com/p/557504425
  • https://access.redhat.com/articles/3666211

ADD --link

参见我另一篇文档( https://blog.csdn.net/duke_ding2/article/details/135543261 )。

注意:该功能貌似目前被disable了。

COPY

COPY 指令和 ADD 指令大同小异。其差别在于, COPY 指令只能复制本地文件,无法复制远程文件,比如URL远程文件和Git远程仓库。另外, ADD 指令在添加本地文件时,会自动把tar文件解压。

此外, --parent 选项只能用于 COPY ,不能用于 ADD

COPY --parent

语法:

COPY [--parents[=<boolean>]] <src>... <dest>

创建 Dockerfile 文件如下:

# syntax=docker/dockerfile-upstream:master-labsFROM alpineWORKDIR mydirCOPY ./xxx/yyy/a.txt ./xxx/zzz/a.txt dir1/COPY --parents ./xxx/yyy/a.txt ./xxx/zzz/a.txt dir2/

构建:

docker build -t kai0111_12 .

查看:

docker run kai0111_12 tree .
.
├── dir1
│   └── a.txt
└── dir2└── xxx├── yyy│   └── a.txt└── zzz└── a.txt5 directories, 3 files

其中, dir1/a.txt./xxx/zzz/a.txt

注:其行为类似于Linux cp 命令的 --parents 选项:

cp --parents xxx/yyy/a.txt xxx/zzz/a.txt /tmp/tree /tmp/xxx    
/tmp/xxx
├── yyy
│   └── a.txt
└── zzz└── a.txt

但有一点不同:如果没有 --parents 选项,则文件冲突时, cp 命令会报错:

cp xxx/yyy/a.txt xxx/zzz/a.txt /tmp/ 
cp: will not overwrite just-created '/tmp/a.txt' with 'xxx/zzz/a.txt'

COPY 指令则会覆盖文件。

通常layer的数量越少越好,所以可以利用 --parents ,尽量少用 COPY 指令,在指令里包含多个 <src> ,保持目标文件和源文件结构一致。

注: --parents 只对 COPY 有效,在 ADD 指令里使用 --parents 会报错:

ERROR: failed to solve: dockerfile parse error on line 9: unknown flag: parents

使用ADD还是COPY?

前面提到,二者的区别在于, COPY 指令只能复制本地文件,无法复制远程文件,比如URL远程文件和Git远程仓库。另外, ADD 指令在添加本地文件时,会自动把tar文件解压。那么,一般情况下,使用时该如何选择呢?

我的理解是: COPY 包含最基本的“文件复制”功能,而 ADD 包含一些“高级”功能。因此,如果是“高级”用法,则只能用 ADD ,而如果是常规的文件复制,则用 COPY (直观,没有歧义)。

参考

  • https://docs.docker.com/engine/reference/builder
  • https://docs.docker.com/develop/develop-images/instructions/#add-or-copy

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/239656.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

将图片添加到 PDF 的 5 种方法

需要一种称为 PDF 编辑器的特定工具才能将图片添加到 PDF。尽管大多数浏览器在查看和注释 PDF 文件方面都非常出色&#xff0c;但如果您使用图像到 PDF 技术&#xff0c;则只能将照片放入 PDF 中。无需修改即可将 PDF 文件恢复为原始格式的能力是使用此类软件程序甚至在线服务的…

基于Matlab/Simulink开发自动驾驶的解决方案

文章目录 处理自动驾驶数据 仿真自动驾驶场景 设计感知算法 设计规划和控制算法 生成代码和部署算法 集成和测试 参考文献 使用 MATLAB/Simulink开发自动驾驶&#xff0c;能够深入建模真实世界的行为、减少车辆测试并验证嵌入式软件的功能&#xff0c;从而推进自动驾驶感…

基于ssm的线上旅游体验系统+vue论文

目 录 目 录 I 摘 要 III ABSTRACT IV 1 绪论 1 1.1 课题背景 1 1.2 研究现状 1 1.3 研究内容 2 2 系统开发环境 3 2.1 vue技术 3 2.2 JAVA技术 3 2.3 MYSQL数据库 3 2.4 B/S结构 4 2.5 SSM框架技术 4 3 系统分析 5 3.1 可行性分析 5 3.1.1 技术可行性 5 3.1.2 操作可行性 5 3…

安防视频监控系统EasyCVR设备分组中在线/离线数量统计的开发与实现

安防视频监控EasyCVR系统具备较强的兼容性&#xff0c;它可以支持国标GB28181、RTSP/Onvif、RTMP&#xff0c;以及厂家的私有协议与SDK&#xff0c;如&#xff1a;海康ehome、海康sdk、大华sdk、宇视sdk、华为sdk、萤石云sdk、乐橙sdk等。EasyCVR平台可覆盖多类型的设备接入&am…

05.neuvector网络学习与管控实现

原文链接&#xff0c;欢迎大家关注我的github 一、网络的策略学习 1.1.非主机模式的网络连接学习 agent进程侧&#xff1a; 调用taskAddContainer->taskInterceptContainer->programDP->DPCtrlAddTapPort为所有非host模式的容器向dp传送 DPAddTapPortReq对象数据.&…

第 3 场 蓝桥杯小白入门赛 解题报告 | 珂学家 | 单调队列优化的DP + 三指针滑窗

前言 整体评价 T5, T6有点意思&#xff0c;这场小白入门场&#xff0c;好像没真正意义上的签到&#xff0c;整体感觉是这样。 A. 召唤神坤 思路: 前后缀拆解 #include <iostream> #include <algorithm> #include <vector> using namespace std;int main()…

爬虫案例—抓取豆瓣电影的电影名称、评分、简介、评价人数

爬虫案例—抓取豆瓣电影的电影名称、评分、简介、评价人数 豆瓣电影网址&#xff1a;https://movie.douban.com/top250 主页截图和要抓取的内容如下图&#xff1a; 分析&#xff1a; 第一页的网址&#xff1a;https://movie.douban.com/top250?start0&filter 第二页的…

时间差异导致数据缺失,如何调整Grafana时间与Prometheus保持同步?

Grafana时间如何调快或调慢&#xff1f; 在k8s环境中&#xff0c;常使用prometheusgrafana做监控组件&#xff0c;prometheus负责采集、存储数据&#xff0c;grafana负责监控数据的可视化。 在实际的使用中&#xff0c;有时会遇到这样的问题&#xff0c;k8s集群中的时间比真实…

unity C#中使用ref、out区别和使用案例

文章目录 ref 关键字out 关键字 在Unity&#xff08;以及C#编程语言中&#xff09;&#xff0c; ref 和 out 都是用来传递参数的引用&#xff0c;这意味着它们允许函数修改实参变量&#xff0c;并且这些修改会反映到调用函数的地方。但它们之间确实存在一些关键区别和使用场景…

【数据结构 | 直接选择排序】

直接选择排序 基本思路直接插入排序SelectSort 基本思路 直接插入排序&#xff08;StraightInsertionSort&#xff09;的基本操作是将一个记录插入到已经排好序的有序表中&#xff0c;从而得到一个新的、记录数增1的有序表。 我们可以同时从数组的头部和尾部同时进行排序工作…

Jenkins集成Sonar Qube

下载插件 重启Jenkins 容器 sonarqube 使用令牌 Jenkins 配置 重新构建

智能合约笔记

前言&#xff1a; 首先了解下为什么会出现智能合约&#xff0c;打个比方现在有两个人A和B打赌明天会不会下雨&#xff0c;每个人赌注100元&#xff0c;如果第二天下雨则A拿走200元&#xff0c;否则B拿走200元&#xff0c;这样就有一个问题&#xff0c;赌注要到第二天才能见效&…

每日一题——LeetCode1189.气球的最大数量

方法一 个人方法&#xff1a; 统计text字符串中b、a、l、o、n 这几个字符出现的次数 l和n需要两个才能拼成一个balloon&#xff0c;所以碰到l和o加1&#xff0c;其他字符加2 最后求出出现次数最少的那个字符再除以2就是能拼凑成的单词数量&#xff0c;避免出现小数要使用向下…

MySQL 从零开始:04 增删改查

文章目录 1、准备工作2、insert 增加数据2.1 添加所有列的数据2.2 添加部分列2.3 一次插入多条数据 3、delete 删除记录4、update 更新记录5、select 查询记录5.1 查询所有行所有列5.2 查询指定行的所有列5.3 查询所有行的指定列5.4 查询指定行的指定列 在上一小节中介绍了 MyS…

leetcode第365题:水壶问题

有两个水壶&#xff0c;容量分别为 jug1Capacity 和 jug2Capacity 升。水的供应是无限的。确定是否有可能使用这两个壶准确得到 targetCapacity 升。 如果可以得到 targetCapacity 升水&#xff0c;最后请用以上水壶中的一或两个来盛放取得的 targetCapacity 升水。 你可以&a…

C练习——杨辉三角

题目&#xff1a; 打印近似杨辉三角&#xff0c;行数n自选 百度找的杨辉三角&#xff0c;参考一下&#xff1a; 解析&#xff1a; 把它的全部元素左对齐&#xff0c;就可以看成近似杨辉三角的样子 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 …… 每个数等于它上方两数…

第一个 OpenGL 程序:旋转的立方体(VS2022 / MFC)

文章目录 OpenGL API开发环境在 MFC 中使用 OpenGL初始化 OpenGL绘制图形重置视口大小 创建 MFC 对话框项目添加 OpenGL 头文件和库文件初始化 OpenGL画一个正方形OpenGL 坐标系改变默认颜色 重置视口大小绘制立方体使用箭头按键旋转立方体深度测试添加纹理应用纹理换一个纹理 …

随笔03 笔记整理

图源&#xff1a;文心一言 关于我的考研与信息安全类博文整理~&#x1f95d;&#x1f95d; 第1版&#xff1a;整理考研类博文~&#x1f9e9;&#x1f9e9; 第2版&#xff1a;提前列出博文链接&#xff0c;以便小伙伴查阅~&#x1f9e9;&#x1f9e9; 第3版&#xff1a;整理We…

SLF4J Spring Boot日志框架

JAVA日志框架 JAVA有好多优秀的日志框架&#xff0c;比如log4j、log4j2、logback、JUL&#xff08;java.util.logging&#xff09;、JCL&#xff08;JAVA Common Logging&#xff09;等等&#xff0c;logback是后起之秀&#xff0c;是Spring Boot默认日志框架。 今天文章的目…

快速了解——逻辑回归及模型评估方法

一、逻辑回归 应用场景&#xff1a;解决二分类问题 1、sigmoid函数 1. 公式&#xff1a; 2. 作用&#xff1a;把 (-∞&#xff0c;∞) 映射到 (0&#xff0c; 1) 3. 数学性质&#xff1a;单调递增函数&#xff0c;拐点在x0&#xff0c;y0.5的位置 4. 导函数公式&#xff1a;f…