kubelet源码分析 kuberuntime的syncpod、createSandbox/createContainer函数(三)

news2024/11/30 0:34:12

kubelet源码分析 kuberuntime的syncpod、createSandbox/createContainer函数(三)

上一篇介绍了killContainer容器部分。当kill后,就需要重新创建sandbox和container,今天介绍最后一部分,创建容器。

在这里插入图片描述
这篇也是整个上面的流程图中最后一步,containerManager的管理

一、syncPod

1.1 syncPod

  • 设置一下返回结果
  • 创建podsandbox,步骤1.2介绍
  • 如果创建失败,记录并返回
  • 创建成功,获得sandbox的状态
  • 如果没有使用主机网络,获得ips
  • 注册回调函数(这个函数就是创建容器函数)
  • 使用回调函数,创建临时容器,init容器,普通容器(二、startContainer)介绍
if podContainerChanges.CreateSandbox {
		var msg string
		var err error
		klog.V(4).InfoS("Creating PodSandbox for pod", "pod", klog.KObj(pod))
		metrics.StartedPodsTotal.Inc()
		//设置一下返回结果
		createSandboxResult := kubecontainer.NewSyncResult(kubecontainer.CreatePodSandbox, format.Pod(pod))
		result.AddSyncResult(createSandboxResult)
		if utilfeature.DefaultFeatureGate.Enabled(features.DynamicResourceAllocation) {
			if m.runtimeHelper.PrepareDynamicResources(pod) != nil {
				return
			}
		}
		//创建podsandbox,步骤1.2介绍
		podSandboxID, msg, err = m.createPodSandbox(ctx, pod, podContainerChanges.Attempt)
		if err != nil {
		    //如果创建失败,记录并返回
			if m.podStateProvider.IsPodTerminationRequested(pod.UID) {
				klog.V(4).InfoS("Pod was deleted and sandbox failed to be created", "pod", klog.KObj(pod), "podUID", pod.UID)
				return
			}
			metrics.StartedPodsErrorsTotal.Inc()
			createSandboxResult.Fail(kubecontainer.ErrCreatePodSandbox, msg)
			klog.ErrorS(err, "CreatePodSandbox for pod failed", "pod", klog.KObj(pod))
			ref, referr := ref.GetReference(legacyscheme.Scheme, pod)
			if referr != nil {
				klog.ErrorS(referr, "Couldn't make a ref to pod", "pod", klog.KObj(pod))
			}
			m.recorder.Eventf(ref, v1.EventTypeWarning, events.FailedCreatePodSandBox, "Failed to create pod sandbox: %v", err)
			return
		}
		klog.V(4).InfoS("Created PodSandbox for pod", "podSandboxID", podSandboxID, "pod", klog.KObj(pod))
		//创建成功,获得sandbox的状态
		resp, err := m.runtimeService.PodSandboxStatus(ctx, podSandboxID, false)
		if err != nil {
			ref, referr := ref.GetReference(legacyscheme.Scheme, pod)
			if referr != nil {
				klog.ErrorS(referr, "Couldn't make a ref to pod", "pod", klog.KObj(pod))
			}
			m.recorder.Eventf(ref, v1.EventTypeWarning, events.FailedStatusPodSandBox, "Unable to get pod sandbox status: %v", err)
			klog.ErrorS(err, "Failed to get pod sandbox status; Skipping pod", "pod", klog.KObj(pod))
			result.Fail(err)
			return
		}
		if resp.GetStatus() == nil {
			result.Fail(errors.New("pod sandbox status is nil"))
			return
		}
		//如果没有使用主机网络,获得ips
		if !kubecontainer.IsHostNetworkPod(pod) {
			podIPs = m.determinePodSandboxIPs(pod.Namespace, pod.Name, resp.GetStatus())
			klog.V(4).InfoS("Determined the ip for pod after sandbox changed", "IPs", podIPs, "pod", klog.KObj(pod))
		}
	}


	podIP := ""
	if len(podIPs) != 0 {
		podIP = podIPs[0]
	}
	//注册一下返回结果
	configPodSandboxResult := kubecontainer.NewSyncResult(kubecontainer.ConfigPodSandbox, podSandboxID)
	result.AddSyncResult(configPodSandboxResult)
	podSandboxConfig, err := m.generatePodSandboxConfig(pod, podContainerChanges.Attempt)
	if err != nil {
		message := fmt.Sprintf("GeneratePodSandboxConfig for pod %q failed: %v", format.Pod(pod), err)
		klog.ErrorS(err, "GeneratePodSandboxConfig for pod failed", "pod", klog.KObj(pod))
		configPodSandboxResult.Fail(kubecontainer.ErrConfigPodSandbox, message)
		return
	}
	//注册回调函数(这个函数就是创建容器函数)
	start := func(ctx context.Context, typeName, metricLabel string, spec *startSpec) error {
		startContainerResult := kubecontainer.NewSyncResult(kubecontainer.StartContainer, spec.container.Name)
		result.AddSyncResult(startContainerResult)
		//如果是回滚的,则取消创建
		isInBackOff, msg, err := m.doBackOff(pod, spec.container, podStatus, backOff)
		if isInBackOff {
			startContainerResult.Fail(err, msg)
			klog.V(4).InfoS("Backing Off restarting container in pod", "containerType", typeName, "container", spec.container, "pod", klog.KObj(pod))
			return err
		}

		metrics.StartedContainersTotal.WithLabelValues(metricLabel).Inc()
		if sc.HasWindowsHostProcessRequest(pod, spec.container) {
			metrics.StartedHostProcessContainersTotal.WithLabelValues(metricLabel).Inc()
		}
		klog.V(4).InfoS("Creating container in pod", "containerType", typeName, "container", spec.container, "pod", klog.KObj(pod))
		//启动容器(二、startContainer介绍)
		if msg, err := m.startContainer(ctx, podSandboxID, podSandboxConfig, spec, pod, podStatus, pullSecrets, podIP, podIPs); err != nil {
			metrics.StartedContainersErrorsTotal.WithLabelValues(metricLabel, err.Error()).Inc()
			if sc.HasWindowsHostProcessRequest(pod, spec.container) {
				metrics.StartedHostProcessContainersErrorsTotal.WithLabelValues(metricLabel, err.Error()).Inc()
			}
			startContainerResult.Fail(err, msg)
			// repetitive log spam
			switch {
			case err == images.ErrImagePullBackOff:
				klog.V(3).InfoS("Container start failed in pod", "containerType", typeName, "container", spec.container, "pod", klog.KObj(pod), "containerMessage", msg, "err", err)
			default:
				utilruntime.HandleError(fmt.Errorf("%v %+v start failed in pod %v: %v: %s", typeName, spec.container, format.Pod(pod), err, msg))
			}
			return err
		}

		return nil
	}

	// Step 5:启动临时容器
	for _, idx := range podContainerChanges.EphemeralContainersToStart {
		start(ctx, "ephemeral container", metrics.EphemeralContainer, ephemeralContainerStartSpec(&pod.Spec.EphemeralContainers[idx]))
	}

	// Step 6: 启动init容器
	if container := podContainerChanges.NextInitContainerToStart; container != nil {
		// 启动init
		if err := start(ctx, "init container", metrics.InitContainer, containerStartSpec(container)); err != nil {
			return
		}
		klog.V(4).InfoS("Completed init container for pod", "containerName", container.Name, "pod", klog.KObj(pod))
	}

	// Step 7: 如果是热更新,改变一下资源请求
	if isInPlacePodVerticalScalingAllowed(pod) {
		if len(podContainerChanges.ContainersToUpdate) > 0 || podContainerChanges.UpdatePodResources {
			m.doPodResizeAction(pod, podStatus, podContainerChanges, result)
		}
	}

	// Step 8: 启动容器
	for _, idx := range podContainerChanges.ContainersToStart {
		start(ctx, "container", metrics.Container, containerStartSpec(&pod.Spec.Containers[idx]))
	}
	return

1.2 CreateSandbox

  • 生成启动sandbox的配置信息。1.3generatePodSandboxConfig介绍
  • 创建目录
  • 启动sandbox。不详介绍,和上一张一样。这里最终通过grpc调用CRI去创建
func (m *kubeGenericRuntimeManager) createPodSandbox(ctx context.Context, pod *v1.Pod, attempt uint32) (string, string, error) {
    //生成启动sandbox的配置信息。1.3generatePodSandboxConfig介绍
	podSandboxConfig, err := m.generatePodSandboxConfig(pod, attempt)
	if err != nil {
		message := fmt.Sprintf("Failed to generate sandbox config for pod %q: %v", format.Pod(pod), err)
		klog.ErrorS(err, "Failed to generate sandbox config for pod", "pod", klog.KObj(pod))
		return "", message, err
	}

	// 创建目录
	err = m.osInterface.MkdirAll(podSandboxConfig.LogDirectory, 0755)
	if err != nil {
		message := fmt.Sprintf("Failed to create log directory for pod %q: %v", format.Pod(pod), err)
		klog.ErrorS(err, "Failed to create log directory for pod", "pod", klog.KObj(pod))
		return "", message, err
	}

	runtimeHandler := ""
	if m.runtimeClassManager != nil {
		runtimeHandler, err = m.runtimeClassManager.LookupRuntimeHandler(pod.Spec.RuntimeClassName)
		if err != nil {
			message := fmt.Sprintf("Failed to create sandbox for pod %q: %v", format.Pod(pod), err)
			return "", message, err
		}
		if runtimeHandler != "" {
			klog.V(2).InfoS("Running pod with runtime handler", "pod", klog.KObj(pod), "runtimeHandler", runtimeHandler)
		}
	}
	//启动sandbox。不详介绍,和上一张一样。这里最终通过grpc调用CRI去创建
	podSandBoxID, err := m.runtimeService.RunPodSandbox(ctx, podSandboxConfig, runtimeHandler)
	if err != nil {
		message := fmt.Sprintf("Failed to create sandbox for pod %q: %v", format.Pod(pod), err)
		klog.ErrorS(err, "Failed to create sandbox for pod", "pod", klog.KObj(pod))
		return "", message, err
	}

	return podSandBoxID, "", nil
}

