mirror of
https://github.com/zalando/postgres-operator.git
synced 2026-10-20 12:31:08 +02:00
Fix rolling update deadlock when pods are stuck in non-running state (#3051)
* add fix to recreate non running pods in syncStatefulsets * remove TestSyncStatefulSetNonRunningPodsDoNotBlockRecreatio * revert pod_test * pod without status --------- Co-authored-by: Felix Kunde <felix-kunde@gmx.de> Co-authored-by: Ida Novindasari <idanovinda@gmail.com>
This commit is contained in:
co-authored by
Felix Kunde
Ida Novindasari
parent
688bbf1b9e
commit
97f4de7cc0
+35
-1
@@ -376,6 +376,36 @@ func (c *Cluster) getPatroniMemberData(pod *v1.Pod) (patroni.MemberData, error)
|
||||
return memberData, nil
|
||||
}
|
||||
|
||||
// podIsNotRunning returns true if a pod is known to be in a non-running state,
|
||||
// e.g. stuck in CreateContainerConfigError, CrashLoopBackOff, ImagePullBackOff, etc.
|
||||
// Pods with no status information are not considered non-running, as they may
|
||||
// simply not have reported status yet.
|
||||
func podIsNotRunning(pod *v1.Pod) bool {
|
||||
if pod.Status.Phase == "" {
|
||||
// No status reported yet — don't treat as non-running
|
||||
return false
|
||||
}
|
||||
if pod.Status.Phase != v1.PodRunning {
|
||||
return true
|
||||
}
|
||||
for _, cs := range pod.Status.ContainerStatuses {
|
||||
if cs.State.Waiting != nil || cs.State.Terminated != nil {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// allPodsRunning returns true only if every pod in the list is in a healthy running state.
|
||||
func (c *Cluster) allPodsRunning(pods []v1.Pod) bool {
|
||||
for i := range pods {
|
||||
if podIsNotRunning(&pods[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *Cluster) recreatePod(podName spec.NamespacedName) (*v1.Pod, error) {
|
||||
stopCh := make(chan struct{})
|
||||
ch := c.registerPodSubscriber(podName)
|
||||
@@ -444,7 +474,8 @@ func (c *Cluster) recreatePods(pods []v1.Pod, switchoverCandidates []spec.Namesp
|
||||
// switchover if
|
||||
// 1. we have not observed a new master pod when re-creating former replicas
|
||||
// 2. we know possible switchover targets even when no replicas were recreated
|
||||
if newMasterPod == nil && len(replicas) > 0 {
|
||||
// 3. the master pod is actually running (can't switchover a dead master)
|
||||
if newMasterPod == nil && len(replicas) > 0 && !podIsNotRunning(masterPod) {
|
||||
masterCandidate, err := c.getSwitchoverCandidate(masterPod)
|
||||
if err != nil {
|
||||
// do not recreate master now so it will keep the update flag and switchover will be retried on next sync
|
||||
@@ -455,6 +486,9 @@ func (c *Cluster) recreatePods(pods []v1.Pod, switchoverCandidates []spec.Namesp
|
||||
}
|
||||
} else if newMasterPod == nil && len(replicas) == 0 {
|
||||
c.logger.Warningf("cannot perform switch over before re-creating the pod: no replicas")
|
||||
} else if podIsNotRunning(masterPod) {
|
||||
c.logger.Warningf("master pod %q is not running, skipping switchover and recreating directly",
|
||||
util.NameFromMeta(masterPod.ObjectMeta))
|
||||
}
|
||||
c.logger.Infof("recreating old master pod %q", util.NameFromMeta(masterPod.ObjectMeta))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user