k3s でローカルストレージを使って minio を動かしてみました。
確認環境
- k3s version v0.5.0 (8c0116dd)
- minio/minio の docker image
k3s
kubectl で接続する k3s サーバーは
curl -sfL https://get.k3s.io | sh -
または
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="--disable-agent" sh -
でインストールしました。 バージョンアップも同じコマンドです。
サーバーでノード追加用のトークンを確認しておきます。 16 進数っぽいところを h に置き換えると以下のような感じです。
root@k3s-01:~# cat /var/lib/rancher/k3s/server/node-token
Khhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh::node:hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
他のノードはサーバーの IP アドレス (仮に 10.1.2.3) と先ほどのトークンを使って
curl -sfL https://get.k3s.io | K3S_URL=https://10.1.2.3:6443 K3S_TOKEN=Khhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh::node:hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh sh -
のように追加します。
kubectl
サーバー上の /etc/rancher/k3s/k3s.yaml
を手元にコピーして ~/.kube/config
に置きます。 すでに他の context が存在する場合は退避しておくか、頑張ってマージします。
ちゃんと設定できていれば、以下のようにノードを確認できます。
% kubectl get node
NAME STATUS ROLES AGE VERSION
k3s-01 Ready <none> XXd v1.14.1-k3s.4
k3s-02 Ready <none> XXd v1.14.1-k3s.4
k3s-03 Ready <none> XXd v1.14.1-k3s.4
StorageClass 作成
local-storage.yaml を作成して kubectl apply -f local-storage.yaml
で適用します。
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
作成できていると、以下のようになります。
% kubectl get storageclass
NAME PROVISIONER AGE
local-storage kubernetes.io/no-provisioner 30h
PersistentVolume 作成
お試し用ということで、適当に tmp と同じパーミッションにして install -m 1777 -d /data/vol1
や install -m 1777 -d /data/vol2
でディレクトリを作成して、対応する PersistentVolume を作成します。 レプリカ数以上の PersistentVolume が必要なので、お試し用ということで、各ノードに2個ずつ作成しました。
hostname が k3s-01,k3s-02,k3s-03 で path が vol1,vol2 の組み合わせで 6 個になりました。
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-pv-01-1
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /data/vol1
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- k3s-01
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-pv-02-1
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /data/vol1
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- k3s-02
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-pv-03-1
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /data/vol1
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- k3s-03
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-pv-01-2
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /data/vol2
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- k3s-01
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-pv-02-2
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /data/vol2
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- k3s-02
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-pv-03-2
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /data/vol2
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- k3s-03
minio もデプロイした後は以下のようになります。
% kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
local-pv-01-1 1Gi RWO Delete Bound default/data-minio-2 local-storage 28h
local-pv-01-2 1Gi RWO Delete Available local-storage 28h
local-pv-02-1 1Gi RWO Delete Bound default/data-minio-1 local-storage 28h
local-pv-02-2 1Gi RWO Delete Bound default/data-minio-3 local-storage 28h
local-pv-03-1 1Gi RWO Delete Bound default/data-minio-0 local-storage 28h
local-pv-03-2 1Gi RWO Delete Available local-storage 28h
minio の deploy
Download から Kubernetes を選んで、 Access Key と Secret Key は空欄にしておくと自動生成してくれるようなので、空欄にしておいて、 Standalone を Distributed に変更して、 Number of Nodes は 4 以上と言われるので 4 にして、 Size は 2 GB 以上と言われるので 2 GB にして生成しました。
実際に使ったものから Access Key と Secret Key を S3 のサンプルのものに書き換えたものが以下になります。
apiVersion: v1
kind: Service
metadata:
name: minio
labels:
app: minio
spec:
clusterIP: None
ports:
- port: 9000
name: minio
selector:
app: minio
---
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: minio
spec:
serviceName: minio
replicas: 4
template:
metadata:
labels:
app: minio
spec:
containers:
- name: minio
env:
- name: MINIO_ACCESS_KEY
value: "AKIAIOSFODNN7EXAMPLE"
- name: MINIO_SECRET_KEY
value: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
image: minio/minio
args:
- server
- http://minio-{0...3}.minio.default.svc.cluster.local/data
ports:
- containerPort: 9000
# These volume mounts are persistent. Each pod in the PetSet
# gets a volume mounted based on this field.
volumeMounts:
- name: data
mountPath: /data
# These are converted to volume claims by the controller
# and mounted at the paths mentioned above.
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 2
# Uncomment and add storageClass specific to your requirements below. Read more https://kubernetes.io/docs/concepts/storage/persistent-volumes/#class-1
storageClassName: local-storage
---
apiVersion: v1
kind: Service
metadata:
name: minio-service
spec:
type: LoadBalancer
ports:
- port: 9000
targetPort: 9000
protocol: TCP
selector:
app: minio
デプロイした後は以下のようになります。
% kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
data-minio-0 Bound local-pv-03-1 1Gi RWO local-storage 28h
data-minio-1 Bound local-pv-02-1 1Gi RWO local-storage 28h
data-minio-2 Bound local-pv-01-1 1Gi RWO local-storage 28h
data-minio-3 Bound local-pv-02-2 1Gi RWO local-storage 28h
% kubectl get pod
NAME READY STATUS RESTARTS AGE
minio-0 1/1 Running 0 28h
minio-1 1/1 Running 0 28h
minio-2 1/1 Running 0 28h
minio-3 1/1 Running 0 28h
svclb-minio-service-b74jd 1/1 Running 0 28h
svclb-minio-service-hnfnj 1/1 Running 0 28h
svclb-minio-service-r8w5g 1/1 Running 0 28h
トラブルシューティング
kubectl describe pod minio-0
で 0/3 nodes are available: 3 node(s) didn't find available persistent volumes to bind.
のように pvc が失敗して pod が起動できない場合は pvc に対応できる pv が足りないのが原因でした。
PersistentVolume の yaml の内容がまずくて、ちゃんと作成できていなかったり、数が足りない場合におきていました。
動作確認
kubectl port-forward minio-0 9000:9000
で port forwarding しつつ http://localhost:9000
を開いて Access Key と Secret Key でログインして試しました。
そして /data/vol1
や /data/vol2
にちゃんとファイルが保存されているのを確認しました。
削除
kubectl delete -f minio-deployment.yaml
だけでは pvc は消えなくて、 pv は pvc を削除しておかないと消せないようで、以下のようにすると消せました。
% kubectl delete -f minio-deployment.yaml
service "minio" deleted
statefulset.apps "minio" deleted
service "minio-service" deleted
% kubectl delete pvc data-minio-{0,1,2,3}
persistentvolumeclaim "data-minio-0" deleted
persistentvolumeclaim "data-minio-1" deleted
persistentvolumeclaim "data-minio-2" deleted
persistentvolumeclaim "data-minio-3" deleted
% kubectl delete -f pv.yaml
persistentvolume "local-pv-01-1" deleted
persistentvolume "local-pv-02-1" deleted
persistentvolume "local-pv-03-1" deleted
persistentvolume "local-pv-01-2" deleted
persistentvolume "local-pv-02-2" deleted
persistentvolume "local-pv-03-2" deleted
% kubectl delete storageclass local-storage
storageclass.storage.k8s.io "local-storage" deleted
/data/vol1
や /data/vol2
も不要なら削除しておきます。 この中身が残っていれば minio の方はデプロイし直せばまた見えるようになりました。
まとめ
kubernetes は勉強中なので、まだよくわかっていないところも多いですが、 チュートリアルによくあるステートレスな pod 以外も動かせるようになりました。
とりあえずローカルストレージの PersistentVolume の使い方がある程度わかったので、 単独サーバーの docker の代わりに使っていけそうな気がしました。