【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列が、マニフェストのdefaultRequestとdefaultの値と一致していることを確認します。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が Ready | kubectl get nodes | 4ノードすべて STATUS: Ready |
| 2 | Calico CNI 稼働中 | kubectl get pods -n calico-system | 全Podが Running |
| 3 | Metrics Server 稼働中 | kubectl top nodes | 各ノードのCPU/メモリ値が表示される |
| 4 | Gateway APIコントローラー稼働中 | kubectl get pods -n envoy-gateway-system | Envoy Gateway Podが Running |
| 5 | GatewayClass 利用可能 | kubectl get gatewayclass | ACCEPTED: True |
| 6 | Namespace app 存在 | kubectl get ns app | STATUS: Active |
| 7 | Namespace db 存在 | kubectl get ns db | STATUS: Active |
| 8 | Namespace monitoring 存在 | kubectl get ns monitoring | STATUS: Active |
| 9 | ResourceQuota app 適用済み | kubectl get resourcequota -n app | app-quota が表示される |
| 10 | ResourceQuota db 適用済み | kubectl get resourcequota -n db | db-quota が表示される |
| 11 | ResourceQuota monitoring 適用済み | kubectl get resourcequota -n monitoring | monitoring-quota が表示される |
| 12 | LimitRange app 適用済み | kubectl get limitrange -n app | app-limitrange が表示される |
| 13 | LimitRange db 適用済み | kubectl get limitrange -n db | db-limitrange が表示される |
| 14 | LimitRange monitoring 適用済み | kubectl get limitrange -n monitoring | monitoring-limitrange が表示される |
| 15 | ServiceAccount developer (app) 存在 | kubectl get sa developer -n app | リソースが表示される |
| 16 | ServiceAccount operator (app) 存在 | kubectl get sa operator -n app | リソースが表示される |
| 17 | ServiceAccount developer (db) 存在 | kubectl get sa developer -n db | リソースが表示される |
| 18 | ServiceAccount operator (db) 存在 | kubectl get sa operator -n db | リソースが表示される |
| 19 | RBAC developer (app): Pod参照 可 | kubectl auth can-i list pods -n app --as=system:serviceaccount:app:developer | yes |
| 20 | RBAC developer (app): Pod削除 不可 | kubectl auth can-i delete pods -n app --as=system:serviceaccount:app:developer | no |
| 21 | RBAC operator (app): Deployment更新 可 | kubectl auth can-i update deployments -n app --as=system:serviceaccount:app:operator | yes |
| 22 | RBAC operator (db): StatefulSet更新 可 | kubectl auth can-i update statefulsets -n db --as=system:serviceaccount:db:operator | yes |
このチェックリストをスクリプト化して一括実行することもできます。
[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の指摘を検証するための最強のツールです。
