自宅サーバーにK3sとSynology CSI Driverをインストールメモ

今まで自宅サーバーにはMicrok8sをインストールしてKubernetesクラスターを構築していましたが、今回はK3sをインストールしてみたので、そのメモ。 Synology CSI Driverを使いたかったのですが、Microk8sだとうまく動作しなかったので、実績のあるK3sを試してみました。

Controlplane(兼Worker)ノード1台(192.168.100.50)、Workerノード2台(192.168.100.51,192.168.100.52)の計3台構成でセットアップしました。

Controlplaneノードのセットアップ

まずはControlplaneノードにK3sをインストールします。192.168.11.50のサーバー上で

curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.35.1+k3s1 \
  K3S_TOKEN=CHANGEME \
  sh -s - server \
  --node-ip=192.168.100.50 \
  --node-name=192.168.100.50 \
  --advertise-address=192.168.100.50 \
  --disable=traefik \
  --disable=local-storage

状態を確認します。

$ sudo systemctl status k3s | cat
● k3s.service - Lightweight Kubernetes
     Loaded: loaded (/etc/systemd/system/k3s.service; enabled; preset: enabled)
     Active: active (running) since Mon 2026-03-02 01:16:57 UTC; 44s ago
       Docs: https://k3s.io
    Process: 4048483 ExecStartPre=/sbin/modprobe br_netfilter (code=exited, status=0/SUCCESS)
    Process: 4048484 ExecStartPre=/sbin/modprobe overlay (code=exited, status=0/SUCCESS)
   Main PID: 4048486 (k3s-server)
      Tasks: 53
     Memory: 799.8M (peak: 800.5M)
        CPU: 18.873s
     CGroup: /system.slice/k3s.service
             ├─4048486 "/usr/local/bin/k3s server"
             ├─4048506 "containerd "
             ├─4048850 /var/lib/rancher/k3s/data/3b8ce3dcb1e1c49c523944bbb534b4c6eddd3f27edc542c5109b7a51ef7fa3f4/bin/containerd-shim-runc-v2 -namespace k8s.io -id d7e77a5d7999a677473d51fd57b56b3e89dacd0284ba5a341f4ab2cdec5db353 -address /run/k3s/containerd/containerd.sock
             └─4048852 /var/lib/rancher/k3s/data/3b8ce3dcb1e1c49c523944bbb534b4c6eddd3f27edc542c5109b7a51ef7fa3f4/bin/containerd-shim-runc-v2 -namespace k8s.io -id 88228a2229353f99ee8defe34a7fa7497a02c225fac451c087324be315603dc4 -address /run/k3s/containerd/containerd.sock

