---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx-block-pvc
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 1Gi
storageClassName: rook-ceph-block
1. PVとPVC
Persistent Volume(PV)はHDD/SSDのように永続化された記憶領域を提供するK8sの機能です。
コンテナべースの仮想化環境ではプロセスが終了すると、それまで内部に保存されていた内容が破棄され、初期化されます。
これはウィルスなどにより外部から汚染された場合でも、再起動によりリセットすれば汚染前の状態の戻るため、健全性を確保できる点で優れています。 しかし、データベースサーバーのように、データを保存することを目的とした用途では、この特徴は困ることになります。
このような仮想化環境では、永続化された(電源を入れ直しても消えない)記憶領域が何かしらの形で準備されていて、KubernetesではPVと呼ばれます。
Kubernetesでは、PVはシステムが準備します。 ユーザーは準備されたPVを利用し、PVC (PV Claim)を定義することで、システム(k8s)に永続化領域を要求し、その割り当てられた領域に必要なデータを保存します。
このSCCPで利用するk8sクラスターでは、大きく2つの方法(Rook/CephとNFS)でPVを準備しています。 現時点ではNFSは古いので、Rook/CephのBlockStorageとFileStorageを利用する例を紹介します。
1.1. BlockStorageを利用したPVC定義 (専有タイプ)
storageClassName: rook-ceph-block を利用することで、任意の容量のPVCを定義することができます。
サンプルの定義ファイルは次のようなものです。
-
name: には、任意の分かりやすい名前を指定します。
-
storage: には、任意の必要なサイズを指定します。
-
Rookを利用する場合、accessModes:には"ReadWriteOnce"だけが指定できます。
-
Rookを利用する場合、一つのPodからのみアクセスできるためDatabase Serverなどに向いています。
1.2. FileStorageを利用したPVC定義 (共有タイプ)
BlockStorageは1つのPodだけがアクセスできるプライベート領域ですが、FileStorageは複数のPodから同時にアクセスできる共有領域です。 以前はnamespace毎にFileStorageを作成することができませんでしたが、Rook/Cephのバージョンが上がり安定して利用できるようになりました。
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx-file-pvc
spec:
accessModes: [ "ReadWriteMany" ]
storageClassName: rook-cephfs
resources:
requests:
storage: 1Gi
-
name: には、BlockStorageと同様に任意の分かりやすい名前を指定します。
-
storage: には、BlockStorageと同様に任意の必要なサイズを指定します。
-
accessModes:には、"ReadWriteOnce"も指定できますが、通常は "ReadWriteMany" を指定するために、FileStorageを利用しますので、このままです。
-
複数のPod(プロセス、サーバー)からアクセスできるので、単一コンテンツを共有したいWebサーバーでの利用に向いています。
2. BlockStorageを利用するWebサーバー
BlockStorageを利用する、Webサーバー(nginx-ceph-block)を準備します。
まず、下記の2つのYAMLファイルをダウンロードしたり、コピー&ペーストするなどして、準備してください。
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-block-storage
spec:
replicas: 1
selector:
matchLabels:
app: nginx-block-storage
template:
metadata:
labels:
app: nginx-block-storage
spec:
containers:
- name: nginx-block-storage
image: nginx:latest
imagePullPolicy: "Always"
ports:
- containerPort: 80
volumeMounts:
- name: nginx-data-storage
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-data-storage
persistentVolumeClaim:
claimName: nginx-block-pvc
このPodにアクセスするには、別途Service定義が必要です。
---
apiVersion: v1
kind: Service
metadata:
name: nginx-block-storage
spec:
type: LoadBalancer
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx-block-storage
最初のBlockStorageの定義ファイルと、この2つのファイルをダウンロードして実行するための手順は次のとおりです。
## あらかじめファイルをダウンロードしている場合は、この3行はスキップ
$ wget https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/volumes.nginx-block-pvc.yaml.txt
$ wget https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/volumes.deploy-nginx-blockstorage.yaml.txt
$ wget https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/volumes.svc-nginx-blockstorage.yaml.txt
## ダウンロードファイルしたファイルをkubectlコマンドで実行する
$ kubectl -n $(id -un) apply -f volumes.nginx-block-pvc.yaml.txt
$ kubectl -n $(id -un) apply -f volumes.deploy-nginx-blockstorage.yaml.txt
$ kubectl -n $(id -un) apply -f volumes.svc-nginx-blockstorage.yaml.txt
ここまで実行したら、Webブラウザで構成したWebサーバーに接続します。
## Webブラウザを開き、作成したWebサーバーに接続する
$ browse http://$(kubectl -n $(id -un) get svc nginx-block-storage -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
まだコンテンツ(index.html)ファイルが配置されていないので、下記のコマンドでファイルを配置します。
$ kubectl -n $(id -un) exec -it "$(kubectl -n $(id -un) get pod -l app=nginx-block-storage -o jsonpath={.items[0].metadata.name})" -- bash -c "echo Hello World, $(id -un) at $(date) > /usr/share/nginx/html/index.html"
またWebブラウザに戻って、ページが表示されることを確認してください。
3. FileStorageを利用するWebサーバー
次に、FileStorageを利用するWebサーバーを準備します。
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-file-storage
spec:
replicas: 2
selector:
matchLabels:
app: nginx-file-storage
template:
metadata:
labels:
app: nginx-file-storage
spec:
containers:
- name: nginx-file-storage
image: nginx:latest
imagePullPolicy: "Always"
ports:
- containerPort: 80
volumeMounts:
- name: nginx-data-storage
mountPath: /usr/share/nginx/html
volumes:
- name: nginx-data-storage
persistentVolumeClaim:
claimName: nginx-file-pvc
次にPodにアクセスするためのServiceを定義します。
---
apiVersion: v1
kind: Service
metadata:
name: nginx-file-storage
spec:
type: LoadBalancer
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx-file-storage
BlockStorageの例と同様に、YAMLファイルをダウンロードして実行するための手順は次のとおりです。
## あらかじめファイルをダウンロードしている場合は、この3行はスキップ
$ wget https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/volumes.nginx-file-pvc.yaml.txt
$ wget https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/volumes.deploy-nginx-filestorage.yaml.txt
$ wget https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/volumes.svc-nginx-filestorage.yaml.txt
## ダウンロードファイルしたファイルをkubectlコマンドで実行する
$ kubectl -n $(id -un) apply -f volumes.nginx-file-pvc.yaml.txt
$ kubectl -n $(id -un) apply -f volumes.deploy-nginx-filestorage.yaml.txt
$ kubectl -n $(id -un) apply -f volumes.svc-nginx-filestorage.yaml.txt
ここまで実行したら、Webブラウザで構成したWebサーバーに接続します。
$ browse http://$(kubectl -n $(id -un) get svc nginx-file-storage -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
まだコンテンツ(index.html)ファイルが配置されていないので、下記のコマンドでファイルを配置します。
$ kubectl -n $(id -un) exec -it "$(kubectl -n $(id -un) get pod -l app=nginx-file-storage -o jsonpath={.items[0].metadata.name})" -- bash -c "echo Hello World, $(id -un) at $(date) > /usr/share/nginx/html/index.html"
またWebブラウザに戻って、ページが表示されることを確認してください。
4. それぞれのWebサーバーの特徴
ここでは2種類のWebサーバー(nginx)を構成しました。
それぞれの設定ファイルは、"block"と"file" 違いはありますが、ほぼ同じです。 ここではその微妙な違いについて説明します。
4.1. 【復習】Webページの開き方
## Block Storage を利用するWebサーバーへの接続
$ browse http://$(kubectl -n $(id -un) get svc nginx-block-storage -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
## File Storage を利用するWebサーバーへの接続
$ browse http://$(kubectl -n $(id -un) get svc nginx-file-storage -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
4.2. replicas: 設定の違い
よくみると、2つのDeployment YAMLファイル(deploy-nginx-blockstorage.yaml.txt, deploy-nginx-filestorage.yaml.txt) の中に、replicas: と書かれている行があります。(.spec.replicas)
これは同時に動作する nginx の Pod(プロセス) の数を指定するものです。複数動作した方が、より多くのアクセスに耐えられるので好ましいですが、BlockStorageの 1 を複数にしてもうまく動きません。
この動きを確認するため、replicasの数を 1 から 2 に変更してみます。
次のコマンドを実行すると、emacsが立ち上がりますので、replicas:の数字を変更します。
$ env EDITOR=emacs kubectl -n $(id -un) edit deploy nginx-block-storage
## 編集が終ったらemacsを終了する
この変更をしても特に動作に変化はありません。
現在の状況を get コマンドから確認してみます。
$ kubectl -n $(id -un) get pod
すると、次のように表示されます。
NAME READY STATUS RESTARTS AGE
nginx-block-storage-5f47458575-g7wvm 1/1 Running 0 84s
nginx-block-storage-5f47458575-nkbg4 0/1 ContainerCreating 0 7s
nginx-file-storage-7976586c4b-4p4xj 1/1 Running 0 26m
nginx-file-storage-7976586c4b-lbnw9 1/1 Running 0 26m
上から3行目のSTATUSが ContainerCreating となっているPodは永遠に動作しません。
こん現任は describe コマンドで分かります。
$ kubectl -n $(id -un) describe pod -l app=nginx-block-storage
すると、次のようなメッセージが表示され、最後が次のようになるはずです。
Warning FailedMount 15s kubelet Unable to attach or mount volumes:
unmounted volumes=[nginx-data-storage], unattached volumes=[kube-api-access-kq479 nginx-data-storage]:
timed out waiting for the condition
これは、nginx-data-storageで要求した記憶領域(ファイルシステム、PVC)をマウントしようとして失敗している様子を表しています。
BlockStorageの特徴は、1つのPodからしか利用できない専有タイプであるためです。
FileStorageの特徴は、複数のPodと共有できることです。 1回index.htmlを変更した後に、何回Webブラウザからアクセスしても同じ内容が確認できるのは、複数のWebサーバーから同じファイルを参照していることを示しています。
課題: 余裕があれば、deploy/nginx-file-storage の replica: 数を2より増やしてみてください。
5. 現在定義されているPVCを確認する
kubectl の get コマンドを応用すれば、現在自分が利用しているPVCの状態を確認することもできます。
$ kubectl -n $(id -un) get pvc
表示される内容は各自の状態によって変化します。下記は1つの出力例です。
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
nginx-block-pvc Bound pvc-b37bf308-310b-4679-90c6-174bcc0dcf6e 1Gi RWO rook-ceph-block 77m
nginx-file-pvc Bound pvc-c2ad02e3-ca2d-4c88-98b5-3999371f804d 1Gi RWX rook-cephfs 44m
6. 応用問題
6.1. Q1. 【任意の名前のBlock Storageを作成】
Block Storage の YAMLファイル(volumes.nginx-block-pvc.yaml.txt、ダウンロード ) をダウンロードし、エディタなどで name: を変更して、異なる名称のPVCを作成してください。
$ kubectl -n $(id -un) get pvc
で前後の変化を確認すること。
A1.解答例
## 現在の状態を確認
$ kubectl -n $(id -un) get pvc
## 存在しないファイル名 (ここでは、new-block-pvc.yaml) でファイルを作成
$ curl https://web-int.u-aizu.ac.jp/%7eyasu-abe/ja/sccp/manual/volumes.nginx-block-pvc.yaml.txt > new-block-pvc.yaml
## name を新しい名前にエディタなどで変更する。ここではsedコマンドを利用する
$ sed -i -e 's/name: .*$/name: new-block-pvc/g' new-block-pvc.yaml
## new-block-pvc.yaml の内容を反映させる
$ kubectl -n $(id -un) apply -f new-block-pvc.yaml
## 変更後の状態を確認
$ kubectl -n $(id -un) get pvc
6.2. Q2. 【Block Storageの削除】
Q1.で作成したBlock Storageを削除してください。
$ kubectl -n $(id -un) get pvc
で前後の変化を確認すること。
A2.解答例
## 方法1. 準備したYAMLファイルを利用して削除する
$ kubectl -n $(id -un) delete -f new-block-pvc.yaml
## 方法2. command::get TYPE::pvc を利用して、対象のNAMEを指定して削除する
$ kubectl -n $(id -un) get pvc
$ kubectl -n $(id -un) delete pvc new-block-pvc
6.3. Q3. 【BlockStorageの拡張】
ストレージの容量は、storage:により大きな値を指定することで拡張できます。 Block Storageで作成した、nginx-block-pvc のサイズを 2Gi に変更してください。
A3.解答例
## 方法1. nginx-block-pvc を作成する時に利用したYAMLファイルを編集します
$ curl https://web-int.u-aizu.ac.jp/~yasu-abe/ja/sccp/manual/volumes.nginx-block-pvc.yaml.txt > nginx-block-pvc.yaml
$ sed -i -e 's/storage: .*$/storage: 2Gi/' nginx-block-pvc.yaml
$ kubectl -n $(id -un) apply -f nginx-block-pvc.yaml`
## 方法2. command::editを利用して、storage: のサイズを変更します。
$ env EDITOR=emacs kubectl -n $(id -un) edit pvc nginx-block-pvc
作成済みのPVCのサイズ(storage:)だけを変更しても即座には反映されません。 実際に利用した時に、始めて変更したサイズで利用できるようになります。 このためQ1, Q2で作成したPVCではなく、既にPodと接続しているPVCを利用しています。
6.4. Q4.【MySQLサーバーへの応用】
公式MySQLサーバーイメージ(DockerHub公式MySQLコンテナイメージ) を利用することを前提としています。
次の要領で、データベースサーバーを動作させてください。
-
BlockStorageを作成する (volumes.nginx-block-pvc.yaml.txtを書き換える)
-
MySQLサーバーを作成するためのDeployment定義する (volumes.deploy-nginx-blockstorage.yaml.txtを書き換える)
-
MySQLサーバーに接続するためのServiceを定義する (volumes.svc-nginx-blockstorage.yaml.txt)
-
mysqlコマンドから接続できることを確認する
方法は一通りではありません。ヒントや解答例は、変更点の少ない最も一般的と思われる構成を前提としています。
ヒント
volumes.nginx-block-pvc.yaml.txt を書き換える行は、以下の項目です。
・name: 行
volumes.deploy-nginx-blockstorage.yaml.txt を書き換える行は以下の項目です。
・ app: 行 (複数)
・ image: 行
・ containerPort: 行
・ mountPath: 行
それぞれに指定する値は、公式MySQLイメージ (mysql:8.0) では、次のような構成になっています。 参考情報 - Dockerfile mysql:8
・接続用ポート番号(containerPort): 3306
・データ保存先(mountPath): /var/lib/mysql
また、新たに、env: 設定 (name: MYSQL_ROOT_PASSWORD, value: "secret") を加える必要があります。(secretの部分は任意で書き換えてください)
設定方法については、k8s公式ガイド - MySQLをデプロイする を参考にしてください。
volumes.svc-nginx-blockstorage.yaml.txt を書き換える行は以下のとおりです。
・name: 行
・port:/targetPort: 行 (Deploymentに記述したポート番号と同じ)
・app: 行 (Deploymentに記述したmatchLabels:の指定と同じ)
Serviceの変更箇所は、name:を除くと、Deploymentに記述した内容と整合性が取れていないと、ネットワーク接続ができないので注意してください。
稼動確認の方法は、各ThinkPadの端末上に、mysqlコマンドがインストールされていますので、次のコマンドが実行できることを確認してください。
## Service名(name:)が "mysql-svc" だという前提でコマンドラインを組み立てています。
$ mysql -u root -p -h $(kubectl -n $(id -un) get svc mysql-svc -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
## パスワードは、Deploymentで MYSQL_ROOT_USER環境変数 に設定した値 (secret 等)
Enter password:
## 次のSQLでUser情報が表示されれば成功です
mysql> select host,user from mysql.user;
+-----------+------------------+
| host | user |
+-----------+------------------+
| % | root |
| localhost | mysql.infoschema |
| localhost | mysql.session |
| localhost | mysql.sys |
| localhost | root |
+-----------+------------------+
5 rows in set (0.00 sec)