LoginSignup
0
0

この記事はなに?

Kubernetes のコンテナ起動時に pvc の扱いでつまづくケースと、その解決方法を記載しています。
また、初期状態の pvc の性質についても簡単に説明します。

※pvc の詳細な説明については割愛します

対象とする読者

  • Kubernetes のコンテナ起動時の pvc の扱いに困っている方
    • 例: pvc を PostgreSQL のデータディレクトリにしたいけれど、エラーが出てしまう
    • 例: pvc を apache ユーザでファイル保存に使いたいけれど、デフォルトだと書き込み権限が無く、ファイルが作れない

本記事の検証環境

  • マウント先コンテナのOS: CentOS7
  • pvc のストレージクラス: drbd

pvc とは?

正式名称は PersistentVolumeClaim (永続ボリューム)。

Kubernetes では通常、コンテナ上でデータを保存すると、
コンテナを削除、再作成した際にデータが消えてしまいます。

これを解消する仕組みが pvc。
pvc を作成し、コンテナにマウントすると、
コンテナを削除、再作成しても pvc のデータは消えません。
※例えが古いですが、外付けハードディスクのようなものです

pvc の初期状態

マウントしたての pvc には以下の性質があります。

  • パーミッションとオーナー
    • デフォルトで 755root:root で作成されます
  • 初期配置されるディレクトリ
    • lost+found が初期ディレクトリとして配置されます
  • 既存ディレクトリにマウントした場合、上書きされます
    例:
    以下のようなディレクトリをもつコンテナがあるとき
    # ls -1 /var/tmp/test
    file1 file2 test_dir
    
    pvc を /var/tmp にマウントすると
    # 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 のマニフェストを修正していきます。

  1. 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 のデータディレクトリ として指定します
  2. この定義でコンテナを作成します
    * 再作成
    # 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
    
    • コンテナの起動には成功しました。
  3. データディレクトリも確認してみます
    * コンテナにログイン
    # 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 のアドベントカレンダーに投稿した記事の再掲です。
過去履歴削除のため、同じ内容で新規作成しました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0