Mar 02 01:17:04 apricot k3s[4048486]:  >
Mar 02 01:17:04 apricot k3s[4048486]: I0302 01:17:04.219794 4048486 controller.go:109] OpenAPI AggregationController: action for item v1beta1.metrics.k8s.io: Rate Limited Requeue.
Mar 02 01:17:08 apricot k3s[4048486]: I0302 01:17:08.298964 4048486 kuberuntime_manager.go:2062] "Updating runtime config through cri with podcidr" CIDR="10.42.0.0/24"
Mar 02 01:17:08 apricot k3s[4048486]: I0302 01:17:08.300170 4048486 kubelet_network.go:47] "Updating Pod CIDR" originalPodCIDR="" newPodCIDR="10.42.0.0/24"
Mar 02 01:17:08 apricot k3s[4048486]: time="2026-03-02T01:17:08Z" level=info msg="Starting network policy controller version v2.6.3-k3s1, built on 2026-02-12T23:46:55Z, go1.25.6"
Mar 02 01:17:08 apricot k3s[4048486]: I0302 01:17:08.792556 4048486 network_policy_controller.go:164] Starting network policy controller
Mar 02 01:17:08 apricot k3s[4048486]: I0302 01:17:08.854866 4048486 network_policy_controller.go:179] Starting network policy controller full sync goroutine
Mar 02 01:17:13 apricot k3s[4048486]: I0302 01:17:13.085374 4048486 pod_startup_latency_tracker.go:108] "Observed pod startup duration" pod="kube-system/coredns-7566b5ff58-vrs2k" podStartSLOduration=5.422428666 podStartE2EDuration="10.085351425s" podCreationTimestamp="2026-03-02 01:17:03 +0000 UTC" firstStartedPulling="2026-03-02 01:17:07.541643538 +0000 UTC m=+15.837752781" lastFinishedPulling="2026-03-02 01:17:12.204566293 +0000 UTC m=+20.500675540" observedRunningTime="2026-03-02 01:17:13.084998533 +0000 UTC m=+21.381107810" watchObservedRunningTime="2026-03-02 01:17:13.085351425 +0000 UTC m=+21.381460689"
Mar 02 01:17:32 apricot k3s[4048486]: I0302 01:17:32.096785 4048486 pod_startup_latency_tracker.go:108] "Observed pod startup duration" pod="kube-system/metrics-server-786d997795-6mjkg" podStartSLOduration=23.628488248 podStartE2EDuration="29.096767377s" podCreationTimestamp="2026-03-02 01:17:03 +0000 UTC" firstStartedPulling="2026-03-02 01:17:07.541467397 +0000 UTC m=+15.837576639" lastFinishedPulling="2026-03-02 01:17:13.009746529 +0000 UTC m=+21.305855768" observedRunningTime="2026-03-02 01:17:14.076915593 +0000 UTC m=+22.373024848" watchObservedRunningTime="2026-03-02 01:17:32.096767377 +0000 UTC m=+40.392876627"
Mar 02 01:17:32 apricot k3s[4048486]: I0302 01:17:32.155898 4048486 handler.go:304] Adding GroupVersion metrics.k8s.io v1beta1 to ResourceManager

kubeconfigをコピーします。

sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown $USER:$USER ~/.kube/config
chmod 600 ~/.kube/config

NodeとPodの状態を確認します。

NAME                  STATUS   ROLES           AGE   VERSION        INTERNAL-IP      EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION     CONTAINER-RUNTIME
node/192.168.100.50   Ready    control-plane   70s   v1.35.1+k3s1   192.168.100.50   <none>        Ubuntu 24.04.2 LTS   6.8.0-90-generic   containerd://2.1.5-k3s1

NAMESPACE     NAME                                  READY   STATUS    RESTARTS   AGE   IP          NODE             NOMINATED NODE   READINESS GATES
kube-system   pod/coredns-7566b5ff58-vrs2k          1/1     Running   0          65s   10.42.0.2   192.168.100.50   <none>           <none>
kube-system   pod/metrics-server-786d997795-6mjkg   1/1     Running   0          65s   10.42.0.3   192.168.100.50   <none>           <none>

Workerノードのセットアップ

Worker 1台目 (192.168.11.51)をセットアップします。192.168.11.51のサーバー上で次を実行します。

curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.35.1+k3s1 \
  K3S_URL=https://192.168.100.50:6443 \
  K3S_TOKEN=CHANGEME \
  sh -s - agent \
  --node-ip=192.168.100.51 \
  --node-name=192.168.100.51

Controlplane(192.168.11.50)のサーバー上でNodeとPodの状態を確認します。

$ kubectl get node,pod -owide -A
NAME                    STATUS   ROLES           AGE    VERSION        INTERNAL-IP      EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION     CONTAINER-RUNTIME
node/192.168.100.50     Ready    control-plane   6m1s   v1.35.1+k3s1   192.168.100.50   <none>        Ubuntu 24.04.2 LTS   6.8.0-90-generic   containerd://2.1.5-k3s1
node/192.168.100.51     Ready    <none>          44s    v1.35.1+k3s1   192.168.100.51   <none>        Ubuntu 24.04.2 LTS   6.8.0-88-generic   containerd://2.1.5-k3s1

