HarborのPVCがfullになってしまったので拡張した作業のメモ

# はじめに

最近はDockerHubの個人向け料金プランがprivateイメージの数による段階的な体系から、privateリポジトリ数・pull可能回数を制限するFreeプランと、ほぼほぼ無制限なProプランに変化したので、一度はFreeプランに戻しましたが、再びProプランに登録しています。

無制限に登録できるPrivateリポジトリが利用できても、外部にコンテナイメージをpushすることが適当でない場合も想定されます。実際にPrivaiteでも外部に配置したくないコンテナがあるため、引き続きkubesprayでdeployしたkubernetes環境にCNCFのHarborを稼動させています。

> 基本的にコンテナイメージに機密情報(ip address, ssh private key, config files, etc.)を埋め込むような事は避けなければいけません。K8sであればConfigMap(cm)やSecretを積極的に使用するべきです。

今回、HarborのPostgreSQLに割り当てられたPVCの使用率が100%となってしまい、サーバーが起動しなくなったので手動で拡張することにしました。

なおこの手法自体は、HarborでなくともPVCの手動拡張、コンテンツのsalvageが必要となる状況で参考になると思います。

# 【留意点】KubernetesにおけるPVCの拡張について

K8s自体はv1.11からPVCの動的拡張に対応しています。Rook/Cephもv1.4がリリースされた現在はFLEXVolumeもCSIのどちらもPVCの動的拡張に対応しています。テスト環境のKubernetes v1.18+Rook/Ceph v1.4のCSI構成では、harbor-helmで同様の事象を発生させても問題なくresize可能でした。

> FLEXVolumeの拡張はRook v1.3から実装されているはずですが確認していません。またCSI構成ではv1.1から対応しているはずですが、手元の環境ではv1.1ではうまく動作せず、v1.4を新規に構成した環境では問題なく稼動しています。

```bash:PVCを1GBから2GBに動機拡張した際の作業手順
$ kubectl -n rook-ceph edit pvc database-data-my-harbor-harbor-database-0
$ kubectl -n rook-ceph delete pod/my-harbor-harbor-database-0
```

この記事は、古いRook/Cephを使っていてPVCの動的拡張がどうしてもできない場合のみを使用している特殊な環境での説明です。

私の経験上、Rook/Cephのアップグレードはいろいろな問題が発生しており、本番環境では気軽にupgradeできません。必要な場合は新規にKubernetesクラスタを別系統で立ち上げて切り替えるつもりです。

# 環境

* Rook/Ceph: v1.0.6 (patched to v1.0.1, Ceph: v14.2.1-20190430)
* Kubernetes v1.16.9 (deployed by Kubespray v2.12.6)
* 拡張対象PVC: database-data-my-harbor-harbor-database-0

# おおまかな手順

PVCの名前を変更することもできないので、単純に名前を変更しようとしてもPVCの移行という作業が発生します。そのため手順を説明したものはありますが、reclaim policyをRetainにしないと対応できないので、Deleteに設定している環境では利用できません。それに少し危険な方法でもあります。

* https://stackoverflow.com/questions/48403542/how-to-rename-persistence-volume-claim

そのためswapのための一時スペースを利用することになると、次のような流れになります。
なおPVCを削除してもreclaim policyによって

1. 適当な名前で新しくPVCを作成する(tmp-data-storage)
2. Podを作成する際に、2つのPVC (database-data-my-harbor-harbor-database-0, tmp-data-storage) をmountする
3. rsync等でデータを移行する
4. オリジナルのPVC(database-data-my-harbor-harbor-database-0)を削除し、再度作成する
5. 2,3の操作で逆の方向にデータをコピーする

ここからの手順は実際のYAMLファイルと手順を掲載します。

## 手順1: 作業用のPVCを作成する

```yaml:01.pvc.create-temppvc.yamlファイルの内容
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: tmp-data-storage
  namespace: harbor
spec:
  accessModes: [ "ReadWriteOnce" ]
  storageClassName: rook-ceph-block
  resources:
    requests:
      storage: 10Gi
```

```bash
$ kubectl apply -f 01.pvc.create-temppvc.yaml
```

## 手順2: 2つのPVCをmountするPodを作成する

手元のファイルを元にしたので、Deploymentとして定義しています。
作業用のimageは慣れているnginx(alpine版)を利用しています。

```yaml:02.deployment.workspace.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: workspace
  namespace: harbor
spec:
  replicas: 1
  selector:
    matchLabels:
      app: workspace
  template:
    metadata:
      labels:
       app: workspace
    spec:
      containers:
      - name: workspace
        image: nginx:1.19.3-alpine
        imagePullPolicy: "Always"
        volumeMounts:
        - name: db-data-storage
          mountPath: /data-src
        - name: temp-data-storage
          mountPath: /data-dest
      volumes:
      - name: db-data-storage
        persistentVolumeClaim:
          claimName: database-data-my-harbor-harbor-database-0 
      - name: temp-data-storage
        persistentVolumeClaim:
          claimName: tmp-data-storage
```

Podを作成します。

```bash:
$ kubectl apply -f 02.deployment.workspace.yaml
```

## 手順3: rsync等でデータを移行する

そのままでは必要なコマンドが不足するので、インストールしています。

```bash:
$ kubectl -n harbor exec -it workspace-6ff4f9d4cf-sm2tb sh
# apk update
# apk add rsync
# rsync -av /data-src/. /data-dest/.
....
# df | grep /data
/dev/rbd6              1038336   1038304        32 100% /data-src
/dev/rbd7             10475520   1048692   9426828  10% /data-dest
```

## 手順4: 4. オリジナルのPVC(database-data-my-harbor-harbor-database-0)を削除し、再度作成する

PVCを削除する前に、作業用のPodを削除します。

```bash:
$ kubectl delete -f 02.deployment.workspace.yaml
```

PVCを削除し、作り直す作業用に、まずPVCの定義を準備します。これは01.pvc.create-temppvc.yamlをコピーし、.metadata.nameを変更しただけのファイルです。

実際に定義されているPVCのsizeは1GBですが、10GBになっている点に注意してください。

```yaml:03.pvc.original-database0.yaml
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: database-data-my-harbor-harbor-database-0
  namespace: harbor
spec:
  accessModes: [ "ReadWriteOnce" ]
  storageClassName: rook-ceph-block
  resources:
    requests:
      storage: 10Gi
```

まず、これを利用して、PVCを削除して、再度作成します。

```bash:pvc作り替えの作業
$ kubectl delete -f 03.pvc.original-database0.yaml

$ kubectl -n harbor get pvc
NAME                            STATUS   VOLUME                                     CAPACITY   ACCESS MODES   
STORAGECLASS      AGE
data-my-harbor-harbor-redis-0   Bound    pvc-4e689c13-75e3-4a9a-af7e-6c54ba1d15d5   1Gi        RWO            
rook-ceph-block   266d
my-harbor-harbor-chartmuseum    Bound    pvc-c0c0b812-9de8-49f8-b16e-0820f79f2b07   5Gi        RWO            
rook-ceph-block   266d
my-harbor-harbor-jobservice     Bound    pvc-b114429b-41e5-48a8-aebe-f15c88a756db   1Gi        RWO            
rook-ceph-block   266d
my-harbor-harbor-registry       Bound    pvc-e60eb40f-8382-4270-a39d-e18bd10d1abe   5Gi        RWO            
rook-ceph-block   266d
tmp-data-storage                Bound    pvc-0dd17f29-c5f6-47f3-ba6a-6f5e0056e414   10Gi       RWO            
rook-ceph-block   41m

# kubectl apply -f 03.pvc.original-database0.yaml
```

## 手順5: Podを再度作成し、逆の手順で元に戻す

rsyncの実行時は、/data-dest/. から /data-src/. に書き戻すことなるので

```bash:
$ kubectl apply -f 02.deployment.workspace.yaml
$ kubectl exec -it workspace-6ff4f9d4cf-qwf6f sh
# ls -al /data-src/
total 4
drwxr-xr-x    2 root     root             6 Oct  7 06:18 .
drwxr-xr-x    1 root     root          4096 Oct  7 06:18 ..

# apk update
# apk add rsync
# rsync -av /data-dest/. /data-src/.
# exit
$
```

作業用のPodはPVCをumountするため、すぐに削除します。

```bash:
$ kubectl delete -f 02.deployment.workspace.yaml
```

不要となった作業用PVCは後からでも削除できるので、すぐに実行する必要はないですが、不要になったタイミングで削除します。

```bash:作業用PVCの削除
$ kubectl delete -f 01.pvc.create-temppvc.yaml
```

## 使用したYAMLファイル

```bash:
$ ls -l
total 16
-rw-rw-r-- 1 ubuntu ubuntu  226 Oct  7 04:41 01.pvc.create-temppvc.yaml
-rw-rw-r-- 1 ubuntu ubuntu  730 Oct  7 05:56 02.deployment.workspace.yaml
-rw-rw-r-- 1 ubuntu ubuntu  251 Oct  7 06:15 03.pvc.original-database0.yaml
```

# さいごに

最終的にPostgreSQLは無事に稼動して問題なくHarborは動き出しています。これから始めるのであれば、動的拡張やstartupProbeが利用できる事を考えると、できるだけ最新のK8s v1.18+Rook/Ceph v1.4以降の利用をお勧めします。

以上