目次
7 章

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 -A
出力例 — 抜粋
NAMESPACE     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          1h

kube-system は K8s が自分自身を回すためのコントロールプレーンコンポーネントが集まっているネームスペースです。coredns (クラスタ DNS)、etcd、apiserver、controller-manager、scheduler、kube-proxy — 第1章 Kubernetes とは で図で見たあのコンポーネントたちがすべてここに生きています。第2章 ローカル環境 から出会ってきましたが名前を押さえなかった隔離空間です。

ネームスペース一覧
kubectl get ns
出力例
NAME              STATUS   AGE
default           Active   3d
kube-node-lease   Active   3d
kube-public       Active   3d
kube-system       Active   3d

デフォルトで作られるシステムネームスペース4つ — defaultkube-systemkube-publickube-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 ネームスペースの中でだけ読み書き可能、その外は見られない」といったポリシーの基本単位です。
  • リソースクォータの単位ResourceQuotaLimitRange オブジェクトでネームスペースごとに 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=true
クラスタスコープのオブジェクト一覧
kubectl api-resources --namespaced=false

運用中に「このオブジェクトに -n を付けるべきか?」が混乱するとき一度回してみれば答えがすぐに出ます。

Namespace を作る #

命令型で一行で作れます。

命令型で作る
kubectl create namespace dev
出力例
namespace/dev created

git に意図を残したいならマニフェストで書きます。

dev-ns.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: dev
  labels:
    env: dev
apply
kubectl apply -f dev-ns.yaml

apiVersion は ConfigMap・Secret と同様にコアグループの v1 です。Namespace 自体はクラスタスコープのオブジェクトなので、その metadata の中に namespace: フィールドを書きません (書けません)。

オブジェクトを特定のネームスペースに入れる道は2通りです。

  • マニフェストに書くmetadata.namespace: dev の一行をオブジェクトの metadata に直接書きます。
  • コマンドにオプションでkubectl apply -f web.yaml -n dev のように -n で指定します。
metadata.namespace で書いた場合
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  namespace: dev
  labels:
    app: web
spec:
  # ... 以下 [第4章](./deployment-and-replicaset/) と同じ

両方が一緒にあるとマニフェストの値が優先します (コマンドオプションはマニフェストに namespace がないときだけ適用されます)。混同を減らすには どちらか一方だけ 使うのがよいです。git に意図を残す観点ではマニフェストに書いておくほうが次の人に親切です — コマンドオプションはシェルの履歴にだけ残り、次に同じマニフェストを見ると「これはどこへ行くのか?」が再び疑問になるからです。

NS 別に見て回る #

-n オプションで1つのネームスペースのオブジェクトだけ見ます。

dev ネームスペースの Pod
kubectl get pods -n dev
kube-system のすべてのオブジェクト
kubectl get all -n kube-system

-A オプションはすべてのネームスペースを一度に見ます。

すべてのネームスペースを一度に
kubectl get pods -A

-n を毎回書くのは煩わしいです。現在のコンテキストのデフォルトネームスペースを変えれば その後はオプションなしでもそのネームスペースへ行くようになります。

デフォルトネームスペースの切り替え
kubectl config set-context --current --namespace=dev
現在のコンテキストの確認
kubectl config view --minify | grep namespace:

このコマンドは ~/.kube/config の現在のコンテキストにデフォルトネームスペースを書いておきます。そのあと kubectl get pods だけ打っても dev の Pod が出てきます。

kubens — 一行でネームスペース切り替え #

上のコマンドが長いので、運用者がほぼ皆使う道具が kubens (kubectx パッケージの相棒) です。一行でネームスペースを乗り換えられます。

kubens 使用
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 を呼ぶには名前の後ろにネームスペースを付けます。

別のネームスペースの Service
http://web.prod/api                     # 短く
http://web.prod.svc.cluster.local/api   # FQDN

K8s クラスタの中のすべての 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=webenv=prodtier=backendprometheus.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
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アプリ名nginxwebkafka
app.kubernetes.io/instanceこのデプロイインスタンスの識別子web-prodkafka-shop
app.kubernetes.io/versionバージョン1.272.4.1
app.kubernetes.io/component役割frontendbackenddatabase
app.kubernetes.io/part-of上位システムshop-platformanalytics
app.kubernetes.io/managed-by管理ツールHelmargocdkubectl

