Tanzu Community Edition + Contour + ExternalDNS でアプリのURL を払い出してみよう

# はじめに
[ExternalDNS](https://github.com/kubernetes-sigs/external-dns) はKuburnetes のService やIngress と同期し、DNSレコードを動的に設定してくれるツールです。Kubernetes クラスタと外部のDNS プロバイダー（例えばAWS であればRoute53）を繋ぐ存在ともいえ、アプリケーションのデプロイ後、名前解決可能なFQDN を自動的に払い出すために役立ちます。

本記事では、Tanzu Community Edition (TCE) にデプロイしたアプリケーションを、Contour とExternalDNS を使ってURL として払い出すまでの道のりを紹介します。

# 環境の準備
今回は最も展開が迅速なTCE のDocker Standalone Cluster(Management Cluster なし)で試します。Docker をホストするOS はLinux です。

デプロイ方法は[ドキュメント](https://tanzucommunityedition.io/docs/latest/getting-started-standalone/)通りなので詳細は割愛しますが、Linux でデプロイする場合の注意点としては、docker をroot 以外のユーザーとして使えるよう以下の手順を忘れずに実行します。

>In Docker, you must create the docker group and add your user before you attempt to create a standalone or management cluster. Complete steps 1 to 4 in the [Manage Docker as a non-root user](https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user) procedure in the Docker documentation.

:::note warn
root ユーザーでインストールスクリプトを叩こうとするとエラーで弾かれます。
:::

なお、Standalone Cluster のデプロイに失敗した場合は、素直に[Tanzu Diagnostics](https://tanzucommunityedition.io/docs/latest/tsg-bootstrap/) やkubectl コマンドでトラシュしてもよいですが、VM であればスナップショットからやり直すのが最も簡単です。もしくは、tanzu standalone-cluster delete でStandalone Cluster を削除したり、それができなかった場合はdocker コマンドで直接コンテナを削除した後に、~/vmware/.config/tanzu/tkg/config.yaml の削除を行います（このファイルにはデプロイしたStandalone Cluster のメタデータが含まれます）。


参考までに、Standalone Cluster デプロイ時はこんな感じのログが出ます。

    $ tanzu standalone-cluster create -i docker tce

    Downloading TKG compatibility file from 'projects.registry.vmware.com/tkg/framework-zshippable/tkg-compatibility'
    Downloading the TKG Bill of Materials (BOM) file from 'projects.registry.vmware.com/tkg/tkg-bom:v1.4.0'
    Downloading the TKr Bill of Materials (BOM) file from 'projects.registry.vmware.com/tkg/tkr-bom:v1.21.2_vmware.1-tkg.1'

    Validating the pre-requisites...
    Identity Provider not configured. Some authentication features won't work.

    Setting up standalone cluster...
    Validating configuration...
    Using infrastructure provider docker:v0.3.23
    Generating cluster configuration...
    Setting up bootstrapper...
    Bootstrapper created. Kubeconfig: /home/vmware/.kube-tkg/tmp/config_haSZnbb8
    Installing providers on bootstrapper...
    Start creating standalone cluster...
    Saving standalone cluster kubeconfig into /home/vmware/.kube/config
    Waiting for bootstrap cluster to get ready for save ...
    Waiting for addons installation...
    Moving all Cluster API objects from bootstrap cluster to standalone cluster...
    Context set for standalone cluster tce as 'tce-admin@tce'.
    Cleaning up unneeded resources (for standalone clusters)...

    Standalone cluster created!


    You can now use Kubectl to access your cluster:

    kubectl get pods -A


    You can also delete the cluster by running the following:

    tanzu standalone-cluster delete [name]


    Some addons might be getting installed! Check their status by running the following:

    kubectl get apps -A

これですぐにTCE でのKuberentes にアクセスすることができます。

```
$ kubectl get node
NAME                        STATUS   ROLES                  AGE    VERSION
tce-control-plane-9ks4t     Ready    control-plane,master   113m   v1.21.2+vmware.1-360497810732255795
tce-md-0-554568695c-9tb8r   Ready    <none>                 112m   v1.21.2+vmware.1-360497810732255795
```

# DNS サーバーの設定
ExternalDNS として対応しているクラウドプロバイダー（レコードの登録先）は下記の通りです。今回はWindows Server 2019 (RFC2136) を使います。

https://github.com/kubernetes-sigs/external-dns

Windows Server DNS 側の設定としては、下記を行います。
1. ゾーンの作成
2. ゾーンに対する動的更新の有効化
3. ゾーン転送の許可

今回は、tuna.lab というゾーンを作成し、ステップ2 と3 を実行しています。

![dynamic-update.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2326226/014154d3-5064-3dcf-681b-0fe1afbca32d.png)
![zone.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2326226/49ea4ee2-183f-9e73-0137-41c034ec1a04.png)

# MetalLB のインストール
Docker でTCE をデプロイした後は、LoadBalancer リソースを準備します。今回は[MetalLB](https://metallb.universe.tf/) を使用します。インストール方法は[コチラ](https://metallb.universe.tf/installation/)。

    kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.11.0/manifests/namespace.yaml
    kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.11.0/manifests/metallb.yaml

ただし、このままだとIP アドレスがLB にアサインされないため、別途Configmap を作成します。

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 172.19.255.1-172.19.255.254
```
IP アドレスのレンジは、自身のdocker 環境に合わせて変更しましょう。


    $ docker network inspect kind
    [
        {
        ~~~
            "IPAM": {
                "Driver": "default",
                "Options": {},
                "Config": [
                    {
                        "Subnet": "172.19.0.0/16",
                        "Gateway": "172.19.0.1"
                    },
                    {
                        "Subnet": "fc00:f853:ccd:e793::/64"
                    }
                ]
            },
        ~~~
    ]

# Contour のインストール

https://tanzucommunityedition.io/docs/latest/package-readme-contour-1.18.1/

次にContour をインストールしてみましょう。なお、Contour については、[コチラ](https://qiita.com/hichtakk/items/b0cac4b766a58755062a)の素晴らしい記事をご参照ください。

TCE ではtanzu package コマンドを使って、Contour やExternalDNS をインストールできます（MetalLB はtanzu package コマンドの対象外なので手動でインストールしました）。

下記ドキュメントに従い、TCE パッケージリポジトリをインストールします。
https://tanzucommunityedition.io/docs/latest/package-management/

    tanzu package repository add tce-repo --url projects.registry.vmware.com/tce/main:0.9.1 --namespace tanzu-package-repo-global

下記のコマンドでインストール可能なバージョンを調べた後、tanzu package install コマンドでcontour をインストールします。

```
$ tanzu package available list contour.community.tanzu.vmware.com --namespace tanzu-package-repo-global

- Retrieving package versions for contour.community.tanzu.vmware.com... 
  NAME                                VERSION  RELEASED-AT           
  contour.community.tanzu.vmware.com  1.17.1   2021-07-23T18:00:00Z  
  contour.community.tanzu.vmware.com  1.17.2   2021-07-23T18:00:00Z  
  contour.community.tanzu.vmware.com  1.18.1   2021-07-23T18:00:00Z 
```

LoadBalancer リソースを既に準備しているため、インストールは下記のコマンドでOK です。

```
tanzu package install contour --package-name contour.community.tanzu.vmware.com --version 1.18.1
```

Pod のステータスが下記のように出力されていればOK です。

```
$ kubectl get pod -n projectcontour
NAME                            READY   STATUS      RESTARTS   AGE
contour-65b57dc6cb-bg26h        1/1     Running     0          58m
contour-65b57dc6cb-wxzwz        1/1     Running     0          59m
contour-certgen-v1.18.1-992bm   0/1     Completed   0          86m
envoy-c2cww                     2/2     Running     0          86m
```

:::note warn
Pod がdocker pull rate limits に引っ掛かった場合は、kubectl edit コマンドでイメージレジストリを無理やり差し替えてしまうことでデプロイできました。 
:::

# ExternalDNS のインストール

https://tanzucommunityedition.io/docs/latest/package-readme-external-dns-0.8.0/

同様に、tanzu package コマンドでExternalDNS をインストールします。tanzu package コマンドに入れるExternalDNS の設定値を含むvalues ファイルは下記のように作成しました。ドメイン名やDNS サーバーのアドレスは適宜変更してください。

```yaml:values.yaml
namespace: external-dns

#! Deployment related configuration
deployment:
  args:
  - --txt-prefix=external-dns- 
  - --txt-owner-id=k8s
  - --provider=rfc2136
  - --rfc2136-host=10.198.99.49
  - --rfc2136-port=53
  - --rfc2136-zone=tuna.lab
  - --rfc2136-insecure
  - --rfc2136-tsig-axfr
  - --source=service
  - --source=contour-httpproxy
  - --domain-filter=tuna.lab
  env: []
  securityContext: []
  volumeMounts: []
  volumes: []
```
バージョンはContour と同様tanzu package コマンドで調べることができます。value ファイルを作成したらさっそくインストールしましょう。

```
$ tanzu package available list --namespace tanzu-package-repo-global external-dns.community.tanzu.vmware.com
- Retrieving package versions for external-dns.community.tanzu.vmware.com... 
  NAME                                     VERSION  RELEASED-AT           
  external-dns.community.tanzu.vmware.com  0.8.0    2021-06-11T18:00:00Z

$ tanzu package install external-dns --package-name external-dns.community.tanzu.vmware.com --version 0.8.0 --values-file values.yaml 
```

インストールの結果、ExternalDNS Pod がこのようなログを吐き出していれば成功です。


    $ kubectl logs -n external-dns external-dns-5bc9d7f96b-xl78h
    ~~~
    time="2021-12-05T16:15:34Z" level=info msg="Instantiating new Kubernetes client"
    time="2021-12-05T16:15:34Z" level=info msg="Using inCluster-config based on serviceaccount-token"
    time="2021-12-05T16:15:34Z" level=info msg="Created Kubernetes client https://100.64.0.1:443"
    time="2021-12-05T16:15:35Z" level=info msg="Created Dynamic Kubernetes client https://100.64.0.1:443"
    time="2021-12-05T16:15:36Z" level=info msg="Configured RFC2136 with zone 'tuna.lab.' and nameserver '10.198.99.49:53'"


これで、アプリケーションをデプロイする準備が整いました。

# アプリケーションのデプロイ
今回デプロイするアプリケーションは、Contour のWeb サイトにもある[kuard](https://github.com/kubernetes-up-and-running/kuard) を使います。

今回は下記をkuard のマニフェストを（ほぼそのまま）利用します。

https://github.com/kubernetes-sigs/external-dns/blob/v0.8.0/docs/tutorials/contour.md

```yaml:kuard.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: kuard
  name: kuard
spec:
  replicas: 3
  selector:
    matchLabels:
      app: kuard
  template:
    metadata:
      labels:
        app: kuard
    spec:
      containers:
      - image: gcr.io/kuar-demo/kuard-amd64:1
        name: kuard
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: kuard
  name: kuard
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 8080
  selector:
    app: kuard
  sessionAffinity: None
  type: ClusterIP
---
apiVersion: projectcontour.io/v1
kind: HTTPProxy
metadata:
  labels:
    app: kuard
  name: kuard
  namespace: default
spec:
  virtualhost:
    fqdn: kuard-docker.tuna.lab
  routes:
    - conditions:
      - prefix: /
      services:
        - name: kuard
          port: 80
```
    $ kubectl get deployment
    NAME           READY   UP-TO-DATE   AVAILABLE   AGE
    kuard          3/3     3            3           35m

httpproxy リソースも問題なく払い出されていることを確認します。

```
$ kubectl get httpproxy
NAME    FQDN                    TLS SECRET   STATUS   STATUS DESCRIPTION
kuard   kuard-docker.tuna.lab                valid    Valid HTTPProxy
```

アプリケーションのデプロイの後、ExternalDNS は動的更新を有効にしたWindows Server にレコードを追加します。

    $ kubectl logs -n external-dns external-dns-5bc9d7f96b-xl78h
    ~~~
    time="2021-12-05T16:18:41Z" level=info msg="Adding RR: kuard-docker.tuna.lab 0 A 172.19.255.1"
    time="2021-12-05T16:18:41Z" level=info msg="Adding RR: external-dns-kuard-docker.tuna.lab 0 TXT \"heritage=external-dns,external-dns/owner=k8s,external-dns/resource=HTTPProxy/default/kuard\""

Windows Server を見ると、DNS レコードが追加されていることが分かります。

![record.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2326226/33bca5f1-e971-e955-9769-352e2c1dd2e5.png)


当然、払い出されたURL でアプリケーションにアクセスすることが可能です。
![kuard.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2326226/6a611e08-3426-5f64-6c20-8bfb7e912ea0.png)