Background
最近在项目上工作的时候,发现Dockerfile中引入的镜像长这个样子:
FROM node:12.18.4-alpine@sha256:757574c5a2102627de54971a0083d4ecd24eb48fdf06b234d063f19f7bbc22fb
EXPOSE 3000
根据我的认知,一个docker image应该是这样组成的:
[repository:tag]
or
repository
那么@
之后是什么呢?
@之后就是所谓的digest
What is digest?
根据官网给出的定义是:
使用V2以及V2以上格式的镜像将会有一个叫做digest的内容可寻址标识符。
根据定义来看,这个digest
其实就是就是根据镜像内容产生的一个ID,官网上说,只要用于产生这个image的输入不变,那么digest就是可以预测的,换句话说只要镜像的内容不变digest也不会变。
当你使用docker build构建镜像的时候,docker会根据内容产生一个digest,比如使用下面这个指令就会输出这个镜像的digest
$ docker build --no-cache -q .
当你使用docker push将这个镜像push到register,这个digest的信息也会跟着镜像被一起存储。
但你使用docker pull将这个镜像pull到本地的时候,你可以将这个image的repository、tag、digest全部带上,唯一的确定这个镜像。
Why we use digest?
当你从网络上下载内容某一个包,如果你想要保证下载的包是完整性并且没有被恶意篡改过,常用的方式就是根据这个包的内容,为这个包生成加密哈希串。可以通过对比这个加密哈希串来保证内容没有被改变过。
这个哈希串就是content adressable identifier(内容可识别标识符)
.
验证方式可以是:
- 从网络上下载一个package
- 根据下载下来的packgae的内容计算出这package的
sha256 hash
- 对比我期待的hash值和计算出的hash值,如果不一致,说明内容被篡改过
想象一个场景:
你向docker-hub中push了一个镜像my-app:v1.0.0,但是你的Docker Hub credentials被人盗取了,这个人可能会将一段恶意代码植入了你的镜像,并且使用带有恶意代码的镜像覆盖了v1.0.0这个镜像版本。
但是你的production,只是pull了my-app:v1.0.0
,并且运行这个镜像,并没有考虑内容是否和以前一样,这时候你的production可能那个已经被恶意代码侵害了。
那么在这种场景下,docker digest能如何帮助我们躲避这种风险呢?
如果你的production不只是定义了版本,而是pull下了这样的镜像
my-app@sha256:saklfjdksajfkdsajfkladsjlfkjdskl
也就是将digest(内容id)带上, docker会帮助我们:
- pull下digest是这个值的镜像
- 计算pull下镜像的sha256,并且对比计算出的结果是否和上面给出的digest一致。
The pros of docker Digest
-
pull镜像的时候,将docker digest带上,而不是只带tag,可以保证我们pull下来的image不会是被篡改过的(因为篡改过的镜像digest肯定不同),帮助我们原理tag被override的风险。
-
pull镜像的时候,将docker digest带上,即使黑客使用手段将某一个digest对应的内容强行修改了,docker也能check出来,因为docker会在pull下镜像的时候,只要根据image的内容计算sha256
-
pull镜像的时候,将docker digest带上可以保证系统的稳定性,通常在prod使用镜像的时候,会推荐大家将确定的tag(而不是latest)带上,这样确保了我们使用的镜像一定是锁定好的某一个版本,同样的到时带上digest更加能够保障我们使用的镜像和我们期待的是同一个版本。
-
提高了
docker pull
的可缓存性,只要digest不变,镜像的内容一定不变,因此如果你想要pull一个带有digest的镜像,docker发现本地有就可以直接使用。
网友评论