第13章 Kubernetes容器持久化存储(PersistentVolume)

一. PV与PVC的关系

• PersistenVolume(PV): 对存储资源创建和使用的抽象,使得存储作为集群中的资源管理
• PersistentVolumeClaim(PVC): 让用户不需要关心具体的Volume实现细节
PV是提供容量,PVC是消费容量,消费这个过程称为绑定
PV分为:静态和动态

二. PV静态供给及应用案例

1. 创建PV

创建名为my-pv的PV,使用的是网络存储NFS

# cat pv.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-pv
spec:
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteMany
  nfs:
    path: /data/nfs/www
    server: 10.40.6.214

注意:10.40.6.214 这台nfs服务器必须存在/data/nfs/www目录,否则容器启动失败
# kubectl create -f pv.yaml
# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                  STORAGECLASS          REASON   AGE
my-pv                                      5Gi        RWX            Retain           Available                                                         48s

2. 创建PVC

创建PVC也就是卷需求模板, 这yaml配置建议和创建Deployment pod的yaml 文件统一到一个文件,使用"---"分割即可

# cat pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 5Gi

# kubectl create -f pvc.yaml
# kubectl get pvc
NAME                           STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/my-pvc   Bound    my-pv    5Gi        RWX                           8m47s

3. PV与PVC绑定

启动容器应用PVC,这个消费过程称为绑定,绑定是否成功主要有三要素:名称、容量和访问模式。

# cat pod-pvc.yaml
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: 10.40.6.165/library/nginx:v1
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
        ports:
        - containerPort: 80
      volumes:
      - name: www
        persistentVolumeClaim:
          claimName: my-pvc


# kubectl create -f pod-pvc.yaml
# kubectl get pv,pvc
NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                  STORAGECLASS          REASON   AGE
persistentvolume/my-pv                                      5Gi        RWX            Retain           Bound    default/my-pvc                                        12m

NAME                           STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/my-pvc   Bound    my-pv    5Gi        RWX                           8m47s

# kubectl get pod

Kubernetes支持持久卷的存储插件:
https://kubernetes.io/docs/concepts/storage/persistent-volumes/

三. PV动态供给及应用案例

Dynamic Provisioning 机制工作的核心在于StorageClass的API对象。
StorageClass 声明存储插件,用于自动创建PVC。

1. 创建PV动态供给流程

image.png

NFS 默认是不支持PV动态供给,需要插件完成, 这插件也是一个pod
Kubernetes支持动态供给的存储插件:
https://kubernetes.io/docs/concepts/storage/storage-classes/

NFS 动态供给存储插件:
https://github.com/kubernetes-incubator/external-storage/tree/master/nfs-client

2. 创建存储类(StorageClass)

# cat storageclass-nfs.yaml 
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
provisioner: fuseim.pri/ifs # or choose another name, must match deployment's env PROVISIONER_NAME'
parameters:
  archiveOnDelete: "true"

# kubectl create -f storageclass-nfs.yaml
# kubectl get storageclass
NAME                  PROVISIONER      AGE
managed-nfs-storage   fuseim.pri/ifs   120m

3. PV动态供给apiserver授权

NFS动态供给插件动态创建PV,要连接apiserver, 所以需要ServiceAccount授权

# cat rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner

---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - 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: ["list", "watch", "create", "update", "patch"]

---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    namespace: default
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
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
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io

# kubectl create -f rbac.yaml

4. 创建NFS动态供给插件(Pod)

动态供给插件(Pod)动态创建PV,需要访问apiverser, 所以要指定刚创建的serviceAccount: nfs-client-provisioner

# cat deployment-nfs.yaml 
apiVersion: apps/v1beta1 
kind: Deployment
metadata:
  name: nfs-client-provisioner
spec:
  replicas: 1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccount: nfs-client-provisioner
      containers:
        - name: nfs-client-provisioner
          image: quay.io/external_storage/nfs-client-provisioner:latest
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: fuseim.pri/ifs
            - name: NFS_SERVER
              value: 10.40.6.214
            - name: NFS_PATH
              value: /data/nfs
      volumes:
        - name: nfs-client-root
          nfs:
            server: 10.40.6.214
            path: /data/nfs


# kubectl create -f deployment-nfs.yaml
# kubectl get deploy,pod
NAME                                           DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
deployment.extensions/nfs-client-provisioner   1         1         1            1           117m

