有没有一种优雅地结束 Kubernetes client-go 中的 Pod 的方法?

huangapple go评论75阅读模式
英文:

Is there a way to gracefully end a pod with the Kubernetes client-go?

问题

主要问题是是否有一种方法可以使用client-go sdk完成一个Pod,我不是要删除一个Pod,我只是想将其状态设置为Completed

在代码中,我尝试更新Pod的状态,但它不起作用,它没有返回错误或崩溃,但Pod没有完成。
我的代码:

func main() {

    // 创建集群内部配置
    config, err := rest.InClusterConfig()
    if err != nil {
        panic(err.Error())
    }
    // 创建客户端集
    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        panic(err.Error())
    }
    for {

        pods, err := clientset.CoreV1().Pods("ns").List(context.TODO(), metav1.ListOptions{})
        if err != nil {
            panic(err.Error())
        }
        for _, pod := range pods.Items {

            podName := pod.Name
            if strings.Contains(strings.ToLower(podName), "single-condition") {

                fmt.Println("获取Pod元数据")
                fmt.Println(pod.Name)
                fmt.Printf("pod.Name %s \n", pod.Name)
                fmt.Printf("Status.Phase %s \n", pod.Status.Phase)
                fmt.Printf("PodIP %s \n", pod.Status.PodIP)

                containers := pod.Status.ContainerStatuses
                if len(containers) > 0 {
                    for _, c := range containers {
                        fmt.Printf("c.Name %s \n", c.Name)
                        fmt.Printf("c.State %s \n", c.State)
                        fmt.Printf("c.State.Terminated %s \n", c.State.Terminated)

                        stateTerminated := c.State.Terminated
                        stateRunning := c.State.Running
                        if stateTerminated == nil && stateRunning != nil {
                            fmt.Printf("c.State.Terminated %s \n", c.State.Terminated)
                            fmt.Printf("stateRunning Reason: %s\n", reflect.TypeOf(c.State.Running))

                            getPod, getErr := clientset.CoreV1().Pods("ns").Get(context.TODO(), "single-condition-pipeline-9rqrs-1224102659", metav1.GetOptions{})
                            if getErr != nil {
                                fmt.Println("错误1")
                                panic(fmt.Errorf("获取失败:%v", getErr))
                            }
                            fmt.Println("更新值")
                            fmt.Printf(" getPodName %d \n", getPod.Name)
                            getPod.Status.Phase = "Succeeded"
                            fmt.Println("更新状态阶段")
                            getContainers := getPod.Status.ContainerStatuses
                            fmt.Printf("len get container %d \n", len(getContainers))
                            _, updateErr := clientset.CoreV1().Pods("argo-workflows").Update(context.TODO(), getPod, metav1.UpdateOptions{})
                            fmt.Println("提交更新")
                            if updateErr != nil {
                                fmt.Println("更新错误")
                                panic(fmt.Errorf("更新失败:%v", updateErr))
                            }

                        } else {
                            fmt.Printf("c.State.Terminated %s \n", c.State.Terminated.Reason)
                            //fmt.Println("Not finished ready!!!")
                            //fmt.Printf("c.State.Running %s \n", c.State.Running)
                            //fmt.Printf("c.State.Waiting %s \n", c.State.Waiting)
                        }
                    }
                }
            }
        }
        time.Sleep(10 * time.Second)

    }
}

一些日志:

