【クラウドネイティブ】kubernetes ストレージ(ボリューム)について

 

 

目次

1 ボリュームボリューム

2種類のボリューム

3 使用方法

一般的な4種類

5 PV&PVC


1 ボリュームボリューム

公式 Web サイトのアドレス: Volume | Kubernetes

コンテナ内のファイルは一時的にディスクに保存されるため、コンテナ内で実行されているより重要なアプリケーションにいくつかの問題が発生します。問題の 1 つは、コンテナーがクラッシュするとファイルが失われることです。kubelet はコンテナーを再起動しますが、コンテナーはクリーンな状態で再起動されます。2 番目の問題は、Pod同じコンテナ内で複数のコンテナを実行し、ファイルを共有するときに発生します。Kubernetes Volume 这一抽象概念能够解决这两个问题。

2種類のボリューム

Kubernetes は多くの種類のボリュームをサポートします。ポッドは、任意の数のボリューム タイプを同時に使用できます。一時ボリュームタイプの存続期間はポッドの存続期間と同じですが、永続ボリュームはポッドよりも存続する可能性があります。Kubernetes は、Pod が存在しなくなった場合にも一時ボリュームを破棄しますが、Kubernetes は永続ボリュームを破棄しません。特定のポッド内のどのタイプのボリュームでも、コンテナーの再起動中にデータが失われることはありません。

ボリュームのコアは、データを含む可能性があり、ポッド内のコンテナーからアクセスできるディレクトリです。使用されるさまざまなタイプのボリュームによって、ディレクトリの形成方法、データの保存にどのメディアが使用されるか、ディレクトリに何が保存されるかが決まります。一般的に使用されるボリューム タイプには、configMap、emptyDir、local、nfs、secretなどが含まれます。

  • ConfigMap: 構成ファイルはキーと値のペアの形式で ConfigMap に保存でき、Pod でファイルまたは環境変数として使用できます。ConfigMap は、アプリケーション構成ファイルなどの機密性の低い構成情報を保存するために使用できます。

  • EmptyDir: ポッドに一時データを保存するために使用できる空のディレクトリです。ポッドが削除されると、ディレクトリも削除されます。

  • ローカル: ローカル ファイル システム内のディレクトリまたはファイルをポッド内のボリュームにマップし、ポッド内のファイルまたはデータを共有するために使用できます。

  • NFS: ネットワーク上の 1 つ以上の NFS 共有ディレクトリをポッドのボリュームにマウントします。これを使用して、複数のポッド間でデータを共有できます。

  • Secret: 機密情報を暗号文の形式で Secret に保存し、Pod 内でファイルまたは環境変数として使用できます。Secret は、ユーザー名、パスワード、証明書などの機密情報を保存するために使用できます。

3 使用方法

ボリュームを使用する場合は、.spec.volumesPodに提供するボリュームをフィールドに設定し、.spec.containers[*].volumeMountsコンテナ内のボリュームの実装位置をフィールドで宣言します。コンテナ内のプロセスによって表示されるファイル システムのビューは、コンテナ イメージの初期コンテンツと、コンテナにマウントされたボリューム (定義されている場合) で構成されます。ルート ファイル システムはコンテナ イメージの内容と一致します。このファイル システムでの書き込み操作は許可されている場合、コンテナー内の後続のプロセスがファイル システムにアクセスするときに表示される内容に影響します。

apiVersion: v1
kind: Pod
metadata:
  name: configmap-pod
spec:
  containers:
    - name: test
      image: busybox:1.28
      volumeMounts:
            ..........
  volumes:
    ............

一般的な4種類

4.1 空のディレクトリ

apiVersion: v1
kind: Pod
metadata:
  name: emptydir-example
spec:
  containers:
    - name: writer
      image: busybox
      command: ["/bin/sh", "-c", "echo 'Hello World!' > /data/hello.txt ; sleep 3600"]
      volumeMounts:
        - name: shared-data
          mountPath: /data
    - name: reader
      image: busybox
      command: ["/bin/sh", "-c", "cat /data/hello.txt ; sleep 3600"]
      volumeMounts:
        - name: shared-data
          mountPath: /data
  volumes:
    - name: shared-data
      emptyDir: {}

总结: emptyDir 是 Host 上创建的临时目录,其优点是能够方便地为 Pod 中的容器提供共享存储,不需要额外的配置。它不具备持久性,如果Pod 不存在了,emptyDir 也就没有了。根据这个特性,emptyDir 特别适合 Pod 中的容器需要临时共享存储空间的场景,比如前面的生产者消费者用例。

4.2 ホストパス

apiVersion: v1
kind: Pod
metadata:
  name: busybox-hostpath
spec:
  containers:
  - name: busybox
    image: busybox
    command: ["/bin/sh", "-c", "echo 'hello' > /data/data.txt && sleep 3600"]
    volumeMounts:
    - name: data
      mountPath: /data
  volumes:
  - name: data
    hostPath:
      path: /data/hostpath

总结: 如果 Pod 被销毀了,hostPath 对应的目录还是会被保留,从这一点来看,hostPath 的持久性比emptyDir 强。不过一旦Host 崩溃,hostPath 也就无法访问了。但是这种方式也带来另外一个问题增加了 pod 与节点的耦合。

4.3 nfs

nfs: ネットワーク ファイルシステム: ネットワーク ファイル ストレージ システム

apiVersion: v1
kind: Pod
metadata:
  name: nfs-test
spec:
  containers:
  - name: busybox
    image: busybox
    command: [ "/bin/sh", "-c", "while true; do sleep 3600; done" ]
    volumeMounts:
    - name: nfs-volume
      mountPath: /mnt/nfs
  volumes:
  - name: nfs-volume
    nfs:
      server: <NFS_SERVER_IP>
      path: /path/to/nfs/share

总结: 相对于 emptyDir 和 hostPath,这种 volume 类型的最大特点就是不依赖 Kuberees Volume 的底层基础设施由独立的存储系统管理,与 Kubernetes 集群是分离的。数据被持久化后,即使整个 Kubernetes 崩溃也不会受损。当然,运维这样的存储系统通常不是一项简单的工作,特别是对可靠性、可用性和扩展性 有较高要求的时候。

5 PV&PVC

5.1 質問

Volume は非常に優れたデータ永続化ソリューションを提供しますが、管理しやすさにはまだ欠点があります。前の nfs の例では、ボリュームを使用するには、ポッドは次の情報を事前に知っている必要があります。

  • 現在のボリュームのタイプと、ボリュームが作成されたことを確認します。

  • ボリュームの特定のアドレス情報を知っている必要があります。

ただし、ポッドは通常、アプリケーション開発者によって保守され、ボリュームは通常、ストレージ システム管理者によって保守されます。上記の情報を取得するには、開発者は管理者に問い合わせるか、自分自身が管理者になる必要があります。これは、アプリケーション開発者とシステム管理者の責任が一緒になるという管理上の問題を引き起こします。システム規模が小さい場合や開発環境であればこの状況でも問題ありませんが、特に本番環境などでクラスタサイズが大きくなると、効率やセキュリティを考慮して解決すべき問題となります。

5.2 PV と PVC

Kubernetes が提供する解決策は ですPersistent Volume 和 Persistent Volume Claim

PersistentVolume (PV) は、管理者によって作成および維持される外部ストレージ システム内のストレージ スペースです。ボリュームと同様に、PV は永続的であり、そのライフサイクルはポッドから独立しています。

Persistent Volume Claim (PVC) は PV に対するクレームです。通常、PVC は一般ユーザーによって作成および保守されます。Podにストレージリソースを割り当てる必要がある場合、ユーザーはPVCを作成し、ストレージリソースの容量やアクセスモード(読み取り専用など)などの情報を指定すると、Kubernetesが条件を満たすPVを検索して提供します。PersistentVolumeClaim を使用すると、ユーザーは実際のスペースが割り当てられる場所やアクセス方法などの基本的な詳細を気にすることなく、必要なストレージ リソースを Kubernetes に伝えるだけで済みます。これらのストレージ プロバイダーの基礎となる情報は管理者に任されており、管理者のみが Persistent Volume の作成の詳細に注意する必要があります。

5.3 基本的な使い方

  • PVの作成

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
spec:
  capacity:
    storage: 1Gi #指定容量大小
  accessModes: # 访问模式 
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  nfs:
    path: /{nfs-server目录名称}
    server: {nfs-server IP 地址}
  • accessModes:サポートされているアクセス モードは 3 つあります。

    • ReadWriteOnce は、PV を読み取り書き込みモードで単一ノードにマウントできることを意味します

      • この PV は、特定のノードによって読み取り/書き込みモードでのみマウントできます。つまり、この PV はポッドによって特定のノードにのみマウントでき、このポッドはこの PV に対して読み取りおよび書き込み操作を実行できます。この PV を他のノードにマウントしようとすると、失敗します。

    • ReadOnlyMany は、PV を読み取り専用モードで複数のノードにマウントできることを意味します。

      • この PV は複数のノードによって読み取り専用モードでマウントできます。つまり、この PV は複数のポッドによって複数のノードにマウントできます。

    • ReadWriteMany は、PV を読み取り/書き込みモードで複数のノードにマウントできることを意味します。

      • この PV は、読み取り/書き込みモードで複数のノードによってマウントできます。つまり、この PV は複数のノード上の複数のポッドによってマウントできます。

  • persistentVolumeReclaimPolicy: PV のリサイクル ポリシーが 3 つの戦略をサポートすることを指定します。

    • 保持: PVC が削除された後、PV とそのデータを保持し、PV 内のデータを手動でクリーンアップします。

    • 削除: PVC が削除された後、PV とそのデータが自動的に削除されます。

    • リサイクル: PVC を削除した後、PV 内のデータを削除して PV を再利用できるように準備します。

      值得注意的是,永続的なボリューム再利用ポリシー只适用于一些类型的 PV,如 NFS、HostPath、iSCSI 等。对于一些云平台提供的存储,如 AWS EBS 和 Azure Disk,由于底层提供商会自动处理 PV 的回收问题,因此该属性不适用。

  • storageClassName: PV クラスを nfs として指定します。これは PV のカテゴリを設定することに相当し、PVC は該当クラスの PV に適用するクラスを指定できます。

  • PVCの作成

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
  storageClassName: nfs # 通过名字进行选择
  #selector:  通过标签形式
  #  matchLabels:
  #    pv-name: nfs-pv
  • PVCを使用

apiVersion: v1
kind: Pod
metadata:
  name: busybox-nfs
spec:
  containers:
  - name: busybox
    image: busybox
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo 'Hello NFS!' >> /data/index.html; sleep 1; done"]
    volumeMounts:
    - name: nfs-volume
      mountPath: /data
  volumes:
  - name: nfs-volume
    persistentVolumeClaim:
      claimName: nfs-pvc

5.4 動的供給

