docker pull 本地镜像 docker pull 国内镜像_tomcat

结论

1.容器镜像版本的管理,生产环境大量使用tag是不合适的。

2.容器镜像版本管理使用digest管理,其准确性高于tag。

3.一个容器镜像的digest,在一个固定的环境中、固定的registry中,其sha256是恒定不变的。本质上,RepoDigest值并不是image的不变属性,它们是image存储方式/位置的属性(例如,取决于压缩实现的特定版本:podman还是docker的pull可能导致使用不同的RepoDigest值,而RepoDigest 显然取决于目标registry主机和存储库名称)。例如,docker load会直接消除镜像的RepoDigest。

4.如果想在registry中的副本之间保留完全相同的image digest,那么就不要使用docker/poman {push,pull,save,load}。在多个不同的镜像仓库之间,使用skopeo copy有助于保证容器镜像digest的一致性。

容器镜像拉取

容器镜像,从使用人员的角度,使用tag的方式拉取肯定是最方便和直观的。红帽官网的镜像,提供docker和podman的拉取方式,如:JWS3.1:

docker pull 本地镜像 docker pull 国内镜像_docker pull 国内镜像_02

在网站上,我们可以看到所有镜像tag的列表:

docker pull 本地镜像 docker pull 国内镜像_docker_03

但是,tag所对应的真正容器镜像并不是固定的。比如latest tag对应的镜像,就会随着时间的推移发生变化。

我们举个例子,使用tag为1.0的docker部署,先pull再run:

docker pull 本地镜像 docker pull 国内镜像_docker_04



docker pull 本地镜像 docker pull 国内镜像_docker_05

现在假设经过了任意时间,让我们再次运行它。

docker pull 本地镜像 docker pull 国内镜像_tomcat_06

容器镜像run起来后,版本变为2?很显然,有人错误地标记了image。

现在,在部署相同的情况下,如果我们按image的digest值提取数据,则可以100%保证无论是今天还是几年后,都可以提取完全相同的image,而不管采用常规标记。SHA值实际上成为image的标签。

我们拉取最新的红帽JWS3.1镜像(不写tag默认就拉latest)先以podman方式拉取:

[root@repo ~]# podman pull registry.access.redhat.com/jboss-webserver-3/webserver31-tomcat8-openshiftTrying to pull registry.access.redhat.com/jboss-webserver-3/webserver31-tomcat8-openshift...Getting image source signaturesCopying blob f897b9608c98 doneCopying blob faa04077df6f doneCopying blob 99a353860a26 doneCopying blob c9ff3e9281bc doneCopying config 44cb270a74 doneWriting manifest to image destinationStoring signatures44cb270a74c90da1fe27a69fbcdcbd06dd97cf383d45ef0860dff82bd67159b1[root@repo ~]# podman images |grep -i webserver31-tomcat8-openshiftregistry.access.redhat.com/jboss-webserver-3/webserver31-tomcat8-openshift   latest                                                                    44cb270a74c9   5 weeks ago     579 MB我们通过命令行确认digest:[root@repo ~]# podman inspect registry.access.redhat.com/jboss-webserver-3/webserver31-tomcat8-openshift | jq '.[]["Digest"]'"sha256:b22c3fea4374e776366d2363184a854b8ba47539df0d02b6907f1e7816d4587f"

我们再以docker的方式进行拉取:

[root@repo ~]# docker pull registry.access.redhat.com/jboss-webserver-3/webserver31-tomcat8-openshiftUsing default tag: latestTrying to pull repository registry.access.redhat.com/jboss-webserver-3/webserver31-tomcat8-openshift ...latest: Pulling from registry.access.redhat.com/jboss-webserver-3/webserver31-tomcat8-openshiftc9ff3e9281bc: Pull completef897b9608c98: Pull complete99a353860a26: Pull completefaa04077df6f: Pull completeDigest: sha256:a4c2a8a314c2d3ade2d7c2b5565bc463ce89eb86d646931a6a9a46b4cb4d6549Status: Downloaded newer image for registry.access.redhat.com/jboss-webserver-3/webserver31-tomcat8-openshift:latest