NAMESPACE     NAME                                  READY   STATUS    RESTARTS   AGE     IP          NODE             NOMINATED NODE   READINESS GATES
kube-system   pod/coredns-7566b5ff58-vrs2k          1/1     Running   0          5m56s   10.42.0.2   192.168.100.50   <none>           <none>
kube-system   pod/metrics-server-786d997795-6mjkg   1/1     Running   0          5m56s   10.42.0.3   192.168.100.50   <none>           <none>

Worker 2台目 (192.168.11.52)をセットアップします。192.168.11.52のサーバー上で次を実行します。

curl -sfL https://get.k3s.io | INSTALL_K3S_VERSION=v1.35.1+k3s1 \
  K3S_URL=https://192.168.100.50:6443 \
  K3S_TOKEN=CHANGEME \
  sh -s - agent \
  --node-ip=192.168.100.52 \
  --node-name=192.168.100.52

Controlplane(192.168.11.50)のサーバー上でNodeとPodの状態を確認します。

$ kubectl get node,pod -owide -A
NAME                  STATUS   ROLES           AGE     VERSION        INTERNAL-IP      EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION      CONTAINER-RUNTIME
node/192.168.100.50   Ready    control-plane   8m39s   v1.35.1+k3s1   192.168.100.50   <none>        Ubuntu 24.04.2 LTS   6.8.0-90-generic    containerd://2.1.5-k3s1
node/192.168.100.51   Ready    <none>          3m22s   v1.35.1+k3s1   192.168.100.51   <none>        Ubuntu 24.04.2 LTS   6.8.0-88-generic    containerd://2.1.5-k3s1
node/192.168.100.52   Ready    <none>          12s     v1.35.1+k3s1   192.168.100.52   <none>        Ubuntu 24.04.2 LTS   6.8.0-101-generic   containerd://2.1.5-k3s1

NAMESPACE     NAME                                  READY   STATUS    RESTARTS   AGE     IP          NODE             NOMINATED NODE   READINESS GATES
kube-system   pod/coredns-7566b5ff58-vrs2k          1/1     Running   0          8m34s   10.42.0.2   192.168.100.50   <none>           <none>
kube-system   pod/metrics-server-786d997795-6mjkg   1/1     Running   0          8m34s   10.42.0.3   192.168.100.50   <none>           <none>

Synology CSI Driverのインストール

次にSynology CSI Driverをインストールします。次のようにマニフェストを用意します。

git clone https://github.com/SynologyOpenSource/synology-csi.git -b v1.2.1
cd synology-csi
cp config/client-info-template.yml config/client-info.yml
vim config/client-info.yml

client-info.ymlにSynology NASの情報を設定します。

Storage Classの設定ファイルを編集します。

vim deploy/kubernetes/v1.20/storage-class.yml 

次の設定にします。

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: synology-iscsi-storage
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: csi.san.synology.com
parameters:
  fsType: 'btrfs'
  dsm: '192.168.100.200'
  location: '/volume1'
  formatOptions: '--nodiscard'
reclaimPolicy: Delete
allowVolumeExpansion: true

次のコマンドでSynology CSI Driverをインストールします。

./scripts/deploy.sh install --basic

次のような出力が得られます。

==== Creates namespace and secrets, then installs synology-csi ====
Current Server Version: v1.35.1+k3s1
Deploy Version: v1.20
namespace/synology-csi created
secret/client-info-secret created
serviceaccount/csi-controller-sa created
clusterrole.rbac.authorization.k8s.io/synology-csi-controller-role created
clusterrolebinding.rbac.authorization.k8s.io/synology-csi-controller-role created
statefulset.apps/synology-csi-controller created
csidriver.storage.k8s.io/csi.san.synology.com created
namespace/synology-csi unchanged
serviceaccount/csi-node-sa created
clusterrole.rbac.authorization.k8s.io/synology-csi-node-role created
clusterrolebinding.rbac.authorization.k8s.io/synology-csi-node-role created
daemonset.apps/synology-csi-node created
storageclass.storage.k8s.io/synology-iscsi-storage created

synology-csi NamespaceのPodの状態を確認します。

