This document will explain how Volume Populators work under the covers by creating our "artisanal" populator. I say artisanal because we will be populating the PVCs manually ourselves using just kubectl. No controllers!
The PVC will look something like this:
kind: PersistentVolumeClaim
metadata:
name: populated-pvc
spec:
dataSourceRef:
apiGroup: artisanal.populators.com
kind: ThankYou
name: thanks-mike
storageClassName: rook-ceph-block
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1GiOnce created, the PVC will be in Pending state until we feel like populating it. And by "populating", I mean placing a nice thank you note on the root of the PVC filesystem.
The dataSourceRef field of the PersistentVolumeClaim refers to an instance of a Custom Resource. So we must declare a CustomResourceDefinition.
cat <<EOF | k create -f -
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: thankyous.artisanal.populators.com
spec:
group: artisanal.populators.com
names:
kind: ThankYou
listKind: ThankYouList
plural: thankyous
singular: thankyou
scope: Namespaced
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
properties:
apiVersion:
type: string
kind:
type: string
spec:
properties:
name:
type: string
required:
- name
type: object
required:
- spec
type: object
served: true
storage: true
EOFcat <<EOF | k create -f -
apiVersion: artisanal.populators.com/v1alpha1
kind: ThankYou
metadata:
name: thanks-mike
spec:
name: Mike
EOFSTORAGECLASS=rook-ceph-block
cat <<EOF | k create -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: populated-pvc
spec:
dataSourceRef:
apiGroup: artisanal.populators.com
kind: ThankYou
name: thanks-mike
storageClassName: ${STORAGECLASS}
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
EOF
k describe pvc populated-pvcObserve "Assuming an external populator will provision the volume" event
k create ns artisanal-pop
cat <<EOF | k create -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
namespace: artisanal-pop
name: populated-pvc-prime
spec:
storageClassName: ${STORAGECLASS}
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
EOF
k describe pvc -n artisanal-popTHANK_YOU_NAME=$(k get thankyou thanks-mike -o=jsonpath='{.spec.name}')
cat <<EOF | k create -f -
apiVersion: v1
kind: Pod
metadata:
namespace: artisanal-pop
name: populator-pod
spec:
containers:
- name: fedora
image: fedora:36
command: ["/bin/bash", "-c"]
args: ["echo 'Thank you very very much ${THANK_YOU_NAME}' > /pvc/thanks.txt"]
volumeMounts:
- name: pvc
mountPath: /pvc
restartPolicy: OnFailure
volumes:
- name: pvc
persistentVolumeClaim:
claimName: populated-pvc-prime
EOF
k get pod -n artisanal-pop populator-pod -wWait for pod status to be Completed
k delete pod -n artisanal-pop populator-podThis is where the magic happens! We reset the claimref to point from PVC' to the target PVC
PV_NAME=$(k get pvc -n artisanal-pop populated-pvc-prime -o=jsonpath='{.spec.volumeName}')
PVC_NAME=populated-pvc
PVC_NAMESPACE=default
PVC_UID=$(k get pvc -n $PVC_NAMESPACE $PVC_NAME -o=jsonpath='{.metadata.uid}')
PVC_RESOURCEVERSION=$(k get pvc -n $PVC_NAMESPACE $PVC_NAME -o=jsonpath='{.metadata.resourceVersion}')
k patch pv $PV_NAME --patch "{\"metadata\": {\"annotations\": {}},\"spec\": {\"claimRef\": {\"namespace\": \"$PVC_NAMESPACE\", \"name\": \"$PVC_NAME\", \"uid\": \"$PVC_UID\", \"resourceVersion\": \"$PVC_RESOURCEVERSION\"}}}"
k get -A pvc -wSee that populated-pvc is now Bound while populated-pvc-prime is Lost
k delete pvc -n artisanal-pop populated-pvc-primecat <<EOF | k create -f -
apiVersion: v1
kind: Pod
metadata:
name: reader-pod
spec:
containers:
- name: fedora
image: fedora:36
command: ["tail"]
args: ["-f", "/dev/null"]
volumeMounts:
- name: pvc
mountPath: /pvc
restartPolicy: OnFailure
volumes:
- name: pvc
persistentVolumeClaim:
claimName: populated-pvc
EOF
k wait pod/reader-pod --for=condition=ready --timeout=60s
k exec -ti reader-pod -- cat /pvc/thanks.txtk delete pod reader-pod
k delete crd thankyous.artisanal.populators.com
k delete pvc populated-pvcSTORAGECLASS=hostpath-csi
cat <<EOF | k create -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: populated-pvc
spec:
dataSourceRef:
apiGroup: artisanal.populators.com
kind: ThankYou
name: thanks-mike
storageClassName: ${STORAGECLASS}
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
EOF
k describe pvc populated-pvccat <<EOF | k create -f -
apiVersion: v1
kind: Pod
metadata:
name: reader-pod
spec:
containers:
- name: fedora
image: fedora:36
command: ["tail"]
args: ["-f", "/dev/null"]
volumeMounts:
- name: pvc
mountPath: /pvc
restartPolicy: OnFailure
volumes:
- name: pvc
persistentVolumeClaim:
claimName: populated-pvc
EOFk get pvc populated-pvc -o yamlk delete pod reader-pod
k delete pvc populated-pvc