Embedded HarborをTKC(TKG Guest Cluster)から使えるようにする


# 問題提起

vSphere for k8sの目玉機能としてvCenterからEmbedded Harborをつくることができるという点です。
こんな感じでvCenterからHarborをいじれるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666491/ebaf7ba0-7d9f-a865-71eb-dd7afacf1b49.png)


基本的には、これをそのまま使えばいいのですが、一つ問題があり、 TKC(Tanzu Kubernetes Guest Cluster)からは利用できないという点です。
理由がHarborのSSL証明書がTKC側で登録がされておらず、使えない状態のためです。

海外のブログで直しかたが紹介されていますが、異様に煩雑な手順となっており、気軽に試せそうにないです。

https://cormachogan.com/2020/06/23/integrating-embedded-vsphere-with-kubernetes-harbor-registry-with-tkg-guest-clusters/

この記事では、上の改良版として

* Step 2.をKubernetesの仕組みで自動化
* Step 3.の手順を汎用化
* Step 4.も改良
* 日本語化
したものとなっています。

# 注意事項

この手段はサポートされた手段ではないです。
また、Privileged Podsの仕組みを使っているので、セキュリティ上よろしくない手段です。
よく理解した上、自己責任でお願いします。

# 手順

## 1. TKCのKubeconfigを生成する

まずTKCのkubeconfigをダウンロードするのですが、手順はここにあるものを使います。

https://docs.vmware.com/en/VMware-vSphere/7.0/vmware-vsphere-with-kubernetes/GUID-C099E736-43A6-464C-9BFA-29B8509F0DA1.html

最後の`tkg-cluster-kubeconfig-admin`を`KUBECONFIG`関数などにエクスポートします。

```
export KUBECONFIG=/enter_dir/tkg-cluster-kubeconfig-admin
```

`kubectl get nodes`などして、問題ないか確認します。

## 2. HarborのRoot証明書をSecretとして登録

次に、Root証明書をゲットします。

[ Cluster ] > [ Configure ] > [ Namespaces ] > [ Image Registry ]にあるのでそれをダウンロードします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666491/38c33cd1-335d-ad76-4713-159a78935eda.png)

これを`./root-certificate.txt`などに保管してkubernetes側に登録します。

```
kubectl create ns harbor-setup
kubectl create secret generic harbor-registry --from-file=./root-certificate.txt -n harbor-setup
```

## 3. TKCノードの証明書を更新するシェルスクリプト(ConfigMap)の用意

以下のシェルスクリプトを作成します。
これによってホストOSの証明書を更新するシェルスクリプトを実行します。

名前は`harbor-setup.sh`としてください。

```bash

#!/bin/bash
set -x

NSENTER="/usr/bin/nsenter -t 1 -m -u -n -i --"

HEAD=`cat /tmp/harbor-cert | head -2 | sed 1d`
${NSENTER} grep -q ${HEAD} /etc/pki/tls/certs/ca-bundle.crt || {

  ${NSENTER} cp /etc/pki/tls/certs/ca-bundle.crt /tmp/
  cat /tmp/harbor-cert  >> /host/ca-bundle.crt

  ${NSENTER} cp /tmp/ca-bundle.crt /etc/pki/tls/certs/ca-bundle.crt
  ${NSENTER} systemctl -a | grep -q docker.service && { 
    ${NSENTER} systemctl restart docker.service
    ${NSENTER} systemctl status docker.service
  }
  ${NSENTER} systemctl -a | grep -q containerd.service && { 
    ${NSENTER} systemctl restart containerd.service
    ${NSENTER} systemctl status containerd.service
  }
}
while true; do
 sleep 3600
done
```
そしてそれをConfigMapとして登録します。

```
kubectl create configmap harbor-setup-bash --from-file=harbor-setup.sh -n harbor-setup
```
## 4. Daemonsetを作成する。

harbor-setupネームスペースで、privileged podの作成を許可します。

```
kubectl create rolebinding  harbor-setup --namespace=harbor-setup --clusterrole=psp:vmware-system-privileged --group=system:serviceaccounts
```

以下を実行します。

```yaml

kubectl create -n harbor-setup -f - <<EOF
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: harbor-setup
spec:
  selector:
    matchLabels:
      job: harbor-setup
  template:
    metadata:
      labels:
        job: harbor-setup
    spec:
      hostPID: true
      containers:
      - image: alpine
        name: harbor-setup
        command: ["sh", "/tmp/harbor-setup.sh"]
        securityContext:
          privileged: true
        volumeMounts:
        - name:  harbor-setup
          mountPath: /tmp/harbor-setup.sh
          subPath: harbor-setup.sh
          readOnly: true
        - name:  harbor-cert
          mountPath: /tmp/harbor-cert
          subPath: root-certificate.txt
          readOnly: true
        - name: host-mount
          mountPath: /host
      volumes:
      - name: harbor-setup
        configMap:
          name: harbor-setup-bash
      - name: harbor-cert
        secret:
          secretName: harbor-registry
      - name: host-mount
        hostPath:
          path: /tmp/
EOF
```
`kubectl get ds -n harbor-setup`でWorkerNode数分起動している確認します。

```
NAME           DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
harbor-setup   3         3         3       3            3           <none>          11s
```

なお、このデーモンセットはprivilegedで走らせているため非常に危険なPodです。
**1分以上したら 以下のコマンドでけしてあげてください**

```
kubectl delete ds harbor-setup -n harbor-setup
```

手順としては以上です。

# 検証

HarborにあるこのイメージをTKCからダウンロードできるか試します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666491/b416c446-05ab-cea5-6260-ebd0e6fece31.png)

## 1. ImagePullSecretをNamespaceごとに生成

面倒ですが、Harborの認証情報はNamespaceごとに作らないといけないです。
検証用のNamespaceを作ります。

```
kubectl create ns pulltest
```

そして、認証情報を登録します。

```
kubectl create -n pulltest secret docker-registry regsecret --docker-server=10.195.35.38 --docker-username=XXXXXXX --docker-password='XXXXXX'
```

XXXX には正しい情報をいれてください。
そして、それを`default`サービスアカウントにパッチします。

```
kubectl patch sa default -n pulltest -p '"imagePullSecrets": [{"name": "regsecret" }]'
```

これで準備完了です。

## 2. 検証する

これでイメージを走らせてみます。

```
kubectl create deployment -n pulltest --image=10.195.35.38/common/nginx test
```

走っていることを確認します。

```
kubectl get po -n pulltest
NAME                   READY   STATUS    RESTARTS   AGE
test-ccf848d49-p42kc   1/1     Running   0          30s
```
ちゃんとイメージがPullされたことを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666491/0a3f3609-d89e-3df8-39d4-649964f5f127.png)

OKですね。成功です。

# まとめ

TKCでHarborをつかうのも簡単にできます。