Dynamic provisioning using EFS
Now that we understand the EFS storage class for Kubernetes, let's create a Persistent Volume and modify the assets
container deployment to mount this volume.
First, let's examine the efspvclaim.yaml
file which defines a PersistentVolumeClaim requesting 5GB of storage from the efs-sc
storage class we created earlier:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: efs-claim
namespace: assets
spec:
accessModes:
- ReadWriteMany
storageClassName: efs-sc
resources:
requests:
storage: 5Gi
We'll update the assets service to:
- Mount the PVC at the location where assets images are stored
- Include an init container that copies the initial images to the EFS volume
- Kustomize Patch
- Deployment/assets
- Diff
apiVersion: apps/v1
kind: Deployment
metadata:
name: assets
spec:
replicas: 2
template:
spec:
initContainers:
- name: copy
image: "public.ecr.aws/aws-containers/retail-store-sample-assets:0.4.0"
command:
["/bin/sh", "-c", "cp -R /usr/share/nginx/html/assets/* /efsvolume"]
volumeMounts:
- name: efsvolume
mountPath: /efsvolume
containers:
- name: assets
volumeMounts:
- name: efsvolume
mountPath: /usr/share/nginx/html/assets
volumes:
- name: efsvolume
persistentVolumeClaim:
claimName: efs-claim
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app.kubernetes.io/created-by: eks-workshop
app.kubernetes.io/type: app
name: assets
namespace: assets
spec:
replicas: 2
selector:
matchLabels:
app.kubernetes.io/component: service
app.kubernetes.io/instance: assets
app.kubernetes.io/name: assets
template:
metadata:
annotations:
prometheus.io/path: /metrics
prometheus.io/port: "8080"
prometheus.io/scrape: "true"
labels:
app.kubernetes.io/component: service
app.kubernetes.io/created-by: eks-workshop
app.kubernetes.io/instance: assets
app.kubernetes.io/name: assets
spec:
containers:
- envFrom:
- configMapRef:
name: assets
image: public.ecr.aws/aws-containers/retail-store-sample-assets:0.4.0
imagePullPolicy: IfNotPresent
livenessProbe:
httpGet:
path: /health.html
port: 8080
periodSeconds: 3
name: assets
ports:
- containerPort: 8080
name: http
protocol: TCP
resources:
limits:
memory: 128Mi
requests:
cpu: 128m
memory: 128Mi
securityContext:
capabilities:
drop:
- ALL
readOnlyRootFilesystem: false
volumeMounts:
- mountPath: /usr/share/nginx/html/assets
name: efsvolume
- mountPath: /tmp
name: tmp-volume
initContainers:
- command:
- /bin/sh
- -c
- cp -R /usr/share/nginx/html/assets/* /efsvolume
image: public.ecr.aws/aws-containers/retail-store-sample-assets:0.4.0
name: copy
volumeMounts:
- mountPath: /efsvolume
name: efsvolume
securityContext: {}
serviceAccountName: assets
volumes:
- name: efsvolume
persistentVolumeClaim:
claimName: efs-claim
- emptyDir:
medium: Memory
name: tmp-volume
app.kubernetes.io/type: app
name: assets
namespace: assets
spec:
- replicas: 1
+ replicas: 2
selector:
matchLabels:
app.kubernetes.io/component: service
app.kubernetes.io/instance: assets
[...]
drop:
- ALL
readOnlyRootFilesystem: false
volumeMounts:
+ - mountPath: /usr/share/nginx/html/assets
+ name: efsvolume
- mountPath: /tmp
name: tmp-volume
+ initContainers:
+ - command:
+ - /bin/sh
+ - -c
+ - cp -R /usr/share/nginx/html/assets/* /efsvolume
+ image: public.ecr.aws/aws-containers/retail-store-sample-assets:0.4.0
+ name: copy
+ volumeMounts:
+ - mountPath: /efsvolume
+ name: efsvolume
securityContext: {}
serviceAccountName: assets
volumes:
+ - name: efsvolume
+ persistentVolumeClaim:
+ claimName: efs-claim
- emptyDir:
medium: Memory
name: tmp-volume
Apply these changes with the following command:
namespace/assets unchanged
serviceaccount/assets unchanged
configmap/assets unchanged
service/assets unchanged
persistentvolumeclaim/efs-claim created
deployment.apps/assets configured
Let's examine the volumeMounts
in the deployment. Notice that our new volume named efsvolume
is mounted at /usr/share/nginx/html/assets
:
- mountPath: /usr/share/nginx/html/assets
name: efsvolume
- mountPath: /tmp
name: tmp-volume
A PersistentVolume (PV) has been automatically created to fulfill our PersistentVolumeClaim (PVC):
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-342a674d-b426-4214-b8b6-7847975ae121 5Gi RWX Delete Bound assets/efs-claim efs-sc 2m33s
Let's examine the details of our PersistentVolumeClaim (PVC):
Name: efs-claim
Namespace: assets
StorageClass: efs-sc
Status: Bound
Volume: pvc-342a674d-b426-4214-b8b6-7847975ae121
Labels: <none>
Annotations: pv.kubernetes.io/bind-completed: yes
pv.kubernetes.io/bound-by-controller: yes
volume.beta.kubernetes.io/storage-provisioner: efs.csi.aws.com
volume.kubernetes.io/storage-provisioner: efs.csi.aws.com
Finalizers: [kubernetes.io/pvc-protection]
Capacity: 5Gi
Access Modes: RWX
VolumeMode: Filesystem
Used By: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ExternalProvisioning 34s persistentvolume-controller waiting for a volume to be created, either by external provisioner "efs.csi.aws.com" or manually created by system administrator
Normal Provisioning 34s efs.csi.aws.com_efs-csi-controller-6b4ff45b65-fzqjb_7efe91cc-099a-45c7-8419-6f4b0a4f9e01 External provisioner is provisioning volume for claim "assets/efs-claim"
Normal ProvisioningSucceeded 33s efs.csi.aws.com_efs-csi-controller-6b4ff45b65-fzqjb_7efe91cc-099a-45c7-8419-6f4b0a4f9e01 Successfully provisioned volume pvc-342a674d-b426-4214-b8b6-7847975ae121
To demonstrate the shared storage functionality, let's create a new file newproduct.png
in the assets directory of the first Pod:
Now verify that this file exists in the second Pod:
chrono_classic.jpg
gentleman.jpg
newproduct.png <-----------
pocket_watch.jpg
smart_1.jpg
smart_2.jpg
test.txt
wood_watch.jpg
As you can see, even though we created the file through the first Pod, the second Pod has immediate access to it because they're both using the same EFS file system.