EKSでは積極的にRDS等のマネージドサービスでデータを保存したいところですが、種々の事情により永続ボリュームを用意しなければならないこともあります。
先日、PostgreSQLコンテナのデータをEFSを用いて永続化してみたので以降に手順をまとめます。
- Amazon EFS CSI driverのデプロイ
- 永続ストレージの設定
- EFSをマウントするDeploymentの作成
- PGDATAの書き込みに失敗
- initContainersで所有者変更
- 正常起動の確認
Amazon EFS CSI driverのデプロイ
リンク先の「Option B」を参考にAmazon EFS CSI driverをデプロイします。
Use persistent storage in Amazon EKS
この手順を終えると以下のようにEFSファイルシステムが出来上がります。
永続ストレージの設定
次のマニフェストでStorageClass、PersistentVolumeおよびPersistentVolumeClaimを作成します。
PVの spec.sci.volumeHandle
には前述の手順で作成したEFSのファイルシステムIDを指定します。
PVの spec.capacity.storage
やPVCの spec.resources.requests.storage
はKubernetesの必須項目であるため設定が必要ですが、EFSは伸縮自在なファイルシステムであるため実際に容量は制限されません。
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: efs-sc provisioner: efs.csi.aws.com --- apiVersion: v1 kind: PersistentVolume metadata: name: efs-pv spec: capacity: storage: 5Gi volumeMode: Filesystem accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain storageClassName: efs-sc csi: driver: efs.csi.aws.com volumeHandle: fs-xxxxxxxx --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: efs-claim spec: accessModes: - ReadWriteMany storageClassName: efs-sc resources: requests: storage: 5Gi
$ kubectl apply -f efs.yml storageclass.storage.k8s.io/efs-sc created persistentvolume/efs-pv created persistentvolumeclaim/efs-claim created
EFSをマウントするDeploymentの作成
EFSでデータを永続化するPostgreSQLコンテナを用意します。
使用するコンテナイメージは以下のエントリで紹介したCentOS7ベースのPostgreSQLです(バージョンは9.6に変更)。
起動時にエントリポイントでDBクラスタを作成( initdb
)します。
DBクラスタのディレクトリ /var/lib/pgsql/9.6/data
(以降、PGDATA)に persistent-storage
と名付けたボリュームをマウントします。
apiVersion: apps/v1 kind: Deployment metadata: ... spec: ... template: ... spec: containers: - name: db ... volumeMounts: - mountPath: /var/lib/pgsql/9.6/data name: persistent-storage volumes: - name: persistent-storage persistentVolumeClaim: claimName: efs-claim
$ kubectl apply -f db.yml deployment.apps/db created
PGDATAの書き込みに失敗
ログを確認してみるとPGDATAを initdb
で初期化する際、権限不足でエラーとなっていました。
ボリュームはrootでマウントされるので、実行ユーザであるpostgresが書き込み権限を持っていなかったわけです。
$ kubectl logs <db-pod-name> ... initdb: could not change permissions of directory "/var/lib/pgsql/9.6/data": Operation not permitted ...
initContainersで所有者変更
fsGroupでいける気がしましたが、どうにもうまくいかなかったのでinitContainersを使います。
db
コンテナが起動する前に change-data-dir-ownership
コンテナでPGDATAの所有者を 26:26
( postgres:postgres
)に変更します。
注意: postgresのUIDとGIDは環境により異なる場合があります(PostgreSQL: Re: Default UID for postgres user in linux)
apiVersion: apps/v1 kind: Deployment metadata: ... spec: ... template: ... spec: initContainers: - name: change-data-dir-ownership image: alpine:3 command: - chown - -R - 26:26 - /var/lib/pgsql/9.6/data volumeMounts: - name: persistent-storage mountPath: /var/lib/pgsql/9.6/data containers: ...
$ kubectl delete -f db.yml $ kubectl apply -f db.yml
正常起動の確認
これでデータベースの初期化に成功し、コンテナが正常稼働しました。
$ kubectl logs -f <db-pod-name> ... fixing permissions on existing directory /var/lib/pgsql/9.6/data ... ok creating subdirectories ... ok selecting default max_connections ... 100 selecting default shared_buffers ... 128MB selecting default timezone ... UTC selecting dynamic shared memory implementation ... posix creating configuration files ... ok running bootstrap script ... ok performing post-bootstrap initialization ... ok syncing data to disk ... ok Success. You can now start the database server using: pg_ctl -D /var/lib/pgsql/9.6/data -l logfile start WARNING: enabling "trust" authentication for local connections You can change this by editing pg_hba.conf or using the option -A, or --auth-local and --auth-host, the next time you run initdb. waiting for server to start....< 2020-10-27 05:01:48.580 UTC >LOG: redirecting log output to logging collector process < 2020-10-27 05:01:48.580 UTC >HINT: Future log output will appear in directory "pg_log". done server started CREATE DATABASE ... waiting for server to shut down.... done server stopped < 2020-10-27 05:02:24.104 UTC >LOG: redirecting log output to logging collector process < 2020-10-27 05:02:24.104 UTC >HINT: Future log output will appear in directory "pg_log".
データベースの一覧を確認します。
$ kubectl exec -it <db-pod-name> -- psql -l List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges -----------+----------+----------+---------+-------+----------------------- postgres | postgres | UTF8 | C | C | template0 | postgres | UTF8 | C | C | =c/postgres + | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | C | C | =c/postgres + | | | | | postgres=CTc/postgres your_db | postgres | UTF8 | C | C | (4 rows)
PGDATA以下のファイルとディレクトリも確認しておきます。
$ kubectl exec -it <db-pod-name> -- ls /var/lib/pgsql/9.6/data PG_VERSION pg_dynshmem pg_multixact pg_stat pg_xlog base pg_hba.conf pg_notify pg_stat_tmp postgresql.auto.conf global pg_ident.conf pg_replslot pg_subtrans postgresql.conf pg_clog pg_log pg_serial pg_tblspc postmaster.opts pg_commit_ts pg_logical pg_snapshots pg_twophase postmaster.pid
再デプロイし、DB初期化処理がスキップされ、かつ前回作成したデータベースが存在することを確認します。
$ kubectl delete -f db.yml $ kubectl apply -f db.yml $ kubectl logs <db-pod-name> < 2020-10-27 05:18:17.340 UTC >LOG: redirecting log output to logging collector process < 2020-10-27 05:18:17.340 UTC >HINT: Future log output will appear in directory "pg_log". $ kubectl exec -it <db-pod-name> -- psql -l List of databases Name | Owner | Encoding | Collate | Ctype | Access privileges -----------+----------+----------+---------+-------+----------------------- postgres | postgres | UTF8 | C | C | template0 | postgres | UTF8 | C | C | =c/postgres + | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | C | C | =c/postgres + | | | | | postgres=CTc/postgres your_db | postgres | UTF8 | C | C | (4 rows)