Tanzu Application Platform (1.6時点)では、こちらのドキュメントに記載されているように、Out of the Box (OOTB) Supply Chainsにて以下のWorkload Typeがサポートサポートされています。
type=web
... スケーラブルなWebアプリケーションを想定したもの。KnativeのServiceリソースをが作成される。Scale to Zero、Zero to Nがサポートされる。type=server
... トラディショナルなWebアプリケーションを想定したもの。K8s標準のDeployment、Serviceリソースが作成される。type=worker
... キューを処理するバックグラウンドアプリケーションを想定したもの。K8s標準のDeploymentが作成される。
type=server
でアプリをデプロイした場合、Ingressでアプリを公開したい場合はIngressリソースを何かしらの方法で作成する必要があります。
以下の3つの方法を紹介します。
kubectl
で直接Ingressリソースを作成する- OOTB SupplyChainで作成されるリソースにIngressを追加する
- Carvel Package Supply Chainを使用する
目次
kubectl
で直接Ingressリソースを作成する
まずはサンプルアプリのWorkloadを作成します。
tanzu apps workload apply hello-nodejs \
--app hello-nodejs \
--git-repo https://github.com/making/hello-nodejs \
--git-branch master \
--type server \
-n demo
このWorkloadから作成されるマニフェストは次のコマンドで確認できます。
kubectl get cm -n demo hello-nodejs-server -ojsonpath='{.data.delivery\.yml}'
次の出力が得られます。
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-nodejs
annotations:
kapp.k14s.io/update-strategy: fallback-on-replace
ootb.apps.tanzu.vmware.com/servicebinding-workload: "true"
kapp.k14s.io/change-rule: upsert after upserting servicebinding.io/ServiceBindings
labels:
app.kubernetes.io/part-of: hello-nodejs
apps.tanzu.vmware.com/workload-type: server
app.kubernetes.io/component: run
carto.run/workload-name: hello-nodejs
spec:
selector:
matchLabels:
app.kubernetes.io/component: run
app.kubernetes.io/part-of: hello-nodejs
apps.tanzu.vmware.com/workload-type: server
carto.run/workload-name: hello-nodejs
template:
metadata:
annotations:
conventions.carto.run/applied-conventions: |-
appliveview-sample/app-live-view-appflavour-check
spring-boot-convention/auto-configure-actuators-check
spring-boot-convention/app-live-view-appflavour-check
developer.conventions/target-containers: workload
labels:
app.kubernetes.io/component: run
app.kubernetes.io/part-of: hello-nodejs
apps.tanzu.vmware.com/workload-type: server
carto.run/workload-name: hello-nodejs
spec:
containers:
- image: ghcr.io/making/workloads/hello-nodejs-demo@sha256:052ffee7966eeda9cf3a0d6a255f70b443ed0c39ab24591ab4b9ab857b30995b
name: workload
resources: {}
securityContext:
runAsUser: 1000
serviceAccountName: default
---
apiVersion: v1
kind: Service
metadata:
name: hello-nodejs
labels:
app.kubernetes.io/part-of: hello-nodejs
apps.tanzu.vmware.com/workload-type: server
app.kubernetes.io/component: run
carto.run/workload-name: hello-nodejs
spec:
selector:
app.kubernetes.io/component: run
app.kubernetes.io/part-of: hello-nodejs
apps.tanzu.vmware.com/workload-type: server
carto.run/workload-name: hello-nodejs
ports:
- targetPort: 8080
port: 8080
name: http
このアプリを例えば、hello-nodejs-demo.tap.192-168-228-200.sslip.io
で公開したい場合 (envoyのExternalIPが192.168.228.201
である前提です)、次のコマンドでIngressを作成すれば良いです。
TAPのmulti cluster構成の場合は、Runクラスタで実行してください。
ただし、app-editor
にはこのコマンドを実行する権限がありません。app-operator
であれば実行可能です。
- TLSを使用しない場合
kubectl create ingress hello-nodejs -n demo \
--rule="hello-nodejs-demo.tap.192-168-228-200.sslip.io/*=hello-nodejs:8080"
アプリにアクセスします。
$ curl -sv http://hello-nodejs-demo.tap.192-168-228-200.sslip.io
> GET / HTTP/1.1
> Host: hello-nodejs-demo.tap.192-168-228-200.sslip.io
> User-Agent: curl/8.1.2
> Accept: */*
>
< HTTP/1.1 200 OK
< x-powered-by: Express
< content-type: text/html; charset=utf-8
< content-length: 14
< etag: W/"e-LQS9yOYOT+WGITCx9XjB8GC9nDI"
< date: Thu, 10 Aug 2023 06:03:01 GMT
< x-envoy-upstream-service-time: 5
< server: envoy
<
Hello World!!
- TLSの証明書をcert-managerで発行する場合
kubectl create ingress hello-nodejs -n demo \
--rule="hello-nodejs-demo.tap.192-168-228-200.sslip.io/*=hello-nodejs:8080,tls=hello-nodejs-tls" \
--annotation cert-manager.io/cluster-issuer=tap-ingress-selfsigned
上記のannotationはtap-ingress-selfsigned
というClusterIssuerが存在することが前提です。
アプリにアクセスします。
$ curl -skv https://hello-nodejs-demo.tap.192-168-228-200.sslip.io
> GET / HTTP/2
> Host: hello-nodejs-demo.tap.192-168-228-200.sslip.io
> User-Agent: curl/8.1.2
> Accept: */*
>
< HTTP/2 200
< x-powered-by: Express
< content-type: text/html; charset=utf-8
< content-length: 14
< etag: W/"e-LQS9yOYOT+WGITCx9XjB8GC9nDI"
< date: Thu, 10 Aug 2023 06:03:53 GMT
< x-envoy-upstream-service-time: 5
< server: envoy
<
Hello World!!
- ContourのTLS Certificate Delegationを使用する場合
kubectl create ingress hello-nodejs -n demo \
--rule="hello-nodejs-demo.tap.192-168-228-200.sslip.io/*=hello-nodejs:8080,tls=tap-default-tls" \
--annotation projectcontour.io/tls-cert-namespace=tanzu-system-ingress
上記のannotationはtanzu-system-ingress
namespaceに*.tap.192-168-228-200.sslip.io
に対するWildcard証明書を含むtap-default-tls
というSecretが存在し、TLSCertificateDelegationで参照可能になっていることが前提です。
kubectl create
を実行する代わりにYAMLを管理したい場合は、上記のコマンドに--dry-run=client -oyaml
オプションをつければ良いです。
また、Contour以外のIngressを使用したい場合は--class
でIngressClass名を指定すれば良いです。
例えば次のようにTAPのRunクラスタにingress-nginxがインストールされている場合、
$ kubectl get ingressclass
NAME CONTROLLER PARAMETERS AGE
nginx k8s.io/ingress-nginx <none> 3m30s
次のように--class=nginx
をつければ良いです。 (ingress-nginx-controllerのExternalIPが192.168.228.201
である前提です。)
kubectl create ingress hello-nodejs -n demo \
--rule="hello-nodejs-demo.tap.192-168-228-201.sslip.io/*=hello-nodejs:8080" \
--class=nginx
アプリにアクセスします。
$ curl -sv http://hello-nodejs-demo.tap.192-168-228-201.sslip.io
> GET / HTTP/1.1
> Host: hello-nodejs-demo.tap.192-168-228-201.sslip.io
> User-Agent: curl/8.1.2
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Thu, 10 Aug 2023 06:11:16 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 14
< Connection: keep-alive
< X-Powered-By: Express
< ETag: W/"e-LQS9yOYOT+WGITCx9XjB8GC9nDI"
<
Hello World!!
この方法はTAPのカスタマイズが不要で、シンプルである反面、デフォルトでは開発者(app-editor
)がIngressを作成できないので、app-operator
に作成を依頼するか、次のようにapp-editor
に権限を追加する必要があります。
kubectl apply -f - << 'EOF'
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: app-editor-with-ingress
labels:
apps.tanzu.vmware.com/aggregate-to-app-editor: "true"
rules:
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- create
- patch
- update
- delete
- deletecollection
EOF
また、Ingressリソースを別途管理する手間が発生します。 次のOOTB SupplyChainで作成されるリソースにIngressを追加する方法であれば、これらの課題は解決されます。
OOTB SupplyChainで作成されるリソースにIngressを追加する
以下のドキュメントに書かれている通り、ClusterConfigTemplateをカスタマイズすることでWorkloadから生成されるマニフェストにIngressを追加することができます。
https://docs.vmware.com/en/VMware-Tanzu-Application-Platform/1.6/tap/workloads-server.html#define-a-workload-type-that-exposes-server-workloads-outside-the-cluster-5
この場合、type=server-ingress
のように新規のWorkload Typeを追加するか、既存のtype=server
にIngressを追加するかの選択肢があります。
新規のWorkload Typeを追加する
既存のserver-template
をコピーして、server-ingress-template
を作成します。
server-ingress-template
を以下に定義します。server-template
からの差分は<------------ Added ---------------->
の部分です。
apiVersion: carto.run/v1alpha1
kind: ClusterConfigTemplate
metadata:
name: server-ingress-template
spec:
configPath: .data
params:
- name: ports
default:
- containerPort: 8080
port: 8080
name: http
healthRule:
alwaysHealthy: {}
ytt: |
#@ load("@ytt:data", "data")
#@ load("@ytt:yaml", "yaml")
#@ load("@ytt:struct", "struct")
#@ load("@ytt:assert", "assert")
#@ def merge_labels(fixed_values):
#@ labels = {}
#@ if hasattr(data.values.workload.metadata, "labels"):
#@ labels.update(data.values.workload.metadata.labels)
#@ end
#@ labels.update(fixed_values)
#@ return labels
#@ end
#@ def intOrString(v):
#@ return v if type(v) == "int" else int(v.strip()) if v.strip().isdigit() else v
#@ end
#@ def merge_ports(ports_spec, containers):
#@ ports = {}
#@ for c in containers:
#@ for p in getattr(c, "ports", []):
#@ ports[p.containerPort] = {"targetPort": p.containerPort, "port": p.containerPort, "name": getattr(p, "name", str(p.containerPort))}
#@ end
#@ end
#@ for p in ports_spec:
#@ targetPort = getattr(p, "containerPort", p.port)
#@ type(targetPort) in ("string", "int") or fail("containerPort must be a string or int")
#@ targetPort = intOrString(targetPort)
#@
#@ port = p.port
#@ type(port) in ("string", "int") or fail("port must be a string or int")
#@ port = int(port)
#@ ports[p.port] = {"targetPort": targetPort, "port": port, "name": getattr(p, "name", str(p.port))}
#@ end
#@ return ports.values()
#@ end
#! <------------ Added ---------------->
#@ def merge_annotations(fixed_values):
#@ annotations = {}
#@ if hasattr(data.values.params, "annotations"):
#@ annotations.update(data.values.params.annotations)
#@ end
#@ annotations.update(fixed_values)
#@ return annotations
#@ end
#! <------------ Added ---------------->
#@ def delivery():
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: #@ data.values.workload.metadata.name
annotations:
kapp.k14s.io/update-strategy: "fallback-on-replace"
ootb.apps.tanzu.vmware.com/servicebinding-workload: "true"
kapp.k14s.io/change-rule: "upsert after upserting servicebinding.io/ServiceBindings"
labels: #@ merge_labels({ "app.kubernetes.io/component": "run", "carto.run/workload-name": data.values.workload.metadata.name })
spec:
selector:
matchLabels: #@ data.values.config.metadata.labels
template: #@ data.values.config
---
apiVersion: v1
kind: Service
metadata:
name: #@ data.values.workload.metadata.name
labels: #@ merge_labels({ "app.kubernetes.io/component": "run", "carto.run/workload-name": data.values.workload.metadata.name })
spec:
selector: #@ data.values.config.metadata.labels
ports:
#@ hasattr(data.values.params, "ports") and len(data.values.params.ports) or assert.fail("one or more ports param must be provided.")
#@ declared_ports = {}
#@ if "ports" in data.values.params:
#@ declared_ports = data.values.params.ports
#@ else:
#@ declared_ports = struct.encode([{ "containerPort": 8080, "port": 8080, "name": "http"}])
#@ end
#@ for p in merge_ports(declared_ports, data.values.config.spec.containers):
- #@ p
#@ end
#! <------------ Added ---------------->
#@ ingress_domain = "tap.192-168-228-200.sslip.io"
#@ cluster_issuer = "tap-ingress-selfsigned"
#@ port = intOrString(data.values.params.ports[0].port) if hasattr(data.values.params, "ports") and len(data.values.params.ports) > 0 and hasattr(data.values.params.ports[0], "port") else 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: #@ data.values.workload.metadata.name
annotations: #@ merge_annotations({"cert-manager.io/cluster-issuer": cluster_issuer, "kapp.k14s.io/change-rule": "upsert after upserting Services"})
labels: #@ merge_labels({ "app.kubernetes.io/component": "run", "carto.run/workload-name": data.values.workload.metadata.name })
spec:
tls:
- secretName: #@ "{}-tls".format(data.values.workload.metadata.name)
hosts:
- #@ "{}-{}.{}".format(data.values.workload.metadata.name, data.values.workload.metadata.namespace, ingress_domain)
rules:
- host: #@ "{}-{}.{}".format(data.values.workload.metadata.name, data.values.workload.metadata.namespace, ingress_domain)
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: #@ data.values.workload.metadata.name
port:
number: #@ port
#! <------------ Added ---------------->
#@ end
---
apiVersion: v1
kind: ConfigMap
metadata:
name: #@ data.values.workload.metadata.name + "-server"
labels: #@ merge_labels({ "app.kubernetes.io/component": "config" })
data:
delivery.yml: #@ yaml.encode(delivery())
この内容をserver-ingress-template.yaml
に保存し、applyします。TAPのmulti cluster構成の場合は、Buildクラスタで実行してください。
kubectl apply -f server-ingress-template.yaml
またSupplyChainから生成されたIngressリソースをDeliverableが作成できるように、次のコマンドでClusterRoleを追加します。TAPのmulti cluster構成の場合は、Runクラスタで実行してください。
cat << 'EOF' > deliverable-with-ingress.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: deliverable-with-ingress
labels:
apps.tanzu.vmware.com/aggregate-to-deliverable: "true"
rules:
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- watch
- create
- patch
- update
- delete
- deletecollection
EOF
kubectl apply -f deliverable-with-ingress.yaml
tap-values.yaml
に以下の内容を追加します。
ootb_supply_chain_basic:
supported_workloads:
- type: web
cluster_config_template_name: config-template
- type: server
cluster_config_template_name: server-template
- type: worker
cluster_config_template_name: worker-template
- type: server-ingress #! <--- Added
cluster_config_template_name: server-ingress-template
設定するキーはootb_supply_chain_<suppy_chain>
であり、上記の例はsupply_chain: basic
の場合です。
次のコマンドでTAPを更新します。TAPのmulti cluster構成の場合は、Buildクラスタで実行してください。
tanzu package installed update -n tap-install tap --values-file tap-values.yaml
次のコマンドを実行して、利用可能なWorkload Typeにserver-ingress
が追加されたことを確認してください。
$ tanzu apps cluster-supply-chain get source-to-url
---
# source-to-url: Ready
---
Supply Chain Selectors
TYPE KEY OPERATOR VALUE
expressions apps.tanzu.vmware.com/workload-type In web
expressions apps.tanzu.vmware.com/workload-type In server
expressions apps.tanzu.vmware.com/workload-type In worker
expressions apps.tanzu.vmware.com/workload-type In server-ingress
expressions apps.tanzu.vmware.com/carvel-package-workflow DoesNotExist
次のコマンドで、type=server-ingress
のWorkloadを作成します。
kubectl delete ingress hello-nodejs -n demo # if exists
tanzu apps workload apply hello-nodejs \
--app hello-nodejs \
--git-repo https://github.com/making/hello-nodejs \
--git-branch master \
--type server-ingress \
-n demo
次のコマンドでWorkloadによって作成されたYAMLを確認できます。
kubectl get cm -n demo hello-nodejs-server -ojsonpath='{.data.delivery\.yml}'
次のようなYAMLが出力されます。Ingressが追加されています。
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-nodejs
annotations:
kapp.k14s.io/update-strategy: fallback-on-replace
ootb.apps.tanzu.vmware.com/servicebinding-workload: "true"
kapp.k14s.io/change-rule: upsert after upserting servicebinding.io/ServiceBindings
labels:
app.kubernetes.io/part-of: hello-nodejs
apps.tanzu.vmware.com/workload-type: server-ingress
app.kubernetes.io/component: run
carto.run/workload-name: hello-nodejs
spec:
selector:
matchLabels:
app.kubernetes.io/component: run
app.kubernetes.io/part-of: hello-nodejs
apps.tanzu.vmware.com/workload-type: server-ingress
carto.run/workload-name: hello-nodejs
template:
metadata:
annotations:
conventions.carto.run/applied-conventions: |-
appliveview-sample/app-live-view-appflavour-check
spring-boot-convention/auto-configure-actuators-check
spring-boot-convention/app-live-view-appflavour-check
developer.conventions/target-containers: workload
labels:
app.kubernetes.io/component: run
app.kubernetes.io/part-of: hello-nodejs
apps.tanzu.vmware.com/workload-type: server-ingress
carto.run/workload-name: hello-nodejs
spec:
containers:
- image: ghcr.io/making/workloads/hello-nodejs-demo@sha256:052ffee7966eeda9cf3a0d6a255f70b443ed0c39ab24591ab4b9ab857b30995b
name: workload
resources: {}
securityContext:
runAsUser: 1000
serviceAccountName: default
---
apiVersion: v1
kind: Service
metadata:
name: hello-nodejs
labels:
app.kubernetes.io/part-of: hello-nodejs
apps.tanzu.vmware.com/workload-type: server-ingress
app.kubernetes.io/component: run
carto.run/workload-name: hello-nodejs
spec:
selector:
app.kubernetes.io/component: run
app.kubernetes.io/part-of: hello-nodejs
apps.tanzu.vmware.com/workload-type: server-ingress
carto.run/workload-name: hello-nodejs
ports:
- targetPort: 8080
port: 8080
name: http
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-nodejs
annotations:
cert-manager.io/cluster-issuer: tap-ingress-selfsigned
kapp.k14s.io/change-rule: upsert after upserting Services
labels:
app.kubernetes.io/part-of: hello-nodejs
apps.tanzu.vmware.com/workload-type: server-ingress
app.kubernetes.io/component: run
carto.run/workload-name: hello-nodejs
spec:
tls:
- secretName: hello-nodejs-tls
hosts:
- hello-nodejs-demo.tap.192-168-228-200.sslip.io
rules:
- host: hello-nodejs-demo.tap.192-168-228-200.sslip.io
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: hello-nodejs
port:
number: 8080
Supply ChainからIngressリソースが作成されたことを確認できます。
$ kubectl get ing -n demo --show-labels
NAME CLASS HOSTS ADDRESS PORTS AGE LABELS
hello-nodejs <none> hello-nodejs-demo.tap.192-168-228-200.sslip.io 192.168.228.200 80, 443 96s app.kubernetes.io/component=run,app.kubernetes.io/part-of=hello-nodejs,apps.tanzu.vmware.com/workload-type=server-ingress,carto.run/workload-name=hello-nodejs,kapp.k14s.io/app=1691647255322645686,kapp.k14s.io/association=v1.4aa1edeb0a707e6a5e81cfde4668a7b0
$ curl -ks https://hello-nodejs-demo.tap.192-168-228-200.sslip.io
Hello World!!
ClusterConfigTemplateの追加とClusterRoleの追加をtanzu package install
のタイミングでまとめて行いたい場合は、次のようにoverlayとしてファイルをSecretに登録すれば良いです。
# Muti Cluster構成の場合はBuild Clusterにて
kubectl -n tap-install create secret generic ootb-templates-server-ingress-template \
-o yaml \
--dry-run=client \
--from-file=server-ingress-template.yaml \
| kubectl apply -f-
# Muti Cluster構成の場合はRun Clusterにて
kubectl -n tap-install create secret generic tap-auth-deliverable-with-ingress \
-o yaml \
--dry-run=client \
--from-file=deliverable-with-ingress.yaml \
| kubectl apply -f-
tap-values.yaml
に以下の設定を追加。
package_overlays:
- name: ootb-templates
secrets:
- name: ootb-templates-server-ingress-template # Muti Cluster構成の場合はBuild Clusterにて
- name: tap-auth
secrets:
- name: tap-auth-deliverable-with-ingress # Muti Cluster構成の場合はRun Clusterにて
TAPを更新します。
tanzu package installed update -n tap-install tap --values-file tap-values.yaml
既存のtype=server
にIngressを追加する
新規のWorkload Typeを追加する方法はTemplateを自分で管理できるので、カスタマイズしやすい一方、
コピー元のtype=server
のテンプレートが更新されたら、更新内容を反映させる必要があります。
次のoverlayを適用して、既存のClusterConfigTemplate server-template
を変更します。
apiVersion: v1
kind: Secret
metadata:
name: ootb-templates-overlay-ingress
namespace: tap-install
type: Opaque
stringData:
overlay-ingress.yaml: |
#@ def merge_annotations_def_string():
#@ return '''
#@ #@ def merge_annotations(fixed_values):
#@ #@ annotations = {}
#@ #@ if hasattr(data.values.params, "annotations"):
#@ #@ annotations.update(data.values.params.annotations)
#@ #@ end
#@ #@ annotations.update(fixed_values)
#@ #@ return annotations
#@ #@ end
#@ '''
#@ end
#@ load("@ytt:overlay", "overlay")
#@ load("@ytt:data", "data")
#@ ingress_domain = data.values.ingress_domain
#@ cluster_issuer = data.values.cluster_issuer
#@overlay/match by=overlay.subset({"kind":"ClusterConfigTemplate", "metadata": {"name": "server-template"}})
---
spec:
#@overlay/replace via=lambda left, right: "{}\n{}".format(left.replace("#@ def delivery():", '\n'.join([ merge_annotations_def_string(), "#@ def delivery():"])), '\n'.join([' {}'.format(x) for x in right.replace("INGRESS_DOMAIN", ingress_domain).replace("CLUSTER_ISSUER", cluster_issuer).split('\n')]))
ytt: |
#@yaml/text-templated-strings
ingress.yml: |
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: (@= data.values.workload.metadata.name @)
annotations:
(@= '\n'.join([' {}'.format(x) for x in yaml.encode(merge_annotations({ "cert-manager.io/cluster-issuer": "CLUSTER_ISSUER", "kapp.k14s.io/change-rule": "upsert after upserting Services" })).split('\n')]) @)
labels:
(@= '\n'.join([' {}'.format(x) for x in yaml.encode(merge_labels({ "app.kubernetes.io/component": "run", "carto.run/workload-name": data.values.workload.metadata.name })).split('\n')]) @)
spec:
tls:
- secretName: (@= data.values.workload.metadata.name @)-tls
hosts:
- (@= "{}-{}.{}".format(data.values.workload.metadata.name, data.values.workload.metadata.namespace, "INGRESS_DOMAIN") @)
rules:
- host: (@= "{}-{}.{}".format(data.values.workload.metadata.name, data.values.workload.metadata.namespace, "INGRESS_DOMAIN") @)
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: (@= data.values.workload.metadata.name @)
port:
number: (@= str(data.values.params.ports[0].port) if hasattr(data.values.params, "ports") and len(data.values.params.ports) > 0 and hasattr(data.values.params.ports[0], "port") else "8080" @)
このファイルをootb-templates-overlay-ingress.yaml
に保存して、applyします。
kubectl apply -f ootb-templates-overlay-ingress.yaml
tap-values.yaml
に次の設定を追加します。
ootb_templates:
ingress_domain: tap.192-168-228-200.sslip.io
cluster_issuer: tap-ingress-selfsigned
package_overlays:
- name: ootb-templates # Muti Cluster構成の場合はBuild Clusterにて
secrets:
- name: ootb-templates-overlay-ingress
TAPを更新します。
tanzu package installed update -n tap-install tap --values-file tap-values.yaml
type=server
でWorkloadを作成します。
tanzu apps workload apply hello-nodejs \
--app hello-nodejs \
--git-repo https://github.com/making/hello-nodejs \
--git-branch master \
--type server \
-n demo
次のコマンドでWorkloadによって作成されたIngressのYAMLを確認できます。
kubectl get cm -n demo hello-nodejs-server -ojsonpath='{.data.ingress\.yml}'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-nodejs
annotations:
cert-manager.io/cluster-issuer: tap-ingress-selfsigned
kapp.k14s.io/change-rule: upsert after upserting Services
labels:
app.kubernetes.io/part-of: hello-nodejs
apps.tanzu.vmware.com/workload-type: server
app.kubernetes.io/component: run
carto.run/workload-name: hello-nodejs
spec:
tls:
- secretName: hello-nodejs-tls
hosts:
- hello-nodejs-demo.tap.192-168-228-200.sslip.io
rules:
- host: hello-nodejs-demo.tap.192-168-228-200.sslip.io
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: hello-nodejs
port:
number: 8080
Supply ChainからIngressリソースが作成されたことを確認できます。
$ kubectl get ing -n demo --show-labels
NAME CLASS HOSTS ADDRESS PORTS AGE LABELS
hello-nodejs <none> hello-nodejs-demo.tap.192-168-228-200.sslip.io 192.168.228.200 80, 443 154m app.kubernetes.io/component=run,app.kubernetes.io/part-of=hello-nodejs,apps.tanzu.vmware.com/workload-type=server,carto.run/workload-name=hello-nodejs,kapp.k14s.io/app=1691647255322645686,kapp.k14s.io/association=v1.4aa1edeb0a707e6a5e81cfde4668a7b0
新規のWorkload Typeを追加する場合に比べて、既存のWorkload Typeを更新する方法は、TAPのバージョンアップでコピー元のtemplateの変更を自動でマージするので、変更を反映させる手間が入りません。 一方で、overlayが次のバージョンでも機能するかどうかはわかりません。バージョンアップ時には必ず動作検証する必要があります。
Supply ChainからIngressを生成する方法は、自動でIngressリソースができるので便利なのですが、Workloadを作る時点で作成されるIngressのhost名が固定されてしまう点です。
今回の例だとIngressリソースにhello-nodejs-demo.tap.192-168-228-200.sslip.io
がハードコードされます。
アプリが動作する環境(Runクラスタなど)が1環境の場合は問題ないのですが、複数のRunクラスタにデプロイしたい場合は問題になります。Supply Chainから生成されるマニフェストを環境に応じてパラメータで変更することができません。
WorkaroundはGitopsモードを利用して、別のRunクラスタに対しては次のようなoverlayをGitレポジトリ上に作れば、デプロイ時にhost名が上書きされます。
#@ load("@ytt:overlay", "overlay")
#@ ingress_domain = "hello-nodejs-demo.production.example.com"
#@overlay/match by=overlay.subset({"kind":"Ingress"})
---
spec:
tls:
#@overlay/match by=overlay.index(0)
- hosts:
#@overlay/match by=overlay.index(0)
- #@ ingress_domain
rules:
#@overlay/match by=overlay.index(0)
- host: #@ ingress_domain
Carvel Package Supply Chainを使用する
Supply Chainから生成されるマニフェストを環境に応じてパラメータで変更することができないという課題を解決するのがCarvel Package Supply Chainsです。 TAP 1.5でAlphaバージョンとして導入され、TAP 1.6時点ではBetaバージョンです。まだ、実験的な機能で制約が多く、 OOTB Basic Supply Chainでのみ利用可能です。
Carvel Package Supply Chainsは通常のSupply Chainのようにマニフェストを作り、pushしますが、そのマニフェストをデプロイするためにDeliverableを作る代わりに、CarvelのPackageリソースを作成します。
このPackageを実行環境(Runクラスタなど)にインストールします。この時作成するPackageInstallリソースに対するパラメータを渡すことで実行環境に応じてパラメータを変更することができるようになります。
Carvel Package Supply Chainsではtype=server
の場合にIngressリソースも作成されます。
なお、TAP 1.6時点では、マニフェストのpush先はGit Repositoryのみなので、Gitopsモードが必須です。
Carvel Package Supply Chainsを有効するには、tap-values.yaml
に次の設定を明示的に追加する必要があります。multi clusterの場合は、Buildクラスタでこの設定が必要です。
ootb_supply_chain_basic:
carvel_package:
workflow_enabled: true
この設定を有効にして、次のコマンドでTAPを更新します。
tanzu package installed update -n tap-install tap --values-file tap-values.yaml
⚠️ Ingressの作成が重複するため、
tap-values.yaml
からootb-templates-overlay-ingress
のoverlay設定を削除してください。
Supply Chainリストを確認するとsource-to-url-package
が追加されていることがわかります。
$ tanzu apps cluster-supply-chain list
NAME READY AGE
basic-image-to-url Ready 6h31m
basic-image-to-url-package Ready 89s
source-to-url Ready 6h31m
source-to-url-package Ready 89s
このSupply Chainを使用するためのパラメータを確認すると、次のようにラベルで apps.tanzu.vmware.com/carvel-package-workflow=true
を設定する必要があります。
$ tanzu apps cluster-supply-chain get source-to-url-package
---
# source-to-url-package: Ready
---
Supply Chain Selectors
TYPE KEY OPERATOR VALUE
expressions apps.tanzu.vmware.com/workload-type In web
expressions apps.tanzu.vmware.com/workload-type In server
expressions apps.tanzu.vmware.com/workload-type In worker
expressions apps.tanzu.vmware.com/carvel-package-workflow In true
実際に次のコマンドでCarvel Package Supply Chainを使ったWorkloadを作成します。 GitOpsモードを使うための設定は本記事では省略します。
tanzu apps workload apply hello-nodejs \
--app hello-nodejs \
--git-repo https://github.com/making/hello-nodejs \
--git-branch master \
--label apps.tanzu.vmware.com/carvel-package-workflow=true \
--type server \
--param gitops_branch=main \
--param gitops_commit_message=Bump \
--param gitops_server_address=https://github.com \
--param gitops_repository_owner=making \
--param gitops_repository_name=tap-gitops-manifests \
--param gitops_user_email=makingx+bot@gmail.com \
--param gitops_user_name=making-bot \
--param gitops_ssh_secret=git-basic \
-n demo
WorkloadのReadyになると、次のようなリソースが作成されます。
$ tanzu apps workload get hello-nodejs --namespace demo
📡 Overview
name: hello-nodejs
type: server
namespace: demo
💾 Source
type: git
url: https://github.com/making/hello-nodejs
branch: master
revision: master@sha1:fde413c0fba0003c218a60bde69c8e254d3b15a6
📦 Supply Chain
name: source-to-url-package
NAME READY HEALTHY UPDATED RESOURCE
source-provider True True 6m25s gitrepositories.source.toolkit.fluxcd.io/hello-nodejs
image-provider True True 5m29s images.kpack.io/hello-nodejs
config-provider True True 5m22s podintents.conventions.carto.run/hello-nodejs
app-config True True 5m22s configmaps/hello-nodejs-server
service-bindings True True 5m22s configmaps/hello-nodejs-with-claims
api-descriptors True True 5m22s configmaps/hello-nodejs-with-api-descriptors
carvel-package True True 5m8s taskruns.tekton.dev/hello-nodejs-carvel-package-j86xm
config-writer True True 4m55s runnables.carto.run/hello-nodejs-pkg-cfg-writer
🚚 Delivery
Delivery resources not found.
💬 Messages
No messages found.
🛶 Pods
NAME READY STATUS RESTARTS AGE
hello-nodejs-build-1-build-pod 0/1 Completed 0 6m27s
hello-nodejs-carvel-package-j86xm-pod 0/3 Completed 0 5m22s
hello-nodejs-pkg-cfg-writer-jsg9x-pod 0/2 Completed 0 5m6s
hello-nodejs-carvel-package-****
でマニフェストをimgpkg
でバンドル化してpushし、hello-nodejs-pkg-cfg-writer-****
でそのimgpkgBundleをPackageリソースに定義し、gitレポジトリにpushします。
実際にpushされたPackageマニフェストは https://github.com/making/tap-gitops-manifests/blob/main/hello-nodejs.demo.tap/packages/20230811080453.0.0.yml です。
バンドル化されたマニフェストを次のコマンドでダウンロード可能です。(visibilityをpublicにしてあるので実際に実行して内容を確認できます)
imgpkg pull -b ghcr.io/making/workloads/hello-nodejs-demo-bundle@sha256:b0a013325c4c089befffd72643d576fb1109bebadce87f2f7b3615aef5ed9d75 -o /tmp/hello-nodejs
ではこのGit上にpushされたPackageリソースをapplyします。multi clusterの場合はRunクラスタにapplyします。 ドキュメントではここでGitOpsツールを使用することを推奨しており、
を使用する方法が紹介されています。前者の2つは追加のインストールなしで利用可能です。
ここではセットアップを省略するため、GitOpsを使用せず単純に次のようにkubectl apply
でPackageリソースを作成します。
kubectl apply -f https://github.com/making/tap-gitops-manifests/raw/main/hello-nodejs.demo.tap/packages/20230811080453.0.0.yml -n demo
次のPackageリソースができました。
$ kubectl get package -n demo
NAME PACKAGEMETADATA NAME VERSION AGE
hello-nodejs.demo.tap.20230811080453.0.0+build.fde413c hello-nodejs.demo.tap 20230811080453.0.0+build.fde413c 5s
このPackageのパラメータを確認します。
$ tanzu package available get -n demo hello-nodejs.demo.tap/20230811080453.0.0+build.fde413c --values-schema
KEY DEFAULT TYPE DESCRIPTION
replicas 1 integer Number of replicas.
workload_name "" string Required. Name of the workload, used by K8s Ingress HTTP rules.
cluster_issuer tap-ingress-selfsigned string CertManager Issuer to use to generate certificate for K8s Ingress.
hostname "" string If set, K8s Ingress will be created with HTTP rules for hostname.
port 8080 integer Port number for the backend associated with K8s Ingress.
Ingressを利用するために、workload_name
をhostname
を設定します。
cat <<EOF > hello-nodejs-values.yaml
workload_name: hello-nodejs
hostname: hello-nodejs-demo.stg.192-168-228-200.sslip.io
EOF
次のコマンドでこのパッケージをインストールします。multi clusterの場合はRunクラスタで実行します。-v
に>= 0.0.0
を指定することで、新しいPackageがKubernetes上に作成されると自動でその新しいバージョンにアップデートされます。
tanzu package install -n demo hello-nodejs -p hello-nodejs.demo.tap -v ">= 0.0.0" --values-file hello-nodejs-values.yaml
インストールが完了したら、次のようなリソースが作成されたことがわかります。
$ kubectl get pkgi,deploy,svc,ing -n demo
NAME PACKAGE NAME PACKAGE VERSION DESCRIPTION AGE
packageinstall.packaging.carvel.dev/hello-nodejs hello-nodejs.demo.tap 20230811080453.0.0+build.fde413c Reconcile succeeded 12s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/hello-nodejs 1/1 1 1 9s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/hello-nodejs ClusterIP 10.96.113.106 <none> 8080/TCP 9s
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress.networking.k8s.io/hello-nodejs <none> hello-nodejs-demo.stg.192-168-228-200.sslip.io 192.168.228.200 80, 443 9s
Ingressで公開されたURLにアクセス可能です。
$ curl -k https://hello-nodejs-demo.stg.192-168-228-200.sslip.io
Hello World!!
Carvel Package Supply Chainの場合、通常のSupply Chainのtype=server
なWorkloadで作成されるリソース(Deployment, Service)に加えて、Ingressが作成されました。
追加作成されるリソースはoverlayで定義されています。このoverlayファイルと変更可能なパラメータの定義はTAP 1.6からtap-values.yaml
で上書き可能です。
デフォルトでは次のような定義になっています。
ootb_templates:
carvel_package:
parameters:
- selector:
matchLabels:
apps.tanzu.vmware.com/workload-type: server
schema: |
#@data/values-schema
---
#@schema/title "Workload name"
#@schema/desc "Required. Name of the workload, used by K8s Ingress HTTP rules."
#@schema/example "tanzu-java-web-app"
#@schema/validation min_len=1
workload_name: ""
#@schema/title "Replicas"
#@schema/desc "Number of replicas."
replicas: 1
#@schema/title "Port"
#@schema/desc "Port number for the backend associated with K8s Ingress."
port: 8080
#@schema/title "Hostname"
#@schema/desc "If set, K8s Ingress will be created with HTTP rules for hostname."
#@schema/example "app.tanzu.vmware.com"
hostname: ""
#@schema/title "Cluster Issuer"
#@schema/desc "CertManager Issuer to use to generate certificate for K8s Ingress."
cluster_issuer: "tap-ingress-selfsigned"
overlays: |
#@ load("@ytt:overlay", "overlay")
#@ load("@ytt:data", "data")
#@overlay/match by=overlay.subset({"apiVersion":"apps/v1", "kind": "Deployment"})
---
spec:
#@overlay/match missing_ok=True
replicas: #@ data.values.replicas
#@ if data.values.hostname != "":
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: #@ data.values.workload_name
annotations:
cert-manager.io/cluster-issuer: #@ data.values.cluster_issuer
ingress.kubernetes.io/force-ssl-redirect: "true"
kubernetes.io/ingress.class: contour
kapp.k14s.io/change-rule: "upsert after upserting Services"
labels:
app.kubernetes.io/component: "run"
carto.run/workload-name: #@ data.values.workload_name
spec:
tls:
- secretName: #@ data.values.workload_name
hosts:
- #@ data.values.hostname
rules:
- host: #@ data.values.hostname
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: #@ data.values.workload_name
port:
number: #@ data.values.port
#@ end
IngressにContourを利用するannotationがついています。前述のようにNginx Ingressを使うようにカスタマイズしてみます。
tap-values.yaml
に次の設定を行います。
ootb_templates:
carvel_package:
parameters:
- selector:
matchLabels:
apps.tanzu.vmware.com/workload-type: server
schema: |
#@data/values-schema
---
#@schema/title "Workload name"
#@schema/desc "Required. Name of the workload, used by K8s Ingress HTTP rules."
#@schema/example "tanzu-java-web-app"
#@schema/validation min_len=1
workload_name: ""
#@schema/title "Replicas"
#@schema/desc "Number of replicas."
replicas: 1
#@schema/title "Port"
#@schema/desc "Port number for the backend associated with K8s Ingress."
port: 8080
#@schema/title "Hostname"
#@schema/desc "If set, K8s Ingress will be created with HTTP rules for hostname."
#@schema/example "app.tanzu.vmware.com"
hostname: ""
#@schema/title "Cluster Issuer"
#@schema/desc "CertManager Issuer to use to generate certificate for K8s Ingress."
cluster_issuer: "tap-ingress-selfsigned"
overlays: |
#@ load("@ytt:overlay", "overlay")
#@ load("@ytt:data", "data")
#@overlay/match by=overlay.subset({"apiVersion":"apps/v1", "kind": "Deployment"})
---
spec:
#@overlay/match missing_ok=True
replicas: #@ data.values.replicas
#@ if data.values.hostname != "":
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: #@ data.values.workload_name
annotations:
cert-manager.io/cluster-issuer: #@ data.values.cluster_issuer
ingress.kubernetes.io/force-ssl-redirect: "true"
#! kubernetes.io/ingress.class: contour <----- Removed
kapp.k14s.io/change-rule: "upsert after upserting Services"
labels:
app.kubernetes.io/component: "run"
carto.run/workload-name: #@ data.values.workload_name
spec:
ingressClassName: nginx #! <----- Added
tls:
- secretName: #@ data.values.workload_name
hosts:
- #@ data.values.hostname
rules:
- host: #@ data.values.hostname
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: #@ data.values.workload_name
port:
number: #@ data.values.port
#@ end
次のコマンドでTAPを更新します。
tanzu package installed update -n tap-install tap --values-file tap-values.yaml
Workloadの状態を確認すると、hello-nodejs-carvel-package-****
とhello-nodejs-pkg-cfg-writer-****
が新たに生成されていることがわかります。
テンプレートの変更を検知して、新しいマニフェストのimgpkg bundle作成とgit pushが行われました。
$ tanzu apps workload get hello-nodejs --namespace demo
📡 Overview
name: hello-nodejs
type: server
namespace: demo
💾 Source
type: git
url: https://github.com/making/hello-nodejs
branch: master
revision: master@sha1:fde413c0fba0003c218a60bde69c8e254d3b15a6
📦 Supply Chain
name: source-to-url-package
NAME READY HEALTHY UPDATED RESOURCE
source-provider True True 9m41s gitrepositories.source.toolkit.fluxcd.io/hello-nodejs
image-provider True True 8m45s images.kpack.io/hello-nodejs
config-provider True True 8m38s podintents.conventions.carto.run/hello-nodejs
app-config True True 8m38s configmaps/hello-nodejs-server
service-bindings True True 8m38s configmaps/hello-nodejs-with-claims
api-descriptors True True 8m38s configmaps/hello-nodejs-with-api-descriptors
carvel-package True True 11s taskruns.tekton.dev/hello-nodejs-carvel-package-v7psj
config-writer Unknown Unknown 4s runnables.carto.run/hello-nodejs-pkg-cfg-writer
🚚 Delivery
Delivery resources not found.
💬 Messages
Workload [HealthyConditionRule]: Not all Steps in the Task have finished executing
🛶 Pods
NAME READY STATUS RESTARTS AGE
hello-nodejs-7455c98c94-c4zlt 1/1 Running 0 4m23s
hello-nodejs-build-1-build-pod 0/1 Completed 0 9m44s
hello-nodejs-carvel-package-j86xm-pod 0/3 Completed 0 8m39s
hello-nodejs-carvel-package-v7psj-pod 0/3 Completed 0 26s
hello-nodejs-pkg-cfg-writer-ctxfx-pod 0/2 Completed 0 13s
hello-nodejs-pkg-cfg-writer-jsg9x-pod 0/2 Completed 0 8m23s
To see logs: "tanzu apps workload tail hello-nodejs --namespace demo --timestamp --since 1h"
生成されたPackageリソースは https://github.com/making/tap-gitops-manifests/blob/main/hello-nodejs.demo.tap/packages/20230811081306.0.0.yml です。 バンドル化されたマニフェストは次のコマンドでダウンロードできます。
imgpkg pull -b ghcr.io/making/workloads/hello-nodejs-demo-bundle@sha256:8971d6979d6823edbe502162ddb9ab6dde665ac807857dbe4ea89857ce2db28c -o /tmp/hello-nodejs
新しいPackageをkubectl
でapplyします。GitOpsを使用している場合(推奨)は自動で新しいPackageが追加されます。
kubectl apply -f https://github.com/making/tap-gitops-manifests/raw/main/hello-nodejs.demo.tap/packages/20230811081306.0.0.yml -n demo
次のコマンドで新しいPackageを確認できます。
$ kubectl get package -n demo
NAME PACKAGEMETADATA NAME VERSION AGE
hello-nodejs.demo.tap.20230811080453.0.0+build.fde413c hello-nodejs.demo.tap 20230811080453.0.0+build.fde413c 5m53s
hello-nodejs.demo.tap.20230811081306.0.0+build.fde413c hello-nodejs.demo.tap 20230811081306.0.0+build.fde413c 6s
PackageInstallが新しいパッケージを検出して、自動でインストールします。次のコマンドで新しいバージョンのパッケージがデプロイされていることがわかり、Ingressのnginxのものが利用されていることがわかります。
$ kubectl get pkgi,deploy,svc,ing -n demo
NAME PACKAGE NAME PACKAGE VERSION DESCRIPTION AGE
packageinstall.packaging.carvel.dev/hello-nodejs hello-nodejs.demo.tap 20230811081306.0.0+build.fde413c Reconcile succeeded 5m44s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/hello-nodejs 1/1 1 1 5m41s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/hello-nodejs ClusterIP 10.96.113.106 <none> 8080/TCP 5m41s
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress.networking.k8s.io/hello-nodejs nginx hello-nodejs-demo.stg.192-168-228-200.sslip.io 192.168.228.201 80, 443 5m41s
Nginx Ingressを経由したRoutingを利用するために、次のようにhostnameを変更します。
cat <<EOF > hello-nodejs-values.yaml
workload_name: hello-nodejs
hostname: hello-nodejs-demo.stg.192-168-228-201.sslip.io
EOF
新しいパラメータを次のコマンドで反映します。
tanzu package installed update -n demo hello-nodejs --values-file hello-nodejs-values.yaml
次のコマンドでIngressのhostnameが更新されたことを確認します。
$ kubectl get pkgi,deploy,svc,ing -n demo
NAME PACKAGE NAME PACKAGE VERSION DESCRIPTION AGE
packageinstall.packaging.carvel.dev/hello-nodejs hello-nodejs.demo.tap 20230811081306.0.0+build.fde413c Reconcile succeeded 6m26s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/hello-nodejs 1/1 1 1 6m23s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/hello-nodejs ClusterIP 10.96.113.106 <none> 8080/TCP 6m23s
NAME CLASS HOSTS ADDRESS PORTS AGE
ingress.networking.k8s.io/hello-nodejs nginx hello-nodejs-demo.stg.192-168-228-201.sslip.io 192.168.228.201 80, 443 6m23s
新しいhostnameを使ってアプリにアクセスします。
$ curl -k https://hello-nodejs-demo.stg.192-168-228-201.sslip.io
Hello World!!
Carvel Package Supply Chainを使うと実行環境(Runクラスタ)毎に、パラメータを変えられることを試せました。 TAP 1.6時点では、実行環境の設定が少し煩雑に感じます。
type=server
でアプリをデプロイした場合に、Ingressでアプリを公開したい場合の3つの方法を紹介しました。
kubectl
で直接Ingressリソースを作成する- OOTB SupplyChainで作成されるリソースにIngressを追加する
- Carvel Package Supply Chainを使用する
TAP 1.6時点では、どれも一長一短です。Carvel Package Supply ChainがGAになれば、これが一番いい選択かもしれません。
現時点ではkubectl
で直接Ingressリソースを作成するか、OOTB SupplyChainで作成されるリソースにIngressを追加するのが現実的ではないでしょうか。