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.mzph.cn/news/628412.shtml

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

相关文章

C++核心编程之类和对象---C++面向对象的三大特性--多态

目录 一、多态 1. 多态的概念 2.多态的分类&#xff1a; 1. 静态多态&#xff1a; 2. 动态多态&#xff1a; 3.静态多态和动态多态的区别&#xff1a; 4.动态多态需要满足的条件&#xff1a; 4.1重写的概念&#xff1a; 4.2动态多态的调用&#xff1a; 二、多态 三、多…

散列函数,哈希表hash table

附上一句话&#xff1a;我知道大家可能曾经了解过这个散列表了&#xff0c;我发现&#xff0c;如果多看几个相关的视频&#xff0c;从不同的表述方式和不同的理解角度来理解这个问题&#xff0c;我会明白的更透彻&#xff0c;也有更多新的收获&#xff0c;尤其是对这个算法的应…

【PostgreSQL】安装和常用命令教程

PostgreSQL window安装教程 window安装PostgreSQL 建表语句&#xff1a; DROP TABLE IF EXISTS student; CREATE TABLE student (id serial NOT NULL,name varchar(100) NOT NULL,sex varchar(5) NOT NULL,PRIMARY KEY (id) );INSERT INTO student (id, name, sex) VALUES (…

无人超市系统的设计与实现:从需求分析到实际应用

✍✍计算机编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java实战 |…

Python超详细基础文件操作(详解版)

一、文件操作 1. 文件打开与关闭 1.1 打开文件 在Python中&#xff0c;你可以使用 open() 函数来打开文件。 以下是一个简单的例子&#xff1a; # 打开文件&#xff08;默认为只读模式&#xff09; file_path example.txt with open(file_path, r) as file:# 执行文件操作…

C语言天花板——指针(进阶2)

好久不见了各位&#xff0c;甚是想念啊&#xff01;&#xff01;&#xff01;&#x1f3b6;&#x1f3b6;&#x1f3b6; 文章接上次的指针(进阶1)(http://t.csdnimg.cn/c39SJ)&#xff0c;我们继续发车咯&#x1f697;&#x1f697;&#x1f697; 五、函数指针 上次我们只是浅…

网卡唯一标识你了解吗?MAC地址详解

本文内容&#xff1a; MAC地址概述 MAC地址组成 单播、组播、广播MAC地址 本地管理和全球管理MAC地址 一、MAC地址概述 MAC地址&#xff08;Media Access Control Address&#xff09;的全称叫做媒体访问控制地址&#xff0c;也称作局域网地址&#xff0c;以太网地址或者物…

爆了,AI表情包制作全攻略揭秘

今天来一篇绝对的干货 在AI如火如荼的今天&#xff0c;各行各业各个领域都有AI的身影&#xff0c;今天给大家一篇AI制作表情包的教程&#xff0c;希望大家都能在AI的浪潮中找到自己的位置 一、制作篇 正常来说需要使用 midjourney&#xff0c;但是目前限制比较多&#xff0c…

【Vue3】3-2 : 组件的概念及组件的基本使用方式

本书目录&#xff1a;点击进入 一、组件的概念 1.1、为什么要做成组件 1.2、【案例】评分组件与按钮组件的抽离过程 二、组件的使用 - 抽离结构 2.1、【案例】简易首页 &#xff1e; 效果 &#xff1e; 代码 - 原始 &#xff1e; 代码 - 组件抽离结构 &#xff1e;…

如何在Windows 10/11的防火墙中禁止和允许某个应用程序,这里提供详细步骤

想阻止应用程序访问互联网吗&#xff1f;以下是如何通过简单的步骤阻止和允许Windows防火墙中的程序。​ 一般来说&#xff0c;大多数用户永远不需要担心应用程序访问互联网。然而&#xff0c;在某些情况下&#xff0c;你需要限制应用程序访问互联网。 例如&#xff0c;有问题…