1.3generatePodSandboxConfig

  • 初始化配置数据
  • 获取dns
  • 如果没有使用主机网络,则获得host
  • 创建目录
  • 注册所需要的port端口
  • 更新配置以包括开销、沙盒级资源
func (m *kubeGenericRuntimeManager) generatePodSandboxConfig(pod *v1.Pod, attempt uint32) (*runtimeapi.PodSandboxConfig, error) {
	//初始化配置数据
	podUID := string(pod.UID)
	podSandboxConfig := &runtimeapi.PodSandboxConfig{
		Metadata: &runtimeapi.PodSandboxMetadata{
			Name:      pod.Name,
			Namespace: pod.Namespace,
			Uid:       podUID,
			Attempt:   attempt,
		},
		Labels:      newPodLabels(pod),
		Annotations: newPodAnnotations(pod),
	}
	//获取dns
	dnsConfig, err := m.runtimeHelper.GetPodDNS(pod)
	if err != nil {
		return nil, err
	}
	podSandboxConfig.DnsConfig = dnsConfig
	//如果没有使用主机网络,则获得host
	if !kubecontainer.IsHostNetworkPod(pod) {
		podHostname, podDomain, err := m.runtimeHelper.GeneratePodHostNameAndDomain(pod)
		if err != nil {
			return nil, err
		}
		podHostname, err = util.GetNodenameForKernel(podHostname, podDomain, pod.Spec.SetHostnameAsFQDN)
		if err != nil {
			return nil, err
		}
		podSandboxConfig.Hostname = podHostname
	}
	//创建目录
	logDir := BuildPodLogsDirectory(pod.Namespace, pod.Name, pod.UID)
	podSandboxConfig.LogDirectory = logDir
    //注册所需要的port端口
	portMappings := []*runtimeapi.PortMapping{}
	for _, c := range pod.Spec.Containers {
		containerPortMappings := kubecontainer.MakePortMappings(&c)

		for idx := range containerPortMappings {
			port := containerPortMappings[idx]
			hostPort := int32(port.HostPort)
			containerPort := int32(port.ContainerPort)
			protocol := toRuntimeProtocol(port.Protocol)
			portMappings = append(portMappings, &runtimeapi.PortMapping{
				HostIp:        port.HostIP,
				HostPort:      hostPort,
				ContainerPort: containerPort,
				Protocol:      protocol,
			})
		}

	}
	if len(portMappings) > 0 {
		podSandboxConfig.PortMappings = portMappings
	}

	lc, err := m.generatePodSandboxLinuxConfig(pod)
	if err != nil {
		return nil, err
	}
	podSandboxConfig.Linux = lc

	if runtime.GOOS == "windows" {
		wc, err := m.generatePodSandboxWindowsConfig(pod)
		if err != nil {
			return nil, err
		}
		podSandboxConfig.Windows = wc
	}

	// 更新配置以包括开销、沙盒级资源
	if err := m.applySandboxResources(pod, podSandboxConfig); err != nil {
		return nil, err
	}
	return podSandboxConfig, nil
}

