この記事は 第二のドワンゴ 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:ここでめちゃくちゃハマった