jmeter--4.参数化的方式

目录 1. 用户定义的变量 2. 用户参数 3. 函数助手 3.1 time获取当前时间 3.2 Random随机数 3.3 随机字符串函数 3.4 字符串变更为大写 4. CSV数据文件设置 5. 接口关联--正则和json等提取 1. 用户定义的变量 线程组->添加->配置元件->用户定义的变量 引用方…

安达发|APS工序排程甘特图功能介绍

工序排程甘特图的主要功能 1. 显示工序时间安排&#xff1a;工序排程甘特图可以清晰地展示生产过程中各个工序的开始时间、结束时间和持续时间&#xff0c;从而帮助企业了解生产过程中各个环节的时间安排。 2. 显示工序进度情况&#xff1a;通过工序排程甘特图&#xff0c;企业…

计算机毕业设计-----SSH高校科研管理系统平台

项目介绍 本项目包含超级管理员、管理员、教师三种角色&#xff1b; 超级管理员角色包含以下功能&#xff1a; 登录,教师管理,管理员管理等功能。 管理员角色包含以下功能&#xff1a; 登录,专业参赛奖项管理,科技论文发表管理,出版专业著作管理,科研项目立项管理,科研项目结…

数据结构--排序

参考【算法】排序算法之希尔排序 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/122632213 1. 排序的定义 2. 插入排序 2.1 直接插入排序 在插入第i&#xff08;i>1)个记录时&#xff0c;前面的i-1个记录已经排好序 void insertSort(int r[],int n) {for(int i2;i<…

《WebKit 技术内幕》之二: HTML 网页和结构

第二章 HTML 网页和结构 HTML网页是利用HTML语言编写的文档&#xff0c;HTML是半结构化的数据表现方式&#xff0c;它的结构特征可以归纳为&#xff1a;树状结构、层次结构和框结构。 1.网页构成 1.1 基本元素和树状结构 HTML网页使用HTML语言撰写的文档&#xff0c;发展到今…

合适的索引顺序

一.前言 正确的顺序依赖于使用索引的查询,并且同时需要考虑如何更好地满足排序和分组的需要。因为哈希或者其他类型的索引并不会像 B-Tree索引一样顺序存储数据,所以这里只针对B-Tree展开讨论。 二.合适的索引顺序 1. 概念 对于如何选择索引顺序有一个经验法则: 将选择性最…

hcip-4

ISIS:中央系统到中央系统 基于OSI模型开发&#xff1b; 集成的ISIS&#xff0c;基于OSI开发后转移到TCP/IP模型执行&#xff1b; 故集成的ISIS既可以在OSI模型&#xff0c;也可在TCP/IP模型工作&#xff1b; ISIS是在ISP中使用的一个IGP协议&#xff0c;其归属于无类别链路状…

HashData湖仓一体方案:方案概览与Hive数据同步

随着云计算、大数据、AI的发展和普及&#xff0c;各行各业的业务场景日益复杂&#xff0c;数据呈现出大规模、多样性的特点&#xff0c;企业对数据仓库的需求也进一步拓展至对多元化数据实时处理的场景。 数据湖是多元数据存储与使用的便捷选择&#xff0c;而云原生具有数据资…

谷歌aab包在Android 14闪退而apk没问题(targetsdk 34)

问题原因 Unity应用(target SDK 34)上线到GooglePlay&#xff0c;有用户反馈fold5设备上&#xff08;Android14系统&#xff09;疯狂闪退&#xff0c;经测试&#xff0c;在小米手机Android14系统的版本复现成功了&#xff0c;奇怪的是apk直接安装没问题&#xff0c;而打包成aa…

浙大恩特客户资源管理系统CrmBasicAction.entcrm接口存在任意文件上传漏洞

@[toc] 免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该文章仅供学习用途使用。 1. 浙大恩特客户资源管理系统接口简介 微信公…