Example

The HostPath can be used to provision local storage in a single node test. This section shows how to deploy and use that driver in Kubernetes.

Deployment

The following .yaml file will deploy a csi-pod with the HostPath CSI driver and the sidecar containers which integrate the driver into Kubernetes. Use it with a cluster that is set up for CSI, either by copying it into a local file or by referencing the latest version directly:

$ kubectl create -f https://raw.githubusercontent.com/kubernetes-csi/docs/master/book/src/example/csi-setup.yaml
storageclass.storage.k8s.io "csi-hostpath-sc" created
serviceaccount "csi-service-account" created
clusterrole.rbac.authorization.k8s.io "csi-cluster-role" created
clusterrolebinding.rbac.authorization.k8s.io "csi-role-binding" created
pod "csi-pod" created
$ kubectl get pods
NAME      READY     STATUS    RESTARTS   AGE
csi-pod   4/4       Running   0          24s
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: csi-hostpath-sc
provisioner: csi-hostpath
reclaimPolicy: Delete
volumeBindingMode: Immediate
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: csi-service-account
  namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: csi-cluster-role
rules:
- apiGroups:
  - ""
  resources:
  - persistentvolumes
  verbs:
  - create
  - delete
  - get
  - list
  - watch
  - update
- apiGroups:
  - ""
  resources:
  - secrets
  verbs:
  - get
  - list
- apiGroups:
  - ""
  resources:
  - persistentvolumeclaims
  verbs:
  - get
  - list
  - watch
  - update
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - get
  - list
  - watch
  - update
- apiGroups:
  - storage.k8s.io
  resources:
  - volumeattachments
  verbs:
  - get
  - list
  - watch
  - update
- apiGroups:
  - storage.k8s.io
  resources:
  - storageclasses
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - events
  verbs:
  - list
  - watch
  - create
  - update
  - patch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: csi-role-binding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: csi-cluster-role
subjects:
- kind: ServiceAccount
  name: csi-service-account
  namespace: default
---
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: hostpath-driver
  name: csi-pod
  namespace: default
spec:
  serviceAccount: csi-service-account
  containers:
  - name: external-provisioner
    args:
    - --v=5
    - --provisioner=csi-hostpath
    - --csi-address=/csi/csi.sock
    image: quay.io/k8scsi/csi-provisioner:v0.2.1
    imagePullPolicy: Always
    volumeMounts:
    - mountPath: /csi
      name: socket-dir
  - name: driver-registrar
    args:
    - --v=5
    - --csi-address=/csi/csi.sock
    env:
    - name: KUBE_NODE_NAME
      valueFrom:
        fieldRef:
          apiVersion: v1
          fieldPath: spec.nodeName
    image: quay.io/k8scsi/driver-registrar:v0.2.0
    imagePullPolicy: Always
    volumeMounts:
    - mountPath: /csi
      name: socket-dir
  - name: external-attacher
    args:
    - --v=5
    - --csi-address=$(ADDRESS)
    env:
    - name: ADDRESS
      value: /csi/csi.sock
    image: quay.io/k8scsi/csi-attacher:v0.2.0
    imagePullPolicy: Always
    volumeMounts:
    - mountPath: /csi
      name: socket-dir
  - name: hostpath-driver
    args:
    - --v=5
    - --endpoint=$(CSI_ENDPOINT)
    - --nodeid=$(KUBE_NODE_NAME)
    env:
    - name: CSI_ENDPOINT
      value: unix:///csi/csi.sock
    - name: KUBE_NODE_NAME
      valueFrom:
        fieldRef:
          apiVersion: v1
          fieldPath: spec.nodeName
    image: quay.io/k8scsi/hostpathplugin:v0.2.0
    imagePullPolicy: Always
    securityContext:
      privileged: true
    volumeMounts:
    - mountPath: /csi
      name: socket-dir
    - mountPath: /var/lib/kubelet/pods
      mountPropagation: Bidirectional
      name: mountpoint-dir
  volumes:
  - hostPath:
      path: /var/lib/kubelet/plugins/csi-hostpath
      type: DirectoryOrCreate
    name: socket-dir
  - hostPath:
      path: /var/lib/kubelet/pods
      type: DirectoryOrCreate
    name: mountpoint-dir

Usage

Dynamic provisioning was enabled by the .yaml file above via the csi-hostpath-sc storage class. We can use this to create and claim a new volume:

$ kubectl create -f https://raw.githubusercontent.com/kubernetes-csi/docs/master/book/src/example/csi-pvc.yaml
persistentvolumeclaim "csi-pvc" created
$ kubectl get pvc
NAME      STATUS    VOLUME                                   CAPACITY   ACCESS MODES   STORAGECLASS      AGE
csi-pvc   Bound     kubernetes-dynamic-pv-bb3d8e2a23d611e8   1Gi        RWO            csi-hostpath-sc   5s
$ kubectl get pv
NAME                                     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS    CLAIM             STORAGECLASS      REASON    AGE
kubernetes-dynamic-pv-bb3d8e2a23d611e8   1Gi        RWO            Delete           Bound     default/csi-pvc   csi-hostpath-sc             8s
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: csi-pvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: csi-hostpath-sc # defined in csi-setup.yaml

The HostPath driver is configured to create new volumes under /tmp inside the csi-pod/hostpath-driver and thus persist as long as the csi-pod itself. We can use such volumes in another pod like this:

$ kubectl create -f https://raw.githubusercontent.com/kubernetes-csi/docs/master/book/src/example/csi-app.yaml
pod "my-csi-app" created
$ kubectl get pods
NAME         READY     STATUS    RESTARTS   AGE
csi-pod      4/4       Running   0          3m
my-csi-app   1/1       Running   0          8s
$ kubectl describe pods/my-csi-app
Name:         my-csi-app
Namespace:    default
Node:         127.0.0.1/127.0.0.1
Start Time:   Fri, 09 Mar 2018 21:17:21 +0100
Labels:       <none>
Annotations:  <none>
Status:       Running
IP:           172.17.0.3
Containers:
  my-frontend:
    Container ID:  docker://52ea6c569abea710166059005416297a654b3216f7ce632516c50498fe130639
    Image:         busybox
    Image ID:      docker-pullable://busybox@sha256:2107a35b58593c58ec5f4e8f2c4a70d195321078aebfadfbfb223a2ff4a4ed21
    Port:          <none>
    Host Port:     <none>
    Command:
      sleep
      1000000
    State:          Running
      Started:      Fri, 09 Mar 2018 21:17:25 +0100
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /data from my-csi-volume (rw)
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-hw8rs (ro)
Conditions:
  Type           Status
  Initialized    True 
  Ready          True 
  PodScheduled   True 
Volumes:
  my-csi-volume:
    Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
    ClaimName:  csi-pvc
    ReadOnly:   false
  default-token-hw8rs:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-hw8rs
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
Events:
  Type    Reason                  Age   From                     Message
  ----    ------                  ----  ----                     -------
  Normal  Scheduled               59s   default-scheduler        Successfully assigned my-csi-app to 127.0.0.1
  Normal  SuccessfulAttachVolume  59s   attachdetach-controller  AttachVolume.Attach succeeded for volume "kubernetes-dynamic-pv-bb3d8e2a23d611e8"
  Normal  SuccessfulMountVolume   59s   kubelet, 127.0.0.1       MountVolume.SetUp succeeded for volume "default-token-hw8rs"
  Normal  SuccessfulMountVolume   58s   kubelet, 127.0.0.1       MountVolume.SetUp succeeded for volume "kubernetes-dynamic-pv-bb3d8e2a23d611e8"
  Normal  Pulling                 58s   kubelet, 127.0.0.1       pulling image "busybox"
  Normal  Pulled                  55s   kubelet, 127.0.0.1       Successfully pulled image "busybox"
  Normal  Created                 55s   kubelet, 127.0.0.1       Created container
  Normal  Started                 55s   kubelet, 127.0.0.1       Started container

kind: Pod
apiVersion: v1
metadata:
  name: my-csi-app
spec:
  containers:
    - name: my-frontend
      image: busybox
      volumeMounts:
      - mountPath: "/data"
        name: my-csi-volume
      command: [ "sleep", "1000000" ]
  volumes:
    - name: my-csi-volume
      persistentVolumeClaim:
        claimName: csi-pvc # defined in csi-pvs.yaml

Confirming the setup

Writing inside the app container should be visible in /tmp of the hostpath-driver container:

$ kubectl exec -ti my-csi-app /bin/sh
/ # touch /data/hello-world
/ # exit
$ kubectl exec -ti csi-pod -c hostpath-driver /bin/sh
/ # find / -name hello-world
/tmp/aba238a3-21f9-11e8-9164-0242ac110002/hello-world

There should be a VolumeAttachment while the app has the volume mounted:

$ kubectl get VolumeAttachment
NAME                                                                   AGE
csi-7bf49991faecc67f5049ed4b72e56b5935d92fb21b69fe782e74ea26e25863a3   7m
$ kubectl describe VolumeAttachment
Name:         csi-7bf49991faecc67f5049ed4b72e56b5935d92fb21b69fe782e74ea26e25863a3
Namespace:    
Labels:       <none>
Annotations:  <none>
API Version:  storage.k8s.io/v1beta1
Kind:         VolumeAttachment
Metadata:
  Creation Timestamp:  2018-03-09T20:17:21Z
  Resource Version:    597
  Self Link:           /apis/storage.k8s.io/v1beta1/volumeattachments/csi-7bf49991faecc67f5049ed4b72e56b5935d92fb21b69fe782e74ea26e25863a3
  UID:                 dfaffa08-23d6-11e8-bf78-fcaa1497a416
Spec:
  Attacher:   csi-hostpath
  Node Name:  127.0.0.1
  Source:
    Persistent Volume Name:  kubernetes-dynamic-pv-bb3d8e2a23d611e8
Status:
  Attached:  true
Events:      <none>

If you encounter any problems, please check the Troubleshooting page.