二、startContainer

  • 拉取镜像 2.1pullimage介绍
  • Step 2: 创建容器
  • 初始化重启次数初始化0
  • 如果存在,则重启次数+1。不存在创建目录
  • 获得创建container的基础配置2.2generateContainerConfig介绍
  • 记录event
  • 创建容器之前的准备
  • 创建容器 最终通过grpc调用CRI去创建
  • PreStart 阶段:在容器启动之前执行预处理操作,例如添加容器到资源管理器中进行资源分配。
  • Step 3:启动容器。最终通过grpc调用CRI去启动
  • 记录event日志
  • Step 4: 执行 post start
  • 最终通过grpc调用CRI去启动
func (m *kubeGenericRuntimeManager) startContainer(ctx context.Context, 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: 拉取镜像
	imageRef, msg, err := m.imagePuller.EnsureImageExists(ctx, 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
	}

	// Step 2: 创建容器
	//重启次数初始化0
	restartCount := 0
	containerStatus := podStatus.FindContainerStatusByName(container.Name)
	//如果存在,则重启次数+1
	if containerStatus != nil {
		restartCount = containerStatus.RestartCount + 1
	} else {
	    //不存在创建目录
		logDir := BuildContainerLogsDirectory(pod.Namespace, pod.Name, pod.UID, container.Name)
		restartCount, err = calcRestartCountByLogDir(logDir)
		if err != nil {
			klog.InfoS("Cannot calculate restartCount from the log directory", "logDir", logDir, "err", err)
			restartCount = 0
		}
	}

	target, err := spec.getTargetID(podStatus)
	if err != nil {
		s, _ := grpcstatus.FromError(err)
		m.recordContainerEvent(pod, container, "", v1.EventTypeWarning, events.FailedToCreateContainer, "Error: %v", s.Message())
		return s.Message(), ErrCreateContainerConfig
	}
	//获得创建container的基础配置2.2generateContainerConfig介绍
	containerConfig, cleanupAction, err := m.generateContainerConfig(ctx, container, pod, restartCount, podIP, imageRef, podIPs, target)
	if cleanupAction != nil {
		defer cleanupAction()
	}
	if err != nil {
		s, _ := grpcstatus.FromError(err)
		//记录event
		m.recordContainerEvent(pod, container, "", v1.EventTypeWarning, events.FailedToCreateContainer, "Error: %v", s.Message())
		return s.Message(), ErrCreateContainerConfig
	}
	//创建容器之前的准备
	err = m.internalLifecycle.PreCreateContainer(pod, container, containerConfig)
	if err != nil {
		s, _ := grpcstatus.FromError(err)
		m.recordContainerEvent(pod, container, "", v1.EventTypeWarning, events.FailedToCreateContainer, "Internal PreCreateContainer hook failed: %v", s.Message())
		return s.Message(), ErrPreCreateHook
	}
	//创建容器 最终通过grpc调用CRI去创建
	containerID, err := m.runtimeService.CreateContainer(ctx, podSandboxID, containerConfig, podSandboxConfig)
	if err != nil {
		s, _ := grpcstatus.FromError(err)
		m.recordContainerEvent(pod, container, containerID, v1.EventTypeWarning, events.FailedToCreateContainer, "Error: %v", s.Message())
		return s.Message(), ErrCreateContainer
	}
	//PreStart 阶段:在容器启动之前执行预处理操作,例如添加容器到资源管理器中进行资源分配。
	err = m.internalLifecycle.PreStartContainer(pod, container, containerID)
	if err != nil {
		s, _ := grpcstatus.FromError(err)
		m.recordContainerEvent(pod, container, containerID, v1.EventTypeWarning, events.FailedToStartContainer, "Internal PreStartContainer hook failed: %v", s.Message())
		return s.Message(), ErrPreStartHook
	}
	m.recordContainerEvent(pod, container, containerID, v1.EventTypeNormal, events.CreatedContainer, fmt.Sprintf("Created container %s", container.Name))

	// Step 3:启动容器。最终通过grpc调用CRI去启动
	err = m.runtimeService.StartContainer(ctx, containerID)
	if err != nil {
		s, _ := grpcstatus.FromError(err)
		m.recordContainerEvent(pod, container, containerID, v1.EventTypeWarning, events.FailedToStartContainer, "Error: %v", s.Message())
		return s.Message(), kubecontainer.ErrRunContainer
	}
	//记录event日志
	m.recordContainerEvent(pod, container, containerID, v1.EventTypeNormal, events.StartedContainer, fmt.Sprintf("Started container %s", container.Name))


	containerMeta := containerConfig.GetMetadata()
	sandboxMeta := podSandboxConfig.GetMetadata()
	legacySymlink := legacyLogSymlink(containerID, containerMeta.Name, sandboxMeta.Name,
		sandboxMeta.Namespace)
	containerLog := filepath.Join(podSandboxConfig.LogDirectory, containerConfig.LogPath)
	if _, err := m.osInterface.Stat(containerLog); !os.IsNotExist(err) {
		if err := m.osInterface.Symlink(containerLog, legacySymlink); err != nil {
			klog.ErrorS(err, "Failed to create legacy symbolic link", "path", legacySymlink,
				"containerID", containerID, "containerLogPath", containerLog)
		}
	}

	// Step 4: 执行 post start
	if container.Lifecycle != nil && container.Lifecycle.PostStart != nil {
		kubeContainerID := kubecontainer.ContainerID{
			Type: m.runtimeName,
			ID:   containerID,
		}
		//最终通过grpc调用CRI去启动
		msg, handlerErr := m.runner.Run(ctx, kubeContainerID, pod, container, container.Lifecycle.PostStart)
		if handlerErr != nil {
			klog.ErrorS(handlerErr, "Failed to execute PostStartHook", "pod", klog.KObj(pod),
				"podUID", pod.UID, "containerName", container.Name, "containerID", kubeContainerID.String())
			m.recordContainerEvent(pod, container, kubeContainerID.ID, v1.EventTypeWarning, events.FailedPostStartHook, "PostStartHook failed")
			if err := m.killContainer(ctx, pod, kubeContainerID, container.Name, "FailedPostStartHook", reasonFailedPostStartHook, nil); err != nil {
				klog.ErrorS(err, "Failed to kill container", "pod", klog.KObj(pod),
					"podUID", pod.UID, "containerName", container.Name, "containerID", kubeContainerID.String())
			}
			return msg, ErrPostStartHook
		}
	}

	return "", nil
}

