成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

跟我學 K8S--代碼: Kubernetes StatefulSet 代碼分析與Unknown 狀

tolerious / 3672人閱讀

摘要:節(jié)點對不會有影響,查詢處于狀態(tài)并一直保持。根據(jù)上一節(jié)描述,此時已經(jīng)有正確的在其他節(jié)點,此時故障節(jié)點恢復(fù)后,執(zhí)行優(yōu)雅刪除,刪除舊的。會從狀態(tài)變?yōu)闋顟B(tài),執(zhí)行優(yōu)雅刪除,,然后執(zhí)行重新調(diào)度與重建操作。會從狀態(tài)直接變成狀態(tài),不涉及重建。

節(jié)點離線后的 pod 狀態(tài)

在 kubernetes 使用過程中,根據(jù)集群的配置不同,往往會因為如下情況的一種或幾種導(dǎo)致節(jié)點 NotReady:

kubelet 進程停止

apiserver 進程停止

etcd 進程停止

kubernetes 管理網(wǎng)絡(luò) Down

當出現(xiàn)這種情況的時候,會出現(xiàn)節(jié)點 NotReady,進而當kube-controller-manager 中的--pod-eviction-timeout定義的值,默認 5 分鐘后,將觸發(fā) Pod eviction 動作。

對于不同類型的 workloads,其對應(yīng)的 pod 處理方式因為 controller-manager 中各個控制器的邏輯不通而不同??偨Y(jié)如下:

deployment: 節(jié)點 NotReady 觸發(fā) eviction 后,pod 將會在新節(jié)點重建(如果有 nodeSelector 或者親和性要求,會處于 Pending 狀態(tài)),故障節(jié)點的 Pod 仍然會保留處于 Unknown 狀態(tài),所以此時看到的 pod 數(shù)多于副本數(shù)。

statefulset: 節(jié)點 NotReady 同樣會對 StatefulSet 觸發(fā) eviction 操作,但是用戶看到的 Pod 會一直處于 Unknown 狀態(tài)沒有變化。

daemonSet: 節(jié)點 NotReady 對 DaemonSet 不會有影響,查詢 pod 處于 NodeLost 狀態(tài)并一直保持。

這里說到,對于 deploymentstatefulSet 類型資源,當節(jié)點 NotReady 后顯示的 pod 狀態(tài)為 Unknown。 這里實際上 etcd 保存的狀態(tài)為 NodeLost,只是顯示時做了處理,與 daemonSet 做了區(qū)分。對應(yīng)代碼中的邏輯為:

### node controller

// 觸發(fā) NodeEviction 操作時會 DeletePods,這個刪除為 GracefulDelete,
// apiserver rest 接口對 PodObj 添加了 DeletionTimestamp
func DeletePods(kubeClient clientset.Interface, recorder record.EventRecorder, nodeName, nodeUID string, daemonStore extensionslisters.DaemonSetLister) (bool, error) {
...
        for _, pod := range pods.Items {
...
        // Set reason and message in the pod object.
        if _, err = SetPodTerminationReason(kubeClient, &pod, nodeName); err != nil {
            if apierrors.IsConflict(err) {
                updateErrList = append(updateErrList,
                    fmt.Errorf("update status failed for pod %q: %v", format.Pod(&pod), err))
                continue
            }
        }
        // if the pod has already been marked for deletion, we still return true that there are remaining pods.
        if pod.DeletionGracePeriodSeconds != nil {
            remaining = true
            continue
        }
        // if the pod is managed by a daemonset, ignore it
        _, err := daemonStore.GetPodDaemonSets(&pod)
        if err == nil { // No error means at least one daemonset was found
            continue
        }

        glog.V(2).Infof("Starting deletion of pod %v/%v", pod.Namespace, pod.Name)
        recorder.Eventf(&pod, v1.EventTypeNormal, "NodeControllerEviction", "Marking for deletion Pod %s from Node %s", pod.Name, nodeName)
        if err := kubeClient.CoreV1().Pods(pod.Namespace).Delete(pod.Name, nil); err != nil {
            return false, err
        }
        remaining = true
    }
...
}

### staging apiserver REST 接口

