この記事はなに?
Kubernetes のコンテナ起動時に pvc の扱いでつまづくケースと、その解決方法を記載しています。
また、初期状態の pvc の性質についても簡単に説明します。
※pvc の詳細な説明については割愛します
対象とする読者
- Kubernetes のコンテナ起動時の pvc の扱いに困っている方
- 例: pvc を PostgreSQL のデータディレクトリにしたいけれど、エラーが出てしまう
- 例: pvc を apache ユーザでファイル保存に使いたいけれど、デフォルトだと書き込み権限が無く、ファイルが作れない
本記事の検証環境
- マウント先コンテナのOS:
CentOS7
- pvc のストレージクラス:
drbd
pvc とは?
正式名称は PersistentVolumeClaim (永続ボリューム)。
Kubernetes では通常、コンテナ上でデータを保存すると、
コンテナを削除、再作成した際にデータが消えてしまいます。
これを解消する仕組みが pvc。
pvc を作成し、コンテナにマウントすると、
コンテナを削除、再作成しても pvc のデータは消えません。
※例えが古いですが、外付けハードディスクのようなものです
pvc の初期状態
マウントしたての pvc には以下の性質があります。
- パーミッションとオーナー
- デフォルトで
755
のroot:root
で作成されます
- デフォルトで
- 初期配置されるディレクトリ
-
lost+found
が初期ディレクトリとして配置されます
-
- 既存ディレクトリにマウントした場合、上書きされます
例:
以下のようなディレクトリをもつコンテナがあるときpvc を /var/tmp にマウントすると# ls -1 /var/tmp/test file1 file2 test_dir
このように、上書きされてしまいます。# ls -1 /var/tmp lost+found
※pvc の初期状態については、コンテナの OS や pvc のストレージクラスによっては異なる可能性があります
pvc の初期化で困ること
-
pvc に root 以外のユーザで書き込みを加えようとすると、
書き込みのパーミッションが無いためファイルなどを作成できません。 -
pvc をアプリケーションの初期ディレクトリにする場合、
空ではないためエラーになることがあります。
今回は、後者に焦点を当てて説明していきます。
※パーミッションの解決方法は一番最後に記載します(解決方法はほぼ同じ)
検証
PostgreSQL のデータディレクトリとして使う場合
※PostgreSQL version 15 を使います
以下のようなマニフェストファイルを書いてみます(一部抜粋)。
spec:
containers:
- name: postgres
image: postgres:15
env:
~省略~
- name: PGDATA
value: /var/lib/postgresql/data
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
volumes:
- name: postgres-data
persistentVolumeClaim:
claimName: pvc-test
PVCのマウントポイントを、そのまま PostgreSQL のデータディレクトリに指定しています。
この状態でコンテナを作ると、
* 作成
# kubectl apply -f postgres.yml
deployment.apps/postgres created
* 確認(エラーになってしまった)
# kubectl get pods
NAME READY STATUS RESTARTS AGE
postgres-XXX-XXX 0/1 Error 1 (2s ago) 109s
エラーになってしまいました。
logs コマンドでエラーの内容を確認してみます。
* エラー内容を確認
# kubectl logs postgres-XXX-XXX
~省略~
initdb: error: directory "/var/lib/postgresql/data" exists but is not empty
initdb: detail: It contains a lost+found directory, perhaps due to it being a mount point.
initdb: hint: Using a mount point directly as the data directory is not recommended.
Create a subdirectory under the mount point.
エラーメッセージを読んでみると、
「error: データディレクトリが空でないためエラーになった」
「hint: マウントポイントをそのままデータディレクトリにするのは非推奨」
「hint: マウントポイントの下にデータディレクトリを作成してね」
となります。
どうやら、pvc がデフォルトで lost+found
ディレクトリを保持しているため、エラーになったようです。
解決方法
先ほどの PostgreSQL の検証で、logs の hint に出ていた通り、
マウントポイントの下にデータディレクトリを作成する
というのが最適解のようです。
ではどうすれば良いのか?
答えは、initContainers
を使うこと。
initContainers を使う
initContainers
(Initコンテナ) とは、
文字通りアプリケーションコンテナの初期化をサポートするコンテナです。
※アプリケーションコンテナ: spec.containers
で作成するコンテナ
主な用途としては
- pvc のように、コンテナ間で共通して使えるリソースの初期化
- アプリケーションコンテナのサービス起動を待機し、完了後に終了する
など。
今回は前者の「リソースの初期化」として使います。
pvc に初期ディレクトリを作る
では、先ほどの PostgreSQL 15 のマニフェストを修正していきます。
-
spec.containers
と同階層にinitContainers
を追加しますspec: containers: - name: postgres image: postgres:15 env: ~省略~ - name: PGDATA # マウント先にある data ディレクトリ を PostgreSQL のデータディレクトリとする value: /var/lib/postgresql/data volumeMounts: - name: postgres-data # マウント先には、データディレクトリの1個上の階層を指定する mountPath: /var/lib/postgresql # ここで初期化する initContainers: - name: initialize image: alpine:latest # マウント先となるディレクトリの下に data ディレクトリを作る command: ['sh', '-c', 'mkdir -p /pgsql/data'] volumeMounts: - name: postgres-data mountPath: "/pgsql" volumes: - name: postgres-data persistentVolumeClaim: claimName: pvc-test
-
initContainers
にて、pvc に data ディレクトリを作ります - pvc をアプリケーションコンテナにマウントし、マウントポイントの下に作成した data ディレクトリを PostgreSQL のデータディレクトリ として指定します
-
- この定義でコンテナを作成します
* 再作成 # kubectl apply -f postgres.yml deployment.apps/postgres configured * 確認(起動成功!) # kubectl get pods NAME READY STATUS RESTARTS AGE postgres-XXX-XXX 1/1 Running 0 99s
- コンテナの起動には成功しました。
- データディレクトリも確認してみます
* コンテナにログイン # kubectl exec -it postgres-XXX-XXX -c postgres -- /bin/bash * マウントポイントを確認 # ls -l /var/lib/postgresql total 20 drwx------ 19 postgres postgres 4096 Oct XX 05:27 data drwx------ 2 postgres root xxxx Oct XX 04:09 lost+found * data 配下を確認(一部抜粋) # ls -l /var/lib/postgresql/data/ -rw------- 1 postgres postgres xxxx Oct XX 05:27 pg_hba.conf -rw------- 1 postgres postgres xxxx Oct XX 05:27 postgresql.conf
- マウントポイントの下にデータディレクトリが配置され、
そこに PostgreSQL のファイルが配置されました。
初期化成功です!
- マウントポイントの下にデータディレクトリが配置され、
(参考)pvc のパーミッションを変える
パーミッションを変える場合も initContainers
で解決できます。
マニフェストファイル(一部抜粋)。
spec:
containers:
~省略~
initContainers:
- name: initalize
image: alpine:latest
command: ['sh', '-c', 'chmod 777 /test']
volumeMounts:
- name: pvc-test
mountPath: "/test"
このように、command 部分で権限を変更すればOKです。
あとがき
本記事は、2023/12 のアドベントカレンダーに投稿した記事の再掲です。
過去履歴削除のため、同じ内容で新規作成しました。