2.1pullimage

  • 如果镜像没有tag,获取默认的(:latest)
  • 生成Annotations
  • 获得已经在本地存储的镜像id
  • 如果本地没有代表需要拉取
  • 如果不需要拉取。(验证拉取规则,这里就是判断不是always或者本地是否有了)
  • 如果本地有且本地有,直接返回返回镜像id
  • 本地没有,记录event
  • 调用grpc去CRI拉取镜像。接收返回结果。
  • 返回镜像id
func (m *imageManager) EnsureImageExists(ctx context.Context, pod *v1.Pod, container *v1.Container, pullSecrets []v1.Secret, podSandboxConfig *runtimeapi.PodSandboxConfig) (string, string, error) {
	logPrefix := fmt.Sprintf("%s/%s/%s", pod.Namespace, pod.Name, container.Image)
	ref, err := kubecontainer.GenerateContainerRef(pod, container)
	if err != nil {
		klog.ErrorS(err, "Couldn't make a ref to pod", "pod", klog.KObj(pod), "containerName", container.Name)
	}

	//如果镜像没有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
	}
	//生成Annotations
	var podAnnotations []kubecontainer.Annotation
	for k, v := range pod.GetAnnotations() {
		podAnnotations = append(podAnnotations, kubecontainer.Annotation{
			Name:  k,
			Value: v,
		})
	}

	spec := kubecontainer.ImageSpec{
		Image:       image,
		Annotations: podAnnotations,
	}
	//获得已经在本地存储的镜像id
	imageRef, err := m.imageService.GetImageRef(ctx, 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 != ""
	//如果不需要拉取。(验证拉取规则,这里就是判断不是always或者本地是否有了)
	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)
			//返回镜像id
			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
	}

	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
	}
	//记录event
	m.podPullingTimeRecorder.RecordImageStartedPulling(pod.UID)
	m.logIt(ref, v1.EventTypeNormal, events.PullingImage, logPrefix, fmt.Sprintf("Pulling image %q", container.Image), klog.Info)
	startTime := time.Now()
	pullChan := make(chan pullResult)
	//调用grpc去CRI拉取镜像
	m.puller.pullImage(ctx, 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.podPullingTimeRecorder.RecordImageFinishedPulling(pod.UID)
	m.logIt(ref, v1.EventTypeNormal, events.PulledImage, logPrefix, fmt.Sprintf("Successfully pulled image %q in %v (%v including waiting)", container.Image, imagePullResult.pullDuration, time.Since(startTime)), klog.Info)
	m.backOff.GC()
	//返回镜像id
	return imagePullResult.imageRef, "", nil
}

