2022/04/07
GKEでNFS
概要
k8sの複数のpod間で共有できる ReadWriteMany
なボリュームの必要ができきたので、GKEでのNFSの構築を行いました。
今回はその備忘録です。
具体的には、ファイルアップロードを行うWebアプリケーションで、大きいファイルだった場合複数のchunkに分けてアップロードするような処理を書いたのですが・・
このアップロード先はk8s上の複数のpodに分散される可能性があり、全てのpodで共有できるvolumeがあると便利だなと思い、NFSを構築しました。
注意事項
※ このvolumeはchunkの格納に一時的に使うためだけのもので、特段可用性などは持たせていません。
もし可用性を持たせる場合は、Rook/Cephなんかをうまく使うのが良いのかなと思います。
chunkが全てアップロードされたら、chunkを一つに繋げてファイルを復元し、GCSなどの可用性の高いファイルストレージに格納する感じです。
参考
ほぼほぼmappedinn/kubernetes-nfs-volume-on-gke: kubernetes-nfs-volume-on-gkeを参考にしています。
実装
GCE Diskを作成します。
your-gce-disk-name
という名前で、200GBのものを作成したものとします。
注意点
nfs serverを動かす、nodeは単一のzone(今回はasia-northeast2-a
)で行う必要があり、(k8sのnodeを作るときにちょっと工夫が必要です。)そのzoneと同じ場所にdiskも作成する必要があります。
terraformの定義だと以下のような感じ
resource "google_compute_disk" "your-gce-disk-name" {
name = "your-gce-disk-name"
size = 200
type = "pd-ssd"
zone = "asia-northeast2-a"
}
NFS server statefulset
NFS serverのStatefulsetをdeployします。
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: nfs-server
namespace: your-namespace
spec:
serviceName: nfs-server
replicas: 1
selector:
matchLabels:
app: nfs-server
template:
metadata:
labels:
app: nfs-server
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: "topology.kubernetes.io/zone"
operator: In
values:
- "asia-northeast2-a"
containers:
- name: nfs-server
image: gcr.io/google_containers/volume-nfs:0.8
ports:
- name: nfs
containerPort: 2049
- name: mountd
containerPort: 20048
- name: rpcbind
containerPort: 111
securityContext:
privileged: true
volumeMounts:
- mountPath: /exports
name: data
volumes:
- name: data
gcePersistentDisk:
pdName: your-gce-disk-name
fsType: ext4
NFS server service
次に、statefulsetの各種ポートに対応したサービスをdeployします。
apiVersion: v1
kind: Service
metadata:
name: nfs-server
namespace: your-namespace
spec:
ports:
- name: nfs
port: 2049
targetPort: nfs
- name: mountd
port: 20048
targetPort: mountd
- name: rpcbind
port: 111
targetPort: rpcbind
selector:
app: nfs-server
PVとPVC
最後に、persistent volumeとpersistent volume claimを定義します。
これを、Webアプリケーション側で指定する感じで利用します。
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs
spec:
storageClassName: nfs
capacity:
storage: 200Gi
accessModes:
- ReadWriteMany
nfs:
server: nfs-server.your-namespace.svc.cluster.local # 先程deployしたserviceのcluster内でのhost名を指定します。
path: "/"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs
namespace: your-namespace
spec:
storageClassName: nfs
accessModes:
- ReadWriteMany
resources:
requests:
storage: 200Gi
Webアプリケーションでの利用
apiVersion: apps/v1
kind: Deployment
metadata:
name: server
namespace: your-namespace
labels:
app: server
spec:
replicas: 2
selector:
matchLabels:
app: server
template:
metadata:
labels:
app: server
spec:
containers:
- name: server
image: your-app-container-image
# ここから↓の部分
volumeMounts:
- name: nfs
mountPath: "/path-to-mount-nfs-directory"
volumes:
- name: nfs
persistentVolumeClaim:
claimName: nfs
こちらで、動作確認が取れました。
以上です。
関連する記事
[小〜中規模向け]GKEにTiDBをデプロイする
MySQL互換のNewSQLであるTiDBをGKEにデプロイしてみました。
NATS JetStream Controllerを使ってNATSをGKEにデプロイする
helm chartのnackを使って、NATS JetStreamサーバーをデプロイして、Stream/Consumerをk8sリソースとして管理する
GKEにDragonflydbをデプロイする
redis互換のdragonflydbをGKEにデプロイしました
[GKE]Kafka Strimziをアップグレードする
GKEにデプロイしているKafka Strimzi 0.26.0を0.30.0にアップグレードする