GeekFactory

int128.hatenablog.com

client-goでserviceのselectorに合致するpodを検索する

Kubernetesのクライアントであるclient-goを利用して,serviceのselectorに合致するpodを検索する方法を紹介します.コマンドラインではserviceの名前を受け取るが,実際の処理はpodに対して行う必要がある場合に活用できます.

クライアントの生成

準備として,コマンドライン引数からクライアントを生成します.genericclioptions.ConfigFlags を使うと,kubectlの標準的なフラグを簡単に追加できます.

func run() error {
    // コマンドライン引数を解析する
    f := pflag.NewFlagSet("example", pflag.ContinueOnError)
    type cmdOptions struct {
        *genericclioptions.ConfigFlags
    }
    var o cmdOptions
    o.ConfigFlags.AddFlags(f)
    if err := f.Parse(os.Args[1:]); err != nil {
        return xerrors.Errorf("invalid flag: %w", err)
    }

    // kubeconfigからクライアントを生成する
    config, err := o.ConfigFlags.ToRESTConfig()
    if err != nil {
        return xerrors.Errorf("could not load the config: %w", err)
    }
    namespace, _, err := o.ConfigFlags.ToRawKubeConfigLoader().Namespace()
    if err != nil {
        return xerrors.Errorf("could not determine the namespace: %w", err)
    }
    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        return xerrors.Errorf("could not create a client: %w", err)
    }
}

実際のツール開発では,pflag を直接利用するのではなく cobra.Command を利用する方が便利かと思います.

serviceの取得とpodの検索

クライアントを利用してserviceを取得してみましょう.ここでは例として echoserver というserviceを取得します.

   serviceName := "echoserver"
    service, err := clientset.CoreV1().Services(namespace).Get(serviceName, metav1.GetOptions{})
    if err != nil {
        return nil, "", xerrors.Errorf("could not find the service: %w", err)
    }
    log.Printf("Service %s found", service.Name)

serviceに対応するpodを検索するには,serviceのselectorを利用します.例えば,echoserver サービスで app=echoserver というselectorが定義されている場合,サービスに対応するpodには app=echoserver というlabelが付いています.kubectlコマンドでserviceとpodの詳細を表示すると,selectorとlabelの関係がよくわかります.

% kubectl describe svc/echoserver
Selector:          app=echoserver

% kubectl describe pod/echoserver-xxx-xxx
Labels:         app=echoserver

クライアントを利用してserviceのselectorに合致するpodを検索します.

   // serviceで定義されているselectorをkey=value形式に変換する
    var selectors []string
    for k, v := range service.Spec.Selector {
        selectors = append(selectors, fmt.Sprintf("%s=%s", k, v))
    }
    selector := strings.Join(selectors, ",")
    // selectorに合致するpodを検索する
    pods, err := clientset.CoreV1().Pods(namespace).List(metav1.ListOptions{LabelSelector: selector})
    if err != nil {
        return nil, "", xerrors.Errorf("could not find the pods by selector %s: %w", selector, err)
    }
    log.Printf("Found pod(s): %+v", pods.Items)

これらのコードを実行すると,以下のような結果が表示されます.

2019/08/19 21:37:48 Service echoserver found
2019/08/19 21:37:48 Found pod(s): []Pod{...}

あとは,podのリストを利用して処理を行えばよいです.

まとめ

client-goを利用して,serviceのselectorに合致するpodを検索する方法を紹介しました.