これらのキーを使う理由は 運用ツール・ダッシュボードが標準として認識するから です。Lens、k9s、Datadog、Helm といったツールがこのキーを見てオブジェクトをまとめて見せてくれます。独自のキーだけ使うより互換性が明らかによいです。独自のキー (例: envteam) を併せて使っても差し支えなく、標準ラベルのセットと独自ラベルを一緒に書くのが一般的な形です。

標準ラベルが付いた Deployment
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: 80

selector の 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-prod
ラベルで一括削除 — 危険
kubectl 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 があり、ラベルで環境とバージョンが付いています。

prod ネームスペースの Deployment + Service
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: 80

dev と staging もほぼ同じマニフェストです — metadata.namespaceinstanceversionenv ラベル程度だけ環境ごとに違い、残りはそのままです。この形が1つのクラスタの中で環境別にオブジェクトがきれいに分かれる運用クラスタの基本です。

運用で同じマニフェストを環境別に少しずつ変えて適用しなければならないとき、毎回手で変えておくとミスが多いです。だから登場する道具が Helm (テンプレート + 値の分離) と Kustomize (ベース + オーバーレイ) です。本章の範囲の外で、第22章 アプリ配備の骨格第20章 GitOps で EKS 上の実戦デプロイと一緒に本格的に扱います。

後片付け・クリーンアップ #

本章で作った dev ネームスペースを整理します。

ネームスペース削除
kubectl delete ns dev
出力例
namespace "dev" deleted

この一行が怖い理由は そのネームスペースの中のすべてのオブジェクトが一緒に消えるという点 です。Deployment、Service、Pod、ConfigMap、Secret、PVC すべて非同期で削除されます。運用クラスタでネームスペース削除はほぼ最後のカードだと見なすべきです — 一度押すとその中のデータまで飛ぶことがあり、第9章 PV / PVC / StorageClass で扱う永続ボリュームの reclaimPolicy 設定によってはディスク自体も一緒に消えることがあります。

現在のネームスペースのデフォルト値を戻す
kubectl config set-context --current --namespace=default

kubens をインストールしておいた環境なら 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 と ReplicaSetDeployment と ReplicaSet。宣言型デプロイ、ローリングアップデート、kubectl rollout、selector immutability。
  • 第5章 ServiceService。ClusterIP / NodePort / LoadBalancer の3段階、クラスタ内部 DNS。
  • 第6章 ConfigMap と SecretConfigMap と Secret。12-factor の「設定は環境に置く」、env / envFrom / volume の3つの注入方式。
  • 第7章 Namespace とラベル (本章) — クラスタの整理法。ネームスペースの RBAC・クォータ・NetworkPolicy 単位、標準ラベルのコンベンション、kubectl -l セレクタ。

これだけあれば K8s マニフェスト1枚を初めて見ても何を意味するのかを読み書きできる水準です。会社のクラスタのマニフェストディレクトリを開いてもオブジェクトの種類とその中のフィールド名がなじみのないものではないはずです。その上に乗るより深いテーマたちが2部 (ワークロードと運用) のあらすじです。

練習問題 #

  1. kubectl create namespace dev で新しいネームスペースを作り、第6章 の web Deployment + ConfigMap + Secret マニフェストを metadata.namespace: dev でまるごと移して kubectl apply してみてください。kubectl get all -n devkubectl get all -n default 出力を並べて書いておき、同じ名前のオブジェクトが2つのネームスペースに同時に存在できるという点を確認します。そのあと dev の web Pod の中で curl http://web.default/curl http://web/ がどんな結果を返すか比較します。
  2. 第4章 の web Deployment に §「標準ラベルのコンベンション」の app.kubernetes.io/* キー6個をすべて付けてみてください。selector の matchLabels には nameinstance だけ入れて version はラベルとしてだけ置く理由を §「selector immutability の落とし穴」と連動させて一段落でメモします。そのあと kubectl get pods,svc,cm -l app.kubernetes.io/instance=<...> がどんなオブジェクトたちを一度にまとめて見せるか確認します。
  3. 独自ラベル team=ateam=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 / ResourceQuotapodSelector にどうそのまま適用されるかを一行で推論します。

一行まとめ: 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 といった運用者の視野へ広げるテーマを扱います。

X