はじめに
Kubernetes上でBitnami Helm Chartを使ってRedmineを構築し,永続ボリュームとしてSynology NASをNFS経由で使えるようにしました.
私が実際に構築した際の手順を記録しておきます.
この記事はRedmine を Helm で初めてデプロイする際に,最初から NFS を使った永続ボリュームを設定したい方に向けています
環境構成
- Kubernates:
v1.30.6+k3s1
- Helm:
v3.17.3
- Redmine: Bitnami Helm Chart
redmine-32.2.5
- NFSサーバ: Synology NAS
1. NFSの準備
RedmineのPVをNFSで扱うために,以下の準備を行いました.
1-1. NAS側でNFS共有ディレクトリを作成
Synology NASの管理画面で以下のようなNFS共有を作成しました.
- 共有フォルダ名:redmine-nfs
- パス:/volume1/redmine-nfs
- アクセス許可:RedmineをデプロイしているkubernetesノードのIPアドレスを許可
1-2. Kubernetesノードにnfs-commonをインストール
ノード側でNFSマウントができるように,各ノードに以下をインストールしました.
monitoring@monitoring-master-ml:~/redmine$ sudo apt-get install nfs-common
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
keyutils libnfsidmap1 rpcbind
Suggested packages:
watchdog
The following NEW packages will be installed:
keyutils libnfsidmap1 nfs-common rpcbind
0 upgraded, 4 newly installed, 0 to remove and 110 not upgraded.
Need to get 400 kB of archives.
After this operation, 1,416 kB of additional disk space will be used.
Do you want to continue? [Y/n] Y
Get:1 http://jp.archive.ubuntu.com/ubuntu noble-updates/main amd64 libnfsidmap1 amd64 1:2.6.4-3ubuntu5.1 [48.3 kB]
Get:2 http://jp.archive.ubuntu.com/ubuntu noble/main amd64 rpcbind amd64 1.2.6-7ubuntu2 [46.5 kB]
Get:3 http://jp.archive.ubuntu.com/ubuntu noble/main amd64 keyutils amd64 1.6.3-3build1 [56.8 kB]
Get:4 http://jp.archive.ubuntu.com/ubuntu noble-updates/main amd64 nfs-common amd64 1:2.6.4-3ubuntu5.1 [248 kB]
Fetched 400 kB in 2s (211 kB/s)
Selecting previously unselected package libnfsidmap1:amd64.
(Reading database ... 124826 files and directories currently installed.)
Preparing to unpack .../libnfsidmap1_1%3a2.6.4-3ubuntu5.1_amd64.deb ...
Unpacking libnfsidmap1:amd64 (1:2.6.4-3ubuntu5.1) ...
Selecting previously unselected package rpcbind.
Preparing to unpack .../rpcbind_1.2.6-7ubuntu2_amd64.deb ...
Unpacking rpcbind (1.2.6-7ubuntu2) ...
Selecting previously unselected package keyutils.
Preparing to unpack .../keyutils_1.6.3-3build1_amd64.deb ...
Unpacking keyutils (1.6.3-3build1) ...
Selecting previously unselected package nfs-common.
Preparing to unpack .../nfs-common_1%3a2.6.4-3ubuntu5.1_amd64.deb ...
Unpacking nfs-common (1:2.6.4-3ubuntu5.1) ...
Setting up libnfsidmap1:amd64 (1:2.6.4-3ubuntu5.1) ...
Setting up rpcbind (1.2.6-7ubuntu2) ...
Created symlink /etc/systemd/system/multi-user.target.wants/rpcbind.service → /usr/lib/systemd/system/rpcbind.service.
Created symlink /etc/systemd/system/sockets.target.wants/rpcbind.socket → /usr/lib/systemd/system/rpcbind.socket.
Setting up keyutils (1.6.3-3build1) ...
Setting up nfs-common (1:2.6.4-3ubuntu5.1) ...
Creating config file /etc/idmapd.conf with new version
Creating config file /etc/nfs.conf with new version
info: Selecting UID from range 100 to 999 ...
info: Adding system user `statd' (UID 111) ...
info: Adding new user `statd' (UID 111) with group `nogroup' ...
info: Not creating home directory `/var/lib/nfs'.
Created symlink /etc/systemd/system/multi-user.target.wants/nfs-client.target → /usr/lib/systemd/system/nfs-client.target.
Created symlink /etc/systemd/system/remote-fs.target.wants/nfs-client.target → /usr/lib/systemd/system/nfs-client.target.
auth-rpcgss-module.service is a disabled or a static unit, not starting it.
nfs-idmapd.service is a disabled or a static unit, not starting it.
nfs-utils.service is a disabled or a static unit, not starting it.
proc-fs-nfsd.mount is a disabled or a static unit, not starting it.
rpc-gssd.service is a disabled or a static unit, not starting it.
rpc-statd-notify.service is a disabled or a static unit, not starting it.
rpc-statd.service is a disabled or a static unit, not starting it.
rpc-svcgssd.service is a disabled or a static unit, not starting it.
Processing triggers for man-db (2.12.0-4build2) ...
Processing triggers for libc-bin (2.39-0ubuntu8.4) ...
Scanning processes...
Scanning candidates...
Scanning linux images...
Running kernel seems to be up-to-date.
Restarting services...
Service restarts being deferred:
systemctl restart unattended-upgrades.service
No containers need to be restarted.
No user sessions are running outdated binaries.
No VM guests are running outdated hypervisor (qemu) binaries on this host.
kubernetesクラスターを使用している場合,マスターノードだけでなく全てのノードに対してインストールを行ってください.
1-3. NFS用のProvisionerをHelmでデプロイ
Helmの nfs-subdir-external-provisioner を使用し,NFS用のStorageClassを作成しました.
NFS用のStorageClassはクラスター全体で利用できるリソースですが,それを動作させるpodを動かすためのネームスペースを作成し,そこに対してデプロイするのがいいと思います.
今回はnfsというネームスペースにデプロイしています.
monitoring@monitoring-master-ml:~/redmine$ helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
monitoring@monitoring-master-ml:~/redmine$ helm install my-redmine oci://registry-1.docker.io/bitnamicharts/redmine -n redmine -f values.yaml
Pulled: registry-1.docker.io/bitnamicharts/redmine:32.2.5
Digest: sha256:120baaa62fc616851a0189cab4009b08354ecdf3e543ceacb122f4c3666e1941
NAME: my-redmine
LAST DEPLOYED: Thu Jun 5 00:31:45 2025
NAMESPACE: redmine
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
CHART NAME: redmine
CHART VERSION: 32.2.5
APP VERSION: 6.0.5
Did you know there are enterprise versions of the Bitnami catalog? For enhanced secure software supply chain features, unlimited pulls from Docker, LTS support, or application customization, see Bitnami Premium or Tanzu Application Catalog. See https://www.arrow.com/globalecs/na/vendors/bitnami for more information.
** Please be patient while the chart is being deployed **
1. Get the Redmine URL:
export NODE_PORT=$(kubectl get --namespace redmine -o jsonpath="{.spec.ports[0].nodePort}" services my-redmine)
export NODE_IP=$(kubectl get nodes --namespace redmine -o jsonpath="{.items[0].status.addresses[0].address}")
echo "Redmine URL: http://$NODE_IP:$NODE_PORT/"
2. Login with the following credentials
export REDMINE_USERNAME=user
export REDMINE_PASSWORD=$(kubectl get secret --namespace "redmine" my-redmine -o jsonpath="{.data.redmine-password}" | base64 -d)
echo Username: $REDMINE_USERNAME
echo Password: $REDMINE_PASSWORD
You can access the DB using the following password:
export MARIADB_PASSWORD=$(kubectl get secret --namespace "redmine" my-redmine-mariadb -o jsonpath="{.data.mariadb-password}" | base64 -d)
⚠ SECURITY WARNING: Original containers have been substituted. This Helm chart was designed, tested, and validated on multiple platforms using a specific set of Bitnami and Tanzu Application Catalog containers. Substituting other containers is likely to cause degraded security and performance, broken chart features, and missing environment variables.
Substituted images detected:
- docker.io/bitnami/redmine:6.0.4-debian-12-r6
- docker.io/bitnami/os-shell:12-debian-12-r42
⚠ WARNING: Original containers have been retagged. Please note this Helm chart was tested, and validated on multiple platforms using a specific set of Tanzu Application Catalog containers. Substituting original image tags could cause unexpected behavior.
Retagged images:
- docker.io/bitnami/redmine:6.0.4-debian-12-r6
- docker.io/bitnami/os-shell:12-debian-12-r42
1-4. StorageClassの確認
デプロイ後,以下のコマンドで nfs-client というStorageClassが追加されていることを確認しました.
monitoring@monitoring-master-ml:~/redmine$ kubectl get storageclass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
local-path (default) rancher.io/local-path Delete WaitForFirstConsumer false 242d
nfs-client cluster.local/nfs-subdir-external-provisioner Delete Immediate true 38d
この nfs-client を values.yaml でRedmineのPVCに指定することで,NFSへの切り替えが可能になります.
StorageClass が存在していても,NFS Provisioner が正常に動いていなければ意味がありません.
以下のコマンドでNFS Provisionerのpodが起動しているかを確認しました.
monitoring@monitoring-master-ml:~/redmine$ kubectl get pod -n nfs
NAME READY STATUS RESTARTS AGE
nfs-subdir-external-provisioner-6dc4f545f-58r6k 1/1 Running 0 14d
2. RedmineのHelmデプロイ
2-1. values.yamlの準備
Helm チャートに含まれている values.yaml をベースに,必要な項目のみを上書きします.
この values.yaml にある設定のうち,以下のように項目を編集しました.
persistence:
storageClass: "nfs-client"
storageClassをnfs-clientと明示します.
私はRedmineとmariaDBの両方に対して個別にstorageClass: "nfs-client"と指定しましたが,このvalues.yamlにはglobal.defaultStorageClassがあるのでそこで指定してもいいかもしれません.
私は作業時にはglobal.defaultStorageClassに気が付けませんでした.
values.yaml 内では,MariaDB の root パスワード(auth.rootPassword)や,Redmine の公開用ポート番号(例:service.nodePorts.http)などの設定も指定できます
2-2. Helmリポジトリの追加と更新
monitoring@monitoring-master-ml:~/redmine$ helm repo add bitnami https://charts.bitnami.com/bitnami
monitoring@monitoring-master-ml:~/redmine$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "nfs-subdir-external-provisioner" chart repository
...Successfully got an update from the "bitnami" chart repository
Update Complete. ⎈Happy Helming!⎈
Helm Chart の提供元は Bitnamiです.
redmine は公式チャートに含まれています.
2-3. Namespaceの作成
任意ですが,運用の管理のためにRedmine用のネームスペースの作成をお勧めします.
monitoring@monitoring-master-ml:~/redmine$ kubectl create namespace redmine
namespace/redmine created
2-4. RedmineのHelmデプロイ
こちらのコマンドを使用してデプロイしました.
- my-redmine:リリース名(任意に変更可能)
- -n redmine:redmineというネームスペースにデプロイ
- -f values.yaml:先ほどカスタマイズしたvalues.yamlを指定
monitoring@monitoring-master-ml:~/redmine$ helm install my-redmine oci://registry-1.docker.io/bitnamicharts/redmine -n redmine -f values.yaml
Pulled: registry-1.docker.io/bitnamicharts/redmine:32.2.5
Digest: sha256:120baaa62fc616851a0189cab4009b08354ecdf3e543ceacb122f4c3666e1941
NAME: my-redmine
LAST DEPLOYED: Thu Jun 5 00:31:45 2025
NAMESPACE: redmine
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
CHART NAME: redmine
CHART VERSION: 32.2.5
APP VERSION: 6.0.5
Did you know there are enterprise versions of the Bitnami catalog? For enhanced secure software supply chain features, unlimited pulls from Docker, LTS support, or application customization, see Bitnami Premium or Tanzu Application Catalog. See https://www.arrow.com/globalecs/na/vendors/bitnami for more information.
** Please be patient while the chart is being deployed **
1. Get the Redmine URL:
export NODE_PORT=$(kubectl get --namespace redmine -o jsonpath="{.spec.ports[0].nodePort}" services my-redmine)
export NODE_IP=$(kubectl get nodes --namespace redmine -o jsonpath="{.items[0].status.addresses[0].address}")
echo "Redmine URL: http://$NODE_IP:$NODE_PORT/"
2. Login with the following credentials
export REDMINE_USERNAME=user
export REDMINE_PASSWORD=$(kubectl get secret --namespace "redmine" my-redmine -o jsonpath="{.data.redmine-password}" | base64 -d)
echo Username: $REDMINE_USERNAME
echo Password: $REDMINE_PASSWORD
You can access the DB using the following password:
export MARIADB_PASSWORD=$(kubectl get secret --namespace "redmine" my-redmine-mariadb -o jsonpath="{.data.mariadb-password}" | base64 -d)
⚠ SECURITY WARNING: Original containers have been substituted. This Helm chart was designed, tested, and validated on multiple platforms using a specific set of Bitnami and Tanzu Application Catalog containers. Substituting other containers is likely to cause degraded security and performance, broken chart features, and missing environment variables.
Substituted images detected:
- docker.io/bitnami/redmine:6.0.4-debian-12-r6
- docker.io/bitnami/os-shell:12-debian-12-r42
⚠ WARNING: Original containers have been retagged. Please note this Helm chart was tested, and validated on multiple platforms using a specific set of Tanzu Application Catalog containers. Substituting original image tags could cause unexpected behavior.
Retagged images:
- docker.io/bitnami/redmine:6.0.4-debian-12-r6
- docker.io/bitnami/os-shell:12-debian-12-r42
3. 動作確認
3-1. podの起動確認
以下のコマンドを実行しました.
monitoring@monitoring-master-ml:~/redmine$ kubectl get po -n redmine
NAME READY STATUS RESTARTS AGE
my-redmine-5d4d5dbd68-nmnvl 1/1 Running 0 24h
my-redmine-mariadb-0 1/1 Running 0 24h
my-redmine(先ほど指定したリリース名)及びmy-redmine-mariaDBのpodのSTATUSがRunningであれば正常に起動しています.
3-2. PVCの確認
以下のコマンドを実行しました.
monitoring@monitoring-master-ml:~/redmine$ kubectl get pvc -n redmine
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
data-my-redmine-mariadb-0 Bound pvc-eb61ab83-f3b7-4696-9d80-beb34f18b289 8Gi RWO nfs-client <unset> 38d
my-redmine Bound pvc-e4ceff1f-83b1-483a-bc03-7f48082b3acf 8Gi RWO nfs-client <unset> 38d
- Redmine用のPVC
- MariaDB用のPVC
の両方のSTATUSがBoundと表示されていて,STORAGECLASSがnfs-clientであればNFS経由でストレージが正しく接続されています.
3-3. RedmineのWebUIへのアクセス確認
以下のコマンドを実行し,EXTERNAL-IP または NodePort を確認し,ブラウザから Redmine にアクセスできるかを確認します.
monitoring@monitoring-master-ml:~/redmine$ kubectl get svc -n redmine
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-redmine NodePort 10.43.34.142 <none> 80:32300/TCP 38d
my-redmine-mariadb ClusterIP 10.43.32.162 <none> 3306/TCP 38d
ポート番号はvalues.yaml内で指定することができるので,実際のポートが環境に応じて異なります.
3-4. ファイルのアップロード確認
チケットを作成し,ファイルを添付することができるか確認します.
その後,NAS上もしくはRedmineのpod内でアップロードしたファイルが確認できれば永続化の動作も正常です.
NAS上で確認した結果の例.
podを再起動してもファイルが保持されているか確認してください
おわりに
RedmineをHelm ChartでKubernetesにデプロイする際に,NFSを使った永続ボリュームを利用する方法を紹介しました.
同様の構成を検討している方の参考になれば幸いです.