OpenShift 4 概念 - OpenShift是如何通过ImageStream访问Image的

OpenShift 4.x HOL教程汇总
说明:本文已经在OpenShift 4.6环境中验证


有关ImageStream的入门操作可参见:
OpenShift 4 Hands-on Lab (3) - 用ImageStream操作Image

ImageStream基本概念

容器镜像存储在镜像注册表中(如Docker Hub、Quay.io),我们可以从那里手动pull出来单独运行,也可以在Kubernetes集群中运行。Kubernetes没有内置的镜像注册表,然而这在企业环境中又是通常是需要的。Red Hat OpenShift 提供了一个开箱即用的集成注册表来填补这一空白,并引入了一个名为ImageStream的新的Kubernetes对象资源,以“Kubernetes-native方式”管理镜像。

ImageStream 是为了支持不同用途而设计的。但在一开始,某些内容可能会让人感到困惑。技术上来说,ImageStream只是一个包含其它实际镜像元数据的Kubernetes对象资源,它可以指向OpenShift管理内部的镜像(是在OpenShift集群内部Registry中的镜像),ImageStream还可以指向外部Registry中的镜像。对于镜像,ImageStream是一个额外的抽象层,它提供了一些额外的功能(例如轮询更新、缓存)。由于 ImageStream 可以有两种不同的行为方式,如果我们区分它们是指向内部镜像还是指向外部镜像,就更容易理解它们。

OpenShift在生成ImageStream的时候,过程大致如下:

  1. OpenShift将提供的Image访问地址当做ImageStreamTag,并通过访问地址获得Image其它元数据,其中包括ImageStreamImage信息。
  2. OpenShift将ImageStreamTag和ImageStreamStream作为重要元数据保存在这个Image对应的ImageStream。

OpenShift应用在使用ImageStream的时候,缺省过程大致如下:

  1. OpenShift根据应用提供的ImageStreamTag在ImageStream中找到对应的ImageStreamImage
  2. OpenShift然后使用ImageStreamImage从远程Registry上pull image,这样就可以使用该Image了

以上是缺省生成ImageStream和通过ImageStream使用Image的过程。除此以外可以定制ImageStream的配置,可以实现以下定制过程:

  1. OpenShift每次使用的Image的时候不使用本地ImageStream中的ImageStreamImage,而是每次都用ImageStreamTag从外部获取一次ImageStreamImage,然后再根据获取到的ImageStreamImage来pull image。
  2. OpenShift在使用ImageStreamImage获取image的时候,缺省每次都从外部pull image,但也可以选择使用已经pull到本地的Image。

Internal Image 和 External Image

Internal Image 和 Internal Registry

首先,下面是关于存储在Internal Registry中的Image的一些注意事项:
在这里插入图片描述

  1. 对于OpenShift内部Registry上的Image,ImageStream和内部Registry是紧密耦合的。例如,is-project命名空间中名为myimage-internal的ImageStream会被映射到image-registry.openshift-image-registry.svc:5000/is-project/myimage-internal。
  2. 如果我们运行一个新的Build,其中output指定的是ImageStream类型,那么镜像将被存储在OpenShift内部注册表中。(【引用#1】如果Build的output指定的是DockerImage类型,那么OpenShift会使用push操作将Image推送到标准的Docker Registry,缺省是DockerHub)。另外同理适用于指定Builder Image的来源。
  3. 如果我们使用Push方法手动向Internal Image Registry推送一个Image,OpenShift会自动创建一个匹配的ImageStream并指向这个Internal Image Registry中的Image。
  4. 如果我们删除了ImageStream,在OpenShift内部的Registry中保存的Image存储也会被删除。
  5. 为了保持OpenShift内部Registry的使用空间,你需要定期Prune Images。在这个过程中,那些在Build或Deployment中被使用到的内部Image会自动保留。

External Image 和 External Registry

在OpenShift之外的External Registry保存了外部Image。ImageStream和External Registry、以及其上的外部Image的关系如下:
在这里插入图片描述

  1. 我们可以用 oc import-image 或 oc tag 命令创建一个指向外部 Image 的 ImageStream,或者直接用 yaml 创建一个 ImageStream。
  2. 一个ImageStream中的标签可以指向来自完全不同的Registry和Repository的Image。通过这种有效的方法可以将相关的外部Image关联起来,而Image可存储在不同的Registry存储库中。
  3. 作为一个抽象层,ImageStream隐藏了Image的实际来源。当构建和部署引用一个ImageStream时,我们可以通过修改ImageStream中的URL来改变正在使用的Image,而不是逐一编辑OpenShift的每个构建和部署。
  4. 当创建或更新Image时,ImageStream 通过其唯一的 sha256 ID(而非Tag)来引用Image 。这使得当外部Registry变化标签的时候,其使用的Image可保持稳定性。
  5. ImageStream 可以定期(15 分钟)监控外部标记是否发生变化(通过–scheduled=true)。
  6. 我们可以在内部Registry中缓存外部Image(通过–reference-policy=local)。这真的很有用,因为它可以使部署更加快速,并且不受外部Registry可用性的影响。
  7. 无论是内部还是外部Image,在ImageStream更新时会自动触发相关的BuildConfigs和DeploymentConfigs。。

确定ImageStream指向的目标和方式

我们可以把OpenShift的ImageStream看成是一个指向Image的指针(当然还有一些其它元数据),ImageStream指向的Image目标可以是多种不同类型的目标,它们包括:

  1. 指向一个external image
  2. 通过pullthrough 指向一个被缓存的external image
  3. 总是使用一个external image的URL
  4. 指向一个internal image
  5. 指向另一个ImageStream

指向External Image

我们可以用以下“oc import-image”命令或“oc tag”命令创建一个存放在is-project下的ImageStream,并让它指向外部Image,这个外部Image就是docker.io/balazsszeti/hello:sleeper。

$ oc new-project is-project
$ oc import-image is-project/myimage-ref-source:mytag --from="docker.io/balazsszeti/hello:sleeper" --confirm
$ oc tag docker.io/balazsszeti/hello:sleeper is-project/myimage-ref-source:mytag

然后我们可以查看这个ImageStream和ImageStreamTag的详细信息。

$ oc get is myimage-ref-source -oyaml
apiVersion: image.openshift.io/v1
kind: ImageStream
metadata:
  annotations:
    openshift.io/image.dockerRepositoryCheck: "2020-04-12T08:18:25Z"
  creationTimestamp: "2020-04-12T08:18:25Z"
  generation: 1
  name: myimage-ref-source
  namespace: is-project
  resourceVersion: "2844402"
  selfLink: /apis/image.openshift.io/v1/namespaces/is-project/imagestreams/myimage-ref-source
  uid: 2e541461-7c96-11ea-8ba8-0a580a81000f
spec:
  lookupPolicy:
    local: false
  tags:
  - from:
      kind: DockerImage
      name: docker.io/balazsszeti/hello:sleeper
    importPolicy: {}
    name: mytag
    referencePolicy:
      type: Source
status:
  dockerImageRepository: image-registry.openshift-image-registry.svc:5000/is-project/myimage-ref-source
  publicDockerImageRepository: default-route-openshift-image-registry.apps.cluster-beijing-78c7.beijing-78c7.example.opentlc.com/is-project/myimage-ref-source
  tags:
  - items:
    - created: "2020-04-12T08:18:25Z"
      dockerImageReference: docker.io/balazsszeti/hello@sha256:42957024b43e121a210a1b3a8a44f497233a2385f7ef48227a6866afdb9b8e1b
      generation: 1
      image: sha256:42957024b43e121a210a1b3a8a44f497233a2385f7ef48227a6866afdb9b8e1b
    tag: mytag
 
$ oc get istag
NAME                       IMAGE REF                                                                                             UPDATED
myimage-ref-source:mytag   docker.io/balazsszeti/hello@sha256:42957024b43e121a210a1b3a8a44f497233a2385f7ef48227a6866afdb9b8e1b   10 minutes ago
  1. 名为mytag的ImageSteamTag指向的是DockerImage类型的External Image,外部镜像URL(名称+Tag)是docker.io/balazsszeti/hello:sleeper。
  2. 这个ImageSteam的mytag实际指向的外部Image是由dockerImageReference所指的sha256 ID,即下面的字符串。在生成ImageStreamTag的时候,OpenShift是使用了docker.io/balazsszeti/hello:sleeper获得的该Image的sha256 ID。这样当在build或deployment命令中引用ImageStreamTag来创建Pod的时候,实际上使用的是用sha256 ID代表的Image。
 docker.io/balazsszeti/hello@sha256:42957024b43e121a210a1b3a8a44f497233a2385f7ef48227a6866afdb9b8e1b
  1. 每次通过ImageSteamTag使用Image的时候使用的是source类型的referencePolicy,即直接从source访问Image。因此如果当时网络不通,则无法访问该Image。
  2. 当生成ImageSteamTag指向sha256 ID后,修改升级外部镜像的tag就不再影响ImageSteamTag了,也就是说即便把外部镜像从“docker.io/balazsszeti/hello:sleeper”改为“docker.io/balazsszeti/hello:sleeper-v1”,只要sha256 ID没有变化,OpenShift的ImageSteamTag就可以继续使用该外部镜像。
  3. 当外部镜像发生变化后需要自动更新ImageSteamTag对应的sha256 ID,那么可以使用oc tag或oc import-image命令的“–scheduled=true”参数,它会在YAML中设置“importPolicy: {scheduled: true}”。
  4. ImageStream是OpenShift扩展的对象,因此OpenShift的Build、DeploymentConfig等对象可以直接使用它。如果需要在Kubernetes的RC、Pod等对象使用ImageStream,可执行以下的命令启动ImageStream的本地名称查询功能。该命令将把ImageStream的Imagestream. spec.lookupPolicy.local设为true。
$ oc set image-lookup IMAGESTREAM

以下是一个例子:如果为名为hello的ImageStream启用了“本地名称”查询功能,那么在pod或其他资源中使用“–image=hello”就可以访问到ImageSteamTag指向的Image,而不是来自上游Image Registry。如果没有启动本地名称查询功能,那么使用“–image=hello”访问Image的时候会出问题,例如下面的“ErrImagePull”错误。

$ oc import-image is-project/hello:latest --from="openshift/hello-openshift:latest" --confirm
$ oc run hello --image=hello
$ oc get pod -w
NAME    READY   STATUS              RESTARTS   AGE
hello   0/1     ContainerCreating   0          5s
hello   0/1     ErrImagePull        0          10s

下面在使用了“set image-lookup”后就可通过“–image=hello”使用该镜像了。

$ oc delete pod hello
$ oc set image-lookup hello 
$ oc run hello --image=hello
$ oc get pod -w
NAME    READY   STATUS              RESTARTS   AGE
hello   0/1     ContainerCreating   0          4s
hello   1/1     Running             0          7s

通过pullthrough指向External Image

为了让ImageStream使用pullthrough特性,我们可以在“oc import-image”或“oc tag”命令中设置“–reference-policy=local”参数。

$ oc import-image is-project/myimage-ref-local:mytag --from="docker.io/balazsszeti/hello:sleeper" --confirm --reference-policy=local
$ oc tag docker.io/balazsszeti/hello:sleeper is-project/myimage-ref-local:mytag --reference-policy=local

“–reference-policy=local”参数会将ImageStream的referencePolicy.local设置成true。

。。。
  referencePolicy:
    type: Local
。。。

当“–reference-policy=local”的时候,StreamImage使用的是pullthrough方式指向External Image,那么:

  1. 根据Image生成Pod的时候会使用Internal Registry上的已经被pulled through的Image。例如:
image-registry.openshift-image-registry.svc:5000/is-project/myimage-ref-local@sha256:42957024b43e121a210a1b3a8a44f497233a2385f7ef48227a6866afdb9b8e1b
  1. 当Image第一次被使用的时后,它会先从External Registry被获取到然后缓存到Internal Registry缓存中。所以在第一次使用Image的时后还不会脱机工作,但一旦缓存后,就再也不需要联系外部注册表了。即使将映像从外部注册表中删除,它也会保留在Internal Registry缓存中。
  2. 和“指向External Image”一样,当External Image的Tag变化后,并且如果sha256 ID还有效,那么不会影响继续使用ImageStreamTag访问镜像,而且Internal Registry的Image缓存也不会更新。当使用手动更新或使用“–scheduled=true”定时更新,更新后的External Image会更新至内部缓存的Image。
  3. 由于Pod是采用Internal Registry sha256 ID获取被缓存的Image,因此如果缓存Image没有被清除,那么Pod就可以被rollback。

每次通过External Image的URL地址获取镜像

通过使用oc tag命令的–reference=true参数可创建一个ImageStream。在通过它运行Pod的时候,OpenShift不会直接使用ImageStreamTag的sha256 ID来找到对应的Image,而是每次都是通过指定的External Image名称和对应的Tag去找那个对应特定的Image。下面我们对比使用–reference=true参数和–reference=false(缺省情况)的区别。

  1. 首先使用–reference=true参数创建一个ImageStream,然后查看是否有ImageStreamTag对象。可以看到当使用–reference=true参数的时候,OpenShift并不会记录Image的sha256 ID信息(不过OpenShift实际是通过sha256 ID识别被使用的Image)。此时OpenShift每次都要通过解析External Image的URL地址(即docker.io/openshift/hello-openshift:latest)解析实际使用的Image(其实最终还要解析到Image的sha256 ID,只不过不在OpenShift的ImageStreamTag中记录该sha256 ID信息了)。因此这种情况是每次访问Image都做一次外部镜像地址的全解析。
$ oc tag docker.io/openshift/hello-openshift:latest is-project/hello-1:latest --reference=true
$ oc get istag hello-1:latest
Error from server (NotFound): imagestreamtags.image.openshift.io "hello-1:latest" not found
  1. 首先使用–reference=false参数创建一个ImageStream,然后查看是否有ImageStreamTag对象。可以看到当使用–reference=false参数的时候,OpenShift会为之创建与ImageStream对应的ImageStreamTag。OpenShift以后实际上是通过ImageStreamTag中记录的sha256 ID定位该Image的,因此从External Image的URL地址解析到Image的sha256 ID过程OpenShift只做一次。
$ oc tag docker.io/openshift/hello-openshift:latest is-project/hello-2:latest --reference=false
$ oc get istag hello-2:latest
NAME             IMAGE REF                                                                                                     UPDATED
hello-2:latest   docker.io/openshift/hello-openshift@sha256:aaea76ff622d2f8bcb32e538e7b3cd0ef6d291953f3e7c9f556c1ba5baf47e2e   5 seconds ago

当我们使用–reference=true的ImageStream的时候,具有以下特性:

  1. 在这种情况下由于ImageStream没有记录ImageSteamTag的sha256 ID信息,因此每次都要使用以下External Image的URL找到该Image。
docker.io/openshift/hello-openshift:latest
  1. 在这种情况下即便使用了–reference-policy=local选项,也无法使用缓存,因此不能离线运行。
  2. 由于每次OpenShift都通过External Image的URL找到所用Tag对应的Image来运行Pod,因此当External Image的Tag升级后,OpenShift可以立即感知出来这种变化,并用新的Tag对应的Image生成Pod。在–reference=false的时候,应配合Pod的“imagePullPolicy: Always”参数一起使用,以让Pod每次都pull到最新的Image。
  3. 在这种情况时,Pod直接使用的是External Image URL获取的Image,而不是用ImageStream配置中的Internal Registry URL(即image-registry.openshift-image-registry.svc:5000/is-project/myimage-reference:mytag)获取Image。
  4. 由于Pod是直接通过External Image的URL获得Image,例如docker.io/openshift/hello-openshift:latest,因此即便rollback,Pod获取到的Image可能会没有变化,因此rollback就不会奏效。

使用Internal Image

通过OpenShift的build生成的Image会推送到 Internal Registry上,OpenShift同时会为其生成ImageStream。

$ oc new-app php~https://github.com/liuxiaoyu-git/php-helloworld
 
$ oc get istag php-helloworld:latest
NAME                    IMAGE REFERENCE                                                                                                                                      UPDATED
php-helloworld:latest   image-registry.openshift-image-registry.svc:5000/is-project/php-helloworld@sha256:759da8784d4c130ff6784fa375141fa65b949ac12eae4f98d537241cb49d6060   3 minutes ago

使用这种方式的ImageStream有以下特性:

  1. 同使用pullthrough方式相同,Pod使用的是Internal Registry和sha256 ID的组合方式访问到Image。
image-registry.openshift-image-registry.svc:5000/is-project/php-helloworld@sha256:759da8784d4c130ff6784fa375141fa65b949ac12eae4f98d537241cb49d6060
  1. 由于Image就在OpenShift的internal registry中,因此可以离线访问到。
  2. 当通过build过程更新了Image的Tag后,Pod会使用更新后的Image。
  3. 其它特性和上面介绍的pullthrough的情况相同。

参考

  1. 本文内容主要源自https://itnext.io/variations-on-imagestreams-in-openshift-4-f8ee5e8be633一文。
  2. Managing build output
  3. Why managing container images on OpenShift is better than on Kubernetes
  4. How to Simplify Container Image Management in Kubernetes with OpenShift Image Streams
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值