查看digest:

[root@repo ~]# docker images --digestsREPOSITORY                                                                   TAG                 DIGEST                                                                    IMAGE ID            CREATED             SIZEregistry.access.redhat.com/jboss-webserver-3/webserver31-tomcat8-openshift   latest              sha256:a4c2a8a314c2d3ade2d7c2b5565bc463ce89eb86d646931a6a9a46b4cb4d6549   44cb270a74c9        5 weeks ago         548 MB

结论:针对相同的镜像:registry.access.redhat.com/jboss-webserver-3/webserver31-tomcat8-openshift:latest:

  • 通过podman拉取到本地,查看到的digest是:b22c3fea4374e776366d2363184a854b8ba47539df0d02b6907f1e7816d4587f
  • 通过docker拉取到本地,查看到的digest是:a4c2a8a314c2d3ade2d7c2b5565bc463ce89eb86d646931a6a9a46b4cb4d6549

那么,为什么同一个镜像,用podman和docker拉取下来,digest的哈希数值不同呢?

RepoDigest值是否是恒定不变

RepoDigest值不是image的不变属性,它们是image存储方式/位置的属性(例如,取决于压缩实现的特定版本:podman还是docker的pull可能导致使用不同的RepoDigest值,而RepoDigest 显然取决于目标注册表主机和存储库名称)。在docker pull中,在拉取image以记录拉取操作的源时设置RepoDigest。

但是,如果想在registry中的副本之间保留完全相同的image,那么就不要使用docker/poman {push,pull,save,load},所有这些操作本质上都涉及某种格式转换/压缩或类似的操作。

我们举例说明,对docker进行进行docker save操作,再查看Digest,变成了e5279c49f93a212cbba3f6640430ab5be982f3afda8eacd45e9f9085f0eaa950

[root@repo ~]# docker save  registry.access.redhat.com/jboss-webserver-3/webserver31-tomcat8-openshift > docker-export.tar [root@repo ~]# skopeo inspect docker-archive:docker-export.tar | jq ".Digest""sha256:e5279c49f93a212cbba3f6640430ab5be982f3afda8eacd45e9f9085f0eaa950"

将系统中此前的镜像删除,

[root@repo /]# docker image rm registry.access.redhat.com/jboss-webserver-3/webserver31-tomcat8-openshiftUntagged: registry.access.redhat.com/jboss-webserver-3/webserver31-tomcat8-openshift:latestUntagged: registry.access.redhat.com/jboss-webserver-3/webserver31-tomcat8-openshift@sha256:a4c2a8a314c2d3ade2d7c2b5565bc463ce89eb86d646931a6a9a46b4cb4d6549Deleted: sha256:44cb270a74c90da1fe27a69fbcdcbd06dd97cf383d45ef0860dff82bd67159b1Deleted: sha256:2f7286327cfe29abd7851d89d84caead89c2f5cd2983bdd144644e38660ea58dDeleted: sha256:bc028cb10e3d2902b70f62404b61651e987a359d0a924b0cba45eeade7e9c7efDeleted: sha256:940311032c0be435b65a79251b988c620f32a49e4a9a4415d53cde0ac45b3e9bDeleted: sha256:49577de6730168df9aef3494209d7618ebdbbc631977f4779fa3d4d079d91dd5

然后加载tar镜像后,再查看digest,是无法直接显示的:

[root@repo /]# docker load -i docker-export.tar49577de67301: Loading layer [==================================================>] 215.1 MB/215.1 MBd02565babdb9: Loading layer [==================================================>] 10.24 kB/10.24 kB59edfeaca1c1: Loading layer [==================================================>] 273.6 MB/273.6 MBcca5cf884bc1: Loading layer [==================================================>] 90.15 MB/90.15 MBLoaded image: registry.access.redhat.com/jboss-webserver-3/webserver31-tomcat8-openshift:latest[root@repo /]# docker images --digestsREPOSITORY                                                                   TAG                 DIGEST              IMAGE ID            CREATED             SIZEregistry.access.redhat.com/jboss-webserver-3/webserver31-tomcat8-openshift   latest                            44cb270a74c9        5 weeks ago         548 MB

原因是:docker load不涉及来自registry的pull,因此无法记录任何RepoDigests;最多只能有一个路径名。

如何避免RepoDigest值变化的问题

在上文中,我们通过podman pull下来了镜像,放到了本地(b22c3fea4374e776366d2363184a854b8ba47539df0d02b6907f1e7816d4587f)。接下来,我们推动到以podman方式运行的docker registry中。先打tag,打完tag后,我们查新tag的镜像,它的digest没有发生变化。

[root@repo webserver31-tomcat8-openshift]#  podman inspect registry.access.redhat.com/jboss-webserver-3/webserver31-tomcat8-openshift | jq '.[]["Digest"]'"sha256:b22c3fea4374e776366d2363184a854b8ba47539df0d02b6907f1e7816d4587f[root@repo webserver31-tomcat8-openshift]# podman psCONTAINER ID  IMAGE                         COMMAND               CREATED      STATUS         PORTS                   NAMES53b6aa7b5023  docker.io/library/registry:2  /entrypoint.sh /e...  5 weeks ago  Up 4 days ago  0.0.0.0:5000->5000/tcp  mirror-registry[root@repo webserver31-tomcat8-openshift]# podman tag registry.access.redhat.com/jboss-webserver-3/webserver31-tomcat8-openshift:latest  repo.ocp4.example.com:5000/jboss-webserver-3/webserver31-tomcat8-openshift:latest[root@repo webserver31-tomcat8-openshift]#  podman inspect repo.ocp4.example.com:5000/jboss-webserver-3/webserver31-tomcat8-openshift:latest | jq '.[]["Digest"]'"sha256:b22c3fea4374e776366d2363184a854b8ba47539df0d02b6907f1e7816d4587f"[root@repo webserver31-tomcat8-openshift]# podman push repo.ocp4.example.com:5000/jboss-webserver-3/webserver31-tomcat8-openshift:latestGetting image source signaturesCopying blob d02565babdb9 doneCopying blob 59edfeaca1c1 doneCopying blob 49577de67301 doneCopying blob cca5cf884bc1 doneCopying config 44cb270a74 doneWriting manifest to image destination

此时,我们将本地缓存的镜像删除,然后从podman运行的docker registry中拉取镜像,再次查看,镜像的digest发生了变化:

[root@repo webserver31-tomcat8-openshift]# podman pull  repo.ocp4.example.com:5000/jboss-webserver-3/webserver31-tomcat8-openshift:latestTrying to pull repo.ocp4.example.com:5000/jboss-webserver-3/webserver31-tomcat8-openshift:latest...Getting image source signaturesCopying blob a660e1760a3a skipped: already existsCopying blob 246226c3ec30 skipped: already existsCopying blob 01caf8c9797a skipped: already existsCopying blob 5bd0fbc2f2ce skipped: already existsCopying config 44cb270a74 doneWriting manifest to image destinationStoring signatures44cb270a74c90da1fe27a69fbcdcbd06dd97cf383d45ef0860dff82bd67159b1[root@repo webserver31-tomcat8-openshift]# podman inspect repo.ocp4.example.com:5000/jboss-webserver-3/webserver31-tomcat8-openshift:latest | jq '.[]["Digest"]'"sha256:e5279c49f93a212cbba3f6640430ab5be982f3afda8eacd45e9f9085f0eaa950"

镜像的digest从从b22c3fea4374e776366d2363184a854b8ba47539df0d02b6907f1e7816d4587f变化成为了:e5279c49f93a212cbba3f6640430ab5be982f3afda8eacd45e9f9085f0eaa950。

也就是多说,podman tag没有使镜像的digest发生变化,但pull/push的操作会使digest发生变化。

要规避这种问题,在不同的镜像仓库之间同步镜像时,尽量使用skopeo copy。而不是docker/podman save load push pull。

例如,我们有两个ocp集群,第一个负责DEV/TEST/SIT/UAT,第二个负责生产。那么在pipeline中,就需要书写镜像拷贝的步骤,如下图所示:

docker pull 本地镜像 docker pull 国内镜像_docker_07