Application Toolkitでsource-to-urlをやってみる

[Cartographerをインストールして基本的なサプライチェーンを作って、Cartographerの使い方を確認してみました](https://qiita.com/masanara/items/389fb060fbf9cd01be82)が、今回は実用的なsource-to-urlを試してみます。

Tanzu Community Edition(TCE)のパッケージに含まれるApplication Toolkit(app-toolkit)は、Kubernetes上のリソースを利用してsource-to-urlを実現するためのコンポーネントで構成されています。[2022年5月6日現在 最新のリリースバージョンはTCE v0.11.0に含まれるApplication Toolkit v0.1.0](https://tanzucommunityedition.io/docs/v0.11/package-readme-app-toolkit-0.1.0/)ですが、ClusterSupplyChainを作成やサプライチェーンの実行に必要なRBAC設定を自身でする必要があったり、kpackからプライベートCAが発行した証明書を使ったレジストリを利用することができません。リリース間近のTCE v0.12.0に含まれるっぽい[Application Toolkit v0.2.0](https://github.com/vmware-tanzu/community-edition/tree/v0.12.0/addons/packages/app-toolkit/0.2.0)は[source-to-urlを実現するためのClusterSupplyChainが含まれていたり](https://github.com/vmware-tanzu/community-edition/tree/v0.12.0/addons/packages/cartographer-catalog/0.3.0)、[プライベートCAが発行した証明書を使ったレジストリを利用することもできそう](https://github.com/vmware-tanzu/community-edition/tree/v0.12.0/addons/packages/cert-injection-webhook/0.1.1)なので、TCEクラスター上にHarborとApplication Toolkit v0.2.0をインストールしてsource-to-urlを試してみました。

Application Toolkit v0.2.0は以下のコンポーネントで構成されるようです。

| Name                                                         | Description                                                  | Version |
| :----------------------------------------------------------- | :----------------------------------------------------------- | :------ |
| [Cartographer](https://tanzucommunityedition.io/docs/v0.12/package-readme-cartographer-0.3.0/) | Cartographer allows you to create secure and reusable supply chains that define all of your application CI and CD in one place, in cluster. | 0.3.0   |
| [Cartographer-Catalog](https://tanzucommunityedition.io/docs/v0.12/package-readme-cartographer-catalog-0.3.0/) | Reusable Cartographer Supply Chains and templates for driving workloads from source code to running Knative service in a cluster. | 0.3.0   |
| [cert-manager](https://tanzucommunityedition.io/docs/v0.12/package-readme-cert-manager-1.8.0/) | Cert Manager provides certificate management functionality.  | 1.8.0   |
| [Contour](https://tanzucommunityedition.io/docs/v0.11/package-readme-contour-1.20.1/) | Contour provides Ingress capabilities for Kubernetes clusters | 1.20.1  |
| [Flux CD Source Controller](https://tanzucommunityedition.io/docs/v0.12/package-readme-fluxcd-source-controller-0.21.2/) | FluxCD Source specialises in artifact acquisition from external sources such as Git, Helm repositories and S3 buckets. | 0.21.2  |
| [Knative Serving](https://tanzucommunityedition.io/docs/v0.12/package-readme-knative-serving-1.0.0/) | Knative Serving provides the ability for users to create serverless workloads from OCI images | 1.0.0   |
| [kpack](https://tanzucommunityedition.io/docs/v0.12/package-readme-kpack-0.5.2/) | kpack provides a platform for building OCI images from source code. | 0.5.2   |
| [kpack-dependencies](https://tanzucommunityedition.io/docs/v0.12/package-readme-kpack-dependencies-0.0.9/) | kpack-dependencies provides a curated set of buildpacks and stacks required by kpack. | 0.0.9   |

## 準備

TCEパッケージリポジトリ version 0.12.0を追加します。

```bash
$ tanzu package repository add tce-repo --url projects.registry.vmware.com/tce/main:0.12.0 --namespace tanzu-package-repo-global
```

パッケージリポジトリが追加されたことを確認します。

```bash
$ tanzu package repository list -n tanzu-package-repo-global
  NAME      REPOSITORY                             TAG     STATUS               DETAILS
  tce-repo  projects.registry.vmware.com/tce/main  0.12.0  Reconcile succeeded
```

リポジトリに含まれるapp-toolkitを確認してみます。

```bash
$ tanzu package available get app-toolkit.community.tanzu.vmware.com/0.2.0
NAME:                             app-toolkit.community.tanzu.vmware.com
VERSION:                          0.2.0
RELEASED-AT:                      2022-04-21 18:59:24 +0000 UTC
DISPLAY-NAME:                     App-Toolkit package for TCE
SHORT-DESCRIPTION:                Kubernetes-native toolkit to support application lifecycle
PACKAGE-PROVIDER:                 VMware
MINIMUM-CAPACITY-REQUIREMENTS:
LONG-DESCRIPTION:                 Meta-Package to install a set of TCE packages that help users to create, iterate and manage their applications
MAINTAINERS:                      [{Glenio Borges} {Kris Applegate} {Ryan Kilroy}]
RELEASE-NOTES:
LICENSE:                          [Apache 2.0]
SUPPORT:                          For help go to #tanzu-community-edition in the kubernetes slack workspace.
CATEGORY:                         [application lifecycle]
```

Harborを利用するためにcert-managerとcontourをインストールします。

```bash
$ tanzu package install cert-manager --package-name cert-manager.community.tanzu.vmware.com --version 1.8.0 -n tanzu-package-repo-global
```

contourはLoadBalancer経由で利用できるようvalue-contour.yamlファイルを作成します。(MetalLBでLoadBalancerを使えるように設定済み)

```yaml
envoy:
  service:
    type: LoadBalancer
  hostPorts:
    enable: true
```

values-contour.yamlファイルを指定してcontourをインストールします。

```bash
$ tanzu package install contour --package-name contour.community.tanzu.vmware.com --version 1.20.1 -f values-contour.yaml -n tanzu-package-repo-global
```

## Harborのインストール

harbor-values.yamlファイルのテンプレートを作成するため、imgpkgでharborパッケージを取得し、パッケージに含まれるvalues.yamlファイルとgenerate-password.shスクリプトを取り出します。

```bash
$ image_url=$(kubectl get package harbor.community.tanzu.vmware.com.2.4.2 -o jsonpath='{.spec.template.spec.fetch[0].imgpkgBundle.image}')
$ imgpkg pull -b $image_url -o /tmp/harbor-package
$ cp /tmp/harbor-package/config/values.yaml harbor-values.yaml
$ cp /tmp/harbor-package/config/scripts/generate-passwords.sh generate-passwords.sh
```

generate-password.shスクリプトを利用して、harbor-values.yamlのパスワード・シークレットを設定し、yqでコメント部分を削除します。

```bash
$ ./generate-passwords.sh harbor-values.yaml
$ yq -i eval '... comments=""' harbor-values.yaml
```

harbor-values.yamlで以下の箇所を修正します。

```yaml
hostname: harbor.tce.example.com
harborAdminPassword: password
network:
  ipFamilies: ["IPv4"]
```

作成したharbor-values.yamlでharborをインストールします。

```bash
$ tanzu package install harbor -p harbor.community.tanzu.vmware.com -v 2.4.2 -n tanzu-package-repo-global -f harbor-values.yaml
```

harborで利用する証明書を指定していないためcert-managerによってharbor向けのプライベートCAが構成され証明書が発行されます。プライベートCAの証明書を取得します。

```bash
$ kubectl get secret -n harbor harbor-ca-key-pair -o=jsonpath='{.data.ca\.crt}' | base64 -d > tce-harbor.crt
```

この時点でcert-manager/contour/harborのインストールが完了します。

```bash
$ tanzu package installed list -n tanzu-package-repo-global
  NAME          PACKAGE-NAME                             PACKAGE-VERSION  STATUS
  cert-manager  cert-manager.community.tanzu.vmware.com  1.8.0            Reconcile succeeded
  contour       contour.community.tanzu.vmware.com       1.20.1           Reconcile succeeded
  harbor        harbor.community.tanzu.vmware.com        2.4.2            Reconcile succeeded
```

## Application Toolkitのインストール


開発者向けのネームスペースでビルドされたコンテナイメージをpushする先のレジストリ(今回はharbor)のクレデンシャルをtanzu CLIでSecretリソースとして作成します。このSecretリソースは、Application Toolkitが作成する開発者向けのネームスペース(demo)に自動的に複製されます。

```bash
export REGISTRY_URL=harbor.tce.example.com
export REGISTRY_USER=admin
export REGISTRY_PASS=password
tanzu secret registry add registry-credentials --server ${REGISTRY_URL} --username ${REGISTRY_USER} --password ${REGISTRY_PASS} --export-to-all-namespaces
```

以下の内容で`values.yaml`を作成します。app-toolkiitにはcert-managerとcontourが含まれていますが、harborの実行に依存するため`excluded_packages`として除外しています。kpackの`ca_cert_data`にはharborのCA証明書(tce-harbor.crt)を指定し、kappコントローラがharborの証明書を信頼するように設定します。

```yaml
excluded_packages:
  - contour.community.tanzu.vmware.com
  - cert-manager.community.tanzu.vmware.com

cartographer_catalog:
  registry:
    server: harbor.tce.example.com
    repository: app-toolkit

developer_namespace: demo

knative_serving:
  domain:
    type: real
    name: tce.example.com

kpack:
  kp_default_repository: "harbor.tce.example.com/tce/kpack"
  kp_default_repository_username: "admin"
  kp_default_repository_password: "password"
  ca_cert_data: |
    -----BEGIN CERTIFICATE-----
    MIIDKDCCAhCgAwIBAgIQUKldItiLh3TJalPDu6/81jANBgkqhkiG9w0BAQsFADAU
    MRIwEAYDVQQDEwlIYXJib3IgQ0EwHhcNMjIwNTA2MDA0MzQwWhcNMzIwNTAzMDA0
    MzQwWjAUMRIwEAYDVQQDEwlIYXJib3IgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB
    DwAwggEKAoIBAQC8SmQv6oYcmDk+FnWS8Lx5aUV7hjWspusxMqlkAKbHtIi9qn1S
    8qyY8HSOz1oXVB7fW6XpbtwOowWtepwk39f7O7A4RN6XsQKj0ETVy72vX6hnvZIr
    u1l6kQkykdnXVoAnPAWiHIPwuSPpuqTy7OHvbqSNix5vPEjRbv6ilLgAu7tOYfEA
    SRpSHyLkQpdYxjcI1ZSp8b/wpzSvTUid9pv+DwCZD4E5xqyNZcqimUTdRMGf6E0E
    5NasHkL9eoIurjw61v5f08AhDOSf27Sekae3PU8cLBMliVO5IOYAPk6DgYh07s4L
    f3S0F2a3svSvsvJtaROUiluKctQhwU9dQUhtAgMBAAGjdjB0MA4GA1UdDwEB/wQE
    AwICBDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUw
    AwEB/zAdBgNVHQ4EFgQUkKtbSAyejxAaY1eU8c5H9IyeXCgwEwYDVR0RBAwwCoII
    aGFyYm9yY2EwDQYJKoZIhvcNAQELBQADggEBABFediViemS9mwxBt6k6Qnar3Osc
    jhKmUjNJSL4v3A0RFDTqn76DRJXGRAM7HM49JB4dMjJ3OTnMoRlMgADvH3i07nZI
    oaPeL8bf9Pe21ticCf2g13qlzJ8P9fZaKGdQZJ4zxZxu3Z3CYxLti3mOSxXk84C3
    QLfphZgdvzZqs0Y6LJpmpDfh2lY4xLLTNwrAut6ZYT54pJr8vIoIbuxt0QXD2lEy
    JyqD86Eyag7jS+Gd1Q4RTcwgJdS2lOLtLwddy672vv9bGOSRBhfTjhBNRyN9Y8Gj
    J3iofBdvpNfm64nAToJ1zLB2I6+VOZBlCkCj4snyUV93LgBzkYEMMUMbvRM=
    -----END CERTIFICATE-----
```

Application Toolkitをインストールします。

```bash
$ tanzu package install app-toolkit --package-name app-toolkit.community.tanzu.vmware.com --version 0.2.0 -f values.yaml -n tanzu-package-repo-global
```

app-toolkitに含まれコンポーネントがすべてインストールされます。

```bash
$ tanzu package installed list -n tanzu-package-repo-global
  NAME                      PACKAGE-NAME                                         PACKAGE-VERSION  STATUS
  app-toolkit               app-toolkit.community.tanzu.vmware.com               0.2.0            Reconcile succeeded
  cartographer              cartographer.community.tanzu.vmware.com              0.3.0            Reconcile succeeded
  cartographer-catalog      cartographer-catalog.community.tanzu.vmware.com      0.3.0            Reconcile succeeded
  cert-injection-webhook    cert-injection-webhook.community.tanzu.vmware.com    0.1.1            Reconcile succeeded
  cert-manager              cert-manager.community.tanzu.vmware.com              1.8.0            Reconcile succeeded
  contour                   contour.community.tanzu.vmware.com                   1.20.1           Reconcile succeeded
  fluxcd-source-controller  fluxcd-source-controller.community.tanzu.vmware.com  0.21.2           Reconcile succeeded
  harbor                    harbor.community.tanzu.vmware.com                    2.4.2            Reconcile succeeded
  knative-serving           knative-serving.community.tanzu.vmware.com           1.0.0            Reconcile succeeded
  kpack                     kpack.community.tanzu.vmware.com                     0.5.2            Reconcile succeeded
  kpack-dependencies        kpack-dependencies.community.tanzu.vmware.com        0.0.9            Reconcile succeeded
```

cartographer-catalogパッケージにより、ClusterSourceTemplate, ClusterImageTemplate、ClusterTemplate、ClusterSupplyChainが作成され、source-to-urlのためのサプライチェーンが構成されます。

```bash
$ kubectl get csc,cst,cit,ct
NAME                                         READY   REASON   AGE
clustersupplychain.carto.run/source-to-url   True    Ready    118m

NAME                                             AGE
clustersourcetemplate.carto.run/git-repository   118m

NAME                                   AGE
clusterimagetemplate.carto.run/image   118m

NAME                            AGE
clustertemplate.carto.run/app   118m
```

source-to-url ClsuterSupplyChainは以下の内容で構成されています。

1. source-provider : 指定されたソースコードから`gitrepositories.source.toolkit.fluxcd.io`リソースを作成します。
2. image-builder : source-providerの`gitrepositories`利用して`images.kpack.io`を作成し、アプリケーションとコンテナイメージをビルドします。
3. deployer : image-builderの`images.kpack.io`を利用して、kapp-controllerにより`service.serving.knative.dev`リソースを作成してPod/HTTPProxy/RevisionのReconcileを行います。

```mermaid
flowchart RL
  Kpack -- commit --> GitRepository
  App -- container image --> Kpack

  subgraph source-provider
  GitRepository
  end

  subgraph image-builder
  Kpack
  end

  subgraph deployer
  App
  end
```

```yaml
apiVersion: carto.run/v1alpha1
kind: ClusterSupplyChain
metadata:
  name: source-to-url
spec:
  params:
  - default:
      repository: app-toolkit
      server: harbor.tce.example.com
    name: registry
  - default: default
    name: cluster_builder
  - default: default
    name: service_account
  - default: go-git
    name: git_implementation
  - default: ""
    name: git_secret
  resources:
  - name: source-provider
    templateRef:
      kind: ClusterSourceTemplate
      name: git-repository
  - name: image-builder
    sources:
    - name: source
      resource: source-provider
    templateRef:
      kind: ClusterImageTemplate
      name: image
  - name: deployer
    images:
    - name: image
      resource: image-builder
    templateRef:
      kind: ClusterTemplate
      name: app
  selector:
    apps.tanzu.vmware.com/workload-type: web
```

kpack-dependenciesパッケージははsource-to-urlに必要なclusterstack、clusterstore、clusterbuilderを構成し、ビルドに利用するOCIイメージが指定したレジストリに登録されます。

```bash
$ kubectl get clusterstack,clusterstore,clusterbuilder
NAME                            READY
clusterstack.kpack.io/base      True 
clusterstack.kpack.io/default   True 

NAME                            READY
clusterstore.kpack.io/default   True 

NAME                              LATESTIMAGE                                                                                                                       READY
clusterbuilder.kpack.io/base      harbor.tce.example.com/tce/kpack:clusterbuilder-base@sha256:c8276cede8f10dd320000db5f796eb20d26d7349bb8967eca38233a8cd7af122      True 
clusterbuilder.kpack.io/default   harbor.tce.example.com/tce/kpack:clusterbuilder-default@sha256:c8276cede8f10dd320000db5f796eb20d26d7349bb8967eca38233a8cd7af122   True 
```

ClusterBuilderには以下のbuildpackageが含まれています。

- paketo-buildpacks/dotnet-core
- paketo-buildpacks/nodejs
- paketo-buildpacks/go
- paketo-buildpacks/python
- paketo-buildpacks/nginx
- paketo-buildpacks/java-native-image
- paketo-buildpacks/java

## cert-injection-webhookのインストール

kpackがbuildを実行する際のPod(`kpack.io/build`ラベルが付与される)はapp-toolkitインストール時のvalues.yamlで、kpackに対して指定した`ca_cert_data`を参照しないため、cert-injection-webhookを利用してビルド実行時に証明書をインジェクトします。cert-injection-webhook-values.yamlを以下の内容で作成して、cert-injection-webhookをインストールします。ca_cert_dataは同じくharborのCA証明書(tce-harbor.crt)を指定します。

```yaml
labels:
- kpack.io/build
ca_cert_data: |
  -----BEGIN CERTIFICATE-----
  MIIDKDCCAhCgAwIBAgIQUKldItiLh3TJalPDu6/81jANBgkqhkiG9w0BAQsFADAU
  MRIwEAYDVQQDEwlIYXJib3IgQ0EwHhcNMjIwNTA2MDA0MzQwWhcNMzIwNTAzMDA0
  MzQwWjAUMRIwEAYDVQQDEwlIYXJib3IgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB
  DwAwggEKAoIBAQC8SmQv6oYcmDk+FnWS8Lx5aUV7hjWspusxMqlkAKbHtIi9qn1S
  8qyY8HSOz1oXVB7fW6XpbtwOowWtepwk39f7O7A4RN6XsQKj0ETVy72vX6hnvZIr
  u1l6kQkykdnXVoAnPAWiHIPwuSPpuqTy7OHvbqSNix5vPEjRbv6ilLgAu7tOYfEA
  SRpSHyLkQpdYxjcI1ZSp8b/wpzSvTUid9pv+DwCZD4E5xqyNZcqimUTdRMGf6E0E
  5NasHkL9eoIurjw61v5f08AhDOSf27Sekae3PU8cLBMliVO5IOYAPk6DgYh07s4L
  f3S0F2a3svSvsvJtaROUiluKctQhwU9dQUhtAgMBAAGjdjB0MA4GA1UdDwEB/wQE
  AwICBDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUw
  AwEB/zAdBgNVHQ4EFgQUkKtbSAyejxAaY1eU8c5H9IyeXCgwEwYDVR0RBAwwCoII
  aGFyYm9yY2EwDQYJKoZIhvcNAQELBQADggEBABFediViemS9mwxBt6k6Qnar3Osc
  jhKmUjNJSL4v3A0RFDTqn76DRJXGRAM7HM49JB4dMjJ3OTnMoRlMgADvH3i07nZI
  oaPeL8bf9Pe21ticCf2g13qlzJ8P9fZaKGdQZJ4zxZxu3Z3CYxLti3mOSxXk84C3
  QLfphZgdvzZqs0Y6LJpmpDfh2lY4xLLTNwrAut6ZYT54pJr8vIoIbuxt0QXD2lEy
  JyqD86Eyag7jS+Gd1Q4RTcwgJdS2lOLtLwddy672vv9bGOSRBhfTjhBNRyN9Y8Gj
  J3iofBdvpNfm64nAToJ1zLB2I6+VOZBlCkCj4snyUV93LgBzkYEMMUMbvRM=
  -----END CERTIFICATE-----
```

```bash
$ tanzu package install cert-injection-webhook --package-name cert-injection-webhook.community.tanzu.vmware.com --version 0.1.1 -n tanzu-package-repo-global -f cert-injection-values.yaml
```

## Worklaodの作成

以下のマニフェストによりWorkloadリソースを作成します。ワークロードリソースにセレクターとして`apps.tanzu.vmware.com/workload-type: web`が指定するとsource-to-urlサプライチェーンによって処理されます。

```yaml
apiVersion: carto.run/v1alpha1
kind: Workload
metadata:
  name: tanzu-java-web-app
  labels:
    apps.tanzu.vmware.com/workload-type: web
spec:
  params:
  - name: annotations
    value:
      autoscaling.knative.dev/minScale: "1"
  source:
    git:
      ref:
        branch: main
      url: https://github.com/masanara/tanzu-java-web-app
```

サプライチェーンが実行され、github上のソースリポジトリがgitrepositoriesリソースとして作成されます。

```bash
$ kubectl get gitrepositories.source.toolkit.fluxcd.io
NAME                 URL                                              READY   STATUS                                                            AGE
tanzu-java-web-app   https://github.com/masanara/tanzu-java-web-app   True    Fetched revision: main/e603173ca2b19ef56a8015bad0eddb4542669370   3m55s
```

kpackによってビルドが実行されています。cert-injection-webhookが正しく実行されている場合、InitContainerが7つ(setup-ca-certs, prepare, analyze, detect, restore, build, export)実行されます。

```bash
$ kubectl get pod
NAME                                   READY   STATUS     RESTARTS   AGE
tanzu-java-web-app-build-1-build-pod   0/1     Init:5/7   0          4m6s
```

しばらく待ってビルドが完了するとPodがCompleted状態となり、imageリソースではレジストリにプッシュしたイメージのタグを確認できます。

```bash
$ kubectl get images.kpack.io
NAME                 LATESTIMAGE                                                                                                                          READY
tanzu-java-web-app   harbor.tce.example.com/app-toolkit/tanzu-java-web-app-demo@sha256:51d89419f5e423fce1394daf6ec33c89c56318045efa7eb01b4de4d2cd42182e   True
```

ビルドが完了すると、ClusterTemplateによりkserviceが作成され、URLが発行されます。

```bash
$ kubectl get service.serving.knative.dev
NAME                 URL                                              LATESTCREATED              LATESTREADY                READY   REASON
tanzu-java-web-app   http://tanzu-java-web-app.demo.tce.example.com   tanzu-java-web-app-00001   tanzu-java-web-app-00001   True
```

発行されたURLにアクセスするとJavaアプリケーションのレスポンスが確認でき、source-to-urlが確認できました。

```bash
$ curl http://tanzu-java-web-app.demo.tce.example.com/
Greetings from Spring Boot + Tanzu!
```

## ソースコードの変更

Workloadによって作成された`gitrepository`リソースはgithub上のリポジトリを1分間隔で確認し、コードの修正を認識するとrevisionを修正します。

```bash
$ kubectl get gitrepositories.source.toolkit.fluxcd.io tanzu-java-web-app
NAME                 URL                                              READY   STATUS                                                            AGE
tanzu-java-web-app   https://github.com/masanara/tanzu-java-web-app   True    Fetched revision: main/3a6fae3d2286ce360c38d01fc49b291336deb223   35m

$ kubectl describe gitrepositories.source.toolkit.fluxcd.io 
...
Events:
  Type    Reason  Age   From               Message
  ----    ------  ----  ----               -------
  Normal  info    32m   source-controller  Fetched revision: main/e603173ca2b19ef56a8015bad0eddb4542669370
  Normal  info    17s   source-controller  Fetched revision: main/3a6fae3d2286ce360c38d01fc49b291336deb223
```

revisionが修正されると、`images.kpack.io`リソースのrevisonが修正され新しいビルドが開始されます。

```bash
$ kubectl get pod
NAME                                                   READY   STATUS      RESTARTS   AGE
tanzu-java-web-app-00001-deployment-68d6575f55-mmn8x   2/2     Running     0          11m
tanzu-java-web-app-build-1-build-pod                   0/1     Completed   0          32m
tanzu-java-web-app-build-2-build-pod                   0/1     Init:2/7    0          23s
```

ビルドが完了すると新しいrevisionでPodが起動し、古いrevisionのPodはTerminateされます。

```bash
$ kubectl get rev
NAME                       CONFIG NAME          K8S SERVICE NAME   GENERATION   READY   REASON   ACTUAL REPLICAS   DESIRED REPLICAS
tanzu-java-web-app-00001   tanzu-java-web-app                      1            True             0                 0
tanzu-java-web-app-00002   tanzu-java-web-app                      2            True             1                 1

$ kubectl get pod
NAME                                                   READY   STATUS        RESTARTS   AGE
tanzu-java-web-app-00001-deployment-68d6575f55-mmn8x   2/2     Terminating   0          12m
tanzu-java-web-app-00002-deployment-56999b6546-qmrsq   2/2     Running       0          29s
tanzu-java-web-app-build-1-build-pod                   0/1     Completed     0          33m
tanzu-java-web-app-build-2-build-pod                   0/1     Completed     0          64s
```

同じURLにアクセスすると、新しいソースコードでビルドされたコンテナイメージが実行されています。

```bash
$ curl http://tanzu-java-web-app.demo.tce.example.com/
Greetings from Spring Boot + Tanzu Comunity Edition!
```

## まとめ

Application Toolkitを使ってsource-to-urlが比較的簡単に実現できました。