Namespace とラベル
1つのクラスタをネームスペースで分けておくモデルとラベル・セレクタの文法を整理します。default の限界、システムネームスペース4つ、RBAC・ResourceQuota・NetworkPolicy の単位としてのネームスペース、kubens 運用のヒント、app.kubernetes.io/* 標準ラベル、kubectl -l の selector 文法までを扱い1部を締めくくります。
1部の最後の章です。本書をたどりながら1つの事実が静かに通り過ぎました — これまで作った Pod、Deployment、Service、ConfigMap、Secret が全部 default ネームスペース1か所に入ったという点です。そして 第4章 Deployment と ReplicaSet の selector からラベルもずっと出会ってきましたが、1か所に整理はしませんでした。本章ではその2つの道具 — Namespace とラベル — でクラスタを人が読める形に整理する方法を扱います。最後には1部第7章の目標から次の部 (2部 ワークロードと運用) を短く予告します。
本章の終わりには 1つのクラスタを環境別・チーム別にきれいに分けた形 が手に入ります。同じマニフェストを dev / staging / prod のどこに入れても自分の場所で互いに衝突なく動作し、権限・リソース・ネットワークポリシーもその区画単位で分けておける土台になります。
default ネームスペースの限界 #
-A オプションを付けてクラスタのすべてのオブジェクトを一度覗き込むと、私たちが作っていないものがたくさん起動しているのが見えます。
kubectl get all -ANAMESPACE NAME READY STATUS RESTARTS AGE
kube-system pod/coredns-5d78c9869d-2xvlw 1/1 Running 0 3d
kube-system pod/etcd-minikube 1/1 Running 0 3d
kube-system pod/kube-apiserver-minikube 1/1 Running 0 3d
kube-system pod/kube-controller-manager-minikube 1/1 Running 0 3d
kube-system pod/kube-proxy-7gbdn 1/1 Running 0 3d
kube-system pod/kube-scheduler-minikube 1/1 Running 0 3d
default pod/web-7f8b6c8f7d-abcde 1/1 Running 0 1hkube-system は K8s が自分自身を回すためのコントロールプレーンコンポーネントが集まっているネームスペースです。coredns (クラスタ DNS)、etcd、apiserver、controller-manager、scheduler、kube-proxy — 第1章 Kubernetes とは で図で見たあのコンポーネントたちがすべてここに生きています。第2章 ローカル環境 から出会ってきましたが名前を押さえなかった隔離空間です。
kubectl get nsNAME STATUS AGE
default Active 3d
kube-node-lease Active 3d
kube-public Active 3d
kube-system Active 3dデフォルトで作られるシステムネームスペース4つ — default、kube-system、kube-public、kube-node-lease — が常に起動しています。一行ずつ押さえておきます。
default—-nオプションなしで作ったオブジェクトが入る場所です。1 ~ 6章のすべてのオブジェクトがここに集まりました。kube-system— K8s コントロールプレーンコンポーネントが住む場所です。一般ユーザーが直接手を出しません。kube-public— 認証なしでも読めるオブジェクトのための場所です。クラスタ情報の公開用で、ほとんど使いません。kube-node-lease— ノードのハートビートを効率的に管理するために 1.13 から分離された場所です。運用者が直接触ることはありません。
ここまではシステムが勝手に回すので大きな問題はありませんが、1つのクラスタで dev / staging / prod を一緒に回したり、チーム A・B が同じクラスタを分け合って使ったり、あるアプリは1まとまりで、あるアプリは別のまとまりで分けておきたかったりするときから default 1か所に全部入れる形が崩れます。同じ名前の Service が環境ごとに別々にあるべきで、権限も環境別に分けるべきで、一方の環境の事故が別の方へ漏れないようにしなければならないからです。
Namespace が解いてくれるもの #
Namespace は一行で要約すると 1つのクラスタの中の仮想クラスタ です。Linux の user アカウントや git の branch と似た筋の分離です — 同じ物理リソースの上に論理的な区画を分けておく道具です。解いてくれる仕事は次の4つが核心です。
- 名前空間の分離 — 同じ名前のオブジェクトを別のネームスペースに別々に置けます。
webという Service が dev と prod の両方に別個に存在でき、互いに衝突しません。 - RBAC の単位 — 権限をネームスペース単位で分けてあげられます。「チーム A は
team-aネームスペースの中でだけ読み書き可能、その外は見られない」といったポリシーの基本単位です。 - リソースクォータの単位 —
ResourceQuotaとLimitRangeオブジェクトでネームスペースごとに CPU・メモリ・オブジェクト個数の上限を置けます。dev が prod のリソースを食い尽くさないように防ぐ道具です。 - NetworkPolicy の単位 — ネームスペースの間のトラフィックを遮断したり許可したりするポリシーを書けます。デフォルトはすべてのネームスペースが互いにトラフィックが通る状態で、これを狭めるには NetworkPolicy を使わなければなりません。
ここで1つを明確に押さえておく価値があります — Namespace 自体はセキュリティ境界ではありません。 単純にオブジェクト名を分けてくれる論理区画にすぎません。本当の隔離は上の4項目のうち後ろの3つ (RBAC、リソースクォータ、NetworkPolicy) が別途行います。Namespace だけ作っておいて RBAC も NetworkPolicy も書かなかったなら、権限のあるユーザーはどのネームスペースのオブジェクトでも見て触れますし、Pod 同士も互いに通信します。本章ではマニフェストの形までだけ扱い、RBAC / NetworkPolicy / ResourceQuota の深さは 第14章 RBAC / NetworkPolicy / ResourceQuota で本格的に扱います。
クラスタスコープ vs ネームスペーススコープ #
オブジェクトには2つの筋があります。ネームスペーススコープ (namespaced) のオブジェクトはどれかのネームスペースに属さなければならず、クラスタスコープ (cluster-scoped) のオブジェクトはネームスペースなしにクラスタ全域に1つで存在します。1 ~ 6章で見たオブジェクトで分けてみると次の通りです。
| スコープ | 例 |
|---|---|
| ネームスペーススコープ | Pod、Deployment、ReplicaSet、Service、ConfigMap、Secret、Job、Ingress |
| クラスタスコープ | Node、PersistentVolume、Namespace 自体、ClusterRole、StorageClass |
Node がネームスペースに属さないのは直感的です — ノードは物理・仮想マシンであり1つのクラスタのリソースであって、どれかの環境に属さないからです。オブジェクトがどちらに属するかをコマンドで確認することもできます。
kubectl api-resources --namespaced=truekubectl api-resources --namespaced=false運用中に「このオブジェクトに -n を付けるべきか?」が混乱するとき一度回してみれば答えがすぐに出ます。
Namespace を作る #
命令型で一行で作れます。
kubectl create namespace devnamespace/dev createdgit に意図を残したいならマニフェストで書きます。
apiVersion: v1
kind: Namespace
metadata:
name: dev
labels:
env: devkubectl apply -f dev-ns.yamlapiVersion は ConfigMap・Secret と同様にコアグループの v1 です。Namespace 自体はクラスタスコープのオブジェクトなので、その metadata の中に namespace: フィールドを書きません (書けません)。
オブジェクトを特定のネームスペースに入れる道は2通りです。
- マニフェストに書く —
metadata.namespace: devの一行をオブジェクトの metadata に直接書きます。 - コマンドにオプションで —
kubectl apply -f web.yaml -n devのように-nで指定します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: dev
labels:
app: web
spec:
# ... 以下 [第4章](./deployment-and-replicaset/) と同じ両方が一緒にあるとマニフェストの値が優先します (コマンドオプションはマニフェストに namespace がないときだけ適用されます)。混同を減らすには どちらか一方だけ 使うのがよいです。git に意図を残す観点ではマニフェストに書いておくほうが次の人に親切です — コマンドオプションはシェルの履歴にだけ残り、次に同じマニフェストを見ると「これはどこへ行くのか?」が再び疑問になるからです。
NS 別に見て回る #
-n オプションで1つのネームスペースのオブジェクトだけ見ます。
kubectl get pods -n devkubectl get all -n kube-system-A オプションはすべてのネームスペースを一度に見ます。
kubectl get pods -A-n を毎回書くのは煩わしいです。現在のコンテキストのデフォルトネームスペースを変えれば その後はオプションなしでもそのネームスペースへ行くようになります。
kubectl config set-context --current --namespace=devkubectl config view --minify | grep namespace:このコマンドは ~/.kube/config の現在のコンテキストにデフォルトネームスペースを書いておきます。そのあと kubectl get pods だけ打っても dev の Pod が出てきます。
kubens — 一行でネームスペース切り替え #
上のコマンドが長いので、運用者がほぼ皆使う道具が kubens (kubectx パッケージの相棒) です。一行でネームスペースを乗り換えられます。
kubens # 現在のネームスペース出力 + 候補一覧
kubens dev # dev へ切り替え
kubens - # 直前のネームスペースへ戻るkubectx がクラスタ (コンテキスト) 切り替え用なら kubens はネームスペース切り替え用です。両方とも1つのパッケージから来ます — Homebrew、apt、scoop のどこでも kubectx を入れれば一緒に入ります。毎日 K8s を触る人にはほぼ必須に近い便利ツールです。
NS の中のオブジェクトはどう互いを呼ぶか #
第5章 Service の DNS の節で見た流れをもう一度押さえる番です。同じネームスペースの中に住む Pod 同士は Service 名だけで互いを呼べました。
http://web/api # web という Service を短い名前で別のネームスペースの Service を呼ぶには名前の後ろにネームスペースを付けます。
http://web.prod/api # 短く
http://web.prod.svc.cluster.local/api # FQDNK8s クラスタの中のすべての Service は <service>.<namespace>.svc.cluster.local という FQDN で解決されます。短く縮めて web.prod だけ書いてもクラスタ DNS が勝手に埋めてくれます。一行で整理すると DNS がネームスペースの間の橋 です — ネームスペースがオブジェクト名を分けておく区画なら、DNS はその区画を越えてオブジェクトを呼べるようにしてくれる通路の役割をします。
ラベル vs アノテーション #
ここで視点を変えて、クラスタ整理のもう1つの軸である ラベル へ移ります。ラベルは 第4章 の selector から実はずっと出会ってきました — Deployment の spec.selector.matchLabels、Pod テンプレートの metadata.labels、第5章 Service の spec.selector がすべてラベルでオブジェクトをまとめて選り分けるメカニズムです。
ラベルとよく混乱するのが アノテーション (annotation) です。両方とも metadata の下にキー・バリューで書く形は同じですが、使い道がはっきり分かれます。
| 比較項目 | ラベル (label) | アノテーション (annotation) |
|---|---|---|
| K8s がマッチングに使用 | はい (selector) | いいえ |
| 長さ・内容 | 短く意味のあるキー・バリュー (数十文字) | 任意 — 長くても OK、JSON・base64 など |
| 用途 | オブジェクトの分類・選択 | ツール・運用者が付けるメモ |
| キーの例 | app=web、env=prod、tier=backend | prometheus.io/scrape: "true"、kubectl.kubernetes.io/last-applied-configuration |
一行の違いは — ラベルは検索キー、アノテーションはメモ紙 です。K8s のコントローラ (Deployment、Service、NetworkPolicy など) がどのオブジェクトを扱うか選ぶときに見るのがラベルで、外部ツール (Prometheus、Helm、ArgoCD、Ingress コントローラなど) や運用者がオブジェクトにメタデータを付け足すときに使うのがアノテーションです。
キーと値の制約も少し違います。ラベルは selector に使われるだけに形式が狭いです — キーは ASCII 英数字に -、_、. 程度、値も同様に短い文字列だけ入ります (両方とも数十文字以内)。アノテーションはその制約が緩んでいて、任意のテキスト・JSON も入れられます。kubectl.kubernetes.io/last-applied-configuration アノテーションがまるごとマニフェストの JSON を持っているのがその例です。
metadata:
name: web
labels:
app: web
env: prod
tier: backend
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
kubernetes.io/change-cause: "bump nginx 1.27 -> 1.28"標準ラベルのコンベンション — app.kubernetes.io/* #
ラベルに app=web のような独自のキーを自由に付けてもよいですが、K8s コミュニティが推奨する標準ラベルのセットがあります。キーの接頭辞が app.kubernetes.io/ で始まる6つです。
| キー | 意味 | 例の値 |
|---|---|---|
app.kubernetes.io/name | アプリ名 | nginx、web、kafka |
app.kubernetes.io/instance | このデプロイインスタンスの識別子 | web-prod、kafka-shop |
app.kubernetes.io/version | バージョン | 1.27、2.4.1 |
app.kubernetes.io/component | 役割 | frontend、backend、database |
app.kubernetes.io/part-of | 上位システム | shop-platform、analytics |
app.kubernetes.io/managed-by | 管理ツール | Helm、argocd、kubectl |
これらのキーを使う理由は 運用ツール・ダッシュボードが標準として認識するから です。Lens、k9s、Datadog、Helm といったツールがこのキーを見てオブジェクトをまとめて見せてくれます。独自のキーだけ使うより互換性が明らかによいです。独自のキー (例: env、team) を併せて使っても差し支えなく、標準ラベルのセットと独自ラベルを一緒に書くのが一般的な形です。
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: prod
labels:
app.kubernetes.io/name: nginx
app.kubernetes.io/instance: web-prod
app.kubernetes.io/version: "1.27"
app.kubernetes.io/component: frontend
app.kubernetes.io/part-of: shop-platform
app.kubernetes.io/managed-by: kubectl
env: prod
spec:
replicas: 3
selector:
matchLabels:
app.kubernetes.io/name: nginx
app.kubernetes.io/instance: web-prod
template:
metadata:
labels:
app.kubernetes.io/name: nginx
app.kubernetes.io/instance: web-prod
app.kubernetes.io/version: "1.27"
app.kubernetes.io/component: frontend
env: prod
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80selector の matchLabels と Pod テンプレートの labels には、標準ラベルの中でも 変わらないものだけ を入れるほうが安全です。version のようなキーを selector に入れておくと、バージョンを上げるとき selector も一緒に変えなければならず、第4章 で見た selector immutability の落とし穴に引っかかりやすいです。
ラベルで選り分ける — kubectl -l #
ラベルが付いていれば kubectl の -l オプションでオブジェクトを選り分けられます。selector の文法は単純な等号から集合表現までいくつかあります。
kubectl get pods -l app=web
kubectl get pods -l env=prod,tier=backend # ANDカンマでつなげば AND です。OR は次の集合表現で書きます。
kubectl get pods -l 'env in (dev,staging)'
kubectl get pods -l 'env notin (prod)'
kubectl get pods -l 'tier' # tier ラベルがあるもの
kubectl get pods -l '!debug' # debug ラベルがないもの複数のオブジェクト種類に一緒に使うこともできます。
kubectl get deploy,svc,cm -l app.kubernetes.io/instance=web-prodkubectl delete pods -l env=dev最後のコマンドは強力です — マッチするすべての Pod を一度に消します。運用クラスタでラベルを間違って入れて意図より多くのオブジェクトを消す事故がときどき起きます。一括削除の前には同じ selector で get を先に回して対象が意図したそれなのか確認するのが安全です。診断ツリーの完成版は 第27章 kubectl デバッグパターン で整理します。
-l セレクタの文法が重要な理由は — 同じ文法が Service の spec.selector、Deployment の spec.selector.matchLabels、NetworkPolicy の podSelector、ResourceQuota の scopeSelector など K8s の中のほぼすべてのオブジェクトのマッチングにそのまま使われるからです。ラベルを一度覚えておけば、その上に乗るオブジェクトたちの selector が自然に読めます。
仮想の運用の一コマ — これを全部合わせると #
これまでの道具を1つのマニフェストのまとまりに合わせてみると、運用クラスタの基本の形が現れます。dev / staging / prod の3つのネームスペース、その中に同じ名前の Deployment・Service・ConfigMap・Secret があり、ラベルで環境とバージョンが付いています。
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: prod
labels:
app.kubernetes.io/name: nginx
app.kubernetes.io/instance: web-prod
app.kubernetes.io/version: "1.27"
app.kubernetes.io/component: frontend
app.kubernetes.io/part-of: shop-platform
env: prod
spec:
replicas: 3
selector:
matchLabels:
app.kubernetes.io/name: nginx
app.kubernetes.io/instance: web-prod
template:
metadata:
labels:
app.kubernetes.io/name: nginx
app.kubernetes.io/instance: web-prod
app.kubernetes.io/component: frontend
env: prod
spec:
containers:
- name: nginx
image: nginx:1.27
ports:
- containerPort: 80
envFrom:
- configMapRef:
name: web-config
- secretRef:
name: db-secret
---
apiVersion: v1
kind: Service
metadata:
name: web
namespace: prod
labels:
app.kubernetes.io/name: nginx
app.kubernetes.io/instance: web-prod
env: prod
spec:
selector:
app.kubernetes.io/name: nginx
app.kubernetes.io/instance: web-prod
ports:
- port: 80
targetPort: 80dev と staging もほぼ同じマニフェストです — metadata.namespace、instance、version、env ラベル程度だけ環境ごとに違い、残りはそのままです。この形が1つのクラスタの中で環境別にオブジェクトがきれいに分かれる運用クラスタの基本です。
運用で同じマニフェストを環境別に少しずつ変えて適用しなければならないとき、毎回手で変えておくとミスが多いです。だから登場する道具が Helm (テンプレート + 値の分離) と Kustomize (ベース + オーバーレイ) です。本章の範囲の外で、第22章 アプリ配備の骨格 と 第20章 GitOps で EKS 上の実戦デプロイと一緒に本格的に扱います。
後片付け・クリーンアップ #
本章で作った dev ネームスペースを整理します。
kubectl delete ns devnamespace "dev" deletedこの一行が怖い理由は そのネームスペースの中のすべてのオブジェクトが一緒に消えるという点 です。Deployment、Service、Pod、ConfigMap、Secret、PVC すべて非同期で削除されます。運用クラスタでネームスペース削除はほぼ最後のカードだと見なすべきです — 一度押すとその中のデータまで飛ぶことがあり、第9章 PV / PVC / StorageClass で扱う永続ボリュームの reclaimPolicy 設定によってはディスク自体も一緒に消えることがあります。
kubectl config set-context --current --namespace=defaultkubens をインストールしておいた環境なら kubens default で一行です。
1部の振り返り — 7章で手に入ったもの #
1部の最後の章なので一度整理します。
- 第1章 Kubernetes とは — なぜ K8s なのか。単一ホストの限界、オーケストレーターが解いてくれるもの、コントロールプレーンとワーカーの図。
- 第2章 ローカル環境 — ローカルクラスタ。minikube / kind / Docker Desktop の3つの使い道と違い、kubectl コンテキスト。
- 第3章 kubectl と最初の Pod — 最初の Pod。マニフェストの背骨 (
apiVersion / kind / metadata / spec)、kubectl apply/get/describe/logs/exec。 - 第4章 Deployment と ReplicaSet — Deployment と ReplicaSet。宣言型デプロイ、ローリングアップデート、
kubectl rollout、selector immutability。 - 第5章 Service — Service。ClusterIP / NodePort / LoadBalancer の3段階、クラスタ内部 DNS。
- 第6章 ConfigMap と Secret — ConfigMap と Secret。12-factor の「設定は環境に置く」、env / envFrom / volume の3つの注入方式。
- 第7章 Namespace とラベル (本章) — クラスタの整理法。ネームスペースの RBAC・クォータ・NetworkPolicy 単位、標準ラベルのコンベンション、kubectl -l セレクタ。
これだけあれば K8s マニフェスト1枚を初めて見ても何を意味するのかを読み書きできる水準です。会社のクラスタのマニフェストディレクトリを開いてもオブジェクトの種類とその中のフィールド名がなじみのないものではないはずです。その上に乗るより深いテーマたちが2部 (ワークロードと運用) のあらすじです。
練習問題 #
kubectl create namespace devで新しいネームスペースを作り、第6章 の web Deployment + ConfigMap + Secret マニフェストをmetadata.namespace: devでまるごと移してkubectl applyしてみてください。kubectl get all -n devとkubectl get all -n default出力を並べて書いておき、同じ名前のオブジェクトが2つのネームスペースに同時に存在できるという点を確認します。そのあと dev の web Pod の中でcurl http://web.default/とcurl http://web/がどんな結果を返すか比較します。- 第4章 の web Deployment に §「標準ラベルのコンベンション」の
app.kubernetes.io/*キー6個をすべて付けてみてください。selector のmatchLabelsにはnameとinstanceだけ入れてversionはラベルとしてだけ置く理由を §「selector immutability の落とし穴」と連動させて一段落でメモします。そのあとkubectl get pods,svc,cm -l app.kubernetes.io/instance=<...>がどんなオブジェクトたちを一度にまとめて見せるか確認します。 - 独自ラベル
team=aとteam=bを持つ Pod を2個同じネームスペースに起動し、kubectl get pods -l 'team in (a)'、kubectl get pods -l 'team notin (a)'、kubectl get pods -l '!team'の3つのコマンドの出力を順に記録します。同じ selector の文法が 第14章 RBAC / NetworkPolicy / ResourceQuota のpodSelectorにどうそのまま適用されるかを一行で推論します。
一行まとめ: Namespace は1つのクラスタの中の仮想クラスタで、名前空間を分けておき RBAC・ResourceQuota・NetworkPolicy の単位になる。ラベルは selector がオブジェクトをまとめて選り分ける検索キーであり、アノテーションはツール・運用者のメモ紙である。マニフェストの本体は環境に関係なく一揃いで置き、環境ごとに違う部分はネームスペースとラベル・ConfigMap・Secret で分離する。
次の章 #
1部が終わりました。2部 ワークロードと運用の最初の章である 第8章 StatefulSet / DaemonSet / Job / CronJob では、Deployment ではない別のコントローラたちを扱います。データベースのように各インスタンスが自分の名前と自分のディスクを持たなければならないワークロード (StatefulSet)、ログ収集器・ノードモニタのようにノードごとに1個ずつ起動すべきワークロード (DaemonSet)、一度回って終わるバッチ作業 (Job・CronJob) の形と選択基準を整理します。
2部全体のあらすじは次の通りです。
| 章 | テーマ |
|---|---|
| 第8章 | StatefulSet・DaemonSet・Job・CronJob — Deployment ではないコントローラたち |
| 第9章 | PV・PVC・StorageClass — 永続データモデル |
| 第10章 | Ingress と Ingress Controller — 外部進入点 |
| 第11章 | resources.requests / limits — Pod のリソース要求と上限 |
| 第12章 | Health check — liveness・readiness・startup probe |
| 第13章 | オートスケーリング — HPA・VPA・Cluster Autoscaler |
| 第14章 | RBAC・NetworkPolicy・ResourceQuota — セキュリティとリソースポリシー |
2部を終えるとクラスタ上のさまざまなワークロードを安定的に運用できる水準に到達します。その次の3部 (深さ) では CNI・Admission Controller・CRD・可観測性・GitOps といった運用者の視野へ広げるテーマを扱います。