NAME                                          READY   STATUS    RESTARTS   AGE
pod/nfs-client-provisioner-6c6f8f9bd6-nclwf   1/1     Running   0          117m

5. PV动态供给应用案例

创建一个statefulset 和 headless service 的mysql服务,在yaml文件定义使用 managed-nfs-storage StorageClass创建PVC。

# cat mysql-statefulset.yaml 
apiVersion: v1
kind: Service
metadata:
  name: mysql
  labels:
    app: mysql
spec:
  ports:
  - port: 3306
    name: mysql
  clusterIP: None
  selector:
    app: mysql-public

---

apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: db
spec:
  serviceName: mysql
  template:
    metadata:
      labels:
        app: mysql-public
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "123456"
        - name: MYSQL_DATABASE
          value: test
        ports:
        - containerPort: 3306
        volumeMounts:
        - mountPath: "/var/lib/mysql"
          name: mysql-data
      volumes:
      - name: mysql-data
        persistentVolumeClaim:
          claimName: mysql-pvc

---

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pvc
  namespace: default
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: managed-nfs-storage
  resources:
    requests:
      storage: 8Gi

# kubectl create -f mysql-statefulset.yaml
# kubectl get svc,pod,pv,pvc
NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
service/mysql        ClusterIP   None         <none>        3306/TCP   58s

NAME                                          READY   STATUS    RESTARTS   AGE
pod/db-0                                      1/1     Running   0          58s

NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                  STORAGECLASS          REASON   AGE
persistentvolume/pvc-a81a2372-9652-11e9-95a4-005056b66bc1   8Gi        RWX            Delete           Bound    default/mysql-pvc      managed-nfs-storage            44s

NAME                              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
persistentvolumeclaim/mysql-pvc   Bound    pvc-a81a2372-9652-11e9-95a4-005056b66bc1   8Gi        RWX            managed-nfs-storage   58s


# kubectl run -it --image mysql:5.7 mysql-client --restart Never --rm /bin/bash
root@mysql-client:/# mysql -h db-0.mysql -uroot -p123456
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
| test               |
+--------------------+
5 rows in set (0.01 sec)

mysql> 

五. StatefulSet 存储状态管理机制

创建一个nginx headless service 和StatefulSet pod,并创建挂载pv与pvc
https://kubernetes.io/docs/tutorials/stateful-application/basic-stateful-set/

# cat nginx-statefulset-pv.yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  selector:
    matchLabels:
      app: nginx
  serviceName: "nginx"
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: nginx
        image: nginx 
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "managed-nfs-storage"
      resources:
        requests:
          storage: 1Gi

# kubectl create -f nginx-statefulset-pv.yaml
# kubectl get pod
NAME                                      READY   STATUS    RESTARTS   AGE
web-0                                     1/1     Running   0          21s
web-1                                     1/1     Running   0          19s

查看有状态应用对存储做了哪些维护,及查看如何动态创建PV :

# kubectl get pv,pvc
NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                  STORAGECLASS          REASON   AGE
persistentvolume/pvc-96003cc3-9655-11e9-95a4-005056b66bc1   1Gi        RWO            Delete           Bound    default/www-web-0      managed-nfs-storage            2m18s
persistentvolume/pvc-977007f8-9655-11e9-95a4-005056b66bc1   1Gi        RWO            Delete           Bound    default/www-web-1      managed-nfs-storage            2m16s

NAME                              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
persistentvolumeclaim/www-web-0   Bound    pvc-96003cc3-9655-11e9-95a4-005056b66bc1   1Gi        RWO            managed-nfs-storage   2m18s
persistentvolumeclaim/www-web-1   Bound    pvc-977007f8-9655-11e9-95a4-005056b66bc1   1Gi        RWO            managed-nfs-storage   2m16s

到nfs 服务器查看 /data/nfs/目录,会自动创建pv相应的目录
# ll /data/nfs/
total 4
drwxrwxrwx 2 root root  6 Jun 24 15:56 default-www-web-0-pvc-96003cc3-9655-11e9-95a4-005056b66bc1
drwxrwxrwx 2 root root  6 Jun 24 15:56 default-www-web-1-pvc-977007f8-9655-11e9-95a4-005056b66bc1

这里的PVC有唯一标识: 0、1,www-web-(0|1),为每个pod提供不同的存储,当某个pod 宕机重新拉起会自动去找对应PVC,比如web-0 pod宕机,重新拉起时会去找到www-web-0,保持pod对应的PVC 是唯一的

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容