$ kubectl get pod -owide -n synology-csi
NAME                        READY   STATUS    RESTARTS   AGE   IP               NODE             NOMINATED NODE   READINESS GATES
synology-csi-controller-0   4/4     Running   0          48s   192.168.100.51   192.168.100.50   <none>           <none>
synology-csi-node-jfnvs     2/2     Running   0          48s   192.168.100.50   192.168.100.50   <none>           <none>
synology-csi-node-r8fpm     2/2     Running   0          48s   192.168.100.52   192.168.100.52   <none>           <none>
synology-csi-node-x44wr     2/2     Running   0          48s   192.168.100.51   192.168.100.51   <none>           <none>

Persistent Volumeの動作確認

次のPVCを作成して、動作を確認します。

cat <<EOF > /tmp/pvc.yaml
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-dynamic-volume-claim
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: synology-iscsi-storage
---
EOF

kubectl apply -f /tmp/pvc.yaml

次のようにPVCがBound状態になれば成功です。

$ kubectl get pvc
NAME                        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS             VOLUMEATTRIBUTESCLASS   AGE
test-dynamic-volume-claim   Bound    pvc-6df54034-c251-4184-9d58-cf7b2fa1c039   1Gi        RWO            synology-iscsi-storage   <unset>                 7s

Synology NAS側のSAN ManagerでLUNとiSCSI Targetも作成されていることを確認できます。

image

image

このPVCをマウントするPodを作成し、読み書きの動作確認を行います。

cat <<EOF > /tmp/pvc-test-pod.yaml
---
apiVersion: v1
kind: Pod
metadata:
  name: pvc-test-pod
spec:
  securityContext:
    runAsUser: 1000
    runAsGroup: 100
    fsGroup: 100
  containers:
  - name: test-container
    image: index.docker.io/library/busybox:latest
    command: ["/bin/sh"]
    args:
      - -c
      - |
        echo "=== PVC Read/Write Test Start ==="
        echo "Mount point check:"
        df -h /mnt/test
        echo ""
        
        echo "=== Write Test ==="
        echo "Hello from PVC test - $(date)" >> /mnt/test/test-file.txt
        echo "File write completed"
        echo ""
        
        echo "=== File Verification ==="
        ls -lah /mnt/test/
        echo ""
        
        echo "=== Read Test ==="
        cat /mnt/test/test-file.txt
        echo ""
        
        echo "=== Test Completed ==="
        sleep infinity
    volumeMounts:
    - name: test-volume
      mountPath: /mnt/test
  volumes:
  - name: test-volume
    persistentVolumeClaim:
      claimName: test-dynamic-volume-claim
  restartPolicy: Never
---
EOF

kubectl apply -f /tmp/pvc-test-pod.yaml

次のようにPodがReadyになれば成功です。

$ kubectl  get pod -owide
NAME           READY   STATUS    RESTARTS   AGE   IP          NODE            NOMINATED NODE   READINESS GATES
pvc-test-pod   1/1     Running   0          24s   10.42.1.4   192.168.100.51  <none>           <none>

ログを確認し、読み書きができていることを確認します。

$ kubectl logs pvc-test-pod 
=== PVC Read/Write Test Start ===
Mount point check:
Filesystem                Size      Used Available Use% Mounted on
/dev/sdc                  1.0G      5.8M    904.6M   1% /mnt/test

=== Write Test ===
File write completed

=== File Verification ===
total 24K    
drwxrwsr-x    1 root     users         26 Mar  2 01:33 .
drwxr-xr-x    3 root     root        4.0K Mar  2 01:33 ..
-rw-r--r--    1 1000     users         51 Mar  2 01:33 test-file.txt

=== Read Test ===
Hello from PVC test - Mon Mar  2 01:31:50 UTC 2026

=== Test Completed ===

次のコマンドでPodを再作成し、データが保持されていることを確認します。

kubectl delete pod pvc-test-pod --force
kubectl apply -f /tmp/pvc-test-pod.yaml

