How to Use Shared Disk PersistentVolumes for Oracle Kubernetes Engine (OKE) in Oracle Cloud Infrastructure (OCI)

上一篇文章我们尝试了在Oracle Cloud的容器云里创建了持久化卷,并且使用该卷创建了一个MySQL数据库的容器。这样数据库里的数据就保存在了容器外部,如果容器崩溃,那么Kubernetes会根据Deployment的定义,重新创建一个容器,而数据则不会丢失。

对于企业在使用存储来说,除了上述的数据持久性保存之外,共享性也是通常会考虑的一个因素,也就是一份存储上的数据同时被多个应用共享读写。

本文阐述如何在Oracle Cloud的容器云中创建和使用共享存储,在这篇文章中我们使用NFS的方式来实现共享。

创建文件系统

首先需要在Oracle Cloud的管理后台创建一个文件系统,菜单项位于File Storage->File Systems。
NewImage

点击页面中的“Create File System”按钮,在新建文件系统的页面中点击“Edit Details”,可以对名字进行修改,实际上直接全部使用默认值也是可以的。
NewImage

为了表意更清晰,我们将文件系统的名字修改为FileSystem-for-OKE,将Export路径修改为“/oke-export”,Mount Target名称不做变化。
这些Oracle Cloud中文件系统的术语的解释,可以参看官方文档。注意的是:其中Export路径在后续的容器配置中会使用到,不过这个路径的名称跟容器中会挂载到的路径没有任何关系,可以随意命名。

修改后的并且创建成功的文件系统,可以在管理后台中看到详细情况。
NewImage

同样,通过oci命令行也可以获得创建成功的文件系统的信息。

$ oci fs file-system list \
> --compartment-id ocid1.tenancy.oc1..aaaaaaaaqxee2wwzpx3s6usguambydweb2q5yfx2y5ux3lwlrpaao4gdun7a \
> --availability-domain lOnA:AP-TOKYO-1-AD-1
{
  "data": [
    {
      "availability-domain": "lOnA:AP-TOKYO-1-AD-1",
      "compartment-id": "ocid1.tenancy.oc1..aaaaaaaaqxee2wwzpx3s6usguambydweb2q5yfx2y5ux3lwlrpaao4gdun7a",
      "defined-tags": {},
      "display-name": "FileSystem-for-OKE",
      "freeform-tags": {},
      "id": "ocid1.filesystem.oc1.ap_tokyo_1.aaaaaaaaaaaafictnzzhillqojxwiotboawxi33lpfxs2mjnmfsc2mia",
      "kms-key-id": "",
      "lifecycle-state": "ACTIVE",
      "metered-bytes": 8704,
      "time-created": "2019-10-21T13:26:40+00:00"
    }
  ]
}

在创建文件系统时,Oracle Cloud会自动创建一个Mount Target,可以在管理后台中看到详细情况。
NewImage

注意这里的IP地址,这个地址在后续创建容器持久化卷的时候也会使用到。

同样,通过oci命令行也可以获得创建成功的挂载目标的信息。

$ oci fs mount-target list \
--compartment-id ocid1.tenancy.oc1..aaaaaaaaqxee2wwzpx3s6usguambydweb2q5yfx2y5ux3lwlrpaao4gdun7a \
--availability-domain lOnA:AP-TOKYO-1-AD-1
{
  "data": [
    {
      "availability-domain": "lOnA:AP-TOKYO-1-AD-1",
      "compartment-id": "ocid1.tenancy.oc1..aaaaaaaaqxee2wwzpx3s6usguambydweb2q5yfx2y5ux3lwlrpaao4gdun7a",
      "defined-tags": {},
      "display-name": "MountTarget-20191021-1322",
      "export-set-id": "ocid1.exportset.oc1.ap_tokyo_1.aaaaaa4np2snfy33nzzhillqojxwiotboawxi33lpfxs2mjnmfsc2mia",
      "freeform-tags": {},
      "id": "ocid1.mounttarget.oc1.ap_tokyo_1.aaaaaa4np2snfy34nzzhillqojxwiotboawxi33lpfxs2mjnmfsc2mia",
      "lifecycle-state": "ACTIVE",
      "private-ip-ids": [
        "ocid1.privateip.oc1.ap-tokyo-1.aaaaaaaa34v43wf2b3j73kme2rtho4rlpm6kit3avszgirkpqm5uspbqnrrq"
      ],
      "subnet-id": "ocid1.subnet.oc1.ap-tokyo-1.aaaaaaaafqsuofe2e34mnfkotolakrzktxmwdasj7dyov3u3jixqablc2qgq",
      "time-created": "2019-10-21T13:26:42+00:00"
    }
  ]
}

可以参看创建文件系统的官方文档

创建PV

创建一个PV的定义yaml文件,内容如下。server部分指定上述的Mount Target的IP地址,path部分指定上述的File System的名字。

$ cat pv-nfs.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteMany
  nfs:
    server: 10.0.10.5
    path: "/oke-export"

创建PV,并检查创建结果。

$ kubectl create -f pv-nfs.yaml

$ kubectl get pv
NAME   CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
nfs    1Gi        RWX            Retain           Available                                   8s

$ kubectl describe pv nfs
Name:            nfs
Labels:          <none>
Annotations:     pv.kubernetes.io/bound-by-controller: yes
Finalizers:      [kubernetes.io/pv-protection]
StorageClass:
Status:          Available
Claim:           default/nfs
Reclaim Policy:  Retain
Access Modes:    RWX
VolumeMode:      Filesystem
Capacity:        1Gi
Node Affinity:   <none>
Message:
Source:
    Type:      NFS (an NFS mount that lasts the lifetime of a pod)
    Server:    10.0.10.5
    Path:      /oke-export
    ReadOnly:  false
Events:        <none>

可以看到现在PV的状态是Available,表示可用,在后续我们创建完PVC之后,这里会显示成Bound,表示该PV已经跟PVC绑定。

创建PVC

创建一个PVC的定义yaml文件,内容如下。

$ cat pvc-nfs.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: ""
  resources:
    requests:
      storage: 1Mi

创建PVC,并检查创建结果。

$ kubectl create -f pvc-nfs.yaml

$ kubectl get pvc
NAME   STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
nfs    Bound    nfs      1Gi        RWX                           4s

$ kubectl describe pvc nfs
Name:          nfs
Namespace:     default
StorageClass:
Status:        Bound
Volume:        nfs
Labels:        <none>
Annotations:   pv.kubernetes.io/bind-completed: yes
               pv.kubernetes.io/bound-by-controller: yes
Finalizers:    [kubernetes.io/pvc-protection]
Capacity:      1Gi
Access Modes:  RWX
VolumeMode:    Filesystem
Events:        <none>
Mounted By:    <none>

创建容器

这里我们使用ReplicationController类型的对象来创建Pod,这样可以指定自动创建多个容器,并共享读写指定的NFS存储。
创建一个RC的定义yaml文件,内容如下。作为测试,我们使用最简单的Nginx镜像,并且指定2个复制。

$ cat rc-nfs.yaml
apiVersion: v1
kind: ReplicationController
metadata:
  name: rc-nfs-test
spec:
  replicas: 2
  selector:
    app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
          - name: nginx
            containerPort: 80
        volumeMounts:
            - name: nfs
              mountPath: "/usr/share/nginx/html"
      volumes:
      - name: nfs
        persistentVolumeClaim:
          claimName: nfs

创建RC,并检查结果。

$ kubectl create -f rc-nfs.yaml

$ kubectl get rc rc-nfs-test
NAME          DESIRED   CURRENT   READY   AGE
rc-nfs-test   2         2         2       6m56s

$ kubectl describe replicationcontrollers/rc-nfs-test
Name:         rc-nfs-test
Namespace:    default
Selector:     app=nginx
Labels:       app=nginx
Annotations:  <none>
Replicas:     2 current / 2 desired
Pods Status:  2 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
  Labels:  app=nginx
  Containers:
   nginx:
    Image:        nginx
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:
      /usr/share/nginx/html from nfs (rw)
  Volumes:
   nfs:
    Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
    ClaimName:  nfs
    ReadOnly:   false
Events:
  Type    Reason            Age   From                    Message
  ----    ------            ----  ----                    -------
  Normal  SuccessfulCreate  16m   replication-controller  Created pod: rc-nfs-test-bqhm9
  Normal  SuccessfulCreate  16m   replication-controller  Created pod: rc-nfs-test-8h884

$ kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
rc-nfs-test-8h884                   1/1     Running   0          3m16s
rc-nfs-test-bqhm9                   1/1     Running   0          3m16s

到目前为止,我们已经创建好了一组(2个)共享使用磁盘的Nginx容器,共享磁盘在容器内的挂载路径是:/usr/share/nginx/html

接下来,测试一下共享读写的效果。计划在一个容器的共享磁盘中创建index.html文件,并且写入了”test sharing disk”这样的文本,之后从另外一个容器中进行查看。

首先,在其中一个容器里创建index.html文件。

$ kubectl exec rc-nfs-test-8h884 touch /usr/share/nginx/html/index.html

写入一行文本。

$ kubectl exec -it rc-nfs-test-8h884 -- /bin/bash
root@rc-nfs-test-8h884:/# cd /usr/share/nginx/html/
root@rc-nfs-test-8h884:/usr/share/nginx/html# ls
index.html
root@rc-nfs-test-8h884:/usr/share/nginx/html# echo "test sharing disk">>/usr/share/nginx/html/index.html

现在我们登录到另外一个容器中,查看是否能够读取到该内容。

$ kubectl exec rc-nfs-test-bqhm9 cat /usr/share/nginx/html/index.html
test sharing disk

Well Done!

Leave a Reply

Your email address will not be published. Required fields are marked *