概要
ラベルという名前ゆえか若干軽視されがちですが、Kubernetesにおいてlabelはリソースを識別する上で非常に重要な要素です。
そのlabelについてKubernetesの初学者が気になる(自身も気になった)ことを挙げて行きます。
気になること
Deploymentにあるlabelが多い
公式ドキュメントに記載されているDeploymentの例を見てみます。
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: # ① app: nginx spec: replicas: 3 selector: matchLabels: # ② app: nginx template: metadata: labels: # ③ app: nginx spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80
この様にlabelに関連するところがなんと3つもあります。
それぞれ役割があり、まとめると以下です。
| 番号 | 説明 |
|---|---|
| ① | Deployment自体のラベル |
| ② | どのPodをDeploymentの対象とするかのラベルセレクター |
| ③ | Pod自体のラベル |
DeploymentのmatchLabelsとtemplateは全て一致させるべき?
先程の②と③についてですが
.spec.selectorは.spec.template.metadata.labelsと一致している必要があり、一致しない場合はAPIによって拒否されます。
ref: https://kubernetes.io/ja/docs/concepts/workloads/controllers/deployment/#selector
とあるように一致しない場合は次のようなエラーになります。
The Deployment "xxxx" is invalid: spec.template.metadata.labels: Invalid value: map[string]string{"app":"nginx", "track":"stable"}:
selectordoes not match templatelabels
ただし次のように一部を一致させる、であればAPIはエラーになりません。
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx # ここだけ一致 track: stable spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80
しかし
セレクターが重複する複数のコントローラーを持つとき、そのコントローラーは互いに競合状態となり、正しくふるまいません。
ref: https://kubernetes.io/ja/docs/concepts/workloads/controllers/deployment/#selector
とあるように、意図せず他のtemplateと一致したりしないよう基本的にはtemplateのラベルとセレクタは全てのラベルを一致させるのが良いでしょう。
labelの一部を一致させたいケースって?
カナリアリリースのユースケースの場合、本番のDeploymentでは以下のようにし
name: frontend replicas: 3 ... labels: app: guestbook tier: frontend track: stable ... image: gb-frontend:v3
カナリアのDeploymentでは
name: frontend-canary replicas: 1 ... labels: app: guestbook tier: frontend track: canary ... image: gb-frontend:v4
のように一部のlabelで区別します。
そしてServiceは共通部分でラベルを一致させます。
selector: app: guestbook tier: frontend
これによって、Deploymentは分けつつも、ServiceがルーティングするPodは両方になりトラフィックがそれぞれ流れるようにできます。
ref: https://kubernetes.io/docs/concepts/cluster-administration/manage-deployment/#canary-deployments
なんでServiceはmatchLabelsがないの?
を読む感じでは歴史的な背景があり、元々は等価ベースのセレクタ(DeploymentでいうmatchLabels)しかなかったものの、後から集合ベースの条件設定(matchExpressions)をできるようにしたためなようです。
なので新しいリソースであるDeploymentなどはmatchLabelsやmatchExpressionsを選べるようにフィールドが増えており、古いリソースであるServiceは等価ベースのみで区別する必要がないのでmatchLabelsが無いようです。
ラベルセレクタがimmutable
ラベルセレクタはimmutableであり、削除・再作成せずに変更をrolloutしようとすると
v1.LabelSelector{MatchLabels:map[string]string{“app”:“nginx”}, MatchExpressions:[]v1.LabelSelectorRequirement(nil)}: field is immutable
のようなエラーが出ます。
これは↓のIssueからラベルセレクタがimmutableになったためです。
ラベルセレクタを変更することで孤児Podが生まれる可能性があるなど、意図しない挙動が発生するためこの判断に至ったようです。
まとめ
Kubernetesの初学者がLabelについて気になることについてまとめてみました。