Skip to content
Commits on Source (22)
......@@ -5,4 +5,5 @@
*.swp
.idea
.vscode/
Dockerfile.dapper[0-9]*
\ No newline at end of file
Dockerfile.dapper[0-9]*
local-path-provisioner
......@@ -155,7 +155,9 @@ data:
"node":"yasker-lp-dev3",
"paths":[]
}
]
],
"setupCommand": "/manager",
"teardownCommand": "/manager"
}
setup: |-
#!/bin/sh
......@@ -171,12 +173,19 @@ data:
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
```
The helperPod is allowed to run on nodes experiencing disk pressure conditions, despite the potential resource constraints. When it runs on such a node, it can carry out specific cleanup tasks, freeing up space in PVCs, and resolving the disk-pressure issue.
#### `config.json`
##### Definition
......@@ -193,6 +202,16 @@ In addition `volumeBindingMode: Immediate` can be used in StorageClass definiti
Please note that `nodePathMap` and `sharedFileSystemPath` are mutually exclusive. If `sharedFileSystemPath` is used, then `nodePathMap` must be set to `[]`.
The `setupCommand` and `teardownCommand` allow you to specify the path to binary files in helperPod that will be called when creating or deleting pvc respectively. This can be useful if you need to use distroless images for security reasons. See the examples/distroless directory for an example. A binary file can take the following parameters:
| Parameter | Description |
| -------------------- | ----------- |
| -p | Volume directory that should be created or removed. | -m | -p | Volume directory that should be created or removed. |
| -m | The PersistentVolume mode (`Block` or `Filesystem`). | -m | The PersistentVolume mode (`Block` or `Filesystem`). |
| -s | Requested volume size in bytes. | -s | Requested volume size in bytes. |
| -a | Action type. Can be `create` or `delete` | -a | -a | Action type.
The `setupCommand` and `teardownCommand` have higher priority than the `setup` and `teardown` scripts from the ConfigMap.
##### Rules
The configuration must obey following rules:
1. `config.json` must be a valid json file.
......@@ -235,7 +254,7 @@ If the reload fails, the provisioner will log the error and **continue using the
To specify the type of volume you want the provisioner to create, add either of the following annotations;
- PVC:
- PVC:
```yaml
annotations:
volumeType: <local or hostPath>
......
......@@ -61,6 +61,7 @@ default values.
| `storageClass.create` | If true, create a `StorageClass` | `true` |
| `storageClass.provisionerName` | The provisioner name for the storage class | `nil` |
| `storageClass.defaultClass` | If true, set the created `StorageClass` as the cluster's default `StorageClass` | `false` |
| `storageClass.defaultVolumeType` | The default volume type this storage class creates | `hostPath` |
| `storageClass.name` | The name to assign the created StorageClass | local-path |
| `storageClass.reclaimPolicy` | ReclaimPolicy field of the class | Delete |
| `nodePathMap` | Configuration of where to store the data on each node | `[{node: DEFAULT_PATH_FOR_NON_LISTED_NODES, paths: [/opt/local-path-provisioner]}]` |
......
......@@ -6,16 +6,16 @@ metadata:
labels:
{{ include "local-path-provisioner.labels" . | indent 4 }}
rules:
- apiGroups: [""]
resources: ["nodes", "persistentvolumeclaims", "configmaps"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["endpoints", "persistentvolumes", "pods"]
verbs: ["*"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "patch"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- 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"]
{{- end -}}
......@@ -2,6 +2,7 @@ apiVersion: v1
kind: ConfigMap
metadata:
name: {{ .Values.configmap.name }}
namespace: {{ .Release.Namespace }}
labels:
{{ include "local-path-provisioner.labels" . | indent 4 }}
data:
......@@ -15,15 +16,20 @@ data:
{{- end }}
{{- $config | toPrettyJson | nindent 4 }}
setup: |-
{{ .Values.configmap.setup | nindent 4 }}
{{- .Values.configmap.setup | nindent 4 }}
teardown: |-
{{ .Values.configmap.teardown | nindent 4 }}
{{- .Values.configmap.teardown | nindent 4 }}
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
{{- if .Values.privateRegistry.registryUrl }}
......
......@@ -2,6 +2,7 @@ apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "local-path-provisioner.fullname" . }}
namespace: {{ .Release.Namespace }}
labels:
{{ include "local-path-provisioner.labels" . | indent 4 }}
spec:
......@@ -12,6 +13,10 @@ spec:
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
app.kubernetes.io/name: {{ include "local-path-provisioner.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
......@@ -21,8 +26,12 @@ spec:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ template "local-path-provisioner.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
{{- if .Values.privateRegistry.registryUrl }}
image: "{{ .Values.privateRegistry.registryUrl }}/{{ .Values.image.repository }}:{{ .Values.image.tag }}"
{{- else }}
......@@ -49,15 +58,15 @@ spec:
- {{ .Values.configmap.name }}
{{- if .Values.workerThreads }}
- --worker-threads
- {{ .Values.workerThreads }}
- {{ .Values.workerThreads | quote }}
{{- end }}
{{- if .Values.provisioningRetryCount }}
- --provisioning-retry-count
- {{ .Values.provisioningRetryCount }}
- {{ .Values.provisioningRetryCount | quote }}
{{- end }}
{{- if .Values.deletionRetryCount }}
- --deletion-retry-count
- {{ .Values.deletionRetryCount }}
- {{ .Values.deletionRetryCount | quote }}
{{- end }}
volumeMounts:
- name: config-volume
......
......@@ -3,7 +3,8 @@ apiVersion: v1
kind: Secret
metadata:
name: {{ .Values.defaultSettings.registrySecret }}
namespace: {{ .Release.Namespace }}
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: {{ template "local-path-provisioner.secret" . }}
{{- end }}
\ No newline at end of file
{{- end }}
{{- if .Values.rbac.create -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ include "local-path-provisioner.fullname" . }}
namespace: {{ .Release.Namespace }}
labels:
{{ include "local-path-provisioner.labels" . | indent 4 }}
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch", "create", "patch", "update", "delete"]
{{- end -}}
{{- if .Values.rbac.create -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ include "local-path-provisioner.fullname" . }}
namespace: {{ .Release.Namespace }}
labels:
{{ include "local-path-provisioner.labels" . | indent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: {{ template "local-path-provisioner.fullname" . }}
subjects:
- kind: ServiceAccount
name: {{ template "local-path-provisioner.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
{{- end -}}
......@@ -3,6 +3,7 @@ apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ template "local-path-provisioner.serviceAccountName" . }}
namespace: {{ .Release.Namespace }}
labels:
{{ include "local-path-provisioner.labels" . | indent 4 }}
imagePullSecrets:
......
......@@ -5,12 +5,11 @@ metadata:
name: {{ .Values.storageClass.name }}
labels:
{{ include "local-path-provisioner.labels" . | indent 4 }}
{{- if .Values.storageClass.defaultClass }}
annotations:
storageclass.kubernetes.io/is-default-class: "true"
{{- end }}
storageclass.kubernetes.io/is-default-class: "{{ .Values.storageClass.defaultClass }}"
defaultVolumeType: "{{ .Values.storageClass.defaultVolumeType }}"
provisioner: {{ template "local-path-provisioner.provisionerName" . }}
volumeBindingMode: WaitForFirstConsumer
volumeBindingMode: {{ .Values.storageClass.volumeBindingMode }}
reclaimPolicy: {{ .Values.storageClass.reclaimPolicy }}
allowVolumeExpansion: true
{{- end }}
......@@ -34,6 +34,9 @@ storageClass:
## Ignored if storageClass.create is false
defaultClass: false
## The default volume type this storage class creates, can be "local" or "hostPath"
defaultVolumeType: hostPath
## Set a StorageClass name
## Ignored if storageClass.create is false
name: local-path
......@@ -41,6 +44,9 @@ storageClass:
## ReclaimPolicy field of the class, which can be either Delete or Retain
reclaimPolicy: Delete
## volumeBindingMode field controls when volume binding and dynamic provisioning should occur, can be "Immediate" or "WaitForFirstConsumer"
volumeBindingMode: WaitForFirstConsumer
# nodePathMap is the place user can customize where to store the data on each node.
# 1. If one node is not listed on the nodePathMap, and Kubernetes wants to create volume on it, the paths specified in
# DEFAULT_PATH_FOR_NON_LISTED_NODES will be used for provisioning.
......@@ -66,6 +72,21 @@ nodePathMap:
# If `sharedFileSystemPath` is used, then `nodePathMap` must be set to `[]`.
# sharedFileSystemPath: ""
podAnnotations: {}
podSecurityContext: {}
# runAsNonRoot: true
securityContext: {}
# allowPrivilegeEscalation: false
# seccompProfile:
# type: RuntimeDefault
# capabilities:
# drop: ["ALL"]
# runAsUser: 65534
# runAsGroup: 65534
# readOnlyRootFilesystem: true
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
......
......@@ -35,9 +35,12 @@ data:
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
......@@ -10,24 +10,50 @@ 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" ]
verbs: [ "get", "list", "watch" ]
- apiGroups: [ "" ]
resources: [ "endpoints", "persistentvolumes", "pods" ]
verbs: [ "*" ]
- apiGroups: [ "" ]
resources: [ "events" ]
verbs: [ "create", "patch" ]
- apiGroups: [ "storage.k8s.io" ]
resources: [ "storageclasses" ]
verbs: [ "get", "list", "watch" ]
- 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
......@@ -122,9 +148,12 @@ data:
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
FROM golang:1.17-alpine AS builder
COPY main.go /main.go
COPY go.mod /go.mod
RUN cd / && CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-extldflags -static -s -w" -o /manager && \
chmod 777 /manager
FROM scratch
COPY --from=builder /manager /manager
ENTRYPOINT [ "/manager" ]
\ No newline at end of file
FROM golang:1.17-alpine AS builder
ARG GIT_REPO
ARG GIT_BRANCH
RUN apk add --no-cache git
ENV GIT_REPO=$GIT_REPO
ENV GIT_BRANCH=$GIT_BRANCH
RUN mkdir /src && \
git clone --depth 1 --branch "${GIT_BRANCH}" "${GIT_REPO}" /src && \
cd /src && \
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-X main.VERSION=dev -extldflags -static -s -w" -o /local-path-provisioner && \
chmod 777 /local-path-provisioner
FROM scratch
COPY --from=builder /local-path-provisioner /local-path-provisioner
ENTRYPOINT [ "/local-path-provisioner" ]
\ No newline at end of file
# Overview
this is an example to use distroless image for local path provisioner
#!/bin/bash
set -e
source=$1
branch=$2
if [ -z "$source" ]; then
source="https://github.com/rancher/local-path-provisioner.git"
fi
if [ -z "$branch" ]; then
branch="master"
fi
docker build --build-arg="GIT_REPO=$source" --build-arg="GIT_BRANCH=$branch" -t lpp-distroless-provider:v0.0.1 -f Dockerfile.provisioner .
docker build -t lpp-distroless-helper:v0.0.1 -f Dockerfile.helper .
kind create cluster --config=kind.yaml --name test-lpp-distroless
kind load docker-image --name test-lpp-distroless lpp-distroless-provider:v0.0.1 lpp-distroless-provider:v0.0.1
kind load docker-image --name test-lpp-distroless lpp-distroless-helper:v0.0.1 lpp-distroless-helper:v0.0.1
kubectl apply -k .
echo "Waiting 30 seconds before deploy sts"
sleep 30
kubectl create -f sts.yaml
echo "Waiting 15 seconds before getting pv"
sleep 15
kubectl get pv
\ No newline at end of file
{
"nodePathMap":[
{
"node":"DEFAULT_PATH_FOR_NON_LISTED_NODES",
"paths":["/opt/local-path-provisioner"]
}
],
"setupCommand": "/manager",
"teardownCommand": "/manager"
}
\ No newline at end of file
module manager
go 1.17
\ No newline at end of file