文章目錄
本文內容主要源自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中的鏡像管理的基本概念。
- Managing build output
- Why managing container images on OpenShift is better than on Kubernetes
- 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的一些注意事項:
- 對於內部圖像,ImageStreams和內部註冊表是緊密耦合的。例如,myproject命名空間中的myimage-internal
ImageStream被映射到image-registry.openshift-image-registry.svc:5000/myproject/myimage-internal
repository。 - 如果我們運行一個新的構建,其中output指定的是ImageStream類型,那麼圖像將被存儲在OpenShift內部註冊表中。(【引用#1】如果Build的output指定的是DockerImage類型,那麼OpenShift會使用push操作將Image推送到標準的Docker Registry,缺省是DockerHub)。另外同理適用於指定Builder Image的來源。
- 如果我們使用Push方法手動向Internal Image Registry推送一個Image,OpenShift會自動創建一個匹配的ImageStream並指向這個Internal Image Registry中的Image。主要注意的是我們必須有推送Image所到Namespace的編輯權限。
- 如果我們刪除了ImageStream,在內部註冊表中保存的Image存儲也會被刪除。
- 爲了保持註冊表的使用空間,你需要定期Prune Images。在這個過程中,哪些在Build或Deployment中被使用到的內部Image會自動保留。
External Image
在OpenShift之外的External Registry保存了外部Image。ImageStream和External Registry、以及其上的外部Image的關係如下:
- 我們可以用 oc import-image 或 oc tag 命令創建一個指向外部圖像的 ImageStream,或者直接用 yaml 創建一個 ImageStream。
- 一個ImageStream中的標籤可以指向來自完全不同的註冊庫和存儲庫的Image。通過這種有效的方法可以將相關的外部Image關聯起來,但Image可存儲在不同的Registry存儲庫中。
- 作爲一個抽象層,ImageStreams隱藏了Image的實際來源。當構建和部署引用一個ImageStream時,我們可以通過修改ImageStream中的URL來改變正在使用的Image,而不是逐一編輯OpenShift的每個構建和部署。
- 當創建或更新Image時,ImageStream 通過其唯一的 sha256 ID(而非Tag)來引用圖像。這使得當外部註冊表變化標籤的時候,其使用的Image可保持穩定性。
- ImageStreams 可以定期(15 分鐘)監控外部標記是否發生變化(通過–scheduled=true)。
- 我們可以在內部註冊表中緩存外部Image(通過–reference-policy=local)。這真的很有用,因爲它可以使部署更加快速,並且不受外部註冊表可用性的影響。
- 另一個重要的功能–無論是內部還是外部映像–是在ImageStream更新時自動觸發相關的BuildConfigs和DeploymentConfigs的能力。這個行爲可以在這些資源上設置(參見 imageChangeParams.automatic=true),通常是啓用的。
確定ImageStream指向的目標和方式
我們可以把OpenShift的ImageStream看成是一個指向Image的指針(當然還有一些其它元數據),ImageStream指向的Image目標可以是多種不同類型的目標,它們包括:
- 指向一個external image
- 通過pullthrough 指向一個被緩存的external image
- 總是使用一個external image的URL
- 指向一個internal image
- 指向另一個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
- 名爲mytag的ImageSteamTag指向的是DockerImage類型的External Image,外部鏡像URL(名稱+Tag)是docker.io/balazsszeti/hello:sleeper。
- 這個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
- 每次通過ImageSteamTag使用Image的時候使用的是source類型的referencePolicy,即直接從source訪問Image。因此如果當時網絡不通,則無法訪問該Image。
- 當生成ImageSteamTag指向sha256 ID後,修改升級外部鏡像的tag就不再影響ImageSteamTag了,也就是說即便把外部鏡像從“docker.io/balazsszeti/hello:sleeper”改爲“docker.io/balazsszeti/hello:sleeper-v1”,只要sha256 ID沒有變化,OpenShift的ImageSteamTag就可以繼續使用該外部鏡像。
- 當外部鏡像發生變化後需要自動更新ImageSteamTag對應的sha256 ID,那麼可以使用oc tag或oc import-image命令的“–scheduled=true”參數,它會在YAML中設置“importPolicy: {scheduled: true}”。
- 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時候,那麼:
- 根據Image生成Pod的時候會使用Internal Registry上的已經被pulled through的Image。例如:
image-registry.openshift-image-registry.svc:5000/myproject/myimage-ref-local@sha256:42957024b43e121a210a1b3a8a44f497233a2385f7ef48227a6866afdb9b8e1b
- 當Image第一次被使用的時後,它會先從External Registry被獲取到然後緩存到Internal Registry緩存中。所以在第一次使用Image的時後還不會脫機工作,但一旦緩存後,就再也不需要聯繫外部註冊表了。即使將映像從外部註冊表中刪除,它也會保留在Internal Registry緩存中。
- 和“指向External Image”一節樣,當External Image的Tag變化後,並且如果sha256 ID還有效,那麼不會影響繼續使用ImageStreamTag訪問鏡像,而且Internal Registry的Image緩存也不會更新。當使用手動更新或使用“–scheduled=true”定時更新,更新後的External Image會更新至內部緩存的Image。
- 由於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(缺省情況)的區別。
- 首先使用–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
- 首先使用–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的時候,具有以下特性:
- 在這種情況下由於沒有ImageSteamTag的sha256 ID,因此Pod每次都要使用以下External Image的URL找到該Image。
docker.io/openshift/hello-openshift:latest
- 在這種情況下即便使用了–reference-policy=local選項,也無法使用緩存,因此不能離線運行。
- 由於每次OpenShift都通過External Image的URL找到所用Tag對應的Image來運行Pod,因此當External Image的Tag升級後,OpenShift可以立即感知出來這種變化,並用新的Tag對應的Image生成Pod。在–reference=false的時候,應配合Pod的“imagePullPolicy: Always”參數一起使用,以讓Pod每次都pull到最新的Image。
- 在這種情況時,Pod直接使用的是External Image URL獲取的Image,而不是用ImageStream配置中的Internal Registry URL(即image-registry.openshift-image-registry.svc:5000/myproject/myimage-reference:mytag)獲取Image。
- 由於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有以下特性:
- 同使用pullthrough方式相同,Pod使用的是Internal Registry和sha256 ID的組合方式訪問到Image。
image-registry.openshift-image-registry.svc:5000/myproject/myimage-internal@sha256:ff3b3c5e3d09bf93e2a05ece04235f4ea8212f36b617161d8f11f374a14aeb74
- 由於Image就在OpenShift的internal registry中,因此可以離線訪問到。
- 當通過build過程更新了Image的Tag後,Pod會使用更新後的Image。
- 其它特性和上面介紹的pullthrough的情況相同。