首页 > 新闻资讯 > 为什么要做容器启动顺序控制?启动成功容器就可以对外提供服务吗?

为什么要做容器启动顺序控制?启动成功容器就可以对外提供服务吗?

时间:2022-08-04 21:39来源:财神爷站

  为什么要做容器启动顺序控制?我们都知道?Pod?中除了?init-container?之外,是允许添加多个容器的。类似?TektonCD?中?task?和?step?的概念就分别与?pod?和?container?对应,而?step?是按照顺序执行的。此外还有服务网格的场景,sidecar?容器需要在服务容器启动之前完成配置的加载,也需要对容器的启动顺序加以控制。否则,服务容器先启动,而?sidecar?还无法提供网络上的支持。

  现实

  期望?

  到了这里肯定有同学会问,spec.containers[]?是一个数组,数组是有顺序的。Kubernetes?也确实是按照顺序来创建和启动容器,但是?容器启动成功,并不表示容器可以对外提供服务。

  在?Kubernetes?1.18?非正式版中曾在?Lifecycle?层面提供了对?sidecar?类型容器的?支持,但是最终该功能并没有落地[2]。

  那到底该怎么做?

  TL;DR

  笔者准备了一个简单的?go?项目[3],用于模拟?sidecar?的启动及配置加载。

  克隆代码后可以通过?make?build?构建出镜像,假如你是用的?minikube?进行的实验,可以通过命令?make?load-2-minikube?将镜像加载到?minikube?节点中。

  使用?Deployment?的方式进行部署,直接用?Pod?也可以。

  apiVersion:?apps/v1kind:Deploymentmetadata:creationTimestamp:nulllabels:app:?samplename:?samplespec:replicas:1selector:matchLabels:app:?samplestrategy:{}template:metadata:creationTimestamp:nulllabels:app:?samplespec:containers:-?image:?addozhang/k8s-container-sequence-sidecar:latestname:?sidecarimagePullPolicy:IfNotPresentlifecycle:postStart:exec:command:-/entrypoint-?wait-?image:?busybox:latestname:?appimagePullPolicy:IfNotPresentcommand:["/bin/sh","-c"]args:["date;?echo?'app?container?started';?tail?-f?/dev/null"]

  下面的截图中,演示了在?sample?命名空间中,pod?内两个容器的执行顺序。

  Kubernetes?源码

  在?kubelet?的源码?pkg/kubelet/kuberuntime/kuberuntime_manager.go?中,#SyncPod?方法用于创建?Pod,步骤比较繁琐,直接看第?7?步:创建普通容器。

  //?SyncPod?syncs?the?running?pod?into?the?desired?pod?by?executing?following?steps:////?1.?Compute?sandbox?and?container?changes.//?2.?Kill?pod?sandbox?if?necessary.//?3.?Kill?any?containers?that?should?not?be?running.//?4.?Create?sandbox?if?necessary.//?5.?Create?ephemeral?containers.//?6.?Create?init?containers.//?7.?Create?normal?containers.func?(m?*kubeGenericRuntimeManager)SyncPod(pod?*v1.Pod,?podStatus?*kubecontainer.PodStatus,?pullSecrets?[]v1.Secret,?backOff?*flowcontrol.Backoff)(result?kubecontainer.PodSyncResult){...//?Step?7:?start?containers?in?podContainerChanges.ContainersToStart.for?_,?idx?:=?range?podContainerChanges.ContainersToStart{start("container",?containerStartSpec(&pod.Spec.Containers[idx]))}return}

  在?#start?方法中调用了?#startContainer?方法,该方法会启动容器,并返回容器启动的结果。注意,这里的结果还?包含了容器的?Lifecycle?hooks?调用。

  也就是说,假如容器的?PostStart?hook?没有正确的返回,kubelet?便不会去创建下一个容器。

  //?startContainer?starts?a?container?and?returns?a?message?indicates?why?it?is?failed?on?error.//?It?starts?the?container?through?the?following?steps://?*?pull?the?image//?*?create?the?container//?*?start?the?container//?*?run?the?post?start?lifecycle?hooks?(if?applicable)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){...//?Step?4:?execute?the?post?start?hook.if?container.Lifecycle!=nil&&?container.Lifecycle.PostStart!=nil{kubeContainerID?:=?kubecontainer.ContainerID{Type:?m.runtimeName,ID:?containerID,}msg,?handlerErr?:=?m.runner.Run(kubeContainerID,?pod,?container,?container.Lifecycle.PostStart)if?handlerErr?!=nil{m.recordContainerEvent(pod,?container,?kubeContainerID.ID,?v1.EventTypeWarning,?events.FailedPostStartHook,?msg)if?err?:=?m.killContainer(pod,?kubeContainerID,?container.Name,"FailedPostStartHook",?reasonFailedPostStartHook,nil);?err?!=nil{klog.ErrorS(fmt.Errorf("%s:?%v",ErrPostStartHook,?handlerErr),"Failed?to?kill?container","pod",?klog.KObj(pod),"podUID",?pod.UID,"containerName",?container.Name,"containerID",?kubeContainerID.String)}return?msg,?fmt.Errorf("%s:?%v",ErrPostStartHook,?handlerErr)}}return"",nil}

  实现方案

  cmd/entrypoint/wait.go#L26[4]?(这里参考了?Istio?的?pilot-agent?实现?)

  在?PostStart?中持续的去检查?/ready?断点,可以?hold?住当前容器的创建流程。保证?/ready?返回?200?后,kubelet?才会去创建下一个容器。

  这样就达到了前面截图中演示的效果。

  for?time.Now.Before(timeoutAt){err?=?checkIfReady(client,?url)if?err?==nil{log.Println("sidecar?is?ready")returnnil}log.Println("sidecar?is?not?ready")time.Sleep(time.Duration(periodMillis)*?time.Millisecond)}return?fmt.Errorf("sidecar?is?not?ready?in?%d?second(s)",?timeoutSeconds)

  参考

  Sidecar?container?lifecycle?changes?in?Kubernetes?1.18[5]

  Delaying?application?start?until?sidecar?is?ready[6]

相关文章
热门手机应用
热门手机游戏