《OpenShift / RHEL / DevSecOps 汇总目录》
文本已在 OpenShift 4.15 环境中进行验证。
什么是节点本地镜像缓存
一个 OpenShift 集群节点在运行 Pod 前需要先从 Registry 拉取到相关 Image。这些镜像会保存在节点本地存储中并作为缓存,这样该节点如果再使用这个 Image 就会先使用节点缓存中的镜像,从而提升 Pod 的启动速度。
OpenShift 是如何使用节点本地镜像缓存
查看节点本地保存的镜像缓存
- 确认可以访问到 https://quay.io/repository/openshiftroadshow/parksmap?tab=tags,其中有测试镜像。
- 执行命令获取当前节点名。
$ oc get node
NAME STATUS ROLES AGE VERSION
control-plane-cluster-cw8ww-1 Ready control-plane,master,worker 30h v1.28.7+f1b5f6c$ NODE_NAME=control-plane-cluster-cw8ww-1
- 执行命令,在 Deployment 中使用 quay.io/openshiftroadshow/parksmap:latest 镜像,并让其运行在指定节点以方便跟踪。
$ oc apply -f - << EOF
kind: Deployment
apiVersion: apps/v1
metadata:name: parksmap
spec:replicas: 1selector:matchLabels:app: parksmaptemplate:metadata:labels:app: parksmapspec:nodeName: ${NODE_NAME}containers:- name: hello-openshiftimage: 'quay.io/openshiftroadshow/parksmap:latest'ports:- containerPort: 8080protocol: TCP- containerPort: 8888protocol: TCPimagePullPolicy: IfNotPresent
EOF
- 运行命令,确认 Pod 可以正常运行起来,并注意 Pod 运行在指定节点上。
$ oc get pod -owide
NAME READY STATUS RESTARTS AGE IP NODE
parksmap-9bdf99cc-km892 1/1 Running 0 32m 10.132.0.114 control-plane-cluster-cw8ww-1
- 进入 Pod 运行的的 Node,并切换到 /host。
$ oc debug node/$NODE_NAME
sh-4.4# chroot /host
- 运行以下命令,确认可以在节点中找到 openshiftroadshow/parksmap:latest 镜像信息。注意镜像的 id 和 digest。
$ cat /var/lib/containers/storage/overlay-images/images.json | jq
......{"id": "0c2f55f381ee738ec77722ea7b92ac97fcfa1cb6ef8e323df929b0ab40c70a47","digest": "sha256:89d1e324846cb431df9039e1a7fd0ed2ba0c51aafbae73f2abd70a83d5fa173b","names": ["quay.io/openshiftroadshow/parksmap:latest"],"names-history": ["quay.io/openshiftroadshow/parksmap:latest"],"layer": "e0c471633f3e337a376fd877385b6bfc287b9144c003aa61c933ec853610e3ce","metadata": "{}","big-data-names": ["sha256:0c2f55f381ee738ec77722ea7b92ac97fcfa1cb6ef8e323df929b0ab40c70a47","manifest-sha256:89d1e324846cb431df9039e1a7fd0ed2ba0c51aafbae73f2abd70a83d5fa173b","manifest"],"big-data-sizes": {"manifest": 1373,"manifest-sha256:89d1e324846cb431df9039e1a7fd0ed2ba0c51aafbae73f2abd70a83d5fa173b": 1373,"sha256:0c2f55f381ee738ec77722ea7b92ac97fcfa1cb6ef8e323df929b0ab40c70a47": 5671},"big-data-digests": {"manifest": "sha256:89d1e324846cb431df9039e1a7fd0ed2ba0c51aafbae73f2abd70a83d5fa173b","manifest-sha256:89d1e324846cb431df9039e1a7fd0ed2ba0c51aafbae73f2abd70a83d5fa173b": "sha256:89d1e324846cb431df9039e1a7fd0ed2ba0c51aafbae73f2abd70a83d5fa173b","sha256:0c2f55f381ee738ec77722ea7b92ac97fcfa1cb6ef8e323df929b0ab40c70a47": "sha256:0c2f55f381ee738ec77722ea7b92ac97fcfa1cb6ef8e323df929b0ab40c70a47"},"created": "2021-02-01T12:52:36.138979177Z"}
- 在 quay.io 中使用 digest 方式获取上述镜像,确认 digest 和上一步返回的 digest 一样。
- 执行命令查找第 6 步返回的 id,确认该镜像已和 /var/lib/containers/storage/overlay-images 中名为 id 的目录对应起来。
$ ls -al /var/lib/containers/storage/overlay-images | grep 0c2f55f381ee738ec77722ea7b92ac97fcfa1cb6ef8e323df929b0ab40c70a47
drwx------. 2 root root 4096 Apr 10 01:15 0c2f55f381ee738ec77722ea7b92ac97fcfa1cb6ef8e323df929b0ab40c70a47
- 退出节点。
- 另外还可以在该节点的 YAML 或“详情”中确认该节点上有此镜像。
镜像缓存是如何被使用
- 在自有 Image Registry 上准备一个自用的测试镜像,例如 quay.io/dawnskyliu/hello-openshift:v1。
- 执行以下命令,在 Deployment 中使用以上镜像。由于 imagePullPolicy 使用了 IfNotPresent 策略,因此如果本地缓存中已有,就不会重新拉取该镜像。
$ oc apply -f - << EOF
kind: Deployment
apiVersion: apps/v1
metadata:name: hello-openshift-v1
spec:replicas: 1selector:matchLabels:app: hello-openshift-v1template:metadata:labels:app: hello-openshift-v1spec:nodeName: ${NODE_NAME}containers:- name: hello-openshiftimage: 'quay.io/dawnskyliu/hello-openshift:v1'ports:- containerPort: 8080protocol: TCP- containerPort: 8888protocol: TCPimagePullPolicy: IfNotPresent
EOF
- 确认使用该镜像的 Pod 可以运行起来。
$ oc get pod
NAME READY STATUS RESTARTS AGE
hello-openshift-v1-6995c77fb5-hvd84 1/1 Running 0 13s
- 可参照上一节确认在节点的存储中已有该镜像的缓存。
- 删除 quay.io/dawnskyliu/hello-openshift:v1 或修改 tag,使访问 quay.io/dawnskyliu/hello-openshift:v1 失效。
- 然后再删除 hello-openshift-v1 部署。
$ oc delete deploy hello-openshift-v1
- 重新执行命令,使用 quay.io/dawnskyliu/hello-openshift:v1 镜像创建部署。确认此时虽然 quay.io/dawnskyliu/hello-openshift:v1 已失效,但通过使用节点本地缓存 pod 还可成功运行。
$ oc apply -f - << EOF
kind: Deployment
apiVersion: apps/v1
metadata:name: hello-openshift-v1
spec:replicas: 1selector:matchLabels:app: hello-openshift-v1template:metadata:labels:app: hello-openshift-v1spec:nodeName: ${NODE_NAME}containers:- name: hello-openshiftimage: 'quay.io/dawnskyliu/hello-openshift:v1'ports:- containerPort: 8080protocol: TCP- containerPort: 8888protocol: TCPimagePullPolicy: IfNotPresent
EOF
- 再次删除 hello-openshift-v1 部署,然后重新启动 NODE_NAME 节点,最后再次创建 hello-openshift-v1 部署,确认 pod 依然可以运行成功。这说明节点本地存储依然发挥作用。
- 再次删除 hello-openshift-v1 部署,然后将 imagePullPolicy 改为 Always 再重新创建部署,确认会失败。这是由于 Always 会重新拉取镜像,但已无法访问到远程的 quay.io/dawnskyliu/hello-openshift:v1 镜像了。
$ oc delete deploy hello-openshift-v1
$ oc apply -f - << EOF
kind: Deployment
apiVersion: apps/v1
metadata:name: hello-openshift-v1
spec:replicas: 1selector:matchLabels:app: hello-openshift-v1template:metadata:labels:app: hello-openshift-v1spec:nodeName: ${NODE_NAME}containers:- name: hello-openshiftimage: 'quay.io/dawnskyliu/hello-openshift:v1'ports:- containerPort: 8080protocol: TCP- containerPort: 8888protocol: TCPimagePullPolicy: Always
EOF
自动清理节点本地镜像缓存
随着保存在节点本地存储的镜像缓存的数量增加,会不断消耗节点的本地存储空间,因此需要定期清理镜像缓存以释放存储空间。运行在节点的 kubelet 提供了清理本地镜像缓存的机制,而 OpenShift 4 是无法手动删除节点镜像缓存的。
基于 oc new-app 生成的部署和基于 YAML 的部署之间的差异
即便不考虑节点本地的镜像缓存,基于 oc new-app 生成的部署和基于 YAML 的部署之间是存在一定差异。
基于 oc new-app 生成的部署
在使用 oc new-app 命令生成部署的时候,虽然在命令中提供的是远程镜像地址,但 OpenShift 首先会把镜像从远程拉到 OpenShift 内部的镜像库中,然后再在 Deployment 的定义中自动通过 ImageStream 使用已在 OpenShift 内部镜像库中的镜像。
基于 YAML 创建的部署
当使用基于 YAML 的部署时候,其容器使用的镜像地址不会发生变化,会直接使用远程镜像库中的镜像。
参考
https://www.redhat.com/en/blog/image-garbage-collection-in-openshift
https://docs.openshift.com/container-platform/4.15/nodes/nodes/nodes-nodes-garbage-collection.html
https://medium.com/kubernetes-tutorials/efficient-node-out-of-resource-management-in-kubernetes-67f158da6e59
https://itnext.io/improve-container-image-availability-and-speed-with-caching-in-kubernetes-870fa7bfa1ed