Sharing an NFS mount across two persistent volume claims
Overview
The following use case describes how a cluster administrator wanting to leverage shared storage for use by two separate containers would configure the solution. This example highlights the use of NFS, but can easily be adapted to other shared storage types, such as GlusterFS. In addition, this example will show configuration of pod security as it relates to shared storage.
Persistent Storage Using NFS provides an explanation of persistent volumes (PVs), persistent volume claims (PVCs), and using NFS as persistent storage. This topic shows and end-to-end example of using an existing NFS cluster and OKD persistent store, and assumes an existing NFS server and exports exist in your OKD infrastructure.
All |
Creating the Persistent Volume
Before creating the PV object in OKD, the persistent volume (PV) file is defined:
Example 1. Persistent Volume Object Definition Using NFS
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv (1)
spec:
capacity:
storage: 1Gi (2)
accessModes:
- ReadWriteMany (3)
persistentVolumeReclaimPolicy: Retain (4)
nfs: (5)
path: /opt/nfs (6)
server: nfs.f22 (7)
readOnly: false
1 | The name of the PV, which is referenced in pod definitions or displayed in various oc volume commands. |
2 | The amount of storage allocated to this volume. |
3 | accessModes are used as labels to match a PV and a PVC. They currently do not define any form of access control. |
4 | The volume reclaim policy Retain indicates that the volume will be preserved after the pods accessing it terminates. |
5 | This defines the volume type being used, in this case the NFS plug-in. |
6 | This is the NFS mount path. |
7 | This is the NFS server. This can also be specified by IP address. |
Save the PV definition to a file, for example nfs-pv.yaml, and create the persistent volume:
# oc create -f nfs-pv.yaml
persistentvolume "nfs-pv" created
Verify that the persistent volume was created:
# oc get pv
NAME LABELS CAPACITY ACCESSMODES STATUS CLAIM REASON AGE
nfs-pv <none> 1Gi RWX Available 37s
Creating the Persistent Volume Claim
A persistent volume claim (PVC) specifies the desired access mode and storage capacity. Currently, based on only these two attributes, a PVC is bound to a single PV. Once a PV is bound to a PVC, that PV is essentially tied to the PVC’s project and cannot be bound to by another PVC. There is a one-to-one mapping of PVs and PVCs. However, multiple pods in the same project can use the same PVC. This is the use case we are highlighting in this example.
Example 2. PVC Object Definition
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfs-pvc (1)
spec:
accessModes:
- ReadWriteMany (2)
resources:
requests:
storage: 1Gi (3)
1 | The claim name is referenced by the pod under its volumes section. |
2 | As mentioned above for PVs, the accessModes do not enforce access right, but rather act as labels to match a PV to a PVC. |
3 | This claim will look for PVs offering 1Gi or greater capacity. |
Save the PVC definition to a file, for example nfs-pvc.yaml, and create the PVC:
# oc create -f nfs-pvc.yaml
persistentvolumeclaim "nfs-pvc" created
Verify that the PVC was created and bound to the expected PV:
# oc get pvc
NAME LABELS STATUS VOLUME CAPACITY ACCESSMODES AGE
nfs-pvc <none> Bound nfs-pv 1Gi RWX 24s
(1)
1 | The claim, nfs-pvc, was bound to the nfs-pv PV. |
Ensuring NFS Volume Access
Access is necessary to a node in the NFS server. On this node, examine the NFS export mount:
[root@nfs nfs]# ls -lZ /opt/nfs/
total 8
-rw-r--r--. 1 root 100003 system_u:object_r:usr_t:s0 10 Oct 12 23:27 test2b
(1)
(2)
1 | the owner has ID 0. |
2 | the group has ID 100003. |
In order to access the NFS mount, the container must match the SELinux label, and either run with a UID of 0, or with 100003 in its supplemental groups range. Gain access to the volume by matching the NFS mount’s groups, which will be defined in the pod definition below.
By default, SELinux does not allow writing from a pod to a remote NFS server. To enable writing to NFS volumes with SELinux enforcing on each node, run:
# setsebool -P virt_use_nfs on
Creating the Pod
A pod definition file or a template file can be used to define a pod. Below is a pod specification that creates a single container and mounts the NFS volume for read-write access:
Example 3. Pod Object Definition
apiVersion: v1
kind: Pod
metadata:
name: hello-openshift-nfs-pod (1)
labels:
name: hello-openshift-nfs-pod
spec:
containers:
- name: hello-openshift-nfs-pod
image: openshift/hello-openshift (2)
ports:
- name: web
containerPort: 80
volumeMounts:
- name: nfsvol (3)
mountPath: /usr/share/nginx/html (4)
securityContext:
supplementalGroups: [100003] (5)
privileged: false
volumes:
- name: nfsvol
persistentVolumeClaim:
claimName: nfs-pvc (6)
1 | The name of this pod as displayed by oc get pod . |
2 | The image run by this pod. |
3 | The name of the volume. This name must be the same in both the containers and volumes sections. |
4 | The mount path as seen in the container. |
5 | The group ID to be assigned to the container. |
6 | The PVC that was created in the previous step. |
Save the pod definition to a file, for example nfs.yaml, and create the pod:
# oc create -f nfs.yaml
pod "hello-openshift-nfs-pod" created
Verify that the pod was created:
# oc get pods
NAME READY STATUS RESTARTS AGE
hello-openshift-nfs-pod 1/1 Running 0 4s
More details are shown in the oc describe pod
command:
[root@ose70 nfs]# oc describe pod hello-openshift-nfs-pod
Name: hello-openshift-nfs-pod
Namespace: default (1)
Image(s): fedora/S3
Node: ose70.rh7/192.168.234.148 (2)
Start Time: Mon, 21 Mar 2016 09:59:47 -0400
Labels: name=hello-openshift-nfs-pod
Status: Running
Reason:
Message:
IP: 10.1.0.4
Replication Controllers: <none>
Containers:
hello-openshift-nfs-pod:
Container ID: docker://a3292104d6c28d9cf49f440b2967a0fc5583540fc3b062db598557b93893bc6f
Image: fedora/S3
Image ID: docker://403d268c640894cbd76d84a1de3995d2549a93af51c8e16e89842e4c3ed6a00a
QoS Tier:
cpu: BestEffort
memory: BestEffort
State: Running
Started: Mon, 21 Mar 2016 09:59:49 -0400
Ready: True
Restart Count: 0
Environment Variables:
Conditions:
Type Status
Ready True
Volumes:
nfsvol:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: nfs-pvc (3)
ReadOnly: false
default-token-a06zb:
Type: Secret (a secret that should populate this volume)
SecretName: default-token-a06zb
Events: (4)
FirstSeen LastSeen Count From SubobjectPath Reason Message
───────── ──────── ───── ──── ───────────── ────── ───────
4m 4m 1 {scheduler } Scheduled Successfully assigned hello-openshift-nfs-pod to ose70.rh7
4m 4m 1 {kubelet ose70.rh7} implicitly required container POD Pulled Container image "openshift3/ose-pod:v3.1.0.4" already present on machine
4m 4m 1 {kubelet ose70.rh7} implicitly required container POD Created Created with docker id 866a37108041
4m 4m 1 {kubelet ose70.rh7} implicitly required container POD Started Started with docker id 866a37108041
4m 4m 1 {kubelet ose70.rh7} spec.containers{hello-openshift-nfs-pod} Pulled Container image "fedora/S3" already present on machine
4m 4m 1 {kubelet ose70.rh7} spec.containers{hello-openshift-nfs-pod} Created Created with docker id a3292104d6c2
4m 4m 1 {kubelet ose70.rh7} spec.containers{hello-openshift-nfs-pod} Started Started with docker id a3292104d6c2
1 | The project (namespace) name. |
2 | The IP address of the OKD node running the pod. |
3 | The PVC name used by the pod. |
4 | The list of events resulting in the pod being launched and the NFS volume being mounted. The container will not start correctly if the volume cannot mount. |
There is more internal information, including the SCC used to authorize the pod, the pod’s user and group IDs, the SELinux label, and more, shown in the oc get pod <name> -o yaml
command:
[root@ose70 nfs]# oc get pod hello-openshift-nfs-pod -o yaml
apiVersion: v1
kind: Pod
metadata:
annotations:
openshift.io/scc: restricted (1)
creationTimestamp: 2016-03-21T13:59:47Z
labels:
name: hello-openshift-nfs-pod
name: hello-openshift-nfs-pod
namespace: default (2)
resourceVersion: "2814411"
selflink: /api/v1/namespaces/default/pods/hello-openshift-nfs-pod
uid: 2c22d2ea-ef6d-11e5-adc7-000c2900f1e3
spec:
containers:
- image: fedora/S3
imagePullPolicy: IfNotPresent
name: hello-openshift-nfs-pod
ports:
- containerPort: 80
name: web
protocol: TCP
resources: {}
securityContext:
privileged: false
terminationMessagePath: /dev/termination-log
volumeMounts:
- mountPath: /usr/share/S3/html
name: nfsvol
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
name: default-token-a06zb
readOnly: true
dnsPolicy: ClusterFirst
host: ose70.rh7
imagePullSecrets:
- name: default-dockercfg-xvdew
nodeName: ose70.rh7
restartPolicy: Always
securityContext:
supplementalGroups:
- 100003 (3)
serviceAccount: default
serviceAccountName: default
terminationGracePeriodSeconds: 30
volumes:
- name: nfsvol
persistentVolumeClaim:
claimName: nfs-pvc (4)
- name: default-token-a06zb
secret:
secretName: default-token-a06zb
status:
conditions:
- lastProbeTime: null
lastTransitionTime: 2016-03-21T13:59:49Z
status: "True"
type: Ready
containerStatuses:
- containerID: docker://a3292104d6c28d9cf49f440b2967a0fc5583540fc3b062db598557b93893bc6f
image: fedora/S3
imageID: docker://403d268c640894cbd76d84a1de3995d2549a93af51c8e16e89842e4c3ed6a00a
lastState: {}
name: hello-openshift-nfs-pod
ready: true
restartCount: 0
state:
running:
startedAt: 2016-03-21T13:59:49Z
hostIP: 192.168.234.148
phase: Running
podIP: 10.1.0.4
startTime: 2016-03-21T13:59:47Z
1 | The SCC used by the pod. |
2 | The project (namespace) name. |
3 | The supplemental group ID for the pod (all containers). |
4 | The PVC name used by the pod. |
Creating an Additional Pod to Reference the Same PVC
This pod definition, created in the same namespace, uses a different container. However, we can use the same backing storage by specifying the claim name in the volumes section below:
Example 4. Pod Object Definition
apiVersion: v1
kind: Pod
metadata:
name: busybox-nfs-pod (1)
labels:
name: busybox-nfs-pod
spec:
containers:
- name: busybox-nfs-pod
image: busybox (2)
command: ["sleep", "60000"]
volumeMounts:
- name: nfsvol-2 (3)
mountPath: /usr/share/busybox (4)
readOnly: false
securityContext:
supplementalGroups: [100003] (5)
privileged: false
volumes:
- name: nfsvol-2
persistentVolumeClaim:
claimName: nfs-pvc (6)
1 | The name of this pod as displayed by oc get pod . |
2 | The image run by this pod. |
3 | The name of the volume. This name must be the same in both the containers and volumes sections. |
4 | The mount path as seen in the container. |
5 | The group ID to be assigned to the container. |
6 | The PVC that was created earlier and is also being used by a different container. |
Save the pod definition to a file, for example nfs-2.yaml, and create the pod:
# oc create -f nfs-2.yaml
pod "busybox-nfs-pod" created
Verify that the pod was created:
# oc get pods
NAME READY STATUS RESTARTS AGE
busybox-nfs-pod 1/1 Running 0 3s
More details are shown in the oc describe pod
command:
[root@ose70 nfs]# oc describe pod busybox-nfs-pod
Name: busybox-nfs-pod
Namespace: default
Image(s): busybox
Node: ose70.rh7/192.168.234.148
Start Time: Mon, 21 Mar 2016 10:19:46 -0400
Labels: name=busybox-nfs-pod
Status: Running
Reason:
Message:
IP: 10.1.0.5
Replication Controllers: <none>
Containers:
busybox-nfs-pod:
Container ID: docker://346d432e5a4824ebf5a47fceb4247e0568ecc64eadcc160e9bab481aecfb0594
Image: busybox
Image ID: docker://17583c7dd0dae6244203b8029733bdb7d17fccbb2b5d93e2b24cf48b8bfd06e2
QoS Tier:
cpu: BestEffort
memory: BestEffort
State: Running
Started: Mon, 21 Mar 2016 10:19:48 -0400
Ready: True
Restart Count: 0
Environment Variables:
Conditions:
Type Status
Ready True
Volumes:
nfsvol-2:
Type: PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
ClaimName: nfs-pvc
ReadOnly: false
default-token-32d2z:
Type: Secret (a secret that should populate this volume)
SecretName: default-token-32d2z
Events:
FirstSeen LastSeen Count From SubobjectPath Reason Message
───────── ──────── ───── ──── ───────────── ────── ───────
4m 4m 1 {scheduler } Scheduled Successfully assigned busybox-nfs-pod to ose70.rh7
4m 4m 1 {kubelet ose70.rh7} implicitly required container POD Pulled Container image "openshift3/ose-pod:v3.1.0.4" already present on machine
4m 4m 1 {kubelet ose70.rh7} implicitly required container POD Created Created with docker id 249b7d7519b1
4m 4m 1 {kubelet ose70.rh7} implicitly required container POD Started Started with docker id 249b7d7519b1
4m 4m 1 {kubelet ose70.rh7} spec.containers{busybox-nfs-pod} Pulled Container image "busybox" already present on machine
4m 4m 1 {kubelet ose70.rh7} spec.containers{busybox-nfs-pod} Created Created with docker id 346d432e5a48
4m 4m 1 {kubelet ose70.rh7} spec.containers{busybox-nfs-pod} Started Started with docker id 346d432e5a48
As you can see, both containers are using the same storage claim that is attached to the same NFS mount on the back end.