2020-10-14に投稿

GKE の kube-proxy が drain されない理由

Qrunch から引っ越し

kubectl drain した時、テストで作った ownerReference の無い Pod がいたために怒られた。
(これらの Pod は --force オプションで削除させることができる)

ふと kube-proxy のことを思い出し、気になって調べた。

GKE だと kube-proxy は /etc/kubernetes/manifests から起動されていて ownerReference は無いはずなのだが、どうやって drain を回避しているのだろうか。

ファイルの manifest から起動しているのでそもそも API server 経由で実際の Pod 削除はできないのだが、Pod の定義だけ (一時的に) 削除することはあり得るのでは?

pkg/kubectl/cmd/drain.go を読むと分かる。

RunDrain()
  deleteOrEvictPodsSimple()
    getPodsForDeletion()
    deleteOrEvictPods()

kubectl drain コマンドにはいくつかのフィルタ条件があり、それらが適用されて残った Pod が
deleteOrEvictPods() に渡される。

各フィルタは getPodsForDeletion() の中で適用される。

// getPodsForDeletion receives resource info for a node, and returns all the pods from the given node that we
// are planning on deleting. If there are any pods preventing us from deleting, we return that list in an error.
func (o *DrainOptions) getPodsForDeletion(nodeInfo *resource.Info) (pods []corev1.Pod, err error) {
    labelSelector, err := labels.Parse(o.PodSelector)
    if err != nil {
        return pods, err
    }

    podList, err := o.client.CoreV1().Pods(metav1.NamespaceAll).List(metav1.ListOptions{
        LabelSelector: labelSelector.String(),
        FieldSelector: fields.SelectorFromSet(fields.Set{"spec.nodeName": nodeInfo.Name}).String()})
    if err != nil {
        return pods, err
    }

    ws := podStatuses{}
    fs := podStatuses{}

    for _, pod := range podList.Items {
        podOk := true
        for _, filt := range []podFilter{o.daemonsetFilter, mirrorPodFilter, o.localStorageFilter, o.unreplicatedFilter} {
            filterOk, w, f := filt(pod)

            podOk = podOk && filterOk

  • -l, --selector='' は drain 対象の Node をフィルタするもので、Pod に作用するものではない。
  • --pod-selector='' で drain で処理する Pod をフィルタする。
    例えば、特定のラベルを持つ Pod を evict/delete 対象から外すには --pod-selector='key!=value' をつける
  • --ignore-daemonsets は DaemonSet から作成された Pod を除外する。(daemonsetFilter)
  • --delete-local-data は emptyDir ボリュームを持つ Pod を除外する。(localStorageFilter)

ownerRefernece の有無は unreplicatedFilter で判定されるが、kube-proxy が除外されるのは mirrorPodFilter だった。

func mirrorPodFilter(pod corev1.Pod) (bool, *warning, *fatal) {
    if _, found := pod.ObjectMeta.Annotations[corev1.MirrorPodAnnotationKey]; found {
        return false, nil, nil
    }
    return true, nil, nil
}

annotation の定義は pkg/apis/core/annotation_key_constants.go を参照する。

    // MirrorAnnotationKey represents the annotation key set by kubelets when creating mirror pods
    MirrorPodAnnotationKey string = "kubernetes.io/config.mirror"

kubernetes.io/config.mirror という annotation を持っているかどうかでフィルタされているようだ。

Mirror Pod って何だ?と思ってググると

Statis Pod が API server 側で見えるようになっているもの (見えるだけで API から制御できないもの) のことを指すらしい。

Static Pod は kubelet が API server ではなく ファイルや HTTP 経由で渡された manifest を元に 作成・起動した Pod のこと => Static Pods

調べてから見つけたが、詳しく説明している記事があった => Draining Kubernetes nodes

ツイッターでシェア
みんなに共有、忘れないようにメモ

albatross0

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント