一、背景

与同事在通过容器云平台(公司采购的某国内商业产品)部署某系统平台时,同事对文件做了修改并重新构建镜像但没有更改Tag。部署应用时,发现没有起效,一开始以为是容器云平台的Bug,后来感觉有可能是Kubernetes的问题,因此动手进行了验证。

二、原因分析

初步粗略判断,出问题的地方可能有:

  • 1、镜像没上传成功,或者镜像仓库有问题
  • 2、容器云平台的问题
  • 3、kubernetes自身的镜像更新判断机制

通过查看、对比镜像 Image ID,确认镜像上传和镜像仓库均没问题。

与供应商沟通,确认若容器云平台前端界面进行修改,则相当于更新yaml文件给Kubernetes执行,中间并没有再加工处理。而同事除了更新镜像内容,还修改过启动命令,因此容器云平台也没有问题。且通过在Kubernetes集群导出应用的yaml文件,确认使用的镜像拉取策略为imagePullPolicy: IfNotPresent,即本地若有镜像则不会重新拉取。

那最后就是Kubernetes自身的镜像更新判断机制了,这个可以通过动手实验来验证下。

三、实践验证

验证思路:构建Nginx镜像,创建Pod并定义imagepullpolicy:ifNotPresent,通过修改index.html内容,来分别实现【重新构建镜像内容但不更改Tag】和【重新构建镜像内容且更改Tag】,进行验证。

  1. 编辑Dockersfile。主要是使用Nginx做为基础镜像,复制一个网页文件进去重新构建验证镜像。
    [root@masterserver imagepullpolicy]# vi Dockerfile
    FROM harbor.xxx.com.cn/library/nginx:1.13.8-alpine
    COPY index.html /usr/share/nginx/html/
  2. Docker Build构建镜像
    [root@masterserver imagepullpolicy]# docker build -t mynginx:1.1 .
    Sending build context to Docker daemon  4.096kB
    Step 1/2 : FROM harbor.xxx.com.cn/library/nginx:1.13.8-alpine
    ---> bb00c21b4edf
    Step 2/2 : COPY index.html /usr/share/nginx/html/
    ---> be86871a6bce
    Successfully built be86871a6bce
    Successfully tagged mynginx:1.1
  3. 使用kubectl run –dry-run且带上imagepullpolicy参数,输出yaml文件。
    [root@masterserver imagepullpolicy]# kubectl run testnginx --image=mynginx:1.1 --dry-run=client --image-pull-policy=IfNotPresent -o yaml > testnginx.yaml
    [root@masterserver imagepullpolicy]# cat testnginx.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
    creationTimestamp: null
    labels:
    run: testnginx
    name: testnginx
    spec:
    containers:
    - image: mynginx:1.1
    imagePullPolicy: IfNotPresent
    name: testnginx
    resources: {}
    dnsPolicy: ClusterFirst
    restartPolicy: Always
    status: {}
  4. 通过kubectl apply -f nginx.yaml,运行pod。
  5. 修改index.html内容,重新构建镜像但不修改tag,再重新kubectl apply。查看pod事件
    [root@masterserver imagepullpolicy]# kubectl describe po mynginx
    Name:         mynginx
    Namespace:    default
    Priority:     0
    Node:         node1/192.168.56.104
    Start Time:   Wed, 05 Aug 2020 11:02:41 +0800
    Labels:       run=mynginx
    Annotations:  Status:  Running
    IP:           10.244.1.12
    IPs:
    IP:  10.244.1.12
    Containers:
    mynginx:
    Container ID:   docker://6aebe0a359144afa5cd9da4e04d8837e62d7c26118b64933d4b71af50cab07f2
    Image:          harbor.xxx.com.cn/test_dmgtest/mynginx:1.1
    Image ID:       docker-pullable://harbor.xxx.com.cn/test_dmgtest/mynginx@sha256:09a2064d81e1ffbb9c126320d5a3c1173585969da9160e26559bbb777ba2ed4d
    Port:           <none>
    Host Port:      <none>
    State:          Running
      Started:      Wed, 05 Aug 2020 11:04:07 +0800
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-768sh (ro)
    Conditions:
    Type              Status
    Initialized       True 
    Ready             True 
    ContainersReady   True 
    PodScheduled      True 
    Volumes:
    default-token-768sh:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-768sh
    Optional:    false
    QoS Class:       BestEffort
    Node-Selectors:  <none>
    Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
    Events:
    Type     Reason     Age                From               Message
    ----     ------     ----               ----               -------
    Normal   Scheduled  <unknown>          default-scheduler  Successfully assigned default/mynginx to node1
    Normal   Pulling    34s (x3 over 78s)  kubelet, node1     Pulling image "harbor.infinitus.com.cn/test_dmgtest/mynginx:1.1"
    Normal   Pulled     <invalid>          kubelet, node1     Container image "harbor.xxx.com.cn/test_dmgtest/mynginx:1.1" already present on machine 
    Normal   Created    <invalid>          kubelet, node1     Created container mynginx
    Normal   Started    <invalid>          kubelet, node1     Started container mynginx

在pod事件中,可以看到 【Container image "harbor.xxx.com.cn/test_dmgtest/mynginx:1.1" already present on machine 】。

而通过Docker images,可以查看image id是两个不同的id。

四、结论

通过实践验证,可以得出结论:当pod定义了imagepullpolicy: IfNotPresent,判断运行pod的node本地有没有镜像。进一步,这个判断机制Kubernetes原生是这样设置的:会根据tag来判断,而不是根据sha id来判断。
所以即使镜像内容变化重新构建镜像但Tag没有更改的话,kubernetes是不会去重新拉取镜像的。