Install local path provisioner
Follow instructions in Rancher Desktop Web
In order to be able to work with persitent storage, it is useful to deploy a local path provisioner so that all pvc created will assing their own persistent volume locally.
You can find intrunctions here
Basically, write a local-path-storage.yaml file with this content:
apiVersion: v1
kind: Namespace
metadata:
name: local-path-storage
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: local-path-provisioner-service-account
namespace: local-path-storage
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: local-path-provisioner-role
namespace: local-path-storage
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch", "create", "patch", "update", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: local-path-provisioner-role
rules:
- apiGroups: [""]
resources: ["nodes", "persistentvolumeclaims", "configmaps", "pods", "pods/log"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "patch", "update", "delete"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "patch"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: local-path-provisioner-bind
namespace: local-path-storage
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: local-path-provisioner-role
subjects:
- kind: ServiceAccount
name: local-path-provisioner-service-account
namespace: local-path-storage
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: local-path-provisioner-bind
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: local-path-provisioner-role
subjects:
- kind: ServiceAccount
name: local-path-provisioner-service-account
namespace: local-path-storage
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: local-path-provisioner
namespace: local-path-storage
spec:
replicas: 1
selector:
matchLabels:
app: local-path-provisioner
template:
metadata:
labels:
app: local-path-provisioner
spec:
serviceAccountName: local-path-provisioner-service-account
containers:
- name: local-path-provisioner
image: rancher/local-path-provisioner:v0.0.32
imagePullPolicy: IfNotPresent
command:
- local-path-provisioner
- --debug
- start
- --config
- /etc/config/config.json
volumeMounts:
- name: config-volume
mountPath: /etc/config/
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: CONFIG_MOUNT_PATH
value: /etc/config/
volumes:
- name: config-volume
configMap:
name: local-path-config
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-path
provisioner: rancher.io/local-path
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete
---
kind: ConfigMap
apiVersion: v1
metadata:
name: local-path-config
namespace: local-path-storage
data:
config.json: |-
{
"nodePathMap":[
{
"node":"DEFAULT_PATH_FOR_NON_LISTED_NODES",
"paths":["/opt/local-path-provisioner"]
}
]
}
setup: |-
#!/bin/sh
set -eu
mkdir -m 0777 -p "$VOL_DIR"
teardown: |-
#!/bin/sh
set -eu
rm -rf "$VOL_DIR"
helperPod.yaml: |-
apiVersion: v1
kind: Pod
metadata:
name: helper-pod
spec:
priorityClassName: system-node-critical
tolerations:
- key: node.kubernetes.io/disk-pressure
operator: Exists
effect: NoSchedule
containers:
- name: helper-pod
image: busybox
imagePullPolicy: IfNotPresent
and
kubectl create -f local-path-storage.yaml
This will create the provisioner as well as a storage class named local-path
kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
hostpath (default) docker.io/hostpath Delete Immediate false 76m
local-path rancher.io/local-path Delete WaitForFirstConsumer false 2m10s
kubectl patch storageclass hostpath -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
storageclass.storage.k8s.io/hostpath patched
kubectl patch storageclass local-path -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
storageclass.storage.k8s.io/local-path patched
kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
hostpath docker.io/hostpath Delete Immediate false 76m
local-path (default) rancher.io/local-path Delete WaitForFirstConsumer false 2m50s
Your PVCs either specify to use this storage class or don't specify anything and the default will be used.
Example specifying storageclass
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: local-path-pvc
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-path
resources:
requests:
storage: 128Mi
to use the default storage class, just remove the storageClassName directive
Bear in mind that the storage class is configured to WaitForFirstConsumer so the persistent volume will not be created until a pod request the PVC.
For some reason, the local-path-provisioner pod keeps on crashing. Inspecting the logs it says:
kubectl logs deployment.apps/local-path-provisioner -n local-path-storage time="2021-02-24T10:39:15Z" level=fatal msg="Error starting daemon: invalid empty flag helper-pod-file and it also does not exist at ConfigMap local-path-storage/local-path-config with err: configmaps \"local-path-config\" is forbidden: User \"system:serviceaccount:local-path-storage:local-path-provisioner-service- ccount\" cannot get resource \"configmaps\" in API group \"\" in the namespace \"local-path-storage\""
to solve it, we need to apply a change to RBAC by creating a file role-local-path.yaml:
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: local-path-provisioner-workaround
namespace: local-path-storage
rules:
- apiGroups:
- ''
resources:
- configmaps
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: local-path-provisioner-workaround
namespace: local-path-storage
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: local-path-provisioner-workaround
subjects:
- kind: ServiceAccount
name: local-path-provisioner-service-account
and applying (not creating) it with
kubectl apply -f role-local-path.yaml -n local-path-storage
then restarting the deployment:
kubectl rollout restart deployment.apps/local-path-provisioner -n local-path-storage
and finally checking that the pod doesn't crash:
kubectl get pod -n local-path-storage
which should result in:
NAME READY STATUS RESTARTS AGE
local-path-provisioner-5897596697-n2gcg 1/1 Running 0 6m40s
If you need to create your own images, you will need a registry.
You can use a public one, such as Dockehub and deal with with thinks like credentials and the like which is good if you want to go to production with your app, or you can deploy your own local registry withing Rancher Desktop. This is only recommended for development.
To deploy a local registry, first create a docker-registry.yaml file:
---
apiVersion: v1
kind: Service
metadata:
name: docker-registry-service
labels:
app: docker-registry
spec:
selector:
app: docker-registry
ports:
- protocol: TCP
port: 5000
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: docker-registry-pvc
labels:
app: docker-registry
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-path
resources:
requests:
storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: docker-registry
labels:
app: docker-registry
spec:
replicas: 1
selector:
matchLabels:
app: docker-registry
template:
metadata:
labels:
app: docker-registry
spec:
containers:
- name: docker-registry
image: registry
ports:
- containerPort: 5000
protocol: TCP
volumeMounts:
- name: storage
mountPath: /var/lib/registry
env:
- name: REGISTRY_HTTP_ADDR
value: :5000
- name: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY
value: /var/lib/registry
volumes:
- name: storage
persistentVolumeClaim:
claimName: docker-registry-pvc
and an ingress.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: '0'
name: docker-registry-ingress
spec:
ingressClassName: nginx
rules:
- host: registry.rancher.lab
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: docker-registry-service
port:
number: 5000
then, create a namespace, the registry and the ingress:
kubectl create ns docker-registry
kubectl create -f docker-registry.yaml -f ingress.yaml