vSphere with TanzuのSupervisorServiceを使ってHarborを構築する

SupervisorServiceとはvSphereのSupervisorから提供するアプリケーションのことで、yamlをvSphereに渡すことで色々なカタログ化されたアプリケーションをSupervisorクラスタ上に展開できるようになる。
現時点では[こちら](https://github.com/vsphere-tmm/Supervisor-Services/blob/main/README.md#supervisor-services-catalog)によると
- vDPP
- Velero
- Cert-Manager
- Harbor
- Contour
- ExternalDNS

が利用できる模様。
ここでは[公式ドキュメント](https://docs.vmware.com/en/VMware-vSphere/8.0/vsphere-with-tanzu-services-workloads/GUID-EB11DFDE-6ED4-4864-9E60-669F50D64397.html#GUID-EB11DFDE-6ED4-4864-9E60-669F50D64397)に従ってHarborをSupervisorServiceとして入れた時の作業をメモ化する。

なお、ここでの前提条件として以下があるものとする。
- vSphere 8.0u1以降
- NSX-Tで有効化したSupervisorCluster

メモの流れとしては以下となる
1. Contourのインストール
2. Harborのインストール
3. 動作確認コンテナイメージとして
  3.1. dockerコマンドで確認
  3.2. Supervisorクラスタから確認
  3.3. Tanzu Kubernetes Clusterから確認

## Contourのインストール

[Supervisor Services Catalog](https://github.com/vsphere-tmm/Supervisor-Services/blob/main/README.md#cloud-native-registry)からContourのyamlをDownloadする。
![1675400670110.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/7f64844e-c9c5-6f8d-d86d-6067edcafd78.png)
[`ワークロード管理`]->[`名前空間`]->[`サービス`]に飛び、「サービスの新規追加」の追加ボタンをクリックし、yamlを追加する。
![1675400712607.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/0cb852f2-d55e-51c6-7ba8-4f6b9fd785d5.png)
なお、vSphereが8.0aとかだと以下のようなエラーが出る。
```
ID contour.tanzu.vmware.com のスーパーバイザー サービスの作成は許可されていません。許可リストファイル /etc/vmware/wcp/supervisor-services-allow-list.txt で定義されているサービス ID のみが許可されます。
```
もしこれが表示された場合はvSphereのバージョンが8.0u1以降になっていることを確認する。

<!-- そこでvCenterにsshログインし、`/etc/vmware/wcp/supervisor-services-allow-list.txt`を開くと以下のようなコメントがある。
```
# if "allow_all_services" in the service config is turned off.
```
`allow_all_services`は`/etc/vmware/wcp/wcpsvc.yaml`に設定があるので、この値を`true`に変更してvCenterを再起動する。
 -->
問題ない場合、以下のように正常に登録できた旨が表示される。
![1675401717634.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/215ebb7a-830b-8992-33f9-97dbbb9db44f.png)
その下の方にcontourが表示されるので、こちらからインストールする。本来はここで設定変更するが、インストール後の設定変更を試してみたかったので、一旦設定はデフォルトで進める。
![1675401802419.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/2096a276-8961-9aac-fe1f-bdd6f04c9c55.png)

なお、スーパーバイザーがNSXと連携できていない場合、以下のようにスーパーバイザーがゼロとなり、インストール先が選べない。
![1682914881788.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/0d2f9701-2afc-d912-2cd4-13c3a6f1a799.png)
しばらく待つと、ContourがvSphere Podとして起動する。
```sh
$ kubectl get all -n svc-contour-domain-c8
NAME                          READY   STATUS           RESTARTS   AGE
pod/contour-8c96bbf96-55ltq   1/1     Running          0          3m41s
pod/contour-8c96bbf96-9cj6s   1/1     Running          0          3m41s
pod/envoy-qbnvn               2/2     Running          0          3m35s

NAME              TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                      AGE
service/contour   ClusterIP   10.96.0.248   <none>        8001/TCP                     3m45s
service/envoy     NodePort    10.96.0.241   <none>        80:30388/TCP,443:30661/TCP   3m45s

NAME                   DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
daemonset.apps/envoy   1         1         1       1            1           <none>          3m46s

NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/contour   2/2     2            2           3m45s

NAME                                DESIRED   CURRENT   READY   AGE
replicaset.apps/contour-8c96bbf96   2         2         2       3m45s
```

![1682918586373.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/56625cae-0081-93d7-2eb2-0f6b8f2c09f5.png)
`kubectl get all`の結果を見ると分かるが、Envoyが`type: Nodeport`で起動している。
これは先程設定せずにContourをデプロイしたためだ。
これを`type: LoadBalancer`に変更して、Envoyが外部に公開するIPアドレスを持つようにする。
[ワークロード管理]からスーパーバイザーを選択し、[`構成`]->[`スーパーバイザーサービス`]で、contourを選択して[`編集]`をクリックする。
`YAMLサービス構成`というYAML入力フォームが出てくるので、[SupervisorServicesのContourのページ](https://github.com/vsphere-tmm/Supervisor-Services/blob/main/README.md#contour-versions)にある[values for v1.18.2](https://vmwaresaas.jfrog.io/ui/api/v1/download?repoKey=supervisor-services&path=contour/v1.18.2/contour-data-values.yml)のyamlを取得して、内容を追記する。
（元の記述は残しておく）
追記してOKを押すと、自動で設定がクラスタ側に反映され、Envoyも自動で再起動する。
```sh
$ kubectl get svc -n svc-contour-domain-c8
NAME      TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)                      AGE
contour   ClusterIP      10.96.0.248   <none>          8001/TCP                     21m
envoy     LoadBalancer   10.96.0.241   10.220.14.228   80:30388/TCP,443:30661/TCP   21m
```
なお、WebUIからもExternal IPは取得できる。
![1682919655555.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/e3767084-e9ac-f9cc-78b3-f95d9317ad91.png)

## Harborのインストール

同じ手順でHarborもインストールする。
Harborのyaml(本体とvalues.yaml)をDownloadする。
![1675400626574.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/0b1218cd-3c1d-062a-20e7-36a1a0846bb1.png)
ダウンロード後、values.yamlを変更する。`hostname`と`storageClass`だけ修正してデプロイする。
`hostname`はドメインを持っていない人は、sslip.ioを利用するとよい。ここでは`ssharbor.10-220-14-228.sslip.io`を指定した。
パスワード等、他のパラメータも変えたい人はここで変えておく。なお変更禁止のパラメータもあるので、[公式手順](https://docs.vmware.com/jp/VMware-vSphere/8.0/vsphere-with-tanzu-services-workloads/GUID-EB11DFDE-6ED4-4864-9E60-669F50D64397.html#-5)を確認した上で変更すること。
変更後、Contourと同じようにサービスにHarborを追加して`スーパーバイザーへのインストール`からインストールする。
インストール完了後、Supervisor Namespaceが作成されてPodが展開される。
```
$ kubectl get pod -n svc-harbor-domain-c8
NAME                                 READY   STATUS    RESTARTS   AGE
harbor-core-78f5b4bf78-z9t79         1/1     Running   0          107m
harbor-database-0                    1/1     Running   0          116m
harbor-exporter-6d85f4f9d8-bdzjm     1/1     Running   0          116m
harbor-jobservice-79dbdb6666-j9hqd   1/1     Running   0          116m
harbor-portal-6cdcbc6f7-bg6dr        1/1     Running   0          116m
harbor-redis-0                       1/1     Running   0          116m
harbor-registry-6c48cb4d5-cs2xq      2/2     Running   0          116m
harbor-trivy-0                       1/1     Running   0          116m
```

Harborへアクセス後、ユーザ名`admin`、パスワード`Harbor12345`でログインすることができる。
![1682921151225.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/746b87b9-04fb-8b88-16c6-165b1605d10b.png)
組み込み版Harborと違って表示項目の多いHarborになっていることが分かる。
なお、インストール後にアクセス先のFQDNを取得する方法が公式に提供されていない気がする（httpproxyリソースは通常の方法では取得不可）。
アクセス先を忘れてしまったら、SupervisorServiceの編集ボタンから取得するのが現時点では解になりそう。

## Harborの利用
### dockerから利用する
試しに適当なイメージをpushしてみる。
まず、Harborの証明書を取得する。ログインして[`Configureation`]->[`System Settings`]から`Registry Root Certifacate`の横の`Download`を選択して証明書をDownloadする。
証明書をContainerランタイムに読み込ませる。Linux+Dockerの場合は以下。環境によって異なるため注意。
```
export HARBOR_HOST=ssharbor.10-220-14-228.sslip.io
sudo mkdir /etc/docker/certs.d/${HARBOR_HOST}
sudo mv ca.crt /etc/docker/certs.d/${HARBOR_HOST}
sudo systemctl restart docker
```
イメージをpushする。
```
docker pull nginx
docker tag nginx ssharbor.10-220-14-228.sslip.io/library/nginx
docker login $HARBOR_HOST -u admin -p Harbor12345
docker push ssharbor.10-220-14-228.sslip.io/library/nginx
```
特にミスがなければpushに成功する。LibraryはPublicだが、docker loginしていないとpushできなかった。ここでのPublicはどうやら子のTanzu Kubernetes Cluster(TKC)に対するPublicの模様。

ついでにpushしたイメージにTrivyよる脆弱性スキャンも実行してみた。
![1682922248317.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/27fe014d-3842-f8eb-a560-f497844e8dd8.png)
問題なく利用できた。

### Supervisor Clusterから利用する
クラスタのノードにHarborの証明書が入っていないため、そのままだと利用できない。
[公式ドキュメント](https://docs.vmware.com/jp/VMware-vSphere/8.0/vsphere-with-tanzu-services-workloads/GUID-EB11DFDE-6ED4-4864-9E60-669F50D64397.html#harbor----7)に、`kube-system`の`ConfigMap`のimage-fetcher-ca-bundleを編集するよう書いてあるのでやってみる。
以下のコマンドで`ConfigMap`を編集する。
```
kubectl edit cm -n kube-system image-fetcher-ca-bundle
```
editで開くと、元々あった証明書は崩れた形式で表示されたので、念の為整形して、シングルクォートで囲まれてたのも外して追記した。
以下の、2番め以降の証明書がHarborの証明書となる。
```yaml
data:
  ca-bundle: |
    -----BEGIN CERTIFICATE----- 
    MIIC/jCCAeagAwIBAgIBADANBgkqhkiG9w0BAQsFADAVMRMwEQYDVQQDEwprdWJl
    cm5ldGVzMB4XDTIzMDQxNzAwNTgwNVoXDTMzMDQxNDAwNTgwNVowFTETMBEGA1UE
    AxMKa3ViZXJuZXRlczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANjm
    zFSMcXuG6wR5YEvs9NdQEMQsXiplQMrYkIBEd2XmO5O8MyDxpQ5ji4ILt6XbyDS8
    0a4W+w0t7/xmosqvYCbWvvbANyUmlad2PDLRPQWtltZKp37Rmkqf/udnMnnpOw2E
    bTHZImagQea0iipzlntEOLNbsbBH3RReLnqvL5EuLHCK/NwEF7lo+gDBh3BwPq7C
    h+91h424VBOUHh1V4UyeKnZHmVxpHoNAHTbhX2LeZH57LP8fa4jQjMZ+RFgy54J4
    2s1b2U16vqSVhDZg+O9PLwR/XSa95eldeCOsQqMb7d5yfGer6elhzI37eBdLumfE
    uNjn+D443xuXW5jPxHECAwEAAaNZMFcwDgYDVR0PAQH/BAQDAgKkMA8GA1UdEwEB
    /wQFMAMBAf8wHQYDVR0OBBYEFPkHmBMrp4KvFMG5PMIsSN6vDR/iMBUGA1UdEQQO
    MAyCCmt1YmVybmV0ZXMwDQYJKoZIhvcNAQELBQADggEBACvl7wfdOrcR0mK9FcP8
    /KN/IFZQBboh3oNb0TVdDEzpmIt18b8T7MA23IikauD2H/2S3iX6sgULL3mL2vS/
    ijeZlRMdtgFccAUeWTs3jCLytSDIiOE5q9IWZ0U9PsNZNvMpig38GxxuVwn1Z/4z
    WyNY1r+wCHeHeVHIm+eisIJSfFTWAWkAA1yHHXjRUIRFPVi1psrbrL1Qs1XsPxAa
    35LbQ/L8SsSVW/50ZZEFnLVR0Wf15lC7dLAbiqWc0hd+6WWnk9GqDS0+DXjRWoJg
    L7ILsvzKudtmDJpUASx+tsxwc6eQCkIMFtLlHb3b5b/pBQLCmq0TzNtDs/O9dJYi
    4oM=
    -----END CERTIFICATE-----
    -----BEGIN CERTIFICATE-----
    MIIDKTCCAhGgAwIBAgIRAN2d+1dEquQvMvzQtyudC+AwDQYJKoZIhvcNAQELBQAw
    FDESMBAGA1UEAxMJSGFyYm9yIENBMB4XDTIzMDUwMTA1NDgzNFoXDTMzMDQyODA1
    NDgzNFowFDESMBAGA1UEAxMJSGFyYm9yIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC
    AQ8AMIIBCgKCAQEA4665pHHeG9aiJeujXkc+xTTnGIRucKdG9ZfJk1BdOzzszHVp
    OrOKVdSU4YnqrPsc1D1vOoFn57whfMURH+A2qbef5nTG2tym4Gx06AQRvR5EUNVQ
    ：（省略）
```
これを保存して先程pushしたイメージを起動してみる。
```
$ kubectl run --image ssharbor.10-220-14-228.sslip.io/library/nginx -n ns1 nginx
pod/nginx created
$ k get pod -n ns1
NAME    READY   STATUS    RESTARTS   AGE
nginx   1/1     Running   0          45s
```
問題ないようだ。何かしらのController系のPodの再起動なども不要だった。

### Tanzu Kubernetes Cluster(TKC)から利用する
Harborがいるスーパーバイザークラスタから作成されたTKCであれば、新規・既存関係なく設定不要で利用できる。
先程pushしたイメージを起動してみる。
```
$ kubectl run --image ssharbor.10-220-14-228.sslip.io/library/nginx -n default nginx
pod/nginx created
$ kubectl get pod
NAME    READY   STATUS              RESTARTS   AGE
nginx   1/1     Running             0          7s
```
こちらも問題なさそう。

## おまけ：SupervisorServiceの中身
Contourのyamlの中はKubernetesリソースとなっており、`kind: Package`と`kind: PackageMetadata`を利用している。
```sh
$ grep ind contour.yml
kind: Package
kind: PackageMetadata
```
またvalues.yamlの方は[Tanzu PackagesのContourの設定ファイル](https://docs.vmware.com/en/VMware-Tanzu-Kubernetes-Grid/1.6/vmware-tanzu-kubernetes-grid-16/GUID-packages-ingress-contour.html#deploy-contour-into-the-workload-cluster-3)と似ていることが分かる。

これより、`kind: App`リソースで動いていると推測できる。ControlPlaneにログインして実際に見てみる。
（ログイン方法は[こちらのkb](https://kb.vmware.com/s/article/90194)参照。自己責任で利用すること）

```
$ kubectl get app -A --kubeconfig /etc/kubernetes/admin.conf
NAMESPACE                           NAME                           DESCRIPTION           SINCE-DEPLOY   AGE
vmware-system-pkgs                  tanzu-addons-manager           Reconcile succeeded   10m            14d
vmware-system-pkgs                  tanzu-auth                     Reconcile succeeded   3m20s          14d
vmware-system-pkgs                  tanzu-capabilities             Reconcile succeeded   2m26s          14d
vmware-system-pkgs                  tanzu-cliplugins               Reconcile succeeded   3m43s          14d
vmware-system-pkgs                  tanzu-featuregates             Reconcile succeeded   39s            14d
vmware-system-pkgs                  tanzu-framework                Reconcile succeeded   2m19s          14d
vmware-system-pkgs                  tkr-service                    Reconcile succeeded   5m54s          14d
vmware-system-supervisor-services   svc-contour.tanzu.vmware.com   Reconcile succeeded   8m58s          131m
vmware-system-supervisor-services   svc-harbor.tanzu.vmware.com    Reconcile succeeded   7m10s          100m
```
HarborとContourのAppリソースが確認できた。トラブルがあった際はTanzu Packageと同じアプローチで臨むと良さそうだ。

## おまけ２
[公式ドキュメント](https://docs.vmware.com/jp/VMware-vSphere/8.0/vsphere-with-tanzu-services-workloads/GUID-052CF490-4B77-4CA2-8A4C-8624718ADA4E.html)の誤植が面白かった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/547981/dd6d589f-e0ca-6088-e1f1-9f2905726dc8.png)
都道府県て。。。