single-condition-pipeline-9rqrs-1224102659
pod.Name single-condition-pipeline-9rqrs-1224102659 
Status.Phase Running 
PodIP XXXXXXXXXXXX
c.Name main 
---------------------------------------------------------------------------------------------
c.State {nil &ContainerStateRunning{StartedAt:2021-10-29 04:41:51 +0000 UTC,} nil} 
c.State.Terminated nil 
c.State.Terminated nil 
stateRunning Reason: *v1.ContainerStateRunning
update values
getPodName %!d(string=single-condition-pipeline-9rqrs-1224102659) 
updated status phase
len get container 2 
commit update
c.Name wait 
c.State {nil &ContainerStateRunning{StartedAt:2021-10-29 04:41:51 +0000 UTC,} nil} 
c.State.Terminated nil 
c.State.Terminated nil 
stateRunning Reason: *v1.ContainerStateRunning
update values
getPodName %!d(string=single-condition-pipeline-9rqrs-1224102659) 
updated status phase
len get container 2 
---------------------------------------------------------------------------------------------
commit update
---------------------------------------------------------------------------------------------
获取Pod元数据
single-condition-pipeline-9rqrs-1224102659
pod.Name single-condition-pipeline-9rqrs-1224102659 
Status.Phase Running 
PodIP XXXXXXXXXX 
c.Name main 
c.State {nil &ContainerStateRunning{StartedAt:2021-10-29 04:41:51 +0000 UTC,} nil} 
c.State.Terminated nil 
c.State.Terminated nil 
stateRunning Reason: *v1.ContainerStateRunning
update values
getPodName %!d(string=single-condition-pipeline-9rqrs-1224102659) 
updated status phase
len get container 2 
commit update
c.Name wait 
c.State {nil &ContainerStateRunning{StartedAt:2021-10-29 04:41:51 +0000 UTC,} nil} 
c.State.Terminated nil 
c.State.Terminated nil 
stateRunning Reason: *v1.ContainerStateRunning
update values
getPodName %!d(string=single-condition-pipeline-9rqrs-1224102659) 
updated status phase
len get container 2 
commit update

所以在这里:https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-readiness-status,它提到了一个Patch,但我不知道如何使用它,所以如果有人可以帮助我或者有其他方法来完成它。

英文:

The main question is if there is a way to finish a pod from the client-go sdk, I'm not trying to delete a pod, I just want to finish it with a Phase-Status: Completed.

In the code, I'm trying to update the pod phase but It doesn't work, It does not return an error or panic but The pod does not finish.
My code:

func main() {
// creates the in-cluster config
config, err := rest.InClusterConfig()
if err != nil {
panic(err.Error())
}
// creates the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
panic(err.Error())
}
for {
pods, err := clientset.CoreV1().Pods("ns").List(context.TODO(), metav1.ListOptions{})
if err != nil {
panic(err.Error())
}
for _, pod := range pods.Items {
podName:= pod.Name
if strings.Contains(strings.ToLower(podName), "single-condition") {
fmt.Println("get pods metadatada")
fmt.Println(pod.Name)
fmt.Printf("pod.Name %s \n", pod.Name)
fmt.Printf("Status.Phase %s \n", pod.Status.Phase)
fmt.Printf("PodIP %s \n", pod.Status.PodIP)
containers := pod.Status.ContainerStatuses
if len(containers) > 0 {
for _ ,c := range containers {
fmt.Printf("c.Name %s \n", c.Name)
fmt.Printf("c.State %s \n", c.State)
fmt.Printf("c.State.Terminated %s \n", c.State.Terminated)
stateTerminated := c.State.Terminated
stateRunning := c.State.Running
if stateTerminated == nil && stateRunning != nil {
fmt.Printf("c.State.Terminated %s \n", c.State.Terminated)
fmt.Printf("stateRunning Reason: %s\n", reflect.TypeOf(c.State.Running))
getPod, getErr := clientset.CoreV1().Pods("ns").Get(context.TODO(), "single-condition-pipeline-9rqrs-1224102659" , metav1.GetOptions{})
if getErr != nil {
fmt.Println("error1")
panic(fmt.Errorf("Failed to get: %v", getErr))
}
fmt.Println("update values")
fmt.Printf(" getPodName %d \n", getPod.Name)
getPod.Status.Phase = "Succeeded"
fmt.Println("updated status phase")
getContainers := getPod.Status.ContainerStatuses
fmt.Printf("len get container %d \n", len(getContainers))
_, updateErr := clientset.CoreV1().Pods("argo-workflows").Update(context.TODO(), getPod, metav1.UpdateOptions{})
fmt.Println("commit update")
if updateErr != nil {
fmt.Println("error updated")
panic(fmt.Errorf("Failed to update: %v", updateErr))
}
} else {
fmt.Printf("c.State.Terminated %s \n", c.State.Terminated.Reason)
//fmt.Println("Not finished ready!!!")
//fmt.Printf("c.State.Running %s \n", c.State.Running)
//fmt.Printf("c.State.Waiting %s \n", c.State.Waiting)
}
}
}
}
}
time.Sleep(10 * time.Second)
}
}

