美文网首页kubelet源码解析
kubelet启动容器之拉取镜像

kubelet启动容器之拉取镜像

作者: 微凉哇 | 来源:发表于2021-11-22 09:52 被阅读0次

基于kubernetes v1.18.6

概览

kubelet启动容器的第一步便是拉取镜像,核心源码如下:

kubernetes\pkg\kubelet\kuberuntime\kuberuntime_container.go

func (m *kubeGenericRuntimeManager) startContainer(podSandboxID string, podSandboxConfig *runtimeapi.PodSandboxConfig, spec *startSpec, pod *v1.Pod, podStatus *kubecontainer.PodStatus, pullSecrets []v1.Secret, podIP string, podIPs []string) (string, error) {
    container := spec.container

    // Step 1: pull the image.
    imageRef, msg, err := m.imagePuller.EnsureImageExists(pod, container, pullSecrets, podSandboxConfig)
    if err != nil {
        s, _ := grpcstatus.FromError(err)
        m.recordContainerEvent(pod, container, "", v1.EventTypeWarning, events.FailedToCreateContainer, "Error: %v", s.Message())
        return msg, err
    }
...
}

接下来我们对m.imagePuller.EnsureImageExists()函数深入分析

函数入参及返回值解析

入参解析

  • pod *v1.Pod入参: 当前容器所属pod实例
  • container *v1.Container: 容器实例(包含镜像名称等元数据信息)
  • pullSecrets []v1.Secret: 拉取镜像所需的凭据
  • podSandboxConfig *runtimeapi.PodSandboxConfig: pod沙箱配置实例(包含主机名、dns、日志目录等)

返回值解析

  • 返回值一镜像像的引用(镜像摘要或ID,如harbor.wl.io/library/redis:5.0.12): 返回本地存储中容器的镜像引用(摘要或ID),如果镜像不在本地存储中返回""。
  • 返回值二镜像拉取信息:失败/成功及原因
  • 返回值三异常:拉取镜像过程中产生的异常(如拉取镜像网络不可达)

设置镜像tag默认值

当容器镜像不存在tag时,会设置缺省tag值: latest

func (m *imageManager) EnsureImageExists(pod *v1.Pod, container *v1.Container, pullSecrets []v1.Secret, podSandboxConfig *runtimeapi.PodSandboxConfig) (string, string, error) {
...
    // If the image contains no tag or digest, a default tag should be applied.
    // 为没有摘要或tag的镜像设置默认tag: latest
    image, err := applyDefaultImageTag(container.Image)
    if err != nil {
        msg := fmt.Sprintf("Failed to apply default image tag %q: %v", container.Image, err)
        m.logIt(ref, v1.EventTypeWarning, events.FailedToInspectImage, logPrefix, msg, klog.Warning)
        return "", msg, ErrInvalidImageName
    }
...
}

例如:下面spec.containers[0].image只声明了镜像名称,未声明tag

$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
  name: nginx-with-no-tag
spec:
  containers:
  - name: nginx
    image: nginx
EOF

查看pod事件,发现并没有因为未指定镜像tag而中断

$ kubectl describe pod nginx-with-no-tag
...
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  119s  default-scheduler  Successfully assigned default/nginx-with-no-tag to node69
  Normal  Pulling    118s  kubelet, node69    Pulling image "nginx"
  Normal  Pulled     74s   kubelet, node69    Successfully pulled image "nginx"
  Normal  Created    73s   kubelet, node69    Created container nginx
  Normal  Started    73s   kubelet, node69    Started container nginx

查询本地镜像列表

$ docker images|grep nginx
nginx                                                                                                           latest                         ea335eea17ab   44 hours ago    141MB

拉取镜像

1.判断是否需要拉取镜像

以下情况需要拉取镜像:

  1. 容器的镜像拉取策略为Always
  2. 容器的镜像拉取策略为IfNotPresent,并且本地没有该镜像

如果需要拉取镜像继续后续流程,如果不需要拉取镜像直接返回,并根据以下场景返回对应信息:

  • 容器的镜像拉取策略为Never,并且本地存在该镜像,则返回: 镜像引用信息(即镜像名称,如harbor.wl.io/library/redis:5.0.12
  • 容器的镜像拉取策略为Never,并且本地不存在该镜像,则返回异常: Container image xxx is not present with pull policy of Never

源码实现

func (m *imageManager) EnsureImageExists(pod *v1.Pod, container *v1.Container, pullSecrets []v1.Secret, podSandboxConfig *runtimeapi.PodSandboxConfig) (string, string, error) {
...
    spec := kubecontainer.ImageSpec{Image: image}
    imageRef, err := m.imageService.GetImageRef(spec)
    if err != nil {
        msg := fmt.Sprintf("Failed to inspect image %q: %v", container.Image, err)
        m.logIt(ref, v1.EventTypeWarning, events.FailedToInspectImage, logPrefix, msg, klog.Warning)
        return "", msg, ErrImageInspect
    }

    present := imageRef != ""
    // 当容器的镜像拉取策略为Never时只用本地的镜像而非从镜像库拉取
    if !shouldPullImage(container, present) {
        if present {
            msg := fmt.Sprintf("Container image %q already present on machine", container.Image)
            m.logIt(ref, v1.EventTypeNormal, events.PulledImage, logPrefix, msg, klog.Info)
            return imageRef, "", nil
        }
        msg := fmt.Sprintf("Container image %q is not present with pull policy of Never", container.Image)
        m.logIt(ref, v1.EventTypeWarning, events.ErrImageNeverPullPolicy, logPrefix, msg, klog.Warning)
        return "", msg, ErrImageNeverPull
    }
...
}

2.判断是否超过镜像拉取时间

--image-pull-progress-deadline值,默认一分钟。

若在此截止日期前未进行镜像拉取,则镜像拉取将被取消。这个特定于docker的标志只在容器运行时被设置为docker时有效

func (m *imageManager) EnsureImageExists(pod *v1.Pod, container *v1.Container, pullSecrets []v1.Secret, podSandboxConfig *runtimeapi.PodSandboxConfig) (string, string, error) {
...
    backOffKey := fmt.Sprintf("%s_%s", pod.UID, container.Image)
    if m.backOff.IsInBackOffSinceUpdate(backOffKey, m.backOff.Clock.Now()) {
        msg := fmt.Sprintf("Back-off pulling image %q", container.Image)
        m.logIt(ref, v1.EventTypeNormal, events.BackOffPullImage, logPrefix, msg, klog.Info)
        return "", msg, ErrImagePullBackOff
    }
...
}

3.拉取镜像操作

调用容器运行时拉取镜像,并开启垃圾回收。

func (m *imageManager) EnsureImageExists(pod *v1.Pod, container *v1.Container, pullSecrets []v1.Secret, podSandboxConfig *runtimeapi.PodSandboxConfig) (string, string, error) {
...
    m.logIt(ref, v1.EventTypeNormal, events.PullingImage, logPrefix, fmt.Sprintf("Pulling image %q", container.Image), klog.Info)
    pullChan := make(chan pullResult)
    m.puller.pullImage(spec, pullSecrets, pullChan, podSandboxConfig)
    imagePullResult := <-pullChan
    if imagePullResult.err != nil {
        m.logIt(ref, v1.EventTypeWarning, events.FailedToPullImage, logPrefix, fmt.Sprintf("Failed to pull image %q: %v", container.Image, imagePullResult.err), klog.Warning)
        m.backOff.Next(backOffKey, m.backOff.Clock.Now())
        if imagePullResult.err == ErrRegistryUnavailable {
            msg := fmt.Sprintf("image pull failed for %s because the registry is unavailable.", container.Image)
            return "", msg, imagePullResult.err
        }

        return "", imagePullResult.err.Error(), ErrImagePull
    }
    m.logIt(ref, v1.EventTypeNormal, events.PulledImage, logPrefix, fmt.Sprintf("Successfully pulled image %q", container.Image), klog.Info)
    m.backOff.GC()
}

相关文章

  • kubelet创建容器之运行容器启动后的钩子

    比如:调用注册中心注册自己 概述 kubelet通过以下四个步骤,来启动pod容器: 拉取镜像 创建容器 启动容器...

  • kubelet启动容器之拉取镜像

    基于kubernetes v1.18.6 概览 kubelet启动容器的第一步便是拉取镜像,核心源码如下: kub...

  • docker初识

    镜像命令:拉取镜像查看镜像容器命令:创建容器启动容器/停止容器容器删除拷贝容器目录挂载查看IP 》拉取镜像,创建容...

  • docker 安装宝塔

    拉取centos基础镜像,用容器启动该基础镜像,直接在这个容器中部署。 1、拉取纯净系统镜像: 2、启动镜像,映射...

  • Centos下的纯命令记录Docker学习(11)- 使用Doc

    数据库安装 拉取postgresql数据库镜像且运行容器 拉取gogs镜像并启动容器 1: 拉取镜像 2:查看镜像...

  • kubelet 拉取私有镜像过程

    kubelet拉取镜像是用许多密钥尝试去拉取,kubelet拉取私有镜像除了可以在yaml里面配置私有镜像仓库密钥...

  • Docker 制作 Elasticsearch 镜像

    1、拉取镜像及相关配置 1.1、拉取镜像 1.2、启动容器 1.3、查看容器启动情况 1.4、如果启动成功则访问 ...

  • 利用Docker,构建宝塔linux面板镜像

    拉取centos基础镜像,用容器启动该基础镜像,直接在这个容器中部署 1.拉取纯净系统镜像 2.启动镜像,映射主机...

  • 服务安装

    MySQL服务 步骤一:拉取镜像 步骤二:启动容器 Tomcat服务 步骤一:拉取镜像 步骤二:启动容器 Ngin...

  • docker

    搜索镜像 拉取镜像 启动镜像 查看所有容器 启动已存在容器 停止容器 进入容器 查询容器运行详细信息 容器打包 查...

网友评论

    本文标题:kubelet启动容器之拉取镜像

    本文链接:https://www.haomeiwen.com/subject/vtfetrtx.html