Tanzu Community Edition でlocal-path-storage を試してみよう 

# はじめに
[local-path-storage (local-path-provisioner)](https://github.com/rancher/local-path-provisioner) は、Kubernetes の各ノードのローカルディスクをPersistent Volume (PV) として利用するためのツールです。Tanzu Community Edition (TCE) で提供されているアプリケーションパッケージの1つですが、主にDocker クラスタでPV を使用するために使います。

今回は、TCE 上でlocal-path-storage を実際に使ってみて、どういったものなのか概要を掴んでみましょう。

# 環境の準備
今回は、最も展開が迅速なTCE のDocker Standalone Cluster (Management Cluster なし)で試します。詳細は[コチラ](https://qiita.com/vkbaba/items/8bcc8da56ee121384dc6)の記事をご参照ください。

# local-path-storage のインストール
https://tanzucommunityedition.io/docs/latest/package-readme-local-path-storage-0.0.20/

Contour やExternalDNS と同様、local-path-storage はパッケージとしてTCE で提供されているため、tanzu package コマンドでインストールします。

    $ tanzu package available list  --namespace tanzu-package-repo-global
    - Retrieving available packages... 
    NAME                                           DISPLAY-NAME        SHORT-DESCRIPTION                                                                                                             
    ~~~
    local-path-storage.community.tanzu.vmware.com  local-path-storage  This package provides local path node storage and primarily supports RWO AccessMode.                                          
    ~~~
```                                                                                        
$ tanzu package available list  local-path-storage.community.tanzu.vmware.com --namespace tanzu-package-repo-global
- Retrieving package versions for local-path-storage.community.tanzu.vmware.com... 
  NAME                                           VERSION  RELEASED-AT           
  local-path-storage.community.tanzu.vmware.com  0.0.19   2021-09-15T00:00:00Z  
  local-path-storage.community.tanzu.vmware.com  0.0.20   2021-09-15T00:00:00Z  

$ tanzu package install local-path-storage --package-name local-path-storage.community.tanzu.vmware.com --version 0.0.20
/ Installing package 'local-path-storage.community.tanzu.vmware.com' 
| Getting namespace 'default' 
| Getting package metadata for 'local-path-storage.community.tanzu.vmware.com' 
| Creating service account 'local-path-storage-default-sa' 
| Creating cluster admin role 'local-path-storage-default-cluster-role' 
| Creating cluster role binding 'local-path-storage-default-cluster-rolebinding' 
- Creating package resource 
\ Package install status: Reconciling 


 Added installed package 'local-path-storage' in namespace 'default'
```

なお、ここでAdded installed package 'local-path-storage' in namespace 'default' と出力されているのは、app リソースがNamespace default にデプロイされているためです。

```
$ kubectl get app
NAME                 DESCRIPTION           SINCE-DEPLOY   AGE
local-path-storage   Reconcile succeeded   6s             167m
```


パッケージのインストールをすると、Namespace "tanzu-local-path-storage" 上にPod がデプロイされます。

```
$ kubectl get pod -n tanzu-local-path-storage 
NAME                                      READY   STATUS    RESTARTS   AGE
local-path-provisioner-8698548d5c-pt5g5   1/1     Running   0          61m
```


**このNamespace "tanzu-local-path-storage" 上にデプロイするPod に対して、**PV がアサインできるようになります。

なお、ドキュメントには下記のような構成ファイルが必須と記載されていますが、これはlocal-path-storage のPod をデプロイするNamespace を変更するためで、Namespace のデフォルト値が"tanzu-local-path-storage" のため、tanzu package コマンドの--values-file オプションに構成ファイルを必ずしも入力する必要はありません。

```yaml:values.yaml
namespace: my-own-namespace
```

https://github.com/vmware-tanzu/community-edition/blob/main/addons/packages/local-path-storage/0.0.20/bundle/config/values.yaml

:::note warn
TCE v0.9.1 / local-path-storage.community.tanzu.vmware.com  0.0.20 現在、構成ファイルを使ってNamespace default 上にlocal-path-storage を作成すると、パッケージを正常にアンインストールできなくなるようです。
:::

さて、インストールが完了したら、アプリケーションをデプロイします。マニフェストは下記を使用しました。

```yaml:volume-test.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: local-path-pvc
  namespace: tanzu-local-path-storage
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: local-path
  resources:
    requests:
      storage: 128Mi
---
apiVersion: v1
kind: Pod
metadata:
  name: volume-test
  namespace: tanzu-local-path-storage
spec:
  containers:
  - name: volume-test
    image: public.ecr.aws/nginx/nginx:1.21
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: volv
      mountPath: /data
    ports:
    - containerPort: 80
  volumes:
  - name: volv
    persistentVolumeClaim:
      claimName: local-path-pvc
```

アプリケーションをデプロイすると、helper と呼ばれるbusybox Pod が一時的にデプロイされ、ノードのパス（デフォルト：/opt/local-path-provisioner/xxx, xxx は作成されたボリューム名を含む）を直接Pod のボリュームとしてマウントします。helper は、マウントするローカルノードのパスやボリュームの作成前後に実行されるスクリプトが記載されているConfigmap local-path-config をもとに実行されます。その後、アプリケーションがPVC によって正常にPV と紐づけられます。

```
$ kubectl describe -n tanzu-local-path-storage configmaps local-path-config 
Name:         local-path-config
Namespace:    tanzu-local-path-storage
Labels:       kapp.k14s.io/app=1638718406558678644
              kapp.k14s.io/association=v1.c9554f67bb9e504f6990a499ff17f204
Annotations:  kapp.k14s.io/identity: v1;tanzu-local-path-storage//ConfigMap/local-path-config;v1
              kapp.k14s.io/original:
                {"apiVersion":"v1","data":{"config.json":"{\n        \"nodePathMap\":[\n        {\n                \"node\":\"DEFAULT_PATH_FOR_NON_LISTED_...
              kapp.k14s.io/original-diff-md5: c6e94dc94aed3401b5d0f26ed6c0bff3

Data
====
config.json:
----
{
        "nodePathMap":[
        {
                "node":"DEFAULT_PATH_FOR_NON_LISTED_NODES",
                "paths":["/opt/local-path-provisioner"]
        }
        ]
}
helperPod.yaml:
----
apiVersion: v1
kind: Pod
metadata:
  name: helper-pod
spec:
  containers:
  - name: helper-pod
    image: busybox
    imagePullPolicy: IfNotPresent
setup:
----
#!/bin/sh
while getopts "m:s:p:" opt
do
    case $opt in
        p)
        absolutePath=$OPTARG
        ;;
        s)
        sizeInBytes=$OPTARG
        ;;
        m)
        volMode=$OPTARG
        ;;
    esac
done

mkdir -m 0777 -p ${absolutePath}
teardown:
----
#!/bin/sh
while getopts "m:s:p:" opt
do
    case $opt in
        p)
        absolutePath=$OPTARG
        ;;
        s)
        sizeInBytes=$OPTARG
        ;;
        m)
        volMode=$OPTARG
        ;;
    esac
done

rm -rf ${absolutePath}

BinaryData
====

```


:::note warn
tanzu package でインストールした場合、TCE のドキュメントには後から設定が可能と記載されていますが、kubectl edit で修正した場合、自動的に修正前の状態に戻ってしまうため、現時点でこのConfigmap を後から修正することはできないようです。busybox のイメージレジストリを修正したい場合などはkuebctl edit を使って直接helper Pod のマニフェストを編集します。
:::

```
$ kubectl get pod -n tanzu-local-path-storage 
NAME                                      READY   STATUS    RESTARTS   AGE
local-path-provisioner-6fb77b84f9-gbbrr   1/1     Running   0          30m
volume-test                               1/1     Running   0          2m3s

$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                                     STORAGECLASS   REASON   AGE
pvc-55018b72-a0ea-4aee-8e0f-d0f3f53d984c   128Mi      RWO            Delete           Bound    tanzu-local-path-storage/local-path-pvc   local-path              66s

$ kubectl get pvc -n tanzu-local-path-storage 
NAME             STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
local-path-pvc   Bound    pvc-55018b72-a0ea-4aee-8e0f-d0f3f53d984c   128Mi      RWO            local-path     2m21s
```

local-path-storage の実体を確認してみましょう。アタッチしたボリュームにファイルを作成します。

```
$ kubectl exec -n tanzu-local-path-storage volume-test -- touch /data/testfile
```
Docker コンテナでKubernetes クラスタが作成されているため、アタッチされるディレクトリの実体はDocker コンテナ上に作成されます。

```
$ docker exec tce-md-0-554568695c-9tb8r ls /opt/
cni
containerd
local-path-provisioner

$ docker exec tce-md-0-554568695c-9tb8r ls /opt/local-path-provisioner
pvc-55018b72-a0ea-4aee-8e0f-d0f3f53d984c_tanzu-local-path-storage_local-path-pvc

$ docker exec tce-md-0-554568695c-9tb8r ls /opt/local-path-provisioner/pvc-55018b72-a0ea-4aee-8e0f-d0f3f53d984c_tanzu-local-path-storage_local-path-pvc
testfile
```
このように、文字通りローカルなパスがストレージとしてPod にアサインされていることが分かりました。

# アンインストール
tanzu package コマンドでアンインストールします。

```
$ tanzu package installed delete local-path-storage
Deleting installed package 'local-path-storage' in namespace 'default'. Are you sure? [y/N]: y
| Uninstalling package 'local-path-storage' from namespace 'default' 
| Getting package install for 'local-path-storage' 
- Deleting package install 'local-path-storage' from namespace 'default' 
\ Package uninstall status: Deleting 
| Deleting service account 'local-path-storage-default-sa' 
| Deleting admin role 'local-path-storage-default-cluster-role' 
| Deleting role binding 'local-path-storage-default-cluster-rolebinding' 

 Uninstalled package 'local-path-storage' from namespace 'default'
```