and some logs:

single-condition-pipeline-9rqrs-1224102659
pod.Name single-condition-pipeline-9rqrs-1224102659 
Status.Phase Running 
PodIP XXXXXXXXXXXX
c.Name main 
---------------------------------------------------------------------------------------------
c.State {nil &ContainerStateRunning{StartedAt:2021-10-29 04:41:51 +0000 UTC,} nil} 
c.State.Terminated nil 
c.State.Terminated nil 
stateRunning Reason: *v1.ContainerStateRunning
update values
getPodName %!d(string=single-condition-pipeline-9rqrs-1224102659) 
updated status phase
len get container 2 
commit update
c.Name wait 
c.State {nil &ContainerStateRunning{StartedAt:2021-10-29 04:41:51 +0000 UTC,} nil} 
c.State.Terminated nil 
c.State.Terminated nil 
stateRunning Reason: *v1.ContainerStateRunning
update values
getPodName %!d(string=single-condition-pipeline-9rqrs-1224102659) 
updated status phase
len get container 2 
---------------------------------------------------------------------------------------------
commit update
---------------------------------------------------------------------------------------------
get pods metadatada
single-condition-pipeline-9rqrs-1224102659
pod.Name single-condition-pipeline-9rqrs-1224102659 
Status.Phase Running 
PodIP XXXXXXXXXX 
c.Name main 
c.State {nil &ContainerStateRunning{StartedAt:2021-10-29 04:41:51 +0000 UTC,} nil} 
c.State.Terminated nil 
c.State.Terminated nil 
stateRunning Reason: *v1.ContainerStateRunning
update values
getPodName %!d(string=single-condition-pipeline-9rqrs-1224102659) 
updated status phase
len get container 2 
commit update
c.Name wait 
c.State {nil &ContainerStateRunning{StartedAt:2021-10-29 04:41:51 +0000 UTC,} nil} 
c.State.Terminated nil 
c.State.Terminated nil 
stateRunning Reason: *v1.ContainerStateRunning
update values
getPodName %!d(string=single-condition-pipeline-9rqrs-1224102659) 
updated status phase
len get container 2 
commit update

so here: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-readiness-status, It mentions a Patch but I don't know how to use it, so if somebody could help me or if there is another way to finish it.

答案1

得分: 2

你不能在 Pod 的 status 字段中设置 phase 或其他任何内容,它是只读的。根据Pod 生命周期文档,在“所有 Pod 中的容器成功终止,并且不会重新启动”之后,你的 Pod 将处于 Succeeded 阶段。因此,只有当你能够使 Pod 中的所有容器以状态码 0 退出,并且 Pod 的 restartPolicy 设置为 onFailureNever 时,才会发生这种情况;如果设置为 Always(默认值),容器最终会重新启动,你的 Pod 最终会返回到 Running 阶段。

总之,你不能通过 Kube API 直接实现你所尝试的操作。你必须:

  1. 确保你的 Pod 具有支持 Succeeded 阶段的 restartPolicy
  2. 通过发送 SIGINTSIGTERM 终止你的应用程序,或通过其自身的 API 命令它。
英文:

You cannot set the phase or anything else in the Pod status field, it is read only. According to the Pod Lifecycle documentation your pod will have a phase of Succeeded after "All containers in the Pod have terminated in success, and will not be restarted." So this will only happen if you can cause all of your pod's containers to exit with status code 0 and if the pod restartPolicy is set to onFailure or Never, if it is set to Always (the default) then the containers will eventually restart and your pod will eventually return to the Running phase.

In summary, you cannot do what you are attempting to do via the Kube API directly. You must:

  1. Ensure your pod has a restartPolicy that can support the Succeeded phase.
  2. Cause your application to terminate, possibly by sending it SIGINT or SIGTERM, or possibly by commanding it via its own API.

huangapple
  • 本文由 发表于 2021年10月29日 15:34:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/69765180.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定