前の例では、PV を事前に作成し、PVC 経由で PV を申請し、Pod で使用しました。この方法は静的プロビジョニング (Static Provision) と呼ばれ、これに相当するのが動的プロビジョニング (Dynamical Provision) です。つまり、要件が満たされていない場合、PVC 条件の PV が動的に作成されます。静的プロビジョニングと比較して、動的プロビジョニングには明らかな利点があります。事前に PV を作成する必要がないため、管理者の作業負荷が軽減され、効率が高くなります。動的プロビジョニングは、StorageClass を通じて実装されます。StorageClass は PV の作成方法を定義しますが、各 StorageClass には、PV を準備するためにどのボリューム プラグインを使用するかを決定するために使用されるプリペアラー (プロビジョナー) があることに注意してください。このフィールドは必ず指定する必要があります。(ストレージ クラス | Kubernetes ) は動的作成を実現できます。例として NFS を見てみましょう。

  • NFSプロバイダーの定義

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nfs-client-provisioner
      labels:
        app: nfs-client-provisioner
      # replace with namespace where provisioner is deployed
      namespace: kube-system
    spec:
      replicas: 1
      strategy:
        type: Recreate
      selector:
        matchLabels:
          app: nfs-client-provisioner
      template:
        metadata:
          labels:
            app: nfs-client-provisioner
        spec:
          serviceAccountName: nfs-client-provisioner
          containers:
            - name: nfs-client-provisioner
              image: chronolaw/nfs-subdir-external-provisioner:v4.0.2
              volumeMounts:
                - name: nfs-client-root
                  mountPath: /persistentvolumes
              env:
                - name: PROVISIONER_NAME
                  value: k8s-sigs.io/nfs-subdir-external-provisioner
                - name: NFS_SERVER
                  value: 10.15.0.25
                - name: NFS_PATH
                  value: /root/nfs/data
          volumes:
            - name: nfs-client-root
              nfs:
                server: 10.15.0.25
                path: /root/nfs/data
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: nfs-client-provisioner
      # replace with namespace where provisioner is deployed
      namespace: kube-system
    ---
    kind: ClusterRole
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: nfs-client-provisioner-runner
    rules:
      - apiGroups: [""]
        resources: ["nodes"]
        verbs: ["get", "list", "watch"]
      - apiGroups: [""]
        resources: ["persistentvolumes"]
        verbs: ["get", "list", "watch", "create", "delete"]
      - apiGroups: [""]
        resources: ["persistentvolumeclaims"]
        verbs: ["get", "list", "watch", "update"]
      - apiGroups: ["storage.k8s.io"]
        resources: ["storageclasses"]
        verbs: ["get", "list", "watch"]
      - apiGroups: [""]
        resources: ["events"]
        verbs: ["create", "update", "patch"]
    ---
    kind: ClusterRoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: run-nfs-client-provisioner
    subjects:
      - kind: ServiceAccount
        name: nfs-client-provisioner
        # replace with namespace where provisioner is deployed
        namespace: kube-system
    roleRef:
      kind: ClusterRole
      name: nfs-client-provisioner-runner
      apiGroup: rbac.authorization.k8s.io
    ---
    kind: Role
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: leader-locking-nfs-client-provisioner
      # replace with namespace where provisioner is deployed
      namespace: kube-system
    rules:
      - apiGroups: [""]
        resources: ["endpoints"]
        verbs: ["get", "list", "watch", "create", "update", "patch"]
    ---
    kind: RoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: leader-locking-nfs-client-provisioner
      # replace with namespace where provisioner is deployed
      namespace: kube-system
    subjects:
      - kind: ServiceAccount
        name: nfs-client-provisioner
        # replace with namespace where provisioner is deployed
        namespace: kube-system
    roleRef:
      kind: Role
      name: leader-locking-nfs-client-provisioner
      apiGroup: rbac.authorization.k8s.io

  • ストレージクラスの定義

    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: mysql-nfs-sc
    provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
    parameters:
      onDelete: "remain"

  • StorageClass を使用して動的に作成する

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: mysql
      labels:
        app: mysql
    spec:
      serviceName: mysql #headless 无头服务  保证网络标识符唯一  必须存在
      replicas: 1
      template:
        metadata:
          name: mysql
          labels:
            app: mysql
        spec:
          containers:
            - name: mysql
              image: mysql/mysql-server:8.0
              imagePullPolicy: IfNotPresent
              env:
                - name: MYSQL_ROOT_PASSWORD
                  value: root
              volumeMounts:
                - mountPath: /var/lib/mysql #自己容器写入数据目录
                  name: data    #保存到指定一个变量中 变量名字就是 data
              ports:
                - containerPort: 3306
          restartPolicy: Always
      volumeClaimTemplates:  #声明动态创建数据卷模板
        - metadata:
            name: data      # 数据卷变量名称
          spec:
            accessModes:    # 访问模式
              - ReadWriteMany
            storageClassName: mysql-nfs-sc # 使用哪个 storage class 模板存储数据
            resources:
              requests:
                storage: 2G
      selector:
        matchLabels:
          app: mysql

おすすめ

転載: blog.csdn.net/weixin_53678904/article/details/132308948