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的情況相同。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章