2.2generateContainerConfig

  • 获得uid或用户名,该用户名将从图像中运行命令
  • 验证RunAsNonRoot。非root验证只支持数字型用户。
  • 配置cmmand和args命令
  • 生成目录
  • 初始化配置
  • 设置平台特定的配置。
  • 设置env
  • 返回容器基本配置
func (m *kubeGenericRuntimeManager) generateContainerConfig(ctx context.Context, container *v1.Container, pod *v1.Pod, restartCount int, podIP, imageRef string, podIPs []string, nsTarget *kubecontainer.ContainerID) (*runtimeapi.ContainerConfig, func(), error) {
	opts, cleanupAction, err := m.runtimeHelper.GenerateRunContainerOptions(ctx, pod, container, podIP, podIPs)
	if err != nil {
		return nil, nil, err
	}
	//获得uid或用户名,该用户名将从图像中运行命令
	uid, username, err := m.getImageUser(ctx, container.Image)
	if err != nil {
		return nil, cleanupAction, err
	}

	// 验证RunAsNonRoot。非root验证只支持数字型用户。
	if err := verifyRunAsNonRoot(pod, container, uid, username); err != nil {
		return nil, cleanupAction, err
	}
	//配置cmmand和args命令
	command, args := kubecontainer.ExpandContainerCommandAndArgs(container, opts.Envs)
	//生成目录
	logDir := BuildContainerLogsDirectory(pod.Namespace, pod.Name, pod.UID, container.Name)
	err = m.osInterface.MkdirAll(logDir, 0755)
	if err != nil {
		return nil, cleanupAction, fmt.Errorf("create container log directory for container %s failed: %v", container.Name, err)
	}
	containerLogsPath := buildContainerLogsPath(container.Name, restartCount)
	restartCountUint32 := uint32(restartCount)
	//初始化配置
	config := &runtimeapi.ContainerConfig{
		Metadata: &runtimeapi.ContainerMetadata{
			Name:    container.Name,
			Attempt: restartCountUint32,
		},
		Image:       &runtimeapi.ImageSpec{Image: imageRef},
		Command:     command,
		Args:        args,
		WorkingDir:  container.WorkingDir,
		Labels:      newContainerLabels(container, pod),
		Annotations: newContainerAnnotations(container, pod, restartCount, opts),
		Devices:     makeDevices(opts),
		CDIDevices:  makeCDIDevices(opts),
		Mounts:      m.makeMounts(opts, container),
		LogPath:     containerLogsPath,
		Stdin:       container.Stdin,
		StdinOnce:   container.StdinOnce,
		Tty:         container.TTY,
	}

	// 设置平台特定的配置。
	if err := m.applyPlatformSpecificContainerConfig(config, container, pod, uid, username, nsTarget); err != nil {
		return nil, cleanupAction, err
	}

	// 设置env
	envs := make([]*runtimeapi.KeyValue, len(opts.Envs))
	for idx := range opts.Envs {
		e := opts.Envs[idx]
		envs[idx] = &runtimeapi.KeyValue{
			Key:   e.Name,
			Value: e.Value,
		}
	}
	config.Envs = envs

	return config, cleanupAction, nil
}

三、总结

到这里,一个kubectl apply的流程就走完了。最终会调用grpc去调用CRI去创建容器。
不管是创建、删除、修改等等操作,都是按照最上面的流程图的步骤来的,从一个pod的创建到最终的删除,都是按照流程图过来。流程图中所有的组件和功能也都详解介绍过了。感兴趣的可以翻历史文章查看。

上一篇:kubelet源码分析 kuberuntime的syncpod、killpod函数(二)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/619929.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

通达信自动包络线指标公式以及ATR通道指标

根据亚历山大埃尔德在其著作《以交易为生》中的描述&#xff0c;自动包络线的设计思路是将通道看作试穿衬衫一样&#xff0c;寻找那些穿起来既不过松也不过紧的衬衫&#xff0c;只让手腕和脖子露在外面。自动包络线能够适应最近的行情波动&#xff0c;只有在极端情况下&#xf…

修电脑屏幕记

21年的时候媳妇买了台联想小新16Pro&#xff0c;最近发现屏幕闪&#xff0c;查了查售后政策&#xff0c;好在屏幕质保两年。 找维修点 从高德地图里搜联想售后很正常吧&#xff01;看看图片带着Lenovo的图片&#xff0c;是不是感觉是官方售后&#xff1f;拨打电话打到的是总部…

AI生成的二维码,真的太好看了!

今天我们迫不及待要和大家分享一组图片。 这是一位二维码开发者——倪豪 Isle of Chaos&#xff0c;与几位同学和老师们一起&#xff0c;使用最新的AI技术生成的非常惊艳的图片。最重要的是&#xff0c;这些图片里面都暗藏了一个可识别的二维码&#xff01; 总之&#xff0c;…

回归分析处理

线性回归 最小二乘法 对于某数据量 有呈线性关系的输出量 &#xff0c;且 &#xff0c;现有对这些数据量的采集序列&#xff0c;这些采集量会存在随机误差&#xff0c;线性回归的目的便是找到保证使误差最小的情况下的回归系数 。 即通过下列方程组求 可利用最小二乘法&a…

SaaS行业的公司为什么都需要一个专业的知识库

随着云计算和人工智能技术的不断发展&#xff0c;SaaS&#xff08;Software as a Service&#xff09;模式已经成为了企业信息化转型的必备选择。SaaS 公司提供的服务可以帮助客户在不增加IT投资的情况下&#xff0c;获得更为高效灵活的IT解决方案。但随着客户数量和服务类型的…

Windows下的网络编程Winsock

文章目录 前言1、服务器下的Winsock1.1、构建编程环境:1.2、WSAData结构体1.3、WSAStartup初始化Winsock1.4、WSACleanup释放Winsock1.5、socket创建套接字1.6、bind绑定套接字&#xff0c;调用其分配IP地址和端口号1.7、listen监听套接字1.8、accept接受客户端连接请求1.9、cl…

k8s helm安装使用

1.前言 Helm 是一个 Kubernetes 包管理工具&#xff0c;它的作用是简化 Kubernetes 应用程序的部署和管理。Helm 允许您将 Kubernetes 应用程序打包为 chart&#xff0c;chart 是一组预定义的 Kubernetes 对象模板&#xff0c;包括 Deployment、Service、Ingress 等。使用 Hel…

python中文情感分析---基于包含分数的情感词典实现对于各语句的情感分析的方案

一、详情简介: 1.此文主要研究方向为:基于包含分数的情感词典实现对于各语句的情感分析&#xff1b; 2.情感分析主要基于文本数据&#xff0c;是自然语言处理&#xff08;NPL&#xff09;的主要内容。情感分析&#xff1a;又称意见挖掘、倾向性分析等。简单而言,是对带有情感…

Unity中的【Dropdown(包括TMP_Dropdown)下拉框当只有一个下拉值时多次点击 OnValueChange事件无效】的改进方法

Dropdown(包括TMP_Dropdown)下拉框当只有一个下拉值时&#xff0c;多次点击下拉框&#xff0c;并选择选项时&#xff0c; OnValueChange事件不响应 一、下拉框提供了一个【onValueChance】的事件接口 当下拉框值变化的时候&#xff0c;代表用户选择了新的值&#xff0c;于是执…

【高级篇】分布式缓存

分布式缓存 – 基于Redis集群解决单机Redis存在的问题 单机的Redis存在四大问题&#xff1a; 1.Redis持久化 Redis有两种持久化方案&#xff1a; RDB持久化AOF持久化 1.1.RDB持久化 RDB全称Redis Database Backup file&#xff08;Redis数据备份文件&#xff09;&#xf…

