本記事には広告(アフィリエイトリンク)が含まれます。

Kubernetes実践編 #04

【Kubernetes実践編 #04】環境構築 — 基盤整備とNamespace・RBAC・基盤コンポーネント

4.1 はじめに

4.1.1 設計フェーズの振り返り — 手元にある設計書

実践編の最初の3回で、TaskBoardの設計書一式が完成しました。手元にある成果物を確認しておきましょう。

成果物答える問い
第1回(構成図)3階層の構成図「何があるか」「どうつながっているか」
第2回(基本設計)5領域の基本設計書「何を使うか」「なぜそれを選ぶか」
第3回(詳細設計)全マニフェスト + パラメータ設計書「具体的にどの値を設定するか」「なぜその値か」

構成図で全体像を描き、基本設計で方針を決め、詳細設計で全パラメータの値と根拠を文書化しました。設計フェーズの成果物は、構築フェーズの「入力」になります。

4.1.2 構築フェーズの開始 — 「設計書から構築する」プロセス

ここから構築フェーズに入ります。

応用編では、毎回kubectlを叩いてリソースを追加してきました。「第1回でNamespaceを作り、第3回でStatefulSetを追加し、第5回でGateway APIを導入し……」と、学習テーマに合わせて場当たり的にTaskBoardを育てていきました。

実践編の構築は違います。設計書が先にあり、その設計書を「クラスタという現実」に変換する作業です。マニフェストの中身は応用編で学んだものと同じですが、「なぜこの順序で適用するのか」「何をもって完了とするのか」を意識しながら進めます。

設計フェーズではkubectlをほぼ使いませんでした。本回から再びkubectlが主要ツールに戻ります。設計書という地図を片手に、実際のクラスタを歩いていきましょう。

4.1.3 本回のゴールと成果物

本回のゴールは、アプリケーションを載せる前の「箱」を作ることです。

具体的には、以下の状態を達成します。

  • 応用編で作成したTaskBoardリソースがリセットされ、白紙の状態に戻っている
  • クラスタ基盤コンポーネント(Calico CNI、Metrics Server、Gateway APIコントローラー)が正常に稼働している
  • 設計書通りにNamespace(app / db / monitoring)が作成され、ResourceQuotaとLimitRangeが適用されている
  • 設計書通りにRBAC(ServiceAccount、Role、RoleBinding)が適用されている
  • 基盤整備の完了確認チェックリストで全項目がパスしている

成果物は「構築済みの基盤環境」と「基盤整備の完了確認チェックリスト」です。

4.2 VMの環境構築手順とK8sの環境構築手順

4.2.1 VMの世界での環境構築 — 何から手をつけるか

VMwareの世界で新しいシステムを構築する場面を思い出してください。設計書が承認された後、実際の構築作業は決まった順序で進みます。

  • 物理基盤の確認: ラックの空き、電源容量、ネットワークケーブルの配線を確認する
  • ESXiホストの準備: ホストがvCenterに登録済みで正常稼働していることを確認する
  • リソースプールの設定: CPU・メモリの割り当て枠をプロジェクト単位で設定する
  • フォルダ構成の作成: vCenter上のフォルダ(Web層、DB層、監視層など)を作成する
  • 権限の設定: Active Directoryと連携し、チームごとのvCenter操作権限を設定する
  • VM作成とOS導入: 上記の「箱」の中にVMを作成し、OSをインストールする
  • ミドルウェア導入: Apache、MySQL、Zabbix Agentなどをインストール・設定する

ポイントは、VMを作る前に「箱」を先に整えていることです。リソースプールがなければCPU・メモリの管理ができません。フォルダがなければVMが散らかります。権限設定がなければ、誰でも何でもできてしまいます。

4.2.2 K8sの環境構築 — アプリを載せる前の「箱」作り

K8sの構築でも順序は同じです。アプリケーション(Deployment、StatefulSet等)を載せる前に、基盤を整える必要があります。

VMの世界K8sの世界役割
ESXiホストの稼働確認Nodeの状態確認 + CNI + Metrics Server基盤インフラが動いている
リソースプール設定ResourceQuota + LimitRangeリソース消費量の制御
フォルダ構成Namespaceリソースの論理的な分離
vCenter権限設定RBAC(ServiceAccount + Role + RoleBinding)操作権限の制御
VM作成・OS導入Deployment / StatefulSet等のapplyアプリケーションの配置

「箱」がない状態でアプリを載せるとどうなるでしょうか。Namespaceがなければ全リソースがdefaultに混在します。ResourceQuotaがなければ1つのアプリがクラスタ全体のリソースを食い潰す可能性があります。RBACがなければ、開発者が本番のStatefulSetを誤って削除できてしまいます。

本回は、この「箱」を作る作業です。

4.2.3 構築順序の設計

実践編の構築は第4回〜第6回の3回にわたります。全体の構築順序を設計し、本回の範囲を明確にしておきましょう。

第4回(本回):基盤整備
  1.  環境リセット(応用編のNamespace削除)
  2.  クラスタ基盤確認(Node / Calico / Metrics Server / Gateway API)
  3.  Namespace作成
  4.  ResourceQuota適用
  5.  LimitRange適用
  6.  RBAC適用(ServiceAccount / Role / RoleBinding)