ログを確認し、ファイルに行が追記されていることを確認します。

$ kubectl logs pvc-test-pod 
=== PVC Read/Write Test Start ===
Mount point check:
Filesystem                Size      Used Available Use% Mounted on
/dev/sdc                  1.0G      5.8M    904.6M   1% /mnt/test

=== Write Test ===
File write completed

=== File Verification ===
total 24K    
drwxrwsr-x    1 root     users         26 Mar  2 01:33 .
drwxr-xr-x    3 root     root        4.0K Mar  2 01:34 ..
-rw-rw-r--    1 1000     users        102 Mar  2 01:34 test-file.txt

=== Read Test ===
Hello from PVC test - Mon Mar  2 01:31:50 UTC 2026
Hello from PVC test - Mon Mar  2 01:31:50 UTC 2026

=== Test Completed ===

次のコマンドでPodとPVCを削除します。

kubectl delete pod pvc-test-pod --force
kubectl delete pvc test-dynamic-volume-claim

SAN ManagerでLUNとiSCSI Targetも削除されていることを確認できます。

HelmでRedisをインストールして動作確認

次にHelmを使ってRedisをインストールし、動作確認を行います。

helm upgrade --install redis \
  oci://registry-1.docker.io/bitnamicharts/redis \
  -n redis \
  --create-namespace --wait \
  --set auth.enabled=false

次のようにPodとPVCが作成されていることを確認します。

$ kubectl get pod,pvc -owide -n redis 
NAME                   READY   STATUS    RESTARTS   AGE     IP           NODE             NOMINATED NODE   READINESS GATES
pod/redis-master-0     1/1     Running   0          2m36s   10.42.1.11   192.168.100.51   <none>           <none>
pod/redis-replicas-0   1/1     Running   0          2m36s   10.42.1.12   192.168.100.51   <none>           <none>
pod/redis-replicas-1   1/1     Running   0          114s    10.42.2.5    192.168.100.52   <none>           <none>
pod/redis-replicas-2   1/1     Running   0          72s     10.42.0.4    192.168.100.50   <none>           <none>

NAME                                                STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS             VOLUMEATTRIBUTESCLASS   AGE     VOLUMEMODE
persistentvolumeclaim/redis-data-redis-master-0     Bound    pvc-5f7792b3-3c49-44d6-8167-0ebc4f4e66fb   8Gi        RWO            synology-iscsi-storage   <unset>                 2m36s   Filesystem
persistentvolumeclaim/redis-data-redis-replicas-0   Bound    pvc-ea541f4a-879a-4ccd-9654-49efc018d87d   8Gi        RWO            synology-iscsi-storage   <unset>                 2m36s   Filesystem
persistentvolumeclaim/redis-data-redis-replicas-1   Bound    pvc-80964ce4-bb0d-4d2d-8b19-881feb82a6ed   8Gi        RWO            synology-iscsi-storage   <unset>                 115s    Filesystem
persistentvolumeclaim/redis-data-redis-replicas-2   Bound    pvc-02e1e1dc-0646-447c-89d5-6f16215d27cf   8Gi        RWO            synology-iscsi-storage   <unset>                 72s     Filesystem

次のコマンドでRedisマスターにポートフォワードし、redis-cliで接続して動作確認を行います。

kubectl port-forward --namespace redis svc/redis-master 6379:6379

次のようにRedisに接続して、データの読み書きができることを確認します。

$ redis-cli -h 127.0.0.1 -p 6379
127.0.0.1:6379> set foo 100
OK
127.0.0.1:6379> get foo
"100"

次のコマンドでRedisをアンインストールし、PVCも削除します。

helm uninstall -n redis redis --wait
kubectl delete pvc -n redis --all
kubectl delete ns redis

K3sにSynology CSI Driverをインストールして、Synology NASのiSCSI LUNをKubernetesのPersistent Volumeとして利用することができました。 K3sは軽量でセットアップも簡単なので、自宅サーバーでKubernetesクラスターを構築するのに便利です。