// 對于優(yōu)雅刪除,到這里其實已經(jīng)停止,不再進一步刪除,剩下的交給 kubelet watch 到變化后去做 delete
func (e *Store) Delete(ctx genericapirequest.Context, name string, options *metav1.DeleteOptions) (runtime.Object, bool, error) {
...
    if graceful || pendingFinalizers || shouldUpdateFinalizers {
            err, ignoreNotFound, deleteImmediately, out, lastExisting = e.updateForGracefulDeletionAndFinalizers(ctx, name, key, options, preconditions, obj)
        }
    // !deleteImmediately covers all cases where err != nil. We keep both to be future-proof.
    if !deleteImmediately || err != nil {
        return out, false, err
    }
...
}
        
// stagging/apiserver中的 rest 接口調(diào)用,設(shè)置了 DeletionTimestamp 和 DeletionGracePeriodSeconds
func (e *Store) updateForGracefulDeletionAndFinalizers(ctx genericapirequest.Context, name, key string, options *metav1.DeleteOptions, preconditions storage.Preconditions, in runtime.Object) (err error, ignoreNotFound, deleteImmediately bool, out, lastExisting runtime.Object) {
...

        if options.GracePeriodSeconds != nil {
            period := int64(*options.GracePeriodSeconds)
            if period >= *objectMeta.GetDeletionGracePeriodSeconds() {
                return false, true, nil
            }
            newDeletionTimestamp := metav1.NewTime(
                objectMeta.GetDeletionTimestamp().Add(-time.Second * time.Duration(*objectMeta.GetDeletionGracePeriodSeconds())).
                    Add(time.Second * time.Duration(*options.GracePeriodSeconds)))
            objectMeta.SetDeletionTimestamp(&newDeletionTimestamp)
            objectMeta.SetDeletionGracePeriodSeconds(&period)
            return true, false, nil
        }
...
}

### node controller 

// SetPodTerminationReason 嘗試設(shè)置 Pod狀態(tài)和原因到 Pod 對象中
func SetPodTerminationReason(kubeClient clientset.Interface, pod *v1.Pod, nodeName string) (*v1.Pod, error) {
    if pod.Status.Reason == nodepkg.NodeUnreachablePodReason {
        return pod, nil
    }

    pod.Status.Reason = nodepkg.NodeUnreachablePodReason
    pod.Status.Message = fmt.Sprintf(nodepkg.NodeUnreachablePodMessage, nodeName, pod.Name)

    var updatedPod *v1.Pod
    var err error
    if updatedPod, err = kubeClient.CoreV1().Pods(pod.Namespace).UpdateStatus(pod); err != nil {
        return nil, err
    }
    return updatedPod, nil
}

### 命令行輸出

// 打印輸出時狀態(tài)的切換,如果 "DeletionTimestamp 不為空" 且 "podStatus 為 NodeLost 狀態(tài)"時,
// 顯示的狀態(tài)為 Unknown
func printPod(pod *api.Pod, options printers.PrintOptions) ([]metav1alpha1.TableRow, error) {
...
    if pod.DeletionTimestamp != nil && pod.Status.Reason == node.NodeUnreachablePodReason {
        reason = "Unknown"
    } else if pod.DeletionTimestamp != nil {
        reason = "Terminating"
    }
...
}
節(jié)點恢復(fù) Ready 后 pod 狀態(tài)

當節(jié)點恢復(fù)后,不同的 workload 對應(yīng)的 pod 狀態(tài)變化也是不同的。

deployment: 根據(jù)上一節(jié)描述,此時 pod 已經(jīng)有正確的 pod 在其他節(jié)點 running,此時故障節(jié)點恢復(fù)后,kubelet 執(zhí)行優(yōu)雅刪除,刪除舊的 PodObj。
statefulset: statefulset 會從Unknown 狀態(tài)變?yōu)?Terminating 狀態(tài),執(zhí)行優(yōu)雅刪除,detach PV,然后執(zhí)行重新調(diào)度與重建操作。
daemonset: daemonset 會從 NodeLost 狀態(tài)直接變成 Running 狀態(tài),不涉及重建。

Statefulset 為什么沒有重建與單副本高可用?

我們往往會考慮下面兩個問題,statefulset 為什么沒有重建? 如何保持單副本 statefulset 的高可用呢?

關(guān)于為什么沒重建

首先簡單介紹下 statefulset 控制器的邏輯。

Statefulset 控制器通過 StatefulSetControl 以及 StatefulPodControl 2個模塊協(xié)調(diào)完成對 statefulSet 類型 workload 的狀態(tài)管理(StatefulSetStatusUpdater)和擴縮控制(StatefulPodControl)。實際上,StatefulsetControl是對 StatefulPodControl 的調(diào)用來增刪改 Pod。

StatefulSet 在 podManagementPolicy 為默認值 OrderedReady 時,會按照整數(shù)順序單調(diào)遞增的依次創(chuàng)建 Pod,否則在 Parallel時,雖然是按整數(shù),但是 Pod 是同時調(diào)度與創(chuàng)建。

具體的邏輯在核心方法 UpdateStatefulSet 中,見圖:

我們看到的 Stateful Pod 一直處于 Unknown 狀態(tài)的原因就是因為這個控制器屏蔽了對該 Pod 的操作。因為在第一節(jié)介紹了,NodeController 的 Pod Eviction 機制已經(jīng)把 Pod 標記刪除,PodObj 中包含的 DeletionTimestamp 被設(shè)置,StatefulSet Controller 代碼檢查 IsTerminating 符合條件,便直接 return 了。

// updateStatefulSet performs the update function for a StatefulSet. This method creates, updates, and deletes Pods in
// the set in order to conform the system to the target state for the set. The target state always contains
// set.Spec.Replicas Pods with a Ready Condition. If the UpdateStrategy.Type for the set is
// RollingUpdateStatefulSetStrategyType then all Pods in the set must be at set.Status.CurrentRevision.
// If the UpdateStrategy.Type for the set is OnDeleteStatefulSetStrategyType, the target state implies nothing about
// the revisions of Pods in the set. If the UpdateStrategy.Type for the set is PartitionStatefulSetStrategyType, then
// all Pods with ordinal less than UpdateStrategy.Partition.Ordinal must be at Status.CurrentRevision and all other
// Pods must be at Status.UpdateRevision. If the returned error is nil, the returned StatefulSetStatus is valid and the
// update must be recorded. If the error is not nil, the method should be retried until successful.
func (ssc *defaultStatefulSetControl) updateStatefulSet(
    ...
    for i := range replicas {
        ...
        // If we find a Pod that is currently terminating, we must wait until graceful deletion
        // completes before we continue to make progress.
        if isTerminating(replicas[i]) && monotonic {
            glog.V(4).Infof(
                "StatefulSet %s/%s is waiting for Pod %s to Terminate",
                set.Namespace,
                set.Name,
                replicas[i].Name)
            return &status, nil
        }
    ...
    }
}


// isTerminating returns true if pod"s DeletionTimestamp has been set
func isTerminating(pod *v1.Pod) bool {
    return pod.DeletionTimestamp != nil
}

那么如何保證單副本高可用?

往往應(yīng)用中有一些 pod 沒法實現(xiàn)多副本,但是又要保證集群能夠自愈,那么這種某個節(jié)點 Down 掉或者網(wǎng)卡壞掉等情況,就會有很大影響,要如何能夠?qū)崿F(xiàn)自愈呢?

對于這種 Unknown 狀態(tài)的 Stateful Pod ,可以通過 force delete 方式去刪除。關(guān)于 ForceDelete,社區(qū)是不推薦的,因為可能會對唯一的標志符(單調(diào)遞增的序列號)產(chǎn)生影響,如果發(fā)生,對 StatefulSet 是致命的,可能會導(dǎo)致數(shù)據(jù)丟失(可能是應(yīng)用集群腦裂,也可能是對 PV 多寫導(dǎo)致)。

kubectl delete pods --grace-period=0 --force

但是這樣刪除仍然需要一些保護措施,以 Ceph RBD 存儲插件為例,當執(zhí)行force delete 前,根據(jù)經(jīng)驗,用戶應(yīng)該先設(shè)置 ceph osd blacklist,防止當遷移過程中網(wǎng)絡(luò)恢復(fù)后,容器繼續(xù)向 PV 寫入數(shù)據(jù)將文件系統(tǒng)弄壞。因為 force delete 是將 PodObj 直接從 ETCD 強制清理,這樣 StatefulSet Controller 將會新建新的 Pod 在其他節(jié)點, 但是故障節(jié)點的 Kubelet 清理這個舊容器需要時間,此時勢必存在 2 個容器mount 了同一塊 PV(故障節(jié)點Pod 對應(yīng)的容器與新遷移Pod 創(chuàng)建的容器),但是如果此時網(wǎng)絡(luò)恢復(fù),那么2 個容器可能同時寫入數(shù)據(jù),后果將是嚴重的

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/32992.html

相關(guān)文章

  • Kubernetes 核心概念

    摘要:核心概念是最小的調(diào)度單元,可以由一個或者多個容器組成。該模式會跟云服務(wù)商有關(guān),比如可以通過等創(chuàng)建一個外部的負載均衡器,將請求轉(zhuǎn)發(fā)到對應(yīng)的服務(wù)組。而可以提供外部服務(wù)可訪問的負載均衡器等。 概述 Kubernetes 有各類資源對象來描述整個集群的運行狀態(tài)。這些對象都需要通過調(diào)用 kubernetes api 來進行創(chuàng)建、修改、刪除,可以通過 kubectl 命令工具,也可以直接調(diào)用 k8...

    Cobub 評論0 收藏0
  • 為什么 kubernetes 天然適合微服務(wù) (3)

    摘要:此文已由作者劉超授權(quán)網(wǎng)易云社區(qū)發(fā)布。五更加適合微服務(wù)和的設(shè)計好了,說了本身,接下來說說的理念設(shè)計,為什么這么適合微服務(wù)。相關(guān)閱讀為什么天然適合微服務(wù)為什么天然適合微服務(wù)為什么天然適合微服務(wù)文章來源網(wǎng)易云社區(qū) 此文已由作者劉超授權(quán)網(wǎng)易云社區(qū)發(fā)布。 歡迎訪問網(wǎng)易云社區(qū),了解更多網(wǎng)易技術(shù)產(chǎn)品運營經(jīng)驗 四、Kubernetes 本身就是微服務(wù)架構(gòu) 基于上面這十個設(shè)計要點,我們再回來看 Kube...

    nicercode 評論0 收藏0
  • zookeeper和etcd有態(tài)服務(wù)部署實踐

    摘要:二總結(jié)使用的和的,能夠很好的支持這樣的有狀態(tài)服務(wù)部署到集群上。部署方式有待優(yōu)化本次試驗中使用靜態(tài)方式部署集群,如果節(jié)點變遷時,需要執(zhí)行等命令手動配置集群,嚴重限制了集群自動故障恢復(fù)擴容縮容的能力。 一. 概述 kubernetes通過statefulset為zookeeper、etcd等這類有狀態(tài)的應(yīng)用程序提供完善支持,statefulset具備以下特性: 為pod提供穩(wěn)定的唯一的...

    dingda 評論0 收藏0
  • zookeeper和etcd有態(tài)服務(wù)部署實踐

    摘要:二總結(jié)使用的和的,能夠很好的支持這樣的有狀態(tài)服務(wù)部署到集群上。部署方式有待優(yōu)化本次試驗中使用靜態(tài)方式部署集群,如果節(jié)點變遷時,需要執(zhí)行等命令手動配置集群,嚴重限制了集群自動故障恢復(fù)擴容縮容的能力。 一. 概述 kubernetes通過statefulset為zookeeper、etcd等這類有狀態(tài)的應(yīng)用程序提供完善支持,statefulset具備以下特性: 為pod提供穩(wěn)定的唯一的...

    jackwang 評論0 收藏0
  • 如何在Kubernetes中管理有態(tài)應(yīng)用

    摘要:在中,被用來管理有狀態(tài)應(yīng)用的對象。并行管理并行管理告訴控制器以并行的方式啟動或者終止所有的。如果設(shè)置為,則控制器將會刪除和重建中的每一。在大部分的情況下,不會使用分隔當希望進行金絲雀發(fā)布,或者執(zhí)行階段發(fā)布時,分隔是很有用的。 在Kubernetes中,StatefulSet被用來管理有狀態(tài)應(yīng)用的API對象。StatefulSets在Kubernetes 1.9版本才穩(wěn)定。Statefu...

    KaltZK 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<