第5回:アプリケーション構築
  7.  コンテナイメージのビルド(Nginx / TaskBoard API)
  8.  Secret / ConfigMap作成
  9.  MySQL StatefulSet + Headless Service + PVC
  10. TaskBoard API Deployment + Service
  11. Nginx Deployment + Service
  12. DB初期化Job
  13. DBバックアップCronJob
  14. ログ収集DaemonSet
  15. HPA / PDB

第6回:ネットワーク構築と結合テスト
  16. Gateway API(Gateway + HTTPRoute)
  17. NetworkPolicy
  18. E2E結合テスト

この順序には理由があります。Namespaceが存在しなければResourceQuotaを適用できません。ResourceQuotaが適用されていなければ、アプリをデプロイした際にリソース管理が効きません。RBACが設定されていなければ、構築後の運用で権限問題が発生します。依存関係の下流から順に積み上げていく——これが構築順序の基本原則です。

本回は上記の1〜6を担当します。

4.3 応用編の環境をリセットする

4.3.1 なぜリセットするのか

応用編の全9回を通じて、TaskBoardは段階的に成長してきました。Namespaceを作り、RBACを設定し、StatefulSetでMySQLを追加し、DaemonSetでログ収集を始め、Gateway APIで外部公開し、NetworkPolicyで通信を制御し、SecurityContextでセキュリティを強化し、HPAでオートスケーリングを設定し、Helmでフロントエンドをパッケージ化しました。

この「完全体」のTaskBoardを、ここで一度リセットします。

応用編のTaskBoardは「学びながら積み上げた結果」です。実践編では「設計書に基づいて構築するプロセス」を体験します。そのために、構築対象を白紙に戻す必要があります。

ただし、クラスタ自体は再作成しません。応用編第6回でCalico CNIに対応したkindクラスタ(CP 1 + Worker 3)を構築し、Metrics Server、Gateway APIコントローラー(Envoy Gateway)も導入済みです。これらのクラスタレベルのコンポーネントはそのまま再利用します。削除するのはユーザーが作成したNamespace(app、db、monitoring)とその中のリソースです。

対象操作理由
ユーザーNamespace(app, db, monitoring)削除TaskBoardのリソースを白紙に戻す
kindクラスタ本体そのまま再利用再構築は時間がかかり、学習目的と合わない
Calico CNIそのまま維持クラスタレベルのコンポーネント
Metrics Server稼働確認kube-system Namespaceにあり、削除されない
Gateway APIコントローラー稼働確認envoy-gateway-system Namespaceにあり、削除されない

応用編の成果が消えるわけではありません。Namespaceとリソースはクラスタから消えますが、応用編で身につけた知識——「StatefulSetがなぜ必要か」「NetworkPolicyのデフォルト拒否はどう動くか」「startupProbeなしでPayara Microがどうなるか」——は、あなたの中に残っています。その知識があるからこそ、これから設計書通りに構築する作業が「手触りのある作業」になります。

4.3.2 ユーザーNamespaceを削除する

まず、応用編のTaskBoardが現在どのような状態かを確認します。リセット前の最後の姿を見ておきましょう。

[Execution User: developer]

# 応用編のTaskBoardの現在の状態を確認
kubectl get all,pvc -n app
kubectl get all,pvc -n db
kubectl get all -n monitoring

Deployment、StatefulSet、Service、CronJob、DaemonSet、HPA、PDB、PVC——応用編で積み上げてきたリソースが一覧に表示されます。これが応用編の集大成です。

では、リセットします。ユーザーNamespaceを削除すると、その中のリソースはすべて連鎖的に削除されます。Deployment、StatefulSet、Service、ConfigMap、Secret、PVC——Namespace内のあらゆるリソースが一括で消えます。

[Execution User: developer]

# ユーザーNamespaceを削除(中のリソースもすべて連鎖削除される)
kubectl delete namespace app db monitoring

以下のような出力が表示されます。

namespace "app" deleted
namespace "db" deleted
namespace "monitoring" deleted

Namespace削除にはしばらく時間がかかる場合があります。StatefulSetのPVCやNetworkPolicy等のリソースが順に削除されるためです。コマンドが返ってくるまで待ちましょう。

4.3.3 クラスタの状態を確認する

削除が完了したら、クラスタの状態を確認します。

[Execution User: developer]

# Namespaceの一覧を確認(app, db, monitoringが消えていること)
kubectl get namespaces

出力例:

NAME                          STATUS   AGE
calico-apiserver              Active   XXd
calico-system                 Active   XXd
default                       Active   XXd
envoy-gateway-system          Active   XXd
kube-node-lease               Active   XXd
kube-public                   Active   XXd
kube-system                   Active   XXd
local-path-storage            Active   XXd
tigera-operator               Active   XXd

app、db、monitoringの3つのNamespaceが消えています。残っているのはシステムNamespace(kube-system等)と、クラスタレベルのコンポーネント用Namespace(calico-system、envoy-gateway-system等)です。これらは今回の構築対象ではないため、そのまま残します。

念のため、ユーザーリソースが残留していないことを確認しておきます。

[Execution User: developer]

# ユーザーリソースの残留確認(何も表示されないことが期待値)
kubectl get all -n app 2>&1
kubectl get all -n db 2>&1
kubectl get all -n monitoring 2>&1
Error from server (NotFound): namespaces "app" not found
Error from server (NotFound): namespaces "db" not found
Error from server (NotFound): namespaces "monitoring" not found

Namespaceごと削除されているため、NotFoundが返ります。リセットは完了です。

4.4 クラスタ基盤コンポーネントを確認する

アプリケーションを載せる前に、クラスタの基盤が正常に動作していることを確認します。VMの世界でESXiホストやvCenterの稼働確認をするのと同じ工程です。

4.4.1 Nodeの状態確認

全ノードがReady状態であることを確認します。

[Execution User: developer]

kubectl get nodes

期待する出力:

NAME                        STATUS   ROLES           AGE   VERSION
k8s-applied-control-plane   Ready    control-plane   XXd   v1.32.0
k8s-applied-worker          Ready    <none>          XXd   v1.32.0
k8s-applied-worker2         Ready    <none>          XXd   v1.32.0
k8s-applied-worker3         Ready    <none>          XXd   v1.32.0

4ノード(Control Plane 1 + Worker 3)がすべてReadyであることを確認します。STATUS列がReadyでないノードがある場合は、kubectl describe node <ノード名>で原因を調査してください。

4.4.2 Calico CNIの確認

応用編第6回で導入したCalico CNIが正常に稼働していることを確認します。CalicoはNetworkPolicyの実行基盤であり、第6回のNetworkPolicy構築で必要になります。

[Execution User: developer]

# Calicoコンポーネントの稼働確認
kubectl get pods -n calico-system

期待する出力(Pod名のサフィックスは環境により異なります):

NAME                                       READY   STATUS    RESTARTS   AGE
calico-kube-controllers-xxxxxxxxxx-xxxxx   1/1     Running   X          XXd
calico-node-xxxxx                          1/1     Running   X          XXd
calico-node-xxxxx                          1/1     Running   X          XXd
calico-node-xxxxx                          1/1     Running   X          XXd
calico-node-xxxxx                          1/1     Running   X          XXd

calico-nodeはDaemonSetとして全ノードに配置されるため、4つ(CP 1 + Worker 3)のPodが稼働しています。calico-kube-controllersはCalicoの制御プレーンです。すべてのPodがRunningであれば正常です。

4.4.3 Metrics Serverの確認

応用編第1回で導入したMetrics Serverが正常に稼働していることを確認します。Metrics Serverはkubectl topコマンドやHPAの基盤となるコンポーネントです。

[Execution User: developer]

# Metrics Serverの稼働確認
kubectl get deployment metrics-server -n kube-system
NAME             READY   UP-TO-DATE   AVAILABLE   AGE
metrics-server   1/1     1            1           XXd

AVAILABLE列が1であることを確認します。次に、実際にメトリクスが取得できることを検証します。

[Execution User: developer]

# Nodeのリソース使用状況を確認
kubectl top nodes
NAME                        CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
k8s-applied-control-plane   XXXm         XX%    XXXMi           XX%
k8s-applied-worker          XXm          X%     XXXMi           XX%
k8s-applied-worker2         XXm          X%     XXXMi           XX%
k8s-applied-worker3         XXm          X%     XXXMi           XX%

ユーザーNamespaceを削除した直後なので、Worker NodeのCPU使用率は低めのはずです。値が表示されていればMetrics Serverは正常に動作しています。

4.4.4 Gateway APIコントローラーの確認

応用編第5回で導入したEnvoy Gatewayが正常に稼働していることを確認します。Gateway APIリソース(Gateway、HTTPRoute)は第6回で適用しますが、コントローラー自体はここで確認しておきます。

[Execution User: developer]

# Envoy Gatewayコントローラーの稼働確認
kubectl get pods -n envoy-gateway-system
NAME                              READY   STATUS    RESTARTS   AGE
envoy-gateway-xxxxxxxxxx-xxxxx    1/1     Running   X          XXd

[Execution User: developer]

# GatewayClassの確認(Envoy Gatewayのインストール時に自動作成される)
kubectl get gatewayclass
NAME   CONTROLLER NAME                                      ACCEPTED   AGE
eg     gateway.envoyproxy.io/gatewayclass-controller         True       XXd

GatewayClassのACCEPTEDがTrueであれば、Envoy Gatewayはリクエストを受け入れ可能な状態です。なお、応用編で作成したGatewayリソースやHTTPRouteは、app Namespaceの削除とともに消えています。これらは第6回で再作成します。

ここまでで、クラスタの基盤が正常であることを確認しました。次は設計書に基づいてNamespaceとリソース管理の「箱」を作っていきます。

4.5 Namespace・ResourceQuota・LimitRangeを適用する

4.5.1 設計書のNamespace設計を確認する

マニフェストを適用する前に、設計書を確認します。「設計書 → apply → 検証」——この3ステップを繰り返すリズムが、実践編の構築プロセスです。

基本設計書(第2回)のセキュリティ設計方針では、以下のNamespace分離を定めています。

Namespace用途配置するコンポーネント
appアプリケーション層Nginx(フロントエンド)、TaskBoard API、Gateway
dbデータベース層MySQL(StatefulSet)、DB初期化Job、バックアップCronJob
monitoring監視・運用層ログ収集DaemonSet

ResourceQuotaとLimitRangeは応用編第1回で設計した値をそのまま使用します。詳細設計書(第3回)で確認した通り、補助マニフェスト(Namespace、ResourceQuota、LimitRange、RBAC等)は応用編で作成したものに変更はありません。

4.5.2 Namespaceを作成する

応用編第1回で使用したのと同じマニフェストで、3つのNamespaceを作成します。ファイルは~/k8s-applied/ディレクトリに保存済みです。念のため内容を確認してから適用しましょう。

[Execution User: developer]

# 設計書の内容を確認(app Namespace)
cat ~/k8s-applied/namespace-app.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: app
  labels:
    team: taskboard
    layer: application

[Execution User: developer]

cat ~/k8s-applied/namespace-db.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: db
  labels:
    team: taskboard
    layer: database

[Execution User: developer]

cat ~/k8s-applied/namespace-monitoring.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: monitoring
  labels:
    team: taskboard
    layer: monitoring

ラベルはteam: taskboard(プロジェクト識別)とlayer(層の識別)の2つです。layerラベルは、NetworkPolicy(第6回)で通信制御の対象を指定する際に使用します。

内容を確認したら、適用します。

[Execution User: developer]

# Namespaceを作成
kubectl apply -f ~/k8s-applied/namespace-app.yaml
kubectl apply -f ~/k8s-applied/namespace-db.yaml
kubectl apply -f ~/k8s-applied/namespace-monitoring.yaml
namespace/app created
namespace/db created
namespace/monitoring created

[Execution User: developer]

# 作成されたことを確認
kubectl get namespaces --show-labels | grep -E "^(NAME|app|db|monitoring)"
NAME         STATUS   AGE   LABELS
app          Active   10s   kubernetes.io/metadata.name=app,layer=application,team=taskboard
db           Active   10s   kubernetes.io/metadata.name=db,layer=database,team=taskboard
monitoring   Active   9s    kubernetes.io/metadata.name=monitoring,layer=monitoring,team=taskboard

3つのNamespaceがActive状態で作成され、ラベルが正しく付与されています。kubernetes.io/metadata.nameラベルはKubernetesが自動付与する組み込みラベルです。

4.5.3 ResourceQuotaを適用する

次に、各NamespaceにResourceQuotaを適用します。応用編第1回で設計した値を確認しましょう。

[Execution User: developer]

# app Namespace用のResourceQuotaを確認
cat ~/k8s-applied/resourcequota-app.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: app-quota
  namespace: app
spec:
  hard:
    requests.cpu: "2"          # CPU requestsの合計上限: 2コア
    requests.memory: "2Gi"     # メモリrequestsの合計上限: 2GiB
    limits.cpu: "4"            # CPU limitsの合計上限: 4コア
    limits.memory: "4Gi"       # メモリlimitsの合計上限: 4GiB
    pods: "20"                 # Pod数の上限

[Execution User: developer]

cat ~/k8s-applied/resourcequota-db.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: db-quota
  namespace: db
spec:
  hard:
    requests.cpu: "1"          # DB層はapp層より控えめ
    requests.memory: "1Gi"
    limits.cpu: "2"
    limits.memory: "2Gi"
    pods: "10"

[Execution User: developer]

cat ~/k8s-applied/resourcequota-monitoring.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
  name: monitoring-quota
  namespace: monitoring
spec:
  hard:
    requests.cpu: "500m"       # 監視層は軽量
    requests.memory: "512Mi"
    limits.cpu: "1"
    limits.memory: "1Gi"
    pods: "10"

設計根拠を振り返ります。app Namespaceはフロントエンド(Nginx)とAPIサーバー(Payara Micro)を収容し、HPAによるスケールアウトも考慮してrequests.cpuを2コアに設定しています。db Namespaceは単一のMySQL StatefulSetが主であるため控えめに。monitoring Namespaceはログ収集DaemonSet(busybox)のみなので最小限の割り当てです。

[Execution User: developer]

# ResourceQuotaを適用
kubectl apply -f ~/k8s-applied/resourcequota-app.yaml
kubectl apply -f ~/k8s-applied/resourcequota-db.yaml
kubectl apply -f ~/k8s-applied/resourcequota-monitoring.yaml
resourcequota/app-quota created
resourcequota/db-quota created
resourcequota/monitoring-quota created

4.5.4 LimitRangeを適用する

ResourceQuotaはNamespace全体のリソース総量を制限しますが、個々のPodに対しては何も言いません。LimitRangeを設定して、resourcesが未指定のPodにデフォルト値を適用し、1つのPodが使えるリソースの範囲を制限します。

[Execution User: developer]

cat ~/k8s-applied/limitrange-app.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: app-limitrange
  namespace: app
spec:
  limits:
    - type: Container
      default:              # limitsのデフォルト値
        cpu: "200m"
        memory: "256Mi"
      defaultRequest:       # requestsのデフォルト値
        cpu: "100m"
        memory: "128Mi"
      max:                  # 1コンテナの上限
        cpu: "1"
        memory: "1Gi"
      min:                  # 1コンテナの下限
        cpu: "50m"
        memory: "32Mi"

[Execution User: developer]

cat ~/k8s-applied/limitrange-db.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: db-limitrange
  namespace: db
spec:
  limits:
    - type: Container
      default:
        cpu: "500m"
        memory: "512Mi"
      defaultRequest:
        cpu: "200m"
        memory: "256Mi"
      max:
        cpu: "1"
        memory: "1Gi"
      min:
        cpu: "100m"
        memory: "128Mi"

[Execution User: developer]

cat ~/k8s-applied/limitrange-monitoring.yaml
apiVersion: v1
kind: LimitRange
metadata:
  name: monitoring-limitrange
  namespace: monitoring
spec:
  limits:
    - type: Container
      default:
        cpu: "100m"
        memory: "128Mi"
      defaultRequest:
        cpu: "50m"
        memory: "64Mi"
      max:
        cpu: "500m"
        memory: "512Mi"
      min:
        cpu: "25m"
        memory: "32Mi"

db Namespaceのデフォルト値はapp Namespaceより大きめに設定しています。MySQLは起動時にメモリを一定量確保するため、デフォルトで512Miを割り当てています。monitoring Namespaceはbusyboxベースの軽量Podが主であるため、最小限の値を設定しています。

[Execution User: developer]

# LimitRangeを適用
kubectl apply -f ~/k8s-applied/limitrange-app.yaml
kubectl apply -f ~/k8s-applied/limitrange-db.yaml
kubectl apply -f ~/k8s-applied/limitrange-monitoring.yaml
limitrange/app-limitrange created
limitrange/db-limitrange created
limitrange/monitoring-limitrange created

4.5.5 適用結果を検証する

「apply → 検証」の検証ステップです。ResourceQuotaとLimitRangeが設計書通りに適用されたことを確認します。

[Execution User: developer]

# app NamespaceのResourceQuotaを確認
kubectl describe resourcequota app-quota -n app
Name:            app-quota
Namespace:       app
Resource         Used  Hard
--------         ----  ----
limits.cpu       0     4
limits.memory    0     4Gi
pods             0     20
requests.cpu     0     2
requests.memory  0     2Gi

Used列がすべて0です。まだ何もデプロイしていないため、リソースは消費されていません。Hard列が設計書の値と一致していることを確認します。

[Execution User: developer]

# db NamespaceのResourceQuotaを確認
kubectl describe resourcequota db-quota -n db
Name:            db-quota
Namespace:       db
Resource         Used  Hard
--------         ----  ----
limits.cpu       0     2
limits.memory    0     2Gi
pods             0     10
requests.cpu     0     1
requests.memory  0     1Gi

[Execution User: developer]

# app NamespaceのLimitRangeを確認
kubectl describe limitrange app-limitrange -n app
Name:       app-limitrange
Namespace:  app
Type        Resource  Min   Max  Default Request  Default Limit  ...
----        --------  ---   ---  ---------------  -------------  ...
Container   cpu       50m   1    100m             200m           ...
Container   memory    32Mi  1Gi  128Mi            256Mi          ...

Default Request列とDefault Limit列が、マニフェストのdefaultRequestdefaultの値と一致していることを確認します。Min / Max列も設計書の通りです。

同様に、db Namespaceとmonitoring Namespaceも確認しておきます。

[Execution User: developer]

# 残りのNamespaceも検証
kubectl describe limitrange db-limitrange -n db
kubectl describe resourcequota monitoring-quota -n monitoring
kubectl describe limitrange monitoring-limitrange -n monitoring

すべてのNamespaceでResourceQuotaとLimitRangeが設計書通りに適用されていることを確認できました。「箱」のリソース管理機能が準備できています。

4.6 RBACを適用する

4.6.1 設計書のRBAC設計を確認する

基本設計書(第2回)のRBAC方針を確認します。TaskBoardでは2つの役割を定義しています。

役割権限の範囲想定する利用者
developer参照・ログ取得のみ(変更不可)開発チームメンバー
operator参照に加えて、Deployment更新・Pod削除が可能運用チーム担当者

この2つの役割をapp NamespaceとdbNamespaceそれぞれに設定します。monitoring Namespaceは運用チームが直接管理する想定のため、RBAC設定は省略しています(クラスタ管理者権限で操作する前提です)。

RBACの3層構造を改めて整理しておきます。

ServiceAccount ──── RoleBinding ──── Role
 (誰が)           (紐づけ)       (何をできるか)
                                     ↕ スコープ: Namespace内

4.6.2 ServiceAccount・Role・RoleBindingを適用する

RBACの適用順序にも依存関係があります。RoleBindingはServiceAccountとRoleの両方を参照するため、先にServiceAccountとRoleを作成する必要があります。

まずServiceAccountから確認・適用します。

[Execution User: developer]

# ServiceAccountの内容を確認(app/developer)
cat ~/k8s-applied/sa-developer-app.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: developer
  namespace: app
  labels:
    app: taskboard
    role: developer

[Execution User: developer]

# ServiceAccountを一括適用(app / db の developer / operator)
kubectl apply -f ~/k8s-applied/sa-developer-app.yaml
kubectl apply -f ~/k8s-applied/sa-operator-app.yaml
kubectl apply -f ~/k8s-applied/sa-developer-db.yaml
kubectl apply -f ~/k8s-applied/sa-operator-db.yaml
serviceaccount/developer created
serviceaccount/operator created
serviceaccount/developer created
serviceaccount/operator created

次にRoleを確認・適用します。developerとoperatorの権限の差に注目してください。

[Execution User: developer]

# developer Roleの内容を確認(app Namespace)
cat ~/k8s-applied/role-developer-app.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: developer
  namespace: app
  labels:
    app: taskboard
    role: developer
rules:
  # Pod の参照(get / list / watch)を許可
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "list", "watch"]
  # Pod のログ取得を許可
  - apiGroups: [""]
    resources: ["pods/log"]
    verbs: ["get"]
  # Service の参照を許可(接続先の確認用)
  - apiGroups: [""]
    resources: ["services"]
    verbs: ["get", "list"]
  # Deployment の参照を許可(状態確認用。更新は不可)
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get", "list"]

[Execution User: developer]

# operator Roleの内容を確認(app Namespace)
cat ~/k8s-applied/role-operator-app.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: operator
  namespace: app
  labels:
    app: taskboard
    role: operator
rules:
  # Pod の参照・ログ取得に加え、削除を許可(障害時の手動再起動用)
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "list", "watch", "delete"]
  - apiGroups: [""]
    resources: ["pods/log"]
    verbs: ["get"]
  # Service の参照を許可
  - apiGroups: [""]
    resources: ["services"]
    verbs: ["get", "list"]
  # Deployment の参照に加え、更新を許可(ローリングアップデート用)
  - apiGroups: ["apps"]
    resources: ["deployments"]
    verbs: ["get", "list", "watch", "update", "patch"]
  # ConfigMap / Secret の参照を許可(設定値の確認用)
  - apiGroups: [""]
    resources: ["configmaps", "secrets"]
    verbs: ["get", "list"]

developerは参照のみ、operatorは更新と削除まで可能——最小権限の原則に基づいた設計です。db Namespaceのoperator Roleには、StatefulSetの管理権限とPVCの参照権限も追加されています。

[Execution User: developer]

# Roleを一括適用
kubectl apply -f ~/k8s-applied/role-developer-app.yaml
kubectl apply -f ~/k8s-applied/role-developer-db.yaml
kubectl apply -f ~/k8s-applied/role-operator-app.yaml
kubectl apply -f ~/k8s-applied/role-operator-db.yaml
role.rbac.authorization.k8s.io/developer created
role.rbac.authorization.k8s.io/developer created
role.rbac.authorization.k8s.io/operator created
role.rbac.authorization.k8s.io/operator created

最後に、ServiceAccountとRoleを紐づけるRoleBindingを適用します。

[Execution User: developer]

# RoleBindingの内容を確認(app/developer)
cat ~/k8s-applied/rolebinding-developer-app.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: developer-binding
  namespace: app
  labels:
    app: taskboard
    role: developer
subjects:
  - kind: ServiceAccount
    name: developer           # 紐づけ対象の ServiceAccount
    namespace: app
roleRef:
  kind: Role
  name: developer             # 紐づける Role
  apiGroup: rbac.authorization.k8s.io

[Execution User: developer]

# RoleBindingを一括適用
kubectl apply -f ~/k8s-applied/rolebinding-developer-app.yaml
kubectl apply -f ~/k8s-applied/rolebinding-operator-app.yaml
kubectl apply -f ~/k8s-applied/rolebinding-developer-db.yaml
kubectl apply -f ~/k8s-applied/rolebinding-operator-db.yaml
rolebinding.rbac.authorization.k8s.io/developer-binding created
rolebinding.rbac.authorization.k8s.io/operator-binding created
rolebinding.rbac.authorization.k8s.io/developer-binding created
rolebinding.rbac.authorization.k8s.io/operator-binding created

RBAC全体の構成をまとめると、以下のようになります。

[app Namespace]
  ServiceAccount: developer ── RoleBinding ── Role: developer(参照・ログのみ)
  ServiceAccount: operator  ── RoleBinding ── Role: operator (更新・削除まで)

[db Namespace]
  ServiceAccount: developer ── RoleBinding ── Role: developer(参照・ログのみ)
  ServiceAccount: operator  ── RoleBinding ── Role: operator (StatefulSet更新・PVC参照まで)

4.6.3 権限を検証する — kubectl auth can-i

RBACの検証にはkubectl auth can-iコマンドを使います。応用編第2回で体験したコマンドですが、今回は設計書の権限設計が正しく反映されているかを体系的にチェックします。

[Execution User: developer]

# === developer(app Namespace)の権限テスト ===

# 許可されるべき操作
kubectl auth can-i list pods -n app \
  --as=system:serviceaccount:app:developer
# 期待値: yes

kubectl auth can-i get pods/log -n app \
  --as=system:serviceaccount:app:developer
# 期待値: yes

kubectl auth can-i list services -n app \
  --as=system:serviceaccount:app:developer
# 期待値: yes

# 拒否されるべき操作
kubectl auth can-i delete pods -n app \
  --as=system:serviceaccount:app:developer
# 期待値: no

kubectl auth can-i update deployments -n app \
  --as=system:serviceaccount:app:developer
# 期待値: no
yes
yes
yes
no
no

developerはPodの参照とログ取得は可能ですが、Pod削除やDeployment更新は拒否されます。設計書通りです。

[Execution User: developer]

# === operator(app Namespace)の権限テスト ===

# 許可されるべき操作
kubectl auth can-i delete pods -n app \
  --as=system:serviceaccount:app:operator
# 期待値: yes

kubectl auth can-i update deployments -n app \
  --as=system:serviceaccount:app:operator
# 期待値: yes

kubectl auth can-i get secrets -n app \
  --as=system:serviceaccount:app:operator
# 期待値: yes

# 拒否されるべき操作(Secretの作成・更新は不可)
kubectl auth can-i create secrets -n app \
  --as=system:serviceaccount:app:operator
# 期待値: no
yes
yes
yes
no

operatorはPod削除やDeployment更新が可能ですが、Secretの作成はできません。参照のみの権限です。

[Execution User: developer]

# === db Namespace固有の権限テスト ===

# operator は StatefulSet を管理できる
kubectl auth can-i update statefulsets -n db \
  --as=system:serviceaccount:db:operator
# 期待値: yes

# operator は PVC を参照できる(DB のデータボリューム確認用)
kubectl auth can-i list persistentvolumeclaims -n db \
  --as=system:serviceaccount:db:operator
# 期待値: yes

# developer は StatefulSet を参照のみ
kubectl auth can-i update statefulsets -n db \
  --as=system:serviceaccount:db:developer
# 期待値: no
yes
yes
no

db Namespaceでは、operatorにStatefulSetの管理権限とPVCの参照権限が追加されていることを確認できました。DB層を扱う運用担当者に必要な権限セットです。

すべてのRBAC検証が設計書通りの結果になりました。「箱」のアクセス制御が正しく設定されています。

4.7 基盤整備の完了確認

4.7.1 チェックリストで最終確認する

VMの世界では、環境構築の最終工程で「完了確認チェックリスト」を実行します。ESXiホストの稼働状態、vCenterの接続性、リソースプールの設定値——すべての項目をチェックして「構築完了」を判定します。

K8sの構築でも同じです。ここまでの作業をチェックリストで網羅的に検証します。以下のチェックリストを順に実行してください。

#チェック項目確認コマンド期待結果
1全Nodeが Readykubectl get nodes4ノードすべて STATUS: Ready
2Calico CNI 稼働中kubectl get pods -n calico-system全Podが Running
3Metrics Server 稼働中kubectl top nodes各ノードのCPU/メモリ値が表示される
4Gateway APIコントローラー稼働中kubectl get pods -n envoy-gateway-systemEnvoy Gateway Podが Running
5GatewayClass 利用可能kubectl get gatewayclassACCEPTED: True
6Namespace app 存在kubectl get ns appSTATUS: Active
7Namespace db 存在kubectl get ns dbSTATUS: Active
8Namespace monitoring 存在kubectl get ns monitoringSTATUS: Active
9ResourceQuota app 適用済みkubectl get resourcequota -n appapp-quota が表示される
10ResourceQuota db 適用済みkubectl get resourcequota -n dbdb-quota が表示される
11ResourceQuota monitoring 適用済みkubectl get resourcequota -n monitoringmonitoring-quota が表示される
12LimitRange app 適用済みkubectl get limitrange -n appapp-limitrange が表示される
13LimitRange db 適用済みkubectl get limitrange -n dbdb-limitrange が表示される
14LimitRange monitoring 適用済みkubectl get limitrange -n monitoringmonitoring-limitrange が表示される
15ServiceAccount developer (app) 存在kubectl get sa developer -n appリソースが表示される
16ServiceAccount operator (app) 存在kubectl get sa operator -n appリソースが表示される
17ServiceAccount developer (db) 存在kubectl get sa developer -n dbリソースが表示される
18ServiceAccount operator (db) 存在kubectl get sa operator -n dbリソースが表示される
19RBAC developer (app): Pod参照 可kubectl auth can-i list pods -n app --as=system:serviceaccount:app:developeryes
20RBAC developer (app): Pod削除 不可kubectl auth can-i delete pods -n app --as=system:serviceaccount:app:developerno
21RBAC operator (app): Deployment更新 可kubectl auth can-i update deployments -n app --as=system:serviceaccount:app:operatoryes
22RBAC operator (db): StatefulSet更新 可kubectl auth can-i update statefulsets -n db --as=system:serviceaccount:db:operatoryes

このチェックリストをスクリプト化して一括実行することもできます。

[Execution User: developer]

# 基盤整備チェックスクリプト
echo "=== 基盤整備 完了確認チェックリスト ==="
echo ""

echo "[1] Node状態"
kubectl get nodes -o wide --no-headers | awk '{printf "  %-35s %s\n", $1, $2}'
echo ""

echo "[2] Calico CNI"
kubectl get pods -n calico-system --no-headers | awk '{printf "  %-45s %s\n", $1, $3}'
echo ""

echo "[3] Metrics Server"
kubectl top nodes --no-headers 2>/dev/null && echo "  OK: メトリクス取得可能" || echo "  NG: メトリクス取得不可"
echo ""

echo "[4] Gateway APIコントローラー"
kubectl get pods -n envoy-gateway-system --no-headers | awk '{printf "  %-45s %s\n", $1, $3}'
echo ""

echo "[5] Namespace"
for ns in app db monitoring; do
  STATUS=$(kubectl get ns $ns -o jsonpath='{.status.phase}' 2>/dev/null)
  echo "  $ns: ${STATUS:-NOT FOUND}"
done
echo ""

echo "[6] ResourceQuota"
for ns in app db monitoring; do
  RQ=$(kubectl get resourcequota -n $ns --no-headers 2>/dev/null | awk '{print $1}')
  echo "  $ns: ${RQ:-NOT FOUND}"
done
echo ""

echo "[7] LimitRange"
for ns in app db monitoring; do
  LR=$(kubectl get limitrange -n $ns --no-headers 2>/dev/null | awk '{print $1}')
  echo "  $ns: ${LR:-NOT FOUND}"
done
echo ""

echo "[8] RBAC(権限サンプルチェック)"
echo -n "  developer(app) list pods: "
kubectl auth can-i list pods -n app --as=system:serviceaccount:app:developer
echo -n "  developer(app) delete pods: "
kubectl auth can-i delete pods -n app --as=system:serviceaccount:app:developer
echo -n "  operator(app) update deployments: "
kubectl auth can-i update deployments -n app --as=system:serviceaccount:app:operator
echo -n "  operator(db) update statefulsets: "
kubectl auth can-i update statefulsets -n db --as=system:serviceaccount:db:operator
echo ""
echo "=== チェック完了 ==="

全項目が期待結果と一致していれば、基盤整備は完了です。

4.7.2 「アプリを載せる準備ができた」状態

ここまでの作業で、クラスタは以下の状態になっています。

[kindクラスタ: k8s-applied]
  ├── Control Plane × 1 .............. Ready
  ├── Worker Node × 3 ................ Ready
  │
  ├── [kube-system]
  │     └── Metrics Server ........... 稼働中
  │
  ├── [calico-system]
  │     ├── calico-kube-controllers .. 稼働中
  │     └── calico-node × 4 ......... 稼働中(全ノード)
  │
  ├── [envoy-gateway-system]
  │     └── envoy-gateway ........... 稼働中
  │
  ├── [app Namespace] ................ 作成済み
  │     ├── ResourceQuota: app-quota
  │     ├── LimitRange: app-limitrange
  │     ├── SA: developer → Role: developer → RoleBinding
  │     └── SA: operator  → Role: operator  → RoleBinding
  │
  ├── [db Namespace] ................. 作成済み
  │     ├── ResourceQuota: db-quota
  │     ├── LimitRange: db-limitrange
  │     ├── SA: developer → Role: developer → RoleBinding
  │     └── SA: operator  → Role: operator  → RoleBinding
  │
  └── [monitoring Namespace] ......... 作成済み
        ├── ResourceQuota: monitoring-quota
        └── LimitRange: monitoring-limitrange

VMの世界で言えば、「ESXiホストが稼働し、vCenterに登録され、リソースプールが設定され、フォルダが作成され、権限が設定された」状態です。VMはまだ1台も作っていません。しかし、VMを安全に作り始めるための基盤は整いました。

K8sの世界でも同じです。DeploymentもStatefulSetもまだapplyしていません。しかし、それらを安全にデプロイするための基盤——リソース管理、アクセス制御、ネットワーク基盤——は整備されています。

4.8 この回のまとめ

4.8.1 成果物の確認 — 構築済み基盤環境 + チェックリスト

本回の成果物は以下の2つです。

  • 構築済みの基盤環境: 応用編のリソースをリセットし、クラスタ基盤の正常稼働を確認し、設計書通りにNamespace・ResourceQuota・LimitRange・RBACを適用した状態
  • 基盤整備の完了確認チェックリスト: 22項目のチェックリスト。全項目をパスし、「アプリを載せる準備が整った」ことを確認済み

4.8.2 応用編との違いを振り返る — 「設計書ありき」の構築

本回で適用したリソースは、応用編第1回(Namespace/ResourceQuota/LimitRange)と第2回(RBAC)で学んだものと同じです。マニフェストの中身も同じです。しかし、構築のプロセスはまったく違いました。

観点応用編の構築実践編の構築(本回)
構築の動機「次はこの機能を学ぼう」「設計書にこう書いたから」
構築順序回ごとにバラバラ依存関係を考慮した計画的順序
確認方法動けばOKチェックリストで網羅的に検証
構築記録なし手順書として記録
設計根拠「応用編で学ぶから」「基本設計書・詳細設計書に記載」

応用編では「Namespaceとは何か」「ResourceQuotaはどう動くか」を体験することが目的でした。実践編では「設計書で定めた通りにNamespaceとResourceQuotaを適用し、チェックリストで検証する」ことが目的です。

同じリソースでも、「学習のための構築」と「設計書に基づく構築」では、作業の進め方も検証の深さも異なります。応用編で身につけた知識があるからこそ、設計書の内容を理解し、検証結果を正しく判断できる。両方の経験が揃って、はじめて本番の構築に耐えうるスキルになります。

4.8.3 次回予告 — 基盤の上にアプリケーションを載せる

基盤が整いました。次回(第5回)は、この基盤の上にTaskBoardのアプリケーションを載せていきます。

コンテナイメージのビルド、Secret/ConfigMapの作成、MySQL StatefulSet、TaskBoard API Deployment、Nginx Deployment、DB初期化Job、バックアップCronJob、ログ収集DaemonSet、HPA、PDB——第3回で設計した全マニフェストを、依存関係を考慮した順序でデプロイしていきます。

設計書がある。基盤も整った。次はその上にアプリケーションを載せて、TaskBoardを「設計書通りに」動かす番です。

AIコラム — 構築手順のダブルチェック

構築フェーズでは、設計書に書かれたマニフェストを順にapplyしていきます。しかし、マニフェストの数が増えると「この順番で本当に大丈夫か」「抜け漏れはないか」が心配になります。

こんなとき、AIに構築手順のダブルチェックを依頼すると効率的です。

💡 AIの活用ヒント

マニフェストをapplyする前に、AIに以下のようなプロンプトを送ってみましょう。

「以下のマニフェスト一覧をこの順序でapplyする予定です。依存関係に問題がないか確認してください。
1. namespace-app.yaml
2. namespace-db.yaml
3. namespace-monitoring.yaml
4. resourcequota-app.yaml
5. limitrange-app.yaml
6. sa-developer-app.yaml
7. role-developer-app.yaml
8. rolebinding-developer-app.yaml
……」

AIは依存関係の問題(例:「RoleBindingより先にRoleが必要です」)や、抜け漏れ(例:「db Namespace用のLimitRangeが一覧にありません」)を指摘してくれます。

ただし、AIのチェックを過信せず、最終判断は設計書と自分の知識で行いましょう。応用編で手を動かして得た「この順序でないと動かない」という体験こそが、AIの指摘を検証するための最強のツールです。