OpenShift 4 概念 (1) - ImageStream


本文内容主要源自https://itnext.io/variations-on-imagestreams-in-openshift-4-f8ee5e8be633一文。

ImageStream基本概念

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

ImageStreams 是为了支持不同用途而设计的。但在一开始,某些参数可能会让人感到困惑。本文将对于OpenShift中的镜像管理的基本概念。

  1. Managing build output
  2. Why managing container images on OpenShift is better than on Kubernetes
  3. How to Simplify Container Image Management in Kubernetes with OpenShift Image Streams

技术上来说,ImageStream只是一个包含元数据的Kubernetes资源。除了管理内部的镜像–通常是在OpenShift集群中构建的–ImageStreams可以指向外部注册表中的图像。在这种情况下,它们只是一个额外的抽象层,提供了一些额外的功能(例如轮询更新、缓存)。由于 ImageStream 可以有两种不同的行为方式,如果我们区分它们是指向内部图像还是指向外部图像,就更容易理解它们。

Internal Image 和 External Image

Internal Image 和 Internal Image Registry

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

  1. 对于内部图像,ImageStreams和内部注册表是紧密耦合的。例如,myproject命名空间中的myimage-internal
    ImageStream被映射到image-registry.openshift-image-registry.svc:5000/myproject/myimage-internal
    repository。
  2. 如果我们运行一个新的构建,其中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。主要注意的是我们必须有推送Image所到Namespace的编辑权限。
  4. 如果我们删除了ImageStream,在内部注册表中保存的Image存储也会被删除。
  5. 为了保持注册表的使用空间,你需要定期Prune Images。在这个过程中,哪些在Build或Deployment中被使用到的内部Image会自动保留。

External Image

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

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

确定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命令或tag命令创建一个存放在myproject下的ImageStream,并让它指向外部Image,这个外部Image就是docker.io/balazsszeti/hello:sleeper。

$ oc import-image myproject/myimage-ref-source:mytag --from="docker.io/balazsszeti/hello:sleeper" --confirm
$ oc tag docker.io/balazsszeti/hello:sleeper myproject/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: myproject
  resourceVersion: "2844402"
  selfLink: /apis/image.openshift.io/v1/namespaces/myproject/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/myproject/myimage-ref-source
  publicDockerImageRepository: default-route-openshift-image-registry.apps.cluster-beijing-78c7.beijing-78c7.example.opentlc.com/myproject/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 myproject/hello:latest --from="openshift/hello-openshift:latest" --confirm
$ oc run hello --image=hello
$ oc get pod -w
NAME             READY   STATUS              RESTARTS   AGE
hello-1-deploy   0/1     ContainerCreating   0          4s
hello-1-mnnmz    0/1     Pending             0          0s
hello-1-mnnmz    0/1     ContainerCreating   0          0s
hello-1-deploy   1/1     Running             0          9s
hello-1-mnnmz    0/1     ContainerCreating   0          7s
hello-1-mnnmz    0/1     ErrImagePull        0          8s

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

$ oc delete dc hello
$ oc set image-lookup hello 
$ oc run hello --image=hello
$ oc get pod -w
NAME             READY   STATUS              RESTARTS   AGE
hello-1-vxcph    0/1     Pending             0          0s
hello-1-vxcph    0/1     ContainerCreating   0          0s
hello-1-deploy   1/1     Running             0          9s
hello-1-vxcph    0/1     ContainerCreating   0          7s
hello-1-vxcph    1/1     Running             0          9s
hello-1-deploy   0/1     Completed           0          18s
hello-1-deploy   0/1     Completed           0          18s

通过pullthrough指向External Image

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

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

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

。。。
  referencePolicy:
    type: Local
。。。

当StreamImage使用的是pullthrough方式指向External Image时候,那么:

  1. 根据Image生成Pod的时候会使用Internal Registry上的已经被pulled through的Image。例如:
image-registry.openshift-image-registry.svc:5000/myproject/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并不会为之创建与ImageStream对应的ImageStreamTag,当然就没有Image的sha256 ID了。此时OpenShift每次都要通过解析External Image的URL地址(即docker.io/openshift/hello-openshift:latest)解析实际使用的Image(其实最终还要解析到Image的sha256 ID)。因此这种情况是每次都做一次外部镜像地址的全解析。
$ oc tag docker.io/openshift/hello-openshift:latest myproject/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 myproject/hello-2:latest --reference=false
$ oc get istag hello-2:latest
$ oc get istag hello-2:latest
NAME             IMAGE REF                                                                                                     UPDATED
hello-2:latest   docker.io/openshift/hello-openshift@sha256:aaea76ff622d2f8bcb32e538e7b3cd0ef6d291953f3e7c9f556c1ba5baf47e2e   5 seconds ago

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

  1. 在这种情况下由于没有ImageSteamTag的sha256 ID,因此Pod每次都要使用以下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/myproject/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-build --to='myimage-internal:mytag' --strategy=docker --binary=true --name=myimage-internal
$ oc start-build myimage-internal --from-dir=.  --follow 
 
$ oc get is myimage-internal
NAME               IMAGE REPOSITORY                                                                                                               TAGS   UPDATED
myimage-internal   default-route-openshift-image-registry.apps.cluster-beijing-78c7.beijing-78c7.example.opentlc.com/myproject/myimage-internal

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

  1. 同使用pullthrough方式相同,Pod使用的是Internal Registry和sha256 ID的组合方式访问到Image。
image-registry.openshift-image-registry.svc:5000/myproject/myimage-internal@sha256:ff3b3c5e3d09bf93e2a05ece04235f4ea8212f36b617161d8f11f374a14aeb74
  1. 由于Image就在OpenShift的internal registry中,因此可以离线访问到。
  2. 当通过build过程更新了Image的Tag后,Pod会使用更新后的Image。
  3. 其它特性和上面介绍的pullthrough的情况相同。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章