Help us understand the problem. What is going on with this article?

GKE上にNFSを構築する方法

別の記事で永続ディスク(Persistent Disk)設定方法を紹介しましたが、永続ディスクの制限は複数ノードからマウントして同時に読み書きできない。
本記事では、NFS(Network File System)を利用して、その制限を解決する方法を紹介致します。

実施手順

  • Persistent Disk作成
  • Persistent Diskフォーマット
  • Persistent Diskを使って、NFSサーバ立ち上げ
  • NFSを使って、GKE中にストレージを作成
  • GKEのストレージマウントのPod作成

最初の2つのステップ(Persistent Disk作成、とPersistent Diskフォーマット)は別の記事で紹介したため、それらの記事を参照してください。

※本手順はGCPとgcloudコマンドの利用経験があることが望ましいです。

ワークフォルダの構成

nfs_on_gke
├── README.md
├── cloudbuild.dummyjob.yaml
├── deployment
│   ├── dummy_job_01.deployment.yaml
│   └── dummy_job_02.deployment.yaml
├── dummyjob.Dockerfile
├── job
│   └── dummyjob.go
├── nfs-container.deployment.yaml
├── nfs-service.deployment.yaml
└── nfs-volume.yaml

1. Persistent Diskを使って、NFSサーバ立ち上げ

nfs-container.deployment.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nfs-server
spec:
  replicas: 1
  selector:
    matchLabels:
      role: nfs-server
  template:
    metadata:
      labels:
        role: nfs-server
    spec:
      containers:
      - name: nfs-server
        image: gcr.io/google_containers/volume-nfs:latest
        ports:
          - name: nfs
            containerPort: 2049
          - name: mountd
            containerPort: 20048
          - name: rpcbind
            containerPort: 111
        securityContext:
          privileged: true
        volumeMounts:
          - mountPath: /exports
            name: mypvc
      volumes:
        - name: mypvc
          gcePersistentDisk:
            pdName: gce-nfs-disk
            fsType: ext4
nfs-service.deployment.yaml
apiVersion: v1
kind: Service
metadata:
  name: nfs-server
spec:
  ports:
    - name: nfs
      port: 2049
    - name: mountd
      port: 20048
    - name: rpcbind
      port: 111
  selector:
    role: nfs-server
  type: LoadBalancer

GKEにデプロイ

# クラスタ作成
gcloud container clusters create ds-gke-small-cluster \
    --project ds-project \
    --zone asia-northeast1-b \
    --machine-type n1-standard-1 \
    --num-nodes 1 \
    --enable-stackdriver-kubernetes

# k8sコントロールツールをインストール
gcloud components install kubectl
kubectl version

# GKEのクラスタにアクセスするため、credentialsを設定
gcloud container clusters get-credentials --zone asia-northeast1-b ds-gke-small-cluster

# デプロイ NFSサーバ
kubectl apply -f nfs-container.deployment.yaml

# 外からアクセスするため、NFSサービスをデプロイ。クラスタ内でアクセスしかない場合、このステップをスキップ
kubectl apply -f nfs-service.deployment.yaml

デプロイ後の確認
gcp_gke_kubernetes_nfs_devsamurai_001.png
gcp_gke_kubernetes_nfs_devsamurai_002.png

2. NFSを使って、GKE中にストレージを作成

nfs-volume.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-data-volume
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany
  nfs:
    server: "xx.xx.xx.xx"
    path: "/exports"
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: nfs-data-volume
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: ""
  resources:
    requests:
      storage: 10Gi

ボリューム定義実施

# PersistentVolumeとPersistentVolumeClaimを作成。複数接続で読み書きできるaccessModes(ReadWriteMany)
kubectl apply -f nfs-volume.yaml

定義実施後確認
gcp_gke_kubernetes_nfs_devsamurai_003.png

3. GKEのストレージマウントのPod作成

golangで簡単なジョブを作成する。
ジョブ処理はoutput-pathにサンプル10ファイルを作成する。予定は複数ジョブを稼働して、共有用のNFSにファイルを作成する。

dummyjob.go
package main

import (
    "flag"
    "fmt"
    "io/ioutil"
    "log"
    "os"
    "time"
)

var jobName = flag.String("job-name", "", "specify job name")
var outputPath = flag.String("output-path", "", "specify output path for job")

func main() {

    flag.Parse()

    outlog("Dummy Job start ...")

    for i := 0; i < 10; i++ {
        unixtime := time.Now().Unix()
        fileName := fmt.Sprint(*jobName, "_", unixtime, ".txt")

        // make a file
        file, err := os.Create(*outputPath + "/" + fileName)
        if err != nil {
            log.Fatal(err)
        }
        outlog("created a file: ", fileName)

        // out some
        file.WriteString("hello from " + *jobName)
        file.Close()

        // sleep to delay process
        time.Sleep(2 * time.Second)
    }

    // list all file in path
    outlog("List all files:")
    files, err := ioutil.ReadDir(*outputPath)
    if err != nil {
        log.Fatal(err)
    }

    for _, file := range files {
        outlog(file.Name())
    }

    outlog("Dummy Job finished.")

}

func outlog(args ...string) {
    log.Println(*jobName+":", args)
}
dummyjob.Dockerfile
FROM alpine:latest
WORKDIR /app
COPY ./dummyjob /app
cloudbuild.dummyjob.yaml
steps:
# go build
- name: golang:1.12
  dir: .
  args: ['go', 'build', '-o', 'dummyjob', 'job/dummyjob.go']
  env: ["CGO_ENABLED=0"]

# docker build
- name: 'gcr.io/cloud-builders/docker'
  dir: .
  args: [
         'build',
         '-t', '${_GCR_REGION}/${_GCR_PROJECT}/${_GCR_IMAGE_NAME}:${_GCR_TAG}',
         '-f', 'dummyjob.Dockerfile',
         '--cache-from', '${_GCR_REGION}/${_GCR_PROJECT}/${_GCR_IMAGE_NAME}:${_GCR_TAG}',
         '.'
        ]

# push image to Container Registry
- name: 'gcr.io/cloud-builders/docker'
  args: ["push", '${_GCR_REGION}/${_GCR_PROJECT}/${_GCR_IMAGE_NAME}']

substitutions:
  # # GCR region name to push image
  _GCR_REGION: asia.gcr.io
  # # Project ID
  _GCR_PROJECT: project-abc123
  # # Image name
  _GCR_IMAGE_NAME: dummy-job
  # # Image tag
  _GCR_TAG: latest

イメージをビルドして、2つのジョブをデプロイする

# build dummy-job image on Container Registry
gcloud builds submit --config cloudbuild.dummyjob.yaml

# deploy job
kubectl apply -f deployment/dummy_job_01.deployment.yaml
kubectl apply -f deployment/dummy_job_02.deployment.yaml

ビルドイメージの確認
gcp_gke_kubernetes_nfs_devsamurai_004.png

デプロイジョブはGKEの中に確認
gcp_gke_kubernetes_nfs_devsamurai_005.png

2つのジョブはNFSを共有利用できることを稼働ログで確認できます。
gcp_gke_kubernetes_nfs_devsamurai_006.png

NFSを共有して読み書きできることを確認できました。

本記事で利用したソースコードはこちら

https://github.com/itdevsamurai/gke/tree/master/nfs

最後まで読んで頂き、どうも有難う御座います!

DevSamurai 橋本

関連記事:GKEの中で永続ディスク(Persistent Disk)の利用方法

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした