ラベルとアノテーションの違い
v1.37 時点(2026年10月28日 確認)
目次
この記事ではリソースに付けるキーと値の組である ラベル と アノテーション の違いを、図で説明します。ラベルはオブジェクトを選ぶためのもので、アノテーションは選ぶためではない情報を付けるためのもの、という区別がわかります。キーと値の書き方の決まり、推奨のラベル、ラベルを複数の次元で付ける設計の考え方もわかります。後半では kind のクラスタで、ラベルを付けた 3 つの Deployment を作ります。続けてラベルで絞り込み、一覧、ラベルの追加と書き換え、アノテーションの追加をまとめて行います。最後に同じ条件で Pod と Deployment を消して、結果を比べます。
第4回からいくつもの回で「ラベルの仕組みは第42回」「アノテーションは第42回」と予告してきました。この回では第11回で見たラベルとラベルセレクタの決まりを前提にしています。まだの方は先にこちらをどうぞ。
ReplicaSet を動かして理解する同じ Pod を指定した数だけ動かし続ける ReplicaSet の仕組みを図で説明します。ReplicaSet がラベルセレクタで Pod を選んで数える決まり、自分のものにする Pod の条件、数を減らすときに消す Pod の選び方を押さえ、kind のクラスタでラベルを書き換えた Pod が管理から外れる様子を観察する手順を紹介します。以下の図は後半の手順で作る Pod に付けたラベルと、ラベルセレクタ tier=frontend で選ばれる範囲を表しています。
4 つの Pod にはどれも app.kubernetes.io/name: my-app のラベルが付いています。そのうえで tier(層)と track(バージョンの系統)の 2 つのラベルで分けています。tier=frontend のセレクタは track の値を見ないので、stable と canary の両方の Pod を選びます。tier: backend の Pod は選びません。このように、1 つのオブジェクトに複数のラベルを付けておくと、どの次元でも絞り込めます。
参考:Labels and Selectors | Kubernetes、Managing Workloads | Kubernetes
ラベルとアノテーションとは
ラベル と アノテーション はどちらもオブジェクトの metadata(第5回)に書くキーと値の組です。公式ドキュメントによると、オブジェクトに情報(メタデータ)を付けるには、ラベルとアノテーションのどちらも使えます。1 つのオブジェクトに両方を付けることもできます。
違いは使い道です。Annotations のページは、ラベルは オブジェクトを選んだり、条件を満たすオブジェクトの集まりを見つけたりするのに使える のに対して、アノテーションはオブジェクトを見分けたり選んだりするのには使わない、と説明しています。Labels and Selectors のページも、ラベルはオブジェクトをまとめたり、その一部を選んだりするのに使えるとし、見分けるためではない情報はアノテーションに記録するべきだ(should)としています。2 つの違いを、公式ドキュメントと API リファレンスに沿って次の表にまとめます。
| 項目 | ラベル | アノテーション |
|---|---|---|
| 目的 | 利用者にとって意味のある、オブジェクトを特徴づける性質(どの層か、どのバージョンかなど)を表す。名前のように 1 つに決めるものではない | 見分けるためではない、任意の情報(non-identifying metadata)を付ける |
| 選ぶのに使うか | 使う。ラベルセレクタで選べ、一覧(list)や監視(watch)を効率よく絞り込める | 使わない。API リファレンスでは、問い合わせには使えない(not queryable)とされている |
| 値 | 63 文字以内で、使える文字に決まりがある | 文字の決まりは無く、JSON のような構造化されたデータも書ける |
| 読む側 | Service や ReplicaSet などのセレクタ、kubectl の -l | ツールやライブラリなどのクライアント(API を使う側のプログラム) |
参考:Labels and Selectors | Kubernetes、Annotations | Kubernetes、ObjectMeta | Kubernetes API Reference、Managing Workloads | Kubernetes
API リファレンスによると、metadata.annotations は外部のツールが任意の情報を保存したり取り出したりするために付けることができるもので、オブジェクトを変更するときは残しておくべきだ(should be preserved)とされています。なお、第19回で見た Downward API を使えば、Pod のラベルとアノテーションのどちらの値もコンテナに渡せます。
参考:ObjectMeta | Kubernetes API Reference、Downward API | Kubernetes
なぜラベルとアノテーションが必要なのか
第11回で見たとおり、名前や UID と違って、ラベルは一意ではありません。たくさんのオブジェクトが同じラベルを持つことで、名前を 1 つずつ覚えなくても「このラベルを持つもの」という条件でまとめて扱えます。
参考:Labels and Selectors | Kubernetes、Labels and Selectors | Kubernetes
この仕組みはこれまでの回のあちこちで使ってきました。ReplicaSet と Deployment(第11回、第12回)は数える Pod を、Service(第21回)は通信を届ける Pod を、ラベルセレクタで選びます。NetworkPolicy(第25回)は規則を当てる Pod を、nodeSelector(第31回)は Pod を置くノードを、ラベルで選びます。どの Pod か、どのノードかを決める多くの場面で、ラベルが手がかりになっていました。
参考:Labels and Selectors | Kubernetes、Labels and Selectors | Kubernetes、NetworkPolicy | Kubernetes API Reference
一方で、オブジェクトには選ぶためではない情報も付けたくなります。ビルドの番号、責任者の連絡先、ツールが覚えておきたい設定などです。こうした情報をラベルに入れると、値の文字の決まりに収まらないことがあると考えられます。また、ラベルはオブジェクトを特徴づける性質なので、選ぶつもりの無い情報が混ざると、セレクタで使うラベルとの区別がつきにくくなるはずです。公式ドキュメントは、この種の情報は外部のデータベースなどにも置けるが、そうするとデプロイや管理、調査のための共通のライブラリやツールを作るのがずっと難しくなる、と説明しています。この種の情報をオブジェクトそのものに付けておけるのがアノテーションです。第7回の kubectl apply が付ける last-applied も、ツール(kubectl)が自分のデータを覚えておくためのアノテーションです。
参考:Annotations | Kubernetes、kubectl annotate | Kubernetes、Declarative Management of Kubernetes Objects Using Configuration Files | Kubernetes
ラベルとアノテーションの仕組み
キーと値の書き方
ラベルとアノテーションのキーは同じ決まりで書きます。どちらのキーも、省略できる接頭辞と名前を / でつないだ形です。値の決まりは違います。公式ドキュメントの決まりを次の表にまとめます。
| 項目 | ラベル | アノテーション |
|---|---|---|
| キーの名前の部分 | 必須。63 文字以内で、英数字で始まって英数字で終わり、間には -、_、.、英数字を使える | ラベルと同じ |
| キーの接頭辞 | 省略できる。付けるときは DNS のサブドメイン(DNS ラベルを . でつないだもので、合わせて 253 文字以内)にし、/ を続ける | ラベルと同じ |
| 値 | 63 文字以内で、空でもよい。空でなければ英数字で始まって英数字で終わり、間には -、_、.、英数字を使える | 文字の決まりは無い。特殊な文字、空白、JSON や YAML のような構造化されたデータを含む、どんな文字列でもよい |
参考:Labels and Selectors | Kubernetes、Annotations | Kubernetes
アノテーションには大きさの上限があります。v1.37 時点の公式ドキュメントによると、1 つのオブジェクトのすべてのアノテーションのキーと値を合わせた大きさは、256 KiB を超えてはなりません(must not)。1 KiB は 1024 バイトです。
参考:Annotations | Kubernetes、Resource Management for Pods and Containers | Kubernetes
アノテーションのキーと値は文字列でなければなりません(must)。数値、真偽値、リストなどはキーにも値にも使えません。API リファレンスにも、ラベルは文字列のキーと値の組だと書かれています。設定のよい習慣をまとめた公式ドキュメントのページは、YAML の真偽値には落とし穴があるとして、真偽値に見えるものは念のため引用符で囲むよう勧めています。第25回で、ラベルの値を access: "true" と引用符で囲んだのも、true が文字列ではなく真偽値として読まれるのを避けるためだと考えられます。
参考:Annotations | Kubernetes、ObjectMeta | Kubernetes API Reference、Configuration Overview | Kubernetes
接頭辞にも決まりがあります。接頭辞を省いたキーは利用者のものとみなされます。kube-scheduler、kube-controller-manager、kube-apiserver、kubectl、ほかのサードパーティーの自動化ツールのように、利用者のオブジェクトにラベルやアノテーションを自動で付けるシステムの部品は、接頭辞を付けなければなりません(must)。また、kubernetes.io/ と k8s.io/ の接頭辞は Kubernetes の中心のコンポーネントのために予約されています。接頭辞の決まりはラベルとアノテーションのどちらのページにも書かれています。
参考:Labels and Selectors | Kubernetes、Annotations | Kubernetes
Well-Known Labels, Annotations and Taints のページは、kubernetes.io と k8s.io の下にあるラベル、アノテーション、taint(第32回)をすべて Kubernetes が予約している、と書いています。このページには node-role.kubernetes.io/control-plane(第15回)や app.kubernetes.io/name のように、kubernetes.io の前に語を足した接頭辞のキーも載っています。同じページには、このページが値の一覧であると同時に、値を割り当てるときの調整の場でもあると書かれています。予約とは、これらの範囲のキーの名前と意味を Kubernetes のプロジェクトが決めるということだと読めます。後半の手順で app.kubernetes.io/name を付けるのは、後で見る推奨のラベルとして、決められた意味で使うためです。自分で新しいキーを作るなら、kubectl label のリファレンスの説明にある example.com/my-app のように、自分が管理するドメインを接頭辞に使うのが自然だと考えられます。
参考:Well-Known Labels, Annotations and Taints | Kubernetes、kubectl label | Kubernetes
Kubernetes が意味を決めているラベルとアノテーション
これまでの回には、Kubernetes が意味を決めているラベルやアノテーションがいくつも出てきました。Kubernetes やツールが付けるものと、利用者が付けて使うものがあります。主なものを次の表にまとめます。
| キー | 種類 | 付けるものと役割 | 扱った回 |
|---|---|---|---|
kubernetes.io/metadata.name | ラベル | kube-apiserver がすべての Namespace に付ける。値は Namespace の名前で、変えられない | 第25回、第37回 |
kubernetes.io/hostname など | ラベル | kubelet がノードに付ける標準のラベル | 第31回 |
node-role.kubernetes.io/control-plane | ラベル | kubeadm が、管理するコントロールプレーンのノードに付ける | 第15回、第31回 |
pod-template-hash | ラベル | Deployment のコントローラーが、作るか自分のものにした ReplicaSet に付ける。変えないよう注意されている | 第6回、第11回 |
kubectl.kubernetes.io/last-applied-configuration | アノテーション | kubectl apply が付ける。中身は作るのに使ったマニフェスト | 第5回、第7回 |
deployment.kubernetes.io/revision | アノテーション | Deployment のコントローラーが、管理する ReplicaSet に付けるリビジョンの番号で、手で変えるべきではない。公式ドキュメントの kubectl describe deployments の例では、Deployment 自身にも表示されている | 第12回 |
controller.kubernetes.io/pod-deletion-cost | アノテーション | 利用者が Pod に付け、ReplicaSet が数を減らすときに消す順番に影響を与える | 第11回 |
storageclass.kubernetes.io/is-default-class | アノテーション | true にした StorageClass が既定の StorageClass になる。kind では、最初からある standard に付いていると考えられる(第27回) | 第27回 |
参考:Well-Known Labels, Annotations and Taints | Kubernetes、Well-Known Labels, Annotations and Taints | Kubernetes、Well-Known Labels, Annotations and Taints | Kubernetes、Deployments | Kubernetes、Declarative Management of Kubernetes Objects Using Configuration Files | Kubernetes、Well-Known Labels, Annotations and Taints | Kubernetes、Deployments | Kubernetes、Deployments | Kubernetes、Well-Known Labels, Annotations and Taints | Kubernetes、Storage Classes | Kubernetes
pod-template-hash について、公式ドキュメントは「このラベルを変えないでください」と注意しています。このラベルは Deployment の子の ReplicaSet どうしが重ならないようにするためのもので、ReplicaSet のセレクタ、Pod のひな形のラベル、すでにある Pod に入ります。後半の手順で --show-labels を付けて Pod を一覧すると、このラベルも並ぶはずです。
ラベルセレクタで選ぶ
ラベルセレクタの決まりは第11回で見ました。演算子をもう一度まとめると、次の表のとおりです。
| 種類 | 演算子 | 例 |
|---|---|---|
| 等価ベース | = と ==(等しい。2 つは同じ意味)、!=(等しくない) | environment = production、tier != frontend |
| 集合ベース | in、notin、exists(キーだけを書く。前に ! を付けると、そのキーを持たないもの) | environment in (production, qa)、tier notin (frontend, backend)、partition、!partition |
参考:Labels and Selectors | Kubernetes、Labels and Selectors | Kubernetes
条件を , で並べると「かつ」(AND)になり、等価ベースにも集合ベースにも「または」(OR)の演算子はありません。!= と notin はそのキーを持たないものも選びます。くわしくは第11回で説明しています。
参考:Labels and Selectors | Kubernetes、Labels and Selectors | Kubernetes
kubectl では -l かその長い形の --selector でラベルセレクタを書きます。公式ドキュメントによると、一覧(list)と監視(watch)の操作では、ラベルセレクタで返すオブジェクトを絞り込めます。kubectl の -l の条件はこの絞り込みの条件として API に送られると読めます。
この回で新しく使うのは、-l を kubectl get だけでなく kubectl label、kubectl annotate、kubectl delete にも付けて、条件に合うものをまとめて操作するやり方です。v1.37 時点のリファレンスの -l の説明に挙がっている演算子は、kubectl get、kubectl label、kubectl delete では =、==、!=、in、notin です。kubectl annotate では =、==、!= だけで、集合ベースの条件が使えるかはリファレンスからはわかりません。そのため後半の手順では kubectl annotate に等価ベースの条件だけを書きます。
参考:kubectl get | Kubernetes、kubectl label | Kubernetes、kubectl delete | Kubernetes、kubectl annotate | Kubernetes
4 つのコマンドのどの -l の説明にも、キーだけを書く exists の形は挙がっていません。ただ、Labels and Selectors のページには kubectl get pods -l 'environment,environment notin (frontend)' のように、キーだけの条件を kubectl get に書いた例があります。第11回の手順でも -l tier を使いました。
API のオブジェクトの中に書くセレクタは、第11回で見たとおり、リソースの種類で書き方が違います。Service と ReplicationController のセレクタはキーと値を並べる形で、等価ベースの条件だけに対応しています。Job、Deployment、ReplicaSet、DaemonSet のような新しいリソースは、matchLabels と matchExpressions で集合ベースの条件も書け、すべての条件が「かつ」で結ばれます。
参考:Labels and Selectors | Kubernetes、Labels and Selectors | Kubernetes、LabelSelector | Kubernetes API Reference
推奨のラベル
Kubernetes には、ツールどうしが同じ形でオブジェクトを表せるように決めた、推奨のラベル(Recommended Labels)があります。推奨のラベルは「アプリケーション」という考え方を中心にしています。ただし Kubernetes は PaaS(アプリケーションを動かす環境一式を提供するサービス)ではなく、アプリケーションの正式な定義を持たず、強制もしません。アプリケーションはメタデータで緩く表すものとされています。6 つのラベルを次の表にまとめます。例の値は公式ドキュメントの表から取り、part-of の例だけはこの記事で付けた仮の名前 my-shop にしています。
| キー | 説明 | 例 |
|---|---|---|
app.kubernetes.io/name | アプリケーションの名前 | mysql |
app.kubernetes.io/instance | アプリケーションのインスタンス(1 回分のインストール)を見分ける一意の名前 | mysql-abcxyz |
app.kubernetes.io/version | アプリケーションの今のバージョン | 5.7.21 |
app.kubernetes.io/component | 構成の中での部品 | database |
app.kubernetes.io/part-of | このアプリケーションを含む、上位のアプリケーションの名前 | my-shop |
app.kubernetes.io/managed-by | アプリケーションの操作の管理に使うツール | Helm |
公式ドキュメントは注で、これらは推奨のラベルであり、アプリケーションの管理を楽にするが、中心のツールにとって必須ではない(aren’t required)としています。そのうえで、推奨のラベルを十分に活かすには、すべてのリソースのオブジェクトに付けるべきだ(should) としています。
参考:Recommended Labels | Kubernetes、Recommended Labels | Kubernetes
共通のラベルとアノテーションは app.kubernetes.io という共通の接頭辞を持ちます。接頭辞の無いラベルは利用者のものです。この接頭辞によって、共通のラベルが利用者独自のラベルとぶつからないようになっています。name と instance は別々に記録します。表の例の mysql はデータベースの MySQL です。同じアプリケーションを何度もインストールした場合、app.kubernetes.io/name はどれも同じ値で、app.kubernetes.io/instance はインストールごとに違う値です。公式ドキュメントの Examples の節にある Service の例では、name が myservice、instance が myservice-abcxyz です。アプリケーションのインスタンスはそれぞれ一意の名前を持たなければなりません(must)。managed-by の例の Helm は第43回で扱います。
参考:Recommended Labels | Kubernetes、Recommended Labels | Kubernetes、Recommended Labels | Kubernetes
第11回で触れたとおり、手で問い合わせるには app のラベルが便利ですが、ツールや自動化には app.kubernetes.io/name のほうが向いている、と公式ドキュメントは説明しています。後半の手順では app.kubernetes.io/name を使います。
ラベルの設計
公式ドキュメントによると、どのリソースにもラベルを 1 つだけ付けることはできますが、いつもそれがよいやり方とは限りません。リソースの集まりを互いに見分けるために、複数のラベルを使うべき(should)場面がたくさんあります。Labels and Selectors のページは、ラベルの例として次のような次元を挙げています。
| 次元 | 値の例 |
|---|---|
release | stable、canary |
environment | dev、qa、production |
tier | frontend、backend、cache |
partition | customerA、customerB |
track | daily、weekly |
参考:Labels and Selectors | Kubernetes、Labels and Selectors | Kubernetes
同じページの例では、アプリケーションごとに app の値を変えます。層に分かれたアプリケーションでは、さらに tier で層を見分けます。バックエンド(tier: backend)の Redis(データを置くソフトウェア)では、master と replica に role: master と role: replica のような role のラベルを足して、役割を分けることもできるとしています。こうしておくと、ラベルで決めたどの次元でもリソースを切り分けられます。例では、第11回で使った -L(指定したラベルの値を列にする指定)に app、tier、role を渡して Pod を一覧しています。そのラベルを持たない Pod の列は <none> です。さらに -l で app と role の 2 つの次元を組み合わせ、1 つのアプリケーションの中から Redis の replica の Pod だけを選んでいます。
複数のラベルは同じ部品のバージョン違いを分けるのにも使えます。Managing Workloads のページでは、新しいリリースを前のリリースと並べて動かすカナリアリリースの例で、track のラベルを使っています。安定版の Deployment の Pod には track: stable、新しいバージョンには track: canary を付け、2 つの Pod の集まりが重ならないようにします。一方、Service のセレクタには共通の app と tier だけを書き、track を省きます。こうすると、Service は両方のバージョンの Pod に通信を届けます。安定版と新しいバージョンのレプリカの数を変えれば、それぞれが受ける通信の割合(例では 3 対 1)を調整できます。後半の手順の frontend と frontend-canary はこの例の形を借りています。ただしレプリカの数は 2 対 1 にし、Service は作りません。
設計で気を付けたいのは、セレクタに使うラベルです。第6回で見たとおり、Deployment のページはほかの Pod やほかのコントローラー(ReplicaSet など)を、そのセレクタに合うラベルで作るべきではない(should not)と注意しています。セレクタが重なったコントローラーどうしはぶつかり合い、正しく動きません。第11回で見たとおり、Pod のラベルを書き換えてセレクタから外すと、レプリカの数を同時に変えていなければ、外れた Pod は自動で置き換えられます。そのため、セレクタに使うキーの値を kubectl label --overwrite でまとめて書き換えると、外れた Pod は残ったまま、その数だけ新しい Pod が作られ、Pod の合計が増えると考えられます。
セレクタそのものも後から変えにくいものです。公式ドキュメントによると、ラベルセレクタの更新は一般に勧められず、セレクタは前もって計画しておくよう勧められています。apps/v1 の Deployment のセレクタは、作ったあとで変えられません。どうしても変えるときは、Deployment を消して作り直す必要があります。既定では Deployment を消すと動いている Pod も消えるので、そのあいだアプリケーションは止まります。
もう 1 つ、Deployment 自身のラベルと Pod のひな形のラベルは別物です。第11回で ReplicaSet について見たとおり、metadata.labels はそのオブジェクト自身のラベルで、spec.template.metadata.labels は作られる Pod に付くラベルです。Deployment のページによると、apps/v1 では .spec.selector と .metadata.labels はどちらもひな形のラベルから補われません。そのため、両方とも明示的に書かなければなりません(must)。.spec.selector は必須のフィールドで、書かないと受け付けられません。.metadata.labels は、書かないと Deployment 自身にラベルが付かず、-l で選べないと考えられます。
また、Deployment のロールアウト(第12回)は、Pod のひな形が変わったときだけ始まります。ひな形のラベルを変えるとロールアウトが始まりますが、Deployment 自身のラベルを変えても始まりません。
ラベルにするか、アノテーションにするか
迷ったときの目安はその情報で選ぶ必要があるかどうかです。選ぶのに使う情報はラベルにし、選ぶ必要のない情報はアノテーションにします。公式ドキュメントはアノテーションに記録できる情報の例として、次のようなものを挙げています。
- ビルド、リリース、イメージの情報(時刻、リリースの ID、git のブランチ、PR の番号、イメージのハッシュなど)
- ログ、監視、分析、監査の情報の置き場所を指すもの
- デバッグに使える、ライブラリやツールの名前、バージョン、ビルドの情報
- 責任者の電話やポケットベルの番号、またはその情報の置き場所を示すディレクトリの項目(チームの Web サイトなど)
- 利用者から実装への、動きを変えたり標準ではない機能を使ったりする指示
最後の「実装への指示」はこれまでの回にも出てきました。第22回で見た、LoadBalancer の IP アドレスを提供元ごとのアノテーションで指定するやり方や、第24回で見た、Ingress コントローラーごとの拡張の機能をアノテーションで使うやり方は、この使い方にあたると考えられます。公式ドキュメントも、提供元が独自のアノテーションで LoadBalancer の IP アドレスを指定できるならそちらに切り替えるべき(should)だとし、Ingress コントローラーは動きの設定にアノテーションをよく使うと説明しています。
以下の図は後半の手順の Deployment frontend を例に、ラベルとアノテーションがそれぞれどの読み方で使われるかを表しています。ラベルはセレクタの条件と照らし合わせて選ぶのに使われ、アノテーションは中身がそのまま読まれます。図では、ラベルはマニフェストに書いた 3 つだけを、アノテーションは一部だけを示しています。
図の上は -l のようなラベルセレクタで照らし合わせる読み方です。ラベルセレクタが見るのはラベルだけで、アノテーションに同じ形のキーと値を書いても、-l の条件には合いません。図の下は中身をそのまま読む読み方です。後半の手順で利用者が kubectl get -o yaml でアノテーションを読むのは、図の下の「クライアント(ツール・人)」の読み方にあたります。手順ではアノテーションのキーを -l に書いて、何も選ばれないことも確かめます。
参考:Annotations | Kubernetes、ObjectMeta | Kubernetes API Reference
手元で試す
ここまでの内容を手元の kind のクラスタで試す手順を示します。この回用の Namespace に、ラベルを付けた 3 つの Deployment を作ります。ラベルセレクタでいろいろな条件で絞り込んだあと、Deployment と Pod にまとめてラベルを付け、Deployment にアノテーションを付けます。最後に、同じ -l track=canary の条件で Pod と Deployment を消し、結果の違いを確かめます。
この節で引用する出力の例は、公式ドキュメントに載っている、ほかのクラスタで取ったものです。名前や時間などの値は手元とは違います。各段に書く成功の目安は公式ドキュメントから予想される結果で、手元で実行して確かめたものではありません。目安と合わないときは、まず -n labels-demo と --context kind-kind の付け忘れと、打ち間違いが無いかを確かめます。
コマンドは macOS や Linux のシェル(bash や zsh)で実行する前提で書いています。Windows では WSL(Windows の中で Linux を動かす仕組み)などを使ってください。試す環境は次のとおりです。
| 項目 | 内容 |
|---|---|
| kind | v0.33.0 |
| Kubernetes | v1.37.0(kind v0.33.0 の既定のノードイメージ) |
| ノード構成 | シングルノード(クラスタ名 kind):コントロールプレーン 1 |
| 必要なもの | Docker、kubectl(v1.36〜v1.38)、テキストエディタ、端末(ターミナル)2 つ |
参考:Release v0.33.0 · kubernetes-sigs/kind、Version Skew Policy | Kubernetes
この回では第37回と同じく、シングルノードのクラスタを使います。ラベルで選ぶ仕組みはノードの数に関係しないからです。kind でクラスタを作る手順は、以下の記事で解説しています。
kind で検証用のクラスタを作るDocker のコンテナをノードにして、手元のマシンに Kubernetes のクラスタを作るツール kind の仕組みを図で説明します。kind create cluster で何が起きるかを押さえ、シングルノードとマルチノードのクラスタを作って、ノードの正体が Docker のコンテナであることを確かめる手順を紹介します。この回では端末を 2 つ使います。これまでの回と同じく、1 つ目の端末は変化の監視(この回では Pod)に取っておきます。監視は「Namespace を作り、Pod の監視を始める」の段で始めるので、それまで 1 つ目の端末では何もしません。クラスタの準備も含めて、操作は 2 つ目の端末で行います。2 つ目の端末を開いたら、cd でマニフェストを保存するディレクトリに移動しておきます。
シングルノードのクラスタを用意する
2 つ目の端末で、前の回のクラスタが残っていないかを確かめます。
$ kind get clusters
kind が表示されたら、作り直さずにそのまま使えるので、クラスタを作る次のコマンドは飛ばします。表示されなければ、クラスタを作ってから、もう一度一覧します。前の回までの multi-node が表示されても、この回では使いません。
$ kind create cluster
$ kind get clusters
kind get clusters に kind が表示されれば、クラスタができています。第3回で決めたとおり、ここからのコマンドには --context kind-kind を付けて、操作するクラスタをはっきりさせます。続けて、ノードを一覧します。
$ kubectl get nodes --context kind-kind
ノードが 1 つ表示され、STATUS 列が Ready になっていれば準備ができています。Ready になっていなければ、少し待ってからもう一度実行します。数分たっても Ready にならなければ、第3回と同じく kubectl describe node --context kind-kind で、Conditions の Ready の行を確かめます。
この回では手順で作るものを labels-demo という Namespace にまとめます。最後の kubectl delete -l で、手順で作ったもの以外を消さないようにするためです。前の回のクラスタを使い続けている場合は、labels-demo が無いことを確かめます。
$ kubectl get namespace labels-demo --context kind-kind
見つからないことを知らせる 1 行が出れば、そのまま進めます。labels-demo が表示されたら、kubectl get deployments,pods -n labels-demo --context kind-kind で中身を一覧し、自分で作ったものかを確かめます。Namespace を消すと中のリソースも一緒に消えるので(第37回)、残したいものが無いかも先に確かめてください。そのうえで kubectl delete namespace labels-demo --context kind-kind で消します。
Namespace を作り、Pod の監視を始める
2 つ目の端末で、第30回と同じく kubectl create namespace で Namespace を作ります。
$ kubectl create namespace labels-demo --context kind-kind
namespace/labels-demo が作られたことを知らせる 1 行が出るはずです。
1 つ目の端末で、labels-demo の Pod を監視します。-L で tier、track、environment の 3 つのラベルの値を列にします。environment はこのあとの段で付けるラベルです。Pod はまだ無いので、名前を指定せずに Pod 全体を監視します。この監視は片付けの前まで止めずに続けます。この端末に映るのは Pod の変化だけで、Deployment のラベルやアノテーションを変えても映りません。
$ kubectl get pods -n labels-demo -L tier,track,environment --watch --context kind-kind
見つからないことを知らせる 1 行が出たあと、止まったように見えると考えられます。
ラベルを付けた Deployment を作る
以下はこの回で使う架空のアプリケーション my-app のマニフェストです。フロントエンドの安定版(frontend)と新しいバージョン(frontend-canary)、バックエンド(backend)の 3 つの Deployment からなります。「ラベルの設計」で見たカナリアリリースの例をもとに、名前、ラベル、レプリカの数をこの回で決めました。イメージはどれも、これまでの回と同じ nginx です。labels-demo.yaml という名前で保存します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend
namespace: labels-demo
labels:
app.kubernetes.io/name: my-app
tier: frontend
track: stable
spec:
replicas: 2
selector:
matchLabels:
app.kubernetes.io/name: my-app
tier: frontend
track: stable
template:
metadata:
labels:
app.kubernetes.io/name: my-app
tier: frontend
track: stable
spec:
containers:
- name: nginx
image: nginx:1.14.2
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend-canary
namespace: labels-demo
labels:
app.kubernetes.io/name: my-app
tier: frontend
track: canary
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: my-app
tier: frontend
track: canary
template:
metadata:
labels:
app.kubernetes.io/name: my-app
tier: frontend
track: canary
spec:
containers:
- name: nginx
image: nginx:1.14.2
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
namespace: labels-demo
labels:
app.kubernetes.io/name: my-app
tier: backend
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: my-app
tier: backend
template:
metadata:
labels:
app.kubernetes.io/name: my-app
tier: backend
spec:
containers:
- name: nginx
image: nginx:1.14.2参考:Managing Workloads | Kubernetes、Deployments | Kubernetes、Deployment | Kubernetes API Reference
ラベルの付け方のポイントは次の 3 つです。
- 3 つとも、
metadata.labelsとひな形のラベルに同じラベルを書いている - セレクタは
tierかtrackの値が違うので、3 つの Deployment のあいだで重ならない backendにはtrackのラベルを付けていない
metadata.labels にも書いたのは、このあと kubectl get deployments -l などで Deployment 自身をラベルで選ぶためです。
2 つ目の端末で、マニフェストを渡します。マニフェストに Namespace を書いたので、-n は付けません。
$ kubectl apply -f labels-demo.yaml --context kind-kind
3 つの Deployment が作られたことを知らせる 3 行が出るはずです。1 つ目の端末には Pod の行が 4 つ現れ、何度か書き足されていきます。frontend と frontend-canary の Pod はどちらも名前が frontend- で始まるので、TRACK 列で見分けます。1 つ目の端末で見るところは次の 4 つで、どれもこのとおりになるはずです。
STATUS列:4 つともRunningTRACK列:stableが 2 つ(frontend)、canaryが 1 つ(frontend-canary)backend-で始まる Pod のTRACK列:<none>ENVIRONMENT列:4 つとも<none>
4 つの Pod の STATUS 列が Running になったら次に進みます。クラスタを作り直したばかりなら、イメージの取得に時間がかかることがあります(第9回)。数分たっても Running にならなければ、kubectl describe pod <Pod の名前> -n labels-demo --context kind-kind の Events: の欄に並ぶイベント(第3回で触れた、クラスタで起きた出来事の報告)で理由を確かめます。
ラベルで絞り込む
2 つ目の端末で、まずすべてのラベルを表示します。--show-labels はすべてのラベルを最後の列に表示する指定です(第6回)。
$ kubectl get pods -n labels-demo --show-labels --context kind-kind
LABELS 列に、マニフェストに書いたラベルと、Deployment のコントローラーが付けた pod-template-hash が並ぶはずです。
続けて、条件を変えて絞り込みます。どのコマンドにも -L tier,track を付け、選ばれた Pod の tier と track の値を列で確かめられるようにしています。--selector は -l の長い形です。一部のコマンドでは、! や空白、括弧をシェルに解釈させないよう、条件を単一引用符(')で囲んでいます。
$ kubectl get pods -n labels-demo -l tier=frontend -L tier,track --context kind-kind
$ kubectl get pods -n labels-demo --selector tier=frontend,track=stable -L tier,track --context kind-kind
$ kubectl get pods -n labels-demo -l 'track!=canary' -L tier,track --context kind-kind
$ kubectl get pods -n labels-demo -l '!track' -L tier,track --context kind-kind
$ kubectl get pods -n labels-demo -l 'tier in (frontend, backend)' -L tier,track --context kind-kind
参考:Labels and Selectors | Kubernetes、kubectl get | Kubernetes
それぞれで選ばれるはずの Pod を、次の表にまとめます。
| 条件 | 選ばれるはずの Pod(TIER 列 / TRACK 列) | 理由 |
|---|---|---|
tier=frontend | frontend / stable の 2 つと、frontend / canary の 1 つ | track の値は見ない |
tier=frontend,track=stable | frontend / stable の 2 つ | , は「かつ」 |
track!=canary | frontend / stable の 2 つと、backend / <none> の 1 つ | != は track のキーを持たない Pod も選ぶ |
!track | backend / <none> の 1 つ | track のキーを持たないものだけ |
tier in (frontend, backend) | 4 つすべて | 値の「または」は in で書く |
track!=canary の結果は見落としやすいところです。「canary ではない」は「stable である」と同じではありません。track のラベルが無いものも含みます。
Deployment もラベルで選べます。
$ kubectl get deployments -n labels-demo -l tier=frontend --context kind-kind
frontend と frontend-canary の 2 行が表示されるはずです。Deployment が選ばれるのは、Deployment 自身の metadata.labels に tier: frontend を書いたからです。この段のコマンドはどれも一覧するだけなので、1 つ目の端末には変化が無いはずです。この段では各コマンドで上の表のとおりの数と列の値の Pod が表示され、Deployment の一覧にこの 2 行が表示されるはずです。そうなっていれば成功です。
Deployment にまとめてラベルを付ける
kubectl label に -l を付けると、条件に合うリソースにまとめてラベルを付けられます。公式ドキュメントの Labels and Selectors のページには、app=nginx の Pod にまとめて tier=fe を付ける例があります。2 つ目の端末で、3 つの Deployment に environment=dev を付けます。
$ kubectl label deployments -n labels-demo -l app.kubernetes.io/name=my-app environment=dev --context kind-kind
参考:Labels and Selectors | Kubernetes、kubectl label | Kubernetes
Pod や ReplicaSet も同じ app.kubernetes.io/name: my-app を持っていますが、このコマンドでは選ばれないはずです。-l はコマンドに書いた種類(ここでは deployments)の中から選ぶからです。
公式ドキュメントの例(kubectl label pods -l app=nginx tier=fe)では、出力は次のとおりです。
例は 3 つの Pod にラベルを付けたものです。手元では frontend、frontend-canary、backend の 3 つの Deployment について、ラベルを付けたことを知らせる行が 1 つずつ出るはずです。
次に、フロントエンドの 2 つの Deployment だけ、environment を staging に変えます。まず --overwrite を付けずに試します。
$ kubectl label deployments -n labels-demo -l tier=frontend environment=staging --context kind-kind
リファレンスによると、--overwrite を付けないと、すでにあるラベルを書き換えようとしたときにエラーになります。ここでも、すでにある environment を上書きしようとしていることを伝えるエラーが出て、environment は dev のままのはずです。エラーは選んだ 2 つの Deployment のそれぞれについて出ると考えられます。続けて --overwrite を付けて実行します。
$ kubectl label deployments -n labels-demo -l tier=frontend environment=staging --overwrite --context kind-kind
今度は 2 つの Deployment について、ラベルを付けたことを知らせる行が出るはずです。結果を確かめます。
$ kubectl get deployments -n labels-demo -L tier,track,environment --context kind-kind
ENVIRONMENT 列は、frontend と frontend-canary が staging、backend が dev になるはずです。
1 つ目の端末には変化が無いはずです。この段で書き換えたのは Deployment 自身の metadata.labels で、Pod のひな形ではないからです。「ラベルの設計」で見たとおり、ロールアウトはひな形が変わったときだけ始まるので、Pod は作り直されないはずです。Pod の ENVIRONMENT 列も <none> のままのはずです。
この段では Deployment の ENVIRONMENT 列が変わり、1 つ目の端末の Pod には変化が無いはずです。そうなっていれば成功です。
Pod にまとめてラベルを付ける
今度は Pod に直接ラベルを付けます。2 つ目の端末で、tier=frontend の Pod に environment=staging を付けます。前の段で Deployment に付けた environment は Pod には入っていないので、Pod には新しく付けることになり、--overwrite は要りません。
$ kubectl label pods -n labels-demo -l tier=frontend environment=staging --context kind-kind
3 つの Pod について、ラベルを付けたことを知らせる行が出るはずです。1 つ目の端末には、TRACK 列が stable の 2 つと canary の 1 つの Pod の行が、ENVIRONMENT 列を staging にして書き足されるはずです。第11回でラベルを書き換えたときと同じく、Pod が変わるたびに行が書き足されるからです。environment はどのセレクタにも入っていないので、Pod はセレクタから外れないはずです。新しい Pod の行や Terminating の行は現れないと考えられます。
この段では 1 つ目の端末でフロントエンドの 3 つの Pod の ENVIRONMENT 列が staging になるはずです。そうなっていれば成功です。
アノテーションを付ける
kubectl annotate はリソースのアノテーションを書き換えるコマンドで、kubectl label と同じく -l で対象を絞れます。2 つ目の端末で、フロントエンドの 2 つの Deployment に、連絡先のアノテーション contact を付けます。リファレンスの説明に合わせて、-l には等価ベースの条件を書きます。
$ kubectl annotate deployments -n labels-demo -l tier=frontend contact='web-team@example.com' --context kind-kind
参考:kubectl annotate | Kubernetes、Managing Workloads | Kubernetes
2 つの Deployment について、アノテーションを付けたことを知らせる行が出るはずです。続けて、frontend に説明のアノテーション description を付けます。値には空白、括弧、, を入れています。
$ kubectl annotate deployment frontend -n labels-demo description='My app frontend (stable track, 2 replicas)' --context kind-kind
アノテーションの値には文字の決まりが無いので、このまま付けられるはずです。同じ値をラベルとして付けようとするとどうなるかを試します。
$ kubectl label deployment frontend -n labels-demo description='My app frontend (stable track, 2 replicas)' --context kind-kind
ラベルの値には空白や括弧、, を使えないので、ラベルの値が正しくないことを伝えるエラーが出て、ラベルは付かないはずです。エラーの文面は公式ドキュメントでは確かめられません。
参考:Labels and Selectors | Kubernetes、Annotations | Kubernetes
付けたアノテーションを、中身をそのまま表示して確かめます。
$ kubectl get deployment frontend -n labels-demo -o yaml --context kind-kind
出力の metadata.annotations: の下に、contact と description があるはずです。kubectl apply が付けた kubectl.kubernetes.io/last-applied-configuration(第7回)や、deployment.kubernetes.io/revision(「Kubernetes が意味を決めているラベルとアノテーション」の表)も並ぶと考えられます。
続けて、アノテーションのキーを -l に書いて、Deployment を選べるかを試します。比べるために、まずラベルのキーだけを書いた -l tier で選びます。-l tier は値にかかわらず tier のキーのラベルを持つものを選ぶ条件です。
$ kubectl get deployments -n labels-demo -l tier --context kind-kind
$ kubectl get deployments -n labels-demo -l contact --context kind-kind
1 つ目のコマンドでは、3 つの Deployment がすべて表示されるはずです。キーだけを書く形の条件で選べています。2 つ目のコマンドでは、見つからないことを知らせる 1 行が出るはずです。contact はアノテーションで、ラベルではないからです。
最後に、アノテーションを書き換えてから消します。すでにあるアノテーションを書き換えるには、ラベルと同じく --overwrite が要ります。キーの後ろに - を付けると、そのアノテーションを消せます。消すときは --overwrite は要りません。
$ kubectl annotate deployment frontend -n labels-demo description='My app frontend' --overwrite --context kind-kind
$ kubectl annotate deployment frontend -n labels-demo description- --context kind-kind
どちらのコマンドでも、アノテーションを書き換えたことを知らせる行が出るはずです。kubectl get deployment frontend -n labels-demo -o yaml --context kind-kind をもう一度実行すると、description が無くなり、contact が残っているはずです。ラベルも同じく、kubectl label でキーの後ろに - を付けると消せます。この段で書き換えたのは Deployment のアノテーションだけなので、1 つ目の端末には変化が無いはずです。
この段では、空白などを入れた値のアノテーションが付き、同じ値のラベルはエラーになるはずです。-l tier では 3 つが選ばれ、-l contact では何も選ばれないはずです。そうなっていれば成功です。
ラベルで絞って Pod と Deployment を消す
最後に、同じ -l track=canary の条件でまず Pod を、次に Deployment を消して、結果を比べます。kubectl delete -l は条件に合うものをまとめて消すので、先に同じ条件で一覧して、消えるものを確かめます。deployments,pods のように種類を , で並べると、まとめて一覧できます(第11回の rs,pods と同じ書き方です)。
$ kubectl get deployments,pods -n labels-demo -l track=canary --context kind-kind
frontend-canary の Deployment の行と、frontend-canary- で始まる Pod の行が 1 つずつ表示されるはずです。
2 つ目の端末で、track=canary の Pod を消します。
$ kubectl delete pods -n labels-demo -l track=canary --context kind-kind
Pod を消したことを知らせる 1 行が出るはずです。コンテナの終了には既定で 30 秒の猶予があるので(第9回)、コマンドが終わるまで少しかかることがあります。
1 つ目の端末では、TRACK 列が canary の Pod の行が Terminating になるはずです。続けて、TRACK 列が canary の、新しい名前の Pod の行が現れるはずです。第6回で見たとおり、frontend-canary の ReplicaSet が足りない 1 つをひな形から作るからです。
この新しい Pod の ENVIRONMENT 列を見てください。<none> になると考えられます。「Pod にまとめてラベルを付ける」の段で staging を付けたのは消した Pod で、新しい Pod はひな形から作られ、ひな形には environment が無いからです。Pod に直接付けたラベルは、作り直された Pod には引き継がれないと考えられます。Pod にいつも付けておきたいラベルは、ひな形に書きます。ただし、ひな形のラベルを変えると Deployment のロールアウトが始まります。
新しい Pod の STATUS 列が Running になったら、2 つ目の端末で、同じ条件で今度は Deployment を消します。
$ kubectl delete deployments -n labels-demo -l track=canary --context kind-kind
参考:Managing Workloads | Kubernetes、kubectl delete | Kubernetes
公式ドキュメントの例(kubectl delete deployment,services -l app=nginx で Deployment と Service を消した例)では、出力は次のとおりです。
手元では Deployment だけを消すので、例の 1 行目と同じ形で、my-nginx が frontend-canary になった 1 行が出るはずです。1 つ目の端末では、TRACK 列が canary の Pod の行が Terminating になり、今度は新しい Pod は現れないはずです。第6回で見たとおり、Deployment を消すと、既定ではガベージコレクターが従属物の ReplicaSet と Pod も消すからです。
1 つ目の端末で Terminating の行の Pod が消えるのを待ってから(終了の猶予は既定で 30 秒です)、残っているものを確かめます。
$ kubectl get deployments,pods -n labels-demo -l track=canary --context kind-kind
$ kubectl get deployments -n labels-demo --context kind-kind
1 つ目のコマンドでは、見つからないことを知らせる 1 行が出るはずです。Pod が Terminating で表示されたら、30 秒ほど待ってからもう一度実行します。2 つ目のコマンドでは、frontend と backend の 2 行が表示されるはずです。
この段では、次の 3 点が見られるはずです。そうなっていれば成功です。
- Pod を消すと、
TRACK列がcanaryの新しい Pod が作り直される - 作り直された Pod の
ENVIRONMENT列は<none>(ひな形にenvironmentが無いためと考えられる) - Deployment を消すと、Pod も消えて戻らない
片付け
1 つ目の端末で Ctrl+C を押して、Pod の監視を止めます。
2 つ目の端末で、labels-demo の Namespace を消します。中の Deployment と Pod も一緒に消えます(第37回)。
$ kubectl delete namespace labels-demo --context kind-kind
コマンドが終わったら、残っていないかを確かめます。
$ kubectl get namespace labels-demo --context kind-kind
見つからないことを知らせる 1 行が出れば、削除できています。STATUS 列が Terminating で表示されたら、少し待ってからもう一度実行します。削除は非同期に進み(第37回)、中の Pod にも終了の猶予があるので、30 秒以上かかることもあると考えられます。
最後にクラスタを削除し、消えたことを確かめます。続けて次の回を試す場合は、クラスタを残しておいてもかまいません。
$ kind delete cluster
$ kind get clusters
kind delete cluster は存在しないクラスタを指定してもエラーを返しません。kind get clusters に kind が表示されなくなったことを確かめます。kubeconfig に kind-kind のコンテキストが残っていたら、第3回の片付けと同じく kubectl config delete-context kind-kind で消します。
注意点
ラベルとアノテーションでつまずきやすい点を、次の表にまとめます。
| 項目 | 内容 |
|---|---|
| アノテーションでは選べない | ラベルセレクタが見るのはラベルだけ。アノテーションのキーを -l に書いても選ばれない |
| ラベルの値には文字の決まりがある | 63 文字以内で、空白や括弧は使えない。長い説明や JSON はアノテーションに書く |
| キーと値は文字列 | true や数値をマニフェストに書くときは、引用符で囲む(第25回) |
| アノテーションの合計は 256 KiB まで | 1 つのオブジェクトのすべてのアノテーションのキーと値の合計が上限を超えてはならない(must not) |
kubernetes.io/ と k8s.io/ は予約されている | Kubernetes の中心のコンポーネントのための接頭辞。自動でラベルやアノテーションを付けるツールは、接頭辞を付けなければならない(must) |
| 推奨のラベルは必須ではない | 中心のツールには要らない。活かすには、すべてのリソースのオブジェクトに付けるべき(should) |
| セレクタに使うキーの値を書き換えると Pod が外れる | レプリカの数を変えていなければ、外れた Pod は残ったまま、その数だけ新しい Pod が作られ、合計が増えると考えられる(第11回) |
| セレクタを重ねない | セレクタが重なったコントローラーどうしはぶつかり合い、正しく動かない(第6回、第11回) |
| Deployment のセレクタは後から変えられない | apps/v1 では作ったあとで変えられないので、前もって計画する |
| Deployment 自身のラベルとひな形のラベルは別 | Deployment 自身のラベルを変えてもロールアウトは始まらない。ひな形のラベルを変えると始まる |
| Pod に直接付けたラベルは引き継がれないと考えられる | 作り直された Pod はひな形のラベルだけを持つと考えられる。いつも付けたいラベルはひな形に書く |
kubectl delete -l はまとめて消す | 先に同じ条件の kubectl get -l で対象を確かめる。Namespace も確かめる |
参考:Labels and Selectors | Kubernetes、Annotations | Kubernetes、Recommended Labels | Kubernetes、Deployments | Kubernetes、Deployments | Kubernetes、Deployments | Kubernetes、Pods | Kubernetes、kubectl delete | Kubernetes
kubectl delete には消す前に確認を求める -i(--interactive)もあります。リファレンスによると、利用者が確かめたときだけリソースを消します。条件の書き間違いが心配なときに使えます。
関連記事
次の回ではたくさんのマニフェストをまとめて扱う Helm と Kustomize を取り上げます。Helm は推奨のラベル app.kubernetes.io/managed-by の例にも出てきました。
ラベルセレクタの決まりと、ラベルを書き換えた Pod が ReplicaSet の管理から外れる様子については、以下の記事で解説しています。
ReplicaSet を動かして理解する同じ Pod を指定した数だけ動かし続ける ReplicaSet の仕組みを図で説明します。ReplicaSet がラベルセレクタで Pod を選んで数える決まり、自分のものにする Pod の条件、数を減らすときに消す Pod の選び方を押さえ、kind のクラスタでラベルを書き換えた Pod が管理から外れる様子を観察する手順を紹介します。Namespace に自動で付くラベル kubernetes.io/metadata.name と、Namespace を消すと中身も消える仕組みについては、以下の記事で解説しています。