この記事は 第二のドワンゴ Advent Calendar 2019 の20日目の記事です。
投稿が遅くなりました。
「Kubernetesのカスタムコントローラーを作ってみた」的な記事を書きたかったのですが、作ってる際にハマったclient-goでのラベルセレクターの扱いについて書いていこうかと思います。
ラベルセレクターとは
ラベルはユニーク性を提供しません。通常、多くのオブジェクトが同じラベルを保持することを想定します。 ラベルセレクター を介して、クライアントとユーザーはオブジェクトのセットを指定できます。ラベルセレクターはKubernetesにおいてコアなグルーピング機能となります。
Podをスケジュールする際にNodeを決定する nodeSlector もラベルセレクターの一種で、ラベルを持つノードからこの nodeSelector を利用してPodをスケジュールするノードをグルーピングします。
kubectl get コマンドにおいては --selector オプションにて入力可能です。
たとえば全てのネームスペースから、app = myapp というラベルのついて Pod をグルーピングする場合は、以下のようなコマンドを実行します。
kubectl get pods --all-namespaces --selector='app=myapp'
client-go からラベルセレクターを利用する
Podについてラベルセレクターを利用してフィルタリングを行います。
ラベルセレクターなどを利用せずに全てのネームスペースからPodを取得する場合、以下のようなコードになるかと思います。
| package main | |
| import ( | |
| "fmt" | |
| flag "github.com/spf13/pflag" | |
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | |
| "k8s.io/client-go/kubernetes" | |
| "k8s.io/client-go/tools/clientcmd" | |
| ) | |
| func main() { | |
| var ( | |
| apiServerHost, kubeconfigFilePath string | |
| ) | |
| flag.StringVar(&apiServerHost, "master", "", "Address of the Kubernetes API server.") | |
| flag.StringVar(&kubeconfigFilePath, "kubeconfig", "", "Path to a kubeconfig file containing authorization and API server information.") | |
| flag.Parse() | |
| kubeconfig, err := clientcmd.BuildConfigFromFlags(apiServerHost, kubeconfigFilePath) | |
| if err != nil { | |
| panic(err.Error()) | |
| } | |
| clientset, err := kubernetes.NewForConfig(kubeconfig) | |
| if err != nil { | |
| panic(err.Error()) | |
| } | |
| versionInfo, err := clientset.ServerVersion() | |
| if err != nil { | |
| panic(err.Error()) | |
| } | |
| fmt.Printf("Server version: %s\n", versionInfo.String()) | |
| fmt.Println("All pods") | |
| podListAll, err := clientset.CoreV1().Pods(metav1.NamespaceAll).List(metav1.ListOptions{}) | |
| if err != nil { | |
| panic(err.Error()) | |
| } | |
| if len(podListAll.Items) == 0 { | |
| fmt.Println("Not Found") | |
| } | |
| for _, pod := range podListAll.Items { | |
| fmt.Printf("%s/%s\n", pod.GetNamespace(), pod.GetName()) | |
| } | |
| } |
Podのリストを取得する際の ListOptions には、それらしい LabelSelector という文字列を与えることができます。
一方で、ラベルセレクターを表すのLabelSelector構造体には、ListOptionsの LabelSelector が期待する文字列を生成する関数は定義されていません。*1
では、どうするかというと、同パッケージに定義されている FormatLabelSelector(labelSelector *LabelSelector) string を利用します。
labelSelector := &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": "myapp",
},
}
clientset.CoreV1().Pods(metav1.NamespaceAll).List(metav1.ListOptions{
LabelSelector: metav1.FormatLabelSelector(labelSelector),
})
こうすることで、app = myapp というラベルを持つPodを取得することができます。
また、LabelSelector 構造体を利用せずに、ListOptions.LabelSelector に "app=myapp" という文字列を与えることでも同じ結果を得られます。
clientset.CoreV1().Pods(metav1.NamespaceAll).List(metav1.ListOptions{
LabelSelector: "app=myapp",
})
まとめ
client-go からKubernetesラベルセレクターを利用する方法について説明しました。
以下のリポジトリに本記事で使用したコードがあります。
ラベルセレクターは強力な仕組みで kubectl や client-go からでも簡単に利用できます。 カスタムコントローラーを開発する際にも役立てていきたいですね!
*1:ここでめちゃくちゃハマった