はじめに
前の記事の続き。構築したk8s クラスタに NGINX をデプロイし、適当なコンテンツにアクセスすることで動作を確かめる。
コンテンツの配備手法に分け、構築パターンは大きく3種類となる。NFSの利用方法はPV/PVCを利用するパターンとCSIを使うパターンで2つあり、今回は両者とも試す。
- Worker ノードのローカルディスクに静的なHTMLファイルを配置する
- NFSサーバを構築してコンテンツをNFS上に配備する
2-1. k8sからはPV/PVCを経由でアクセスするパターン
2-2. k8sからCSIを利用するパターン - CephFSサーバを構築してコンテンツはCephFS上に配備し、CephFSをWorker ノードにマウントして使用する。
今回はCSI利用までとし、CephFSは別にする。
1. Hello k8s! - ローカルディスクに配備
作成順序は以下。
- 各 Workerノードに
/mnt/data/index.html
を作成 -
hostPath
ボリュームでこのファイルをPodにマウント -
NodePort
を使って外部公開し、curl やブラウザから確認
hostPath
?
k8s-workerノード上のディレクトリやファイルを、Pod のコンテナにマウントする仕組み。
言い換えると、コンテナ内で見えるファイルパスを、実際にはホスト側のファイルシステムに接続するというもの。
1-1. 各 Worker ノードでファイル作成
Worker1/2両者で以下を作成する。
mkdir -p /mnt/data
echo "<h1>Hello from $(hostname)</h1>" | sudo tee /mnt/data/index.html
1-2. NGINX Deployment
k8s を実際に利用する上ではあまり使わない設定ではあるが、
hostPath
指定+nodeSelector
でk8s-Worker1を明示的に指定する。
apiVersion: apps/v1
kind: Deployment
metadata:
# Deploymentの名前。NameSpace内ではユニークである必要がある
name: nginx-hostpath
spec:
# レプリカ数の指定
replicas: 1
selector:
matchLabels:
# 管理対象のPodの名前 template.metadata.labels.appとは原則一致させること
app: nginx-hostpath
template:
metadata:
labels:
# 実際にデプロイするPodの名前 spec.selector.matchLabelsとは原則一致させること
app: nginx-hostpath
spec:
nodeSelector:
kubernetes.io/hostname: <worker1のノード名> # `kubectl get nodes -o wide`で確認
containers:
- name: nginx
image: nginx:stable
ports:
- containerPort: 80
volumeMounts:
# Pod内コンテナから見えるパス。実態はvolumes.hostpath.pathで指定した/mnt/dataになる
- mountPath: /usr/share/nginx/html
name: html-volume
volumes:
- name: html-volume
hostPath:
# Worker ノード上の絶対パス
path: /mnt/data
type: Directory
spec.selector.matchLabels
とspec.template.metadata.labels
この二つは原則一致させる。ただし、Job(1回限りの処理)や CronJob(定期処理)、StatefulSet(State を持つ Pod)との共存する際に使わないことがないわけではない模様。
Podとコンテナ
厳密にはPod ⊃ コンテナとなり、イコールではない。今回の例では 1 Pod = 1コンテナになっているが、1 Podに複数のコンテナを持たせるケースもある。
containerPort: 80
Pod内でどのポートが開いているかを宣言するためのもの。あくまでも情報提供用のフィードのため、これがなくともコンテナは動作するし、このPort番号でもって外部からアクセスできるわけではない。ただし、Service
やkubectl describe pod
などの表示上、Podがどのポートで通信しているかを把握するうえで重要なヒントになるため、宣言しておくことが推奨される。
image: nginx:stable
Docker Hubの公式NGINXイメージ をとってくる。実際には docker.io/library/nginx:stable
からDownloadすることになる。
1-3.NodePort Service
Podを外部公開するため、Serviceを作成する。
apiVersion: v1
kind: Service
metadata:
name: nginx-hostpath-service
spec:
type: NodePort
selector:
app: nginx-hostpath
ports:
- port: 80
targetPort: 80
nodePort: 30080
1-4. Port ???
Port
, targetPort
, NodePort
, また、NGINX Deploymentで使ったcontainerPort
といろいろと出てきて混乱する。まず、対応関係全体図は以下のようになっている。
[外部PC]
↓ http://<NodeIP>:30080 ← nodePort(Serviceが開ける外部ポート)
[Node (kube-proxy)]
↓ ルーティング
Service (type: NodePort)
↓ port: 80(Service内部ポート)
↓ targetPort: 80(PodのPortに転送)
[Pod]
↓
containerPort: 80(実際にコンテナ内でアプリがListenしているPort)
一覧にまとめるとこんな感じ。
フィールド名 | 設定ポイント | 意味 | 例 |
---|---|---|---|
containerPort |
Deployment のコンテナ定義内 | Pod内コンテナがListenしているポート | 80 |
targetPort |
Service | Service がトラフィックを Podのどのポートに転送するか | 80(name 指定も可能) |
port |
Service | Service 自体のポート番号(クラスタ内部で使用) | 80 |
nodePort |
Service (type: NodePort時) | 外部IP + このポートでアクセスできる | 30080(範囲:30000〜32767) |
1-5. 適用
kubectl apply -f nginx-hostpath-deployment.yaml
kubectl apply -f nginx-hostpath-service.yaml
1-6. 正常性確認
1-6-1. Podが正しく起動したか?
ubuntu@k8s-master:~$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-hostpath-7b4445db8d-bsz7l 1/1 Running 1 (145m ago) 6h32m
StatusがRunning になっていればOK.
1-6-2. Serviceが正しく設定されているか?
ubuntu@k8s-master:~$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 172.16.0.1 <none> 443/TCP 3d3h
nginx-hostpath-service NodePort 172.16.246.180 <none> 80:30080/TCP 3d
contaierPort:80とNodePort 30080が紐づいていればOK.
1-6-3. アクセス確認
ubuntu@k8s-master:~$ curl http://192.168.11.122:30080
<h1>Hello from k8s-worker1</h1>
ここで192.168.11.122
はk8s-worker1の外部IP。ブラウザでもよいが、最小限の確認としてcurl
でとれていることを確認する
1-6-4. Podに入ってみる
実際に動き出した Pod に入り状態を確認してみる。
構文はこんな感じ。
kubectl exec -it コンテナ名 -- コンテナ内で実行するコマンド
ubuntu@k8s-master:~$ kubectl exec -it nginx-hostpath-6f6f977f68-tx8zx -- /bin/sh
# ls
# ls
bin dev docker-entrypoint.sh home lib64 mnt proc run srv tmp var
boot docker-entrypoint.d etc lib media opt root sbin sys usr
# exit
ここで-it
は対話モード(インタラクティブ)、 --
は UNIX系のオプションでk8s以外にも使われる特殊な記号。具体的にはPod名などのオプションと、Pod内で実行したいコマンドを区切るために使用する。exec -it
を利用する際は少なくとも一つのPod 内で実行するコマンドを書く必要がある。/bin/sh
であって/bin/bash
ではないのは、コンテナに含まれるパッケージは最低限に絞られており、/bin/bash
も含まれていないため(ps
やvi
も入っていない)。sh
から抜けるには単にexit
でよい。
1-6-5. ダメな例
コンテナ内で何を実行するのかを指定していないと怒られる。
ubuntu@k8s-master:~$ kubectl exec -it nginx-hostpath-7b4445db8d-bsz7l
error: you must specify at least one command for the container
1-6-6. 対話モードでのpod操作の限界
状態確認はできる。設定変更はできない。コンテナにviが含まれていないとかもあるが、それ以前に設定変更したところで Podが再構築されると設定は初期化される。 Podの設定を変更したいのならyamlファイルで行うしかない。
1-7. hostPath の限界
hostPathは検証目的でPodを構築するだけであれば十分だが、
特定のノードに依存するためスケールしない(e.g. worker1/2それぞれのローカルディスクを見ることになる)、セキュリティ的にホストのファイルシステムへアクセスさせるのはリスクがあり、実環境に適用するには心もとない。
マルチノード環境での永続的なストレージを確保するためには、NFSやクラウドプロバイダーのストレージサービスを利用したPersistentVolume(PV)とPersistentVolumeClaim(PVC)の使用が推奨される。これにによって、Podがどのノードで起動しても一貫したストレージアクセスが可能になる。
hostPath 実環境での利用は、物理ハードウェアやUSB機器など、ホストにしか存在しない特殊デバイスとの連携 などにとどめることが推奨される。
2. PV/PVCを使ってみる。
NGINXが参照するファイルをWorker Pod上に直接配備する例では当然ながらスケールしない。Podを増やしていったとしても、すべてのPodが共通のコンテンツにアクセスできる(RWX = Read Write Many)よう、共通のディスク領域を用意する必要がある。
k8s ではこれを実現するためにPV(Persistent Volume)という仕組みが用意されている。
2-1. NFS を構築する
ストレージをどのように作るかの議論は非常に奥深いものがあるが、ここでは最も簡単なNFS
を用いる手法を試す。
2-1-1. NFSの用意(サーバサイド)
今回のラボ構成ではk8s-master ノード上でNFSを動作させる。
# NFSインストールし、/srv/nfs/htdocを共有ディレクトリにする。
sudo apt update
sudo apt install -y nfs-kernel-server
sudo mkdir -p /srv/nfs/htdocs
sudo chmod -R 777 /srv/nfs/htdocs
# exports設定(例)
echo "/srv/nfs/htdocs *(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports
sudo exportfs -rav # /exc/exports の内容を再度読み込み
sudo systemctl restart nfs-server
2-1-1-1. Export 設定のオプション
オプション | 2 |
---|---|
rw | 読み書きを許可(Read/Write) |
sync | 書き込み操作はすぐにディスクへ同期(安全だが遅くなる) |
no_subtree_check | サブディレクトリのチェックを行わない(高速化) |
no_root_squash | クライアント側の root ユーザを、そのままサーバ上でも root として扱う |
no_root_squash
通常は安全性を考えてroot_squash
(= root を nobody に変換)が推奨される。今回の NFS 検証ではアクセス権周りの問題回避のため no_root_squash
を使用するとした。
2-1-2. NFSの用意(Workerノード側)
用意としてはNFS-commonをインストールするだけ。実際にどのNFS領域をマウントするかはk8s側から行うため、ノード側での永続マウントは不要。
sudo apt update
sudo apt install -y nfs-common
2-2. k8s マニフェスト作成
2-2-1. そも、PV/PVC とは?
- PV とは、k8s管理者やCSIドライバによってあらかじめ提供される ストレージリソース
- PVC とは、ユーザ/Podからのストレージ要求
PV(実際に利用できるストレージ量)/PVC(クライアントが利用したい容量)を、k8sがバインドさせる。ユーザサイドでPVCを出すと、デフォルトではk8sが最適なPVを選んでくれる。しかし、PVが複数ある本番環境においては、事故防止のため明示的に紐づけを行うことが推奨される。この例では自動でマッチングする手法を採用。
2-2-2. PersistentVolume/PersistentVolumeClaim を作成
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
nfs:
path: /srv/nfs/htdocs
server: <MASTER_NODE_IP>
persistentVolumeReclaimPolicy: Retain
フィールド | 意味 |
---|---|
capacity.storage |
確保したストレージサイズをk8sに宣言 |
accessModes |
ReadWriteMany は同一クラスタの複数Podからなら同時に読み書き可能 |
nfs.path / server
|
実際のNFSマウント先(K8sノードから見たパス) |
persistentVolumeReclaimPolicy: Retain |
PVCが削除されても実体は保持(上書きや消去防止) |
capacity.storage
この例では1Gi 確保したとしているが、実際にNFS側がこの容量に制限されるわけではない。あくまでも宣言。この辺りを厳密にやろうとすると、NFSでは無理が出てくる。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
フィールド | 意味 |
---|---|
accessModes |
ReadWriteMany を要求。PVと一致する必要あり |
resources.requests.storage |
このPVCが最低限必要とする容量(例:1Gi) |
2-2-3. サンプルスクリプト
touch /srv/nfs/htdocs/index.html
でindex.htmlを空でよいので作成。
#!/bin/sh
HOSTNAME=$(hostname)
echo "<html><body><h1>Hello from $HOSTNAME</h1></body></html>" > /usr/share/nginx/html/index.html
nginx -g 'daemon off;'
chmod +x /srv/nfs/htdocs/start.sh
2-3. NGINXのデプロイ
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-nfs
spec:
replicas: 2
selector:
matchLabels:
app: nginx-nfs
template:
metadata:
labels:
app: nginx-nfs
spec:
securityContext:
appArmorProfile:
type: Unconfined
containers:
- name: nginx
image: nginx:stable
command: ["/bin/sh", "-c", "/mnt/start.sh"]
volumeMounts:
- mountPath: /mnt
name: nfs-volume
volumes:
- name: nfs-volume
persistentVolumeClaim:
claimName: nfs-pvc
特徴的なのが(当然だが)volumes.persistentVolumeClaim
でnfs-pvc
を指定しているところ。
Excuse
spec.securityContext.appArmorProfile.type
は正直なところおまじない。今回の検証ではAppArmorについてはデフォルトからは変更していないため、本来は不要のはず。ただ、ラボ環境のAppArmor周りがどこかおかしくなってしまった様子で、W/Aとして入れている。
apiVersion: v1
kind: Service
metadata:
name: nginx-nfs-service
spec:
type: NodePort
selector:
app: nginx-nfs
ports:
- port: 80
targetPort: 80
nodePort: 30080
2-3-1. デプロイしてみる
kubectl apply -f nfs-pv.yaml
kubectl apply -f nfs-pvc.yaml
kubectl apply -f nginx-nfs-deployment.yaml
kubectl apply -f nginx-nfs-service.yaml
2-3-2. 正常性確認
ubuntu@k8s-master:~$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-hostpath-7b4445db8d-bsz7l 1/1 Running 0 3h28m
nginx-nfs-77bbfbb487-mqwvq 1/1 Running 0 2m32s
nginx-nfs-77bbfbb487-wgmnk 1/1 Running 0 2m24s
nginx-nfs-***
が running であること
ubuntu@k8s-master:~$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
nfs-pvc Bound nfs-pv 1Gi RWX <unset> 99m
PVC が Bound になっていること。
ubuntu@k8s-master:~$ curl http://192.168.11.122:30180
<html><body><h1>Hello from nginx-nfs-c8544878d-jnpwb</h1></body></html>
ubuntu@k8s-master:~$ curl http://192.168.11.122:30180
<html><body><h1>Hello from nginx-nfs-c8544878d-vm976</h1></body></html>
ubuntu@k8s-master:~$ curl http://192.168.11.122:30180
<html><body><h1>Hello from nginx-nfs-c8544878d-vm976</h1></body></html>
ubuntu@k8s-master:~$ curl http://192.168.11.122:30180
<html><body><h1>Hello from nginx-nfs-c8544878d-jnpwb</h1></body></html>
実際にアクセスして別々の Pod から応答が得られること。
2-4. PV/PVC の限界
PV/PVCの仕組みによって宣言的なリソース管理が可能になる。しかし、PVは実態としてのストレージデバイスごとの違い、またオンプレ、クラウドの違いもすべて手動で吸収する必要がある。CSIを導入することでこの辺りを抽象化、Storage Classとして共通な Interfaceを使用できるようになる。
3. CSI を使ってみる
3-1. CSIとStorageClass?
**CSI(Container Storage Interface)**は、Kubernetesが外部のストレージシステムと連携するための標準インターフェースのこと。k8s v1.13 から利用できるようになった。
CSIを利用することで、統一的な仕組みで Storage へアクセスできるようになった。ストレージベンダーから見ると、k8s のコアコードを変更することなく、自社のストレージをk8sに統合できるようになった。
CSIを利用することで、PVCの作成時に必要な Storageが自動的にプロビジョニングされるようになり、手動でのPV作成が不要になった。このほか、スナップショットなどの高度なStorage機能の利用、Security やAccess制御の高度化が可能になる。
StorageClassは、k8sで異なるストレージの Class を定義するリソースのこと。各StorageClassは、特定のCSIドライバー(provisioner)を指定し、そのドライバーに渡すパラメータを含められる。
この関係により、ユーザーはStorageClassを通じて、必要なストレージの種類や特性を抽象的に指定し、実際のストレージのプロビジョニングや管理はCSIドライバーが担う構造となっている。
この規模ではあまりメリットはないが、NFSをPVの代わりにCSI を利用して領域を割り当てることにする。
3-2. CSIドライバの導入
原本はこちら。Helm からのインストールが推奨のようだが、今回はkubectl ベースでのインストール(Helmは検証前...)
ubuntu@k8s-master:~$ curl -skSL https://raw.githubusercontent.com/kubernetes-csi/csi-driver-nfs/v4.11.0/deploy/install-driver.sh | bash -s v4.11.0 --
Installing NFS CSI driver, version: v4.11.0 ...
serviceaccount/csi-nfs-controller-sa created
serviceaccount/csi-nfs-node-sa created
clusterrole.rbac.authorization.k8s.io/nfs-external-provisioner-role created
clusterrolebinding.rbac.authorization.k8s.io/nfs-csi-provisioner-binding created
clusterrole.rbac.authorization.k8s.io/nfs-external-resizer-role created
clusterrolebinding.rbac.authorization.k8s.io/nfs-csi-resizer-role created
csidriver.storage.k8s.io/nfs.csi.k8s.io created
deployment.apps/csi-nfs-controller created
daemonset.apps/csi-nfs-node created
NFS CSI driver installed successfully.
3-2-1. 正常性確認
CSIドライバをインストールするとcsi-nfs-controller
(NFS CSI ドライバのコントローラー側)とcsi-nfs-node
(各ノードに1つずつ常駐するドライバ)がkube-system
にインストールされる。確認方法は以下。
ubuntu@k8s-master:~$ kubectl -n kube-system get pod
NAME READY STATUS RESTARTS AGE
(snip)
csi-nfs-controller-5bf646f7cc-f7nkp 5/5 Running 0 24m
csi-nfs-node-8gwp2 3/3 Running 0 24m
csi-nfs-node-c8f2k 3/3 Running 3 (17m ago) 24m
csi-nfs-node-mvrc9 3/3 Running 0 24m
(snip)
ubuntu@k8s-master:~$ kubectl -n kube-system get pod -o wide -l app=csi-nfs-controller
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
csi-nfs-controller-5bf646f7cc-f7nkp 5/5 Running 0 19m 192.168.11.123 k8s-worker2 <none> <none>
ubuntu@k8s-master:~$
ubuntu@k8s-master:~$ kubectl -n kube-system get pod -o wide -l app=csi-nfs-node
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
csi-nfs-node-8gwp2 3/3 Running 0 20m 192.168.11.123 k8s-worker2 <none> <none>
csi-nfs-node-c8f2k 3/3 Running 3 (19m ago) 20m 192.168.11.122 k8s-worker1 <none> <none>
csi-nfs-node-mvrc9 3/3 Running 0 20m 192.168.11.121 k8s-master <none> <none>
3-2. NFSをCSIから使ってみる。
3-2-1. StorageClass
CSI を利用する場合、PVを定義せず、代わりに StorageClassを利用する。StorageClassを利用すればPVを個別に定義することなく、新しいPodが作られるたびに自動でStorageが作られていく。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-csi
provisioner: nfs.csi.k8s.io
parameters:
server: 192.168.11.121
share: /exported/path
reclaimPolicy: Retain
volumeBindingMode: Immediate
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-dynamic-pvc
spec:
accessModes:
- ReadWriteMany
storageClassName: nfs-csi
resources:
requests:
storage: 1Gi
nfs-pvc.yaml
との差分はstorageClassName: nfs-csi
が追加されたことのみ。ストレージクラス名はnfs-sc.yaml
で定義したものとそろえる
3-2-1. 正常性確認
kubectl get pvc
で新しく定義したPVのStatusがBoundとなっていればOK
ubuntu@k8s-master:~$ kubectl get storageClass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-csi nfs.csi.k8s.io Retain Immediate false 3s
ubuntu@k8s-master:~$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
nfs-dynamic-pvc Bound pvc-342392a4-28d7-4aa2-8d3f-56406398277b 1Gi RWX nfs-csi <unset> 7s
ここでpvc-342392a4-28d7-4aa2-8d3f-56406398277b
ができているが、NFSサーバ上に同名のディレクトリが作成されていることが確認できる。
ubuntu@k8s-master:~$ ls /srv/nfs/htdocs/
index.html pvc-342392a4-28d7-4aa2-8d3f-56406398277b start.sh
3-3. コンテンツの準備
前の正常性確認で、nfs-dynamic-pvcが/srv/nfs/htdocs
の配下にpvc-342392a4-28d7-4aa2-8d3f-56406398277b
が作られたことが確認できた。このディレクトリに先ほど作ったstart.sh
をコピーする。
NFS をexport する際、no_root_squash
を指定して作成したため、PVCのアクセス権限はroot:root で作成されているのに注意。
ubuntu@k8s-master:/srv/nfs/htdocs$ pwd
/srv/nfs/htdocs
ubuntu@k8s-master:/srv/nfs/htdocs$ sudo cp ./index.html ./pvc-342392a4-28d7-4aa2-8d3f-56406398277b/
ubuntu@k8s-master:/srv/nfs/htdocs$ sudo cp ./start.sh ./pvc-342392a4-28d7-4aa2-8d3f-56406398277b/
3-4. Deployment と Service
差分が出てくるのはspec.template.spec.volumes.persistentVolumeClaim.claimNameがnfs-sc-pvc.yaml
で指定したnfs-dynamic-pvc
となっている点。ほかはpodの名称を変更したのみ。
nginx-nfs-csi-service.yaml
もnodePort の番号を少しずらした。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-nfs-csi
spec:
replicas: 2
selector:
matchLabels:
app: nginx-nfs-csi
template:
metadata:
labels:
app: nginx-nfs-csi
spec:
containers:
- name: nginx
image: nginx:stable
command: ["/bin/sh", "-c", "/mnt/start.sh"]
volumeMounts:
- mountPath: /mnt
name: nfs-volume
volumes:
- name: nfs-volume
persistentVolumeClaim:
claimName: nfs-dynamic-pvc
apiVersion: v1
kind: Service
metadata:
name: nginx-nfs-csi-service
spec:
type: NodePort
selector:
app: nginx-nfs-csi
ports:
- port: 80
targetPort: 80
nodePort: 30280
3-5. 適用と正常性確認
ubuntu@k8s-master:~$ kubectl apply -f ./nginx-nfs-csi-deployment.yaml
deployment/nginx-nfs-csi-deployment created
ubuntu@k8s-master:~$ kubectl apply -f ./nginx-nfs-csi-service.yaml
service/nginx-nfs-csi-service created
3-5-1. Service の確認
ubuntu@k8s-master:~$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 172.16.0.1 <none> 443/TCP 3d3h
(snip)
nginx-nfs-csi-service NodePort 172.16.9.152 <none> 80:30280/TCP 4s
3-5-2. Pod の確認
ubuntu@k8s-master:~$ kubectl get pod
NAME READY STATUS RESTARTS AGE
(snip
nginx-nfs-csi-6b564979c-ftw92 1/1 Running 0 12m
nginx-nfs-csi-6b564979c-n9ndv 1/1 Running 0 12m
3-5-3. NodePort での応答を確認する
正しく応答してくれる。
ubuntu@k8s-master:~$ curl http://192.168.11.122:30280
<html><body><h1>Hello from nginx-nfs-csi-6b564979c-ftw92</h1></body></html>
ubuntu@k8s-master:~$ curl http://192.168.11.122:30280
<html><body><h1>Hello from nginx-nfs-csi-6b564979c-n9ndv</h1></body></html>
ubuntu@k8s-master:~$ curl http://192.168.11.122:30280
<html><body><h1>Hello from nginx-nfs-csi-6b564979c-ftw92</h1></body></html>
3-6. NFSの限界
PVでspec.capacity.storage
で用意するディスクサイズを、PVCでspec.resources.requests.storage
で必要なディスクサイズを宣言している。では、宣言した量を超えてpodがデータを使うとなるとどうなるかというと、実は監視されておらず、k8sの範囲の中では利用できてしまう。実際に絞ろうとすると、xfs_quota
やedquota
などを使ってNFS側で頑張るしかない。この辺り、k8sの宣言型で進めるという理想と、実際のStorage 実装のはざまに落ちる。
k8s側からCSIを通じて容量管理をもくろんだ場合、CephFS などといった別のソリューションを探ることになる。