K8s 基礎 #7 Namespace とラベル — クラスタの整理法
K8s 基礎シリーズの最後の記事です。この記事では今まで作ったオブジェクトがなぜ default namespace に集まっていたか、Namespace が何を分離してくれるか、そしてラベルと selector がどうオブジェクトをまとめて見つけるかを整理します。最後にこの 7 編全体を振り返り、次のトラックである K8s 中級で何を扱うかを予告します。
このシリーズは K8s 基礎 7 編です。
- #1 Kubernetes とは — なぜコンテナオーケストレーターが必要か
- #2 ローカル環境 — minikube / kind / Docker Desktop k8s
- #3 kubectl と最初の Pod
- #4 Deployment と ReplicaSet — 宣言的デプロイとローリングアップデート
- #5 Service — ClusterIP / NodePort / LoadBalancer
- #6 ConfigMap と Secret — 設定の分離
- #7 Namespace とラベル — クラスタの整理法 ← この記事
default namespace の限界 #
-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 が自分自身を回すためのコントロールプレーンコンポーネントが集まっている namespace です。coredns (クラスタ DNS)、etcd、apiserver、controller-manager、scheduler、kube-proxy — #1 で図で見たコンポーネントがすべてここに生きています。私たちが #2 から見ていたけれど名前は触れなかった隔離空間です。
kubectl get nsNAME STATUS AGE
default Active 3d
kube-node-lease Active 3d
kube-public Active 3d
kube-system Active 3d既定で作られるシステム namespace が 4 つ — default、kube-system、kube-public、kube-node-lease — 常に立っています。1 行ずつ押さえると。
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 行で要約すると 1 クラスタ内の仮想クラスタ です。Linux のユーザアカウントや git のブランチに似た、同じ物理リソースの上に論理的な区画を作る仕組みです。解いてくれることは次の 4 つが核心です。
- 名前空間の分離 — 同じ名前のオブジェクトを別の namespace に別々に置けます。
webという Service が dev と prod の両方に独立して存在でき、衝突しません。 - RBAC の単位 — 権限を namespace 単位で分けられます。「チーム A は
team-anamespace の中だけ読み書き可能、それ以外は見られない」のようなポリシーの基本単位です。 - リソースクォータの単位 —
ResourceQuotaとLimitRangeオブジェクトで namespace ごとに CPU・メモリ・オブジェクト数の上限を設定できます。dev が prod のリソースを食ってしまわないようにする道具です。 - NetworkPolicy の単位 — namespace 間のトラフィックを遮断したり許可したりするポリシーを書けます。既定では全 namespace が互いに通信できる状態で、これを狭めるには NetworkPolicy が必要です。
ここで 1 つはっきり押さえる価値があります — Namespace 自体はセキュリティ境界ではありません。 単純にオブジェクト名を分ける論理区画にすぎません。本当の隔離は上の 4 項目のうち後ろの 3 つ (RBAC、リソースクォータ、NetworkPolicy) が別途行います。Namespace だけ作っておいて RBAC も NetworkPolicy も書いていないなら、権限のあるユーザはどの namespace のオブジェクトも見て触れますし、Pod 同士も互いに通信します。このシリーズはマニフェストの形までを扱い、RBAC / NetworkPolicy / ResourceQuota の深さは K8s 中級でまとめて扱います。
クラスタスコープ vs namespace スコープ #
オブジェクトには 2 種類あります。namespace スコープ (namespaced) のオブジェクトはどこかの namespace に属さねばならず、クラスタスコープ (cluster-scoped) のオブジェクトは namespace 無しでクラスタ全体に 1 つだけ存在します。私たちが見たオブジェクトで分けると。
| スコープ | 例 |
|---|---|
| namespace スコープ | Pod、Deployment、ReplicaSet、Service、ConfigMap、Secret、Job、Ingress |
| クラスタスコープ | Node、PersistentVolume、Namespace 自体、ClusterRole、StorageClass |
Node が namespace に属さないのは直感的です — ノードは物理・仮想マシンでありクラスタのリソースで、どこかの環境に属するものではないからです。オブジェクトがどちら側に属するかコマンドで確認することもできます。
kubectl api-resources --namespaced=truekubectl api-resources --namespaced=false運用していて「このオブジェクトに -n を付けるべきか?」が混同するときに 1 度回せば答えがすぐ出ます。
Namespace を作る #
命令的に 1 行で作れます。
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: フィールドを書きません (書けません)。
オブジェクトを特定の namespace に入れる道は 2 通りです。
- マニフェストに書く —
metadata.namespace: devの 1 行をオブジェクトの metadata に直接書きます。 - コマンドのオプションで —
kubectl apply -f web.yaml -n devのように-nで指定します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: dev
labels:
app: web
spec:
# ... 以下 [#4](/ja/posts/k8s-basics-4) と同じ両方が同時にあるとマニフェストの値が優先されます (コマンドオプションはマニフェストに namespace が無いときだけ適用)。混乱を減らすには どちらか一方だけ 使うのがいいです。git に意図を残す観点では、マニフェストに書いておく方が次の人に親切です — コマンドオプションはシェル履歴にしか残らず、次に同じマニフェストを見たとき「これはどこに行くのか?」がまた疑問になるからです。
NS 別に眺める #
-n オプションで 1 つの namespace のオブジェクトだけ見ます。
kubectl get pods -n devkubectl get all -n kube-system-A オプションは全 namespace を一度に見ます。
kubectl get pods -A-n を毎回書くのは煩雑です。現在のコンテキストの既定 namespace を変えると その後はオプション無しでもその namespace に行きます。
kubectl config set-context --current --namespace=devkubectl config view --minify | grep namespace:このコマンドは ~/.kube/config の現在のコンテキストに既定 namespace を書いておきます。その後 kubectl get pods だけで dev の Pod が出ます。
kubens — 1 行で namespace を切替 #
上のコマンドが長いので、運用者がほぼ皆使う道具が kubens (kubectx パッケージの相方) です。1 行で namespace を切り替えられます。
kubens # 現在の namespace 出力 + 候補一覧
kubens dev # dev に切替
kubens - # 直前の namespace に戻るkubectx がクラスタ (コンテキスト) 切替用なら kubens は namespace 切替用です。両方とも 1 つのパッケージから来ます — Homebrew、apt、scoop どこでも kubectx を入れれば一緒に入ってきます。毎日 K8s を触る人にはほぼ必須に近い便利道具です。
NS 内のオブジェクトがどう互いを呼ぶか #
#5 の Service 節で見た流れをもう一度押さえる番です。同じ namespace の中に住む Pod 同士は Service 名だけで互いを呼べました。
http://web/api # web という Service を短い名前で別の namespace の Service を呼ぶには名前の後ろに namespace を付けます。
http://web.prod/api # 短く
http://web.prod.svc.cluster.local/api # FQDNK8s クラスタ内の全 Service は <service>.<namespace>.svc.cluster.local という FQDN で解決されます。短く縮めて web.prod だけ書いてもクラスタ DNS が自動で埋めてくれます。1 行で整理すると DNS が namespace 間の橋 です — namespace がオブジェクト名を分ける区画なら、DNS はその区画を超えてオブジェクトを呼べるようにする通路の役目を担います。
ラベル vs アノテーション #
ここで視点を変えて、クラスタ整理のもう 1 つの軸である ラベル に移ります。ラベルは #4 の selector から実はずっと見ていました — Deployment の spec.selector.matchLabels、Pod テンプレートの metadata.labels、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 |
1 行の差は — ラベルは検索キー、アノテーションは付箋 です。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 を先に回して対象が意図したものか確認するのが安全です。
-l セレクタの文法が重要な理由は — 同じ文法が Service の spec.selector、Deployment の spec.selector.matchLabels、NetworkPolicy の podSelector、ResourceQuota の scopeSelector など K8s 内のほぼ全オブジェクトのマッチングにそのまま使われるからです。ラベルを 1 度身につければその上に乗るオブジェクトの selector が自然に読めます。
仮想の運用 1 コマ — これを全部合わせると #
ここまでの道具を 1 つのマニフェスト束にまとめると、運用クラスタの基本の形が現れます。dev / staging / prod 3 つの namespace、その中に同じ名前の 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 (ベース + オーバーレイ) です。両方ともこのシリーズの範囲外で、K8s 上級 / 実践トラックで扱います。
片付け #
この記事で作った dev namespace を片付けます。
kubectl delete ns devnamespace "dev" deletedこの 1 行が怖いのは その namespace の中の全オブジェクトが一緒に消える点 です。Deployment、Service、Pod、ConfigMap、Secret、PVC すべて非同期で削除されます。運用クラスタでの namespace 削除はほぼ最後の手段だと見るべきです — 1 度押せばその中のデータまで飛びかねず、PV (永続ボリューム) の reclaimPolicy 設定によってはディスク自体も一緒に消えることがあります。
kubectl config set-context --current --namespace=defaultkubens を入れている環境なら kubens default で 1 行です。
シリーズ振り返り — 7 編で手に入ったもの #
最後の記事なので 7 編を一度整理します。
- #1 — なぜ K8s か。コンテナ 1 ホストの限界、オーケストレーターが解いてくれること、コントロールプレーンとワーカの絵。
- #2 — ローカルクラスタ。minikube / kind / Docker Desktop の使い分けと違い、kubectl コンテキスト。
- #3 — 最初の Pod。マニフェストの背骨 (
apiVersion / kind / metadata / spec)、kubectl apply/get/describe/logs/exec。 - #4 — Deployment と ReplicaSet。宣言的デプロイ、ローリングアップデート、
kubectl rollout、selector immutability。 - #5 — Service。ClusterIP / NodePort / LoadBalancer の 3 段、クラスタ内部 DNS。
- #6 — ConfigMap と Secret。12-factor の「設定は環境に置く」、env / envFrom / volume の 3 つの注入方式。
- #7 Namespace とラベル — クラスタの整理法 ← この記事。
ここまでくれば K8s マニフェスト 1 枚を初めて見ても何を意味するか読み書きできる水準です。会社のクラスタのマニフェストディレクトリを開いてもオブジェクト種類とその中のフィールド名が見覚えのあるものに見えるはずです。その上に乗るより深いトピックが次のトラックです。
次 — K8s 中級 #
このシリーズで意図的に後回しにしたトピックが K8s 中級 7 編の筋書きです。
| トピック | 説明 |
|---|---|
| StatefulSet / DaemonSet / Job / CronJob | Deployment 以外のコントローラ。データベース、ノードエージェント、一回限りバッチ、スケジュールバッチ。 |
| PV / PVC / StorageClass | 永続データ。Pod が死んでも生き残るディスクのモデル。 |
| Ingress + Ingress Controller | 外部入口を 1 か所に集める。nginx / Traefik / GKE Ingress のようなコントローラ。 |
| resources.requests / limits | Pod の CPU・メモリ要求・上限。スケジューリングと OOM の基準。 |
| Health check | liveness / readiness / startup probe。K8s がコンテナの生存をどう判定するか。 |
| HPA / VPA / Cluster Autoscaler | 負荷に合わせて Pod 数、Pod のリソース、ノード数まで自動調整。 |
| RBAC / NetworkPolicy / ResourceQuota | この記事で短く触れたセキュリティ・リソースポリシーの深さ。 |
この 7 つを扱った後は、会社のクラスタのマニフェストディレクトリに自分のマニフェストを書けるレベルに 1 歩近づきます。その次の K8s 上級 / 実践 では Helm、Kustomize、GitOps (ArgoCD / Flux)、オブザーバビリティ (Prometheus / Grafana / Loki)、クラスタ運用 (アップグレード、バックアップ、マルチクラスタ) のようなトピックを本格的に扱います。
締め #
基礎シリーズ 7 編で K8s の基礎を整理しました。単一ホストから出発してクラスタを立て、最初のマニフェストを書き、複数の Pod を安定して維持し、外部に公開し、設定と秘密値を分離する過程までを追ってきました。マニフェスト 1 枚が実際にクラスタの中でどんなオブジェクトに構成されるか、そしてそれらのオブジェクトが互いにどう繋がっているかを理解できるなら、このシリーズの目的は十分達成されたと言えます。次のトラックである K8s 中級では、この基礎の上にさらに深いトピックを順番に扱います。