Skip to content
Commits on Source (7)
......@@ -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
......@@ -200,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.
......
......@@ -7,7 +7,7 @@ metadata:
{{ include "local-path-provisioner.labels" . | indent 4 }}
rules:
- apiGroups: [""]
resources: ["nodes", "persistentvolumeclaims", "configmaps", "pods"]
resources: ["nodes", "persistentvolumeclaims", "configmaps", "pods", "pods/log"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["persistentvolumes"]
......
......@@ -28,7 +28,7 @@ metadata:
name: local-path-provisioner-role
rules:
- apiGroups: [""]
resources: ["nodes", "persistentvolumeclaims", "configmaps", "pods"]
resources: ["nodes", "persistentvolumeclaims", "configmaps", "pods", "pods/log"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["persistentvolumes"]
......
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
apiVersion: v1
kind: Pod
metadata:
name: helper-pod
spec:
containers:
- name: helper-pod
image: lpp-distroless-helper:v0.0.1
imagePullPolicy: IfNotPresent
\ No newline at end of file
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
\ No newline at end of file
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- local-path-storage.yaml
configMapGenerator:
- name: local-path-config
namespace: local-path-storage
behavior: merge
files:
- helperPod.yaml
- config.json
generatorOptions:
disableNameSuffixHash: true
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"]
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: lpp-distroless-provider:v0.0.1
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
volumes:
- name: config-volume
configMap:
name: local-path-config
---
kind: ConfigMap
apiVersion: v1
metadata:
name: local-path-config
namespace: local-path-storage
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-path
provisioner: rancher.io/local-path
volumeBindingMode: WaitForFirstConsumer
reclaimPolicy: Delete
\ No newline at end of file
package main
import (
"flag"
"fmt"
"os"
"syscall"
)
var (
dirMode string
path string
sizeInBytes string
action string
)
const (
SETUP = "create"
TEARDOWN = "delete"
)
func init() {
flag.StringVar(&path, "p", "", "Absolute path")
flag.StringVar(&sizeInBytes, "s", "", "Size in bytes")
flag.StringVar(&dirMode, "m", "", "Dir mode")
flag.StringVar(&action, "a", "", fmt.Sprintf("Action name. Can be '%s' or '%s'", SETUP, TEARDOWN))
}
func main() {
flag.Parse()
if action != SETUP && action != TEARDOWN {
fmt.Fprintf(os.Stderr, "Incorrect action: %s\n", action)
os.Exit(1)
}
if path == "" {
fmt.Fprintf(os.Stderr, "Path is empty\n")
os.Exit(1)
}
if path == "/" {
fmt.Fprintf(os.Stderr, "Path cannot be '/'\n")
os.Exit(1)
}
if action == TEARDOWN {
err := os.RemoveAll(path)
if err != nil {
fmt.Fprintf(os.Stderr, "Cannot remove directory %s: %s\n", path, err)
os.Exit(1)
}
return
}
syscall.Umask(0)
err := os.MkdirAll(path, 0777)
if err != nil {
fmt.Fprintf(os.Stderr, "Cannot create directory %s: %s\n", path, err)
os.Exit(1)
}
}
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry.k8s.io/nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: local-path
resources:
requests:
storage: 1Gi
\ No newline at end of file
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../pvc-with-rwop-access-mode
- pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: volume-test
spec:
containers:
- name: volume-test
image: nginx:stable-alpine
imagePullPolicy: IfNotPresent
volumeMounts:
- name: volv
mountPath: /data
ports:
- containerPort: 80
volumes:
- name: volv
persistentVolumeClaim:
claimName: local-rwop-volume-pvc
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: local-rwop-volume-pvc
annotations:
volumeType: local
spec:
accessModes:
- ReadWriteOncePod
storageClassName: local-path
resources:
requests:
storage: 128Mi