计算机毕业论文内容参考|基于App的WiFi的网络定时开关的设计与实现

文章目录 导文文章重点前言课题内容、相关技术与方法介绍技术分析技术设计技术实现总结与展望本文总结后续工作展望导文 计算机毕业论文内容参考|基于App的WiFi的网络定时开关的设计与实现 文章重点 前言 随着智能化时代的到来,移动设备已经成为我们生活中不可或缺的一部分。…

《精通特征工程》学习笔记(4):分类变量:自动化时代的数据计数

1.分类变量 分类变量是用来表示类别或标记的。在实际的数据集中&#xff0c;类别的数量总是有限的。类别可以用数字表示&#xff0c;但与数值型变量不同&#xff0c;分类变量的值是不能被排序的。&#xff08;作为行业类型&#xff0c;石油和旅游之间是分不出大小的。&#xf…

java4.6 Spring Boot整合MyBatis

Spring Boot 整合MyBatis &#xff08;一&#xff09;基础环境搭建 1、数据准备 &#xff08;1&#xff09;创建博客数据库blog CREATE DATABASE blog&#xff08;2&#xff09;在博客数据库里创建文章表t_article CREATE TABLE t_article (id int(20) NOT NULL AUTO_INCR…

安全可以被“看见”吗?华云安的答案是“可以,且持续验证”

科技云报道原创。 近年来&#xff0c;随着攻防对抗技术的不断升级&#xff0c;安全运营市场“新贵”不断涌现&#xff0c;从安全信息和事件管理&#xff08;SIEM&#xff09;、扩展检测与响应&#xff08;XDR&#xff09;&#xff0c;到攻击面管理&#xff08;ASM&#xff09;…

地震勘探基础(十三)之地震资料解释

地震资料解释 地震资料解释&#xff08;seismic interpretation&#xff09;就是把经过采集和计算机处理后的地震数据转变为地质信息的过程。也就是由已知实际观测的地震数据反演地下地质特征的过程&#xff0c;因此地震资料解释也可称为地震反演。 根据地震资料类型不同&…

【python】 用来将对象持久化的 pickle 模块

pickle 模块可以对一个 Python 对象的二进制进行序列化和反序列化。说白了&#xff0c;就是它能够实现任意对象与二进制直接的相互转化&#xff0c;也可以实现对象与文本之间的相互转化。 比如&#xff0c;我程序里有一个 python 对象&#xff0c;我想把它存到磁盘里&#xff…

有什么好用的电容笔?好用的苹果平替笔

目前市面上的电容笔品类众多&#xff0c;面对琳琅满目的电容笔&#xff0c;很多人一时之间无从下手&#xff0c;不知道口碑比较好的电容笔是什么牌子&#xff0c;因此小编根据电容笔热卖榜&#xff0c;给大家整理了一期电容笔测评&#xff0c;希望能给大家选购电容笔带来帮助和…

3DVR全景技术引领乡村发展新时代!

导语&#xff1a; 在当代社会&#xff0c;科技的迅猛发展与数字化的浪潮已经深入到各个行业&#xff0c;带来了许多新的机遇与挑战。 数字乡村的概念逐渐引起人们的关注与热议。数字乡村作为现代化与传统农业的结合产物&#xff0c;以数字技术和虚拟现实&#xff08;VR&#…

格灵深瞳发布“深瞳阿瞳目”,体育课离AI越来越近

向上探索更普适的大语言模型&#xff0c;向下寻找更具体的应用场景&#xff0c;AI厂商正在这两条路上狂奔。 在众多应用场景中&#xff0c;教育是AI最重要的应用方向之一。中国有2.91亿在校学生、1844.37万专任教师、2800万台校园终端设备&#xff0c;庞大的用户体量汇聚了海量…

聊一聊关于视频缩略图缓存策略

作者&#xff1a;一只修仙的猿 最近回归android业务开发&#xff0c;开发了如下图的视频剪辑时间轴&#xff08;图源&#xff1a;剪映&#xff09;&#xff1a; 对于时间轴上的缩略图&#xff0c;需要去解码器加载获取。若每次都去解码器获取&#xff0c;会导致缩略图加载卡顿&…