IK.AM

@making's tech note


Tanzu Application Platformをkapp-controllerを使ったGitOpsでインストールするメモ

🗃 {Dev/CaaS/Kubernetes/TAP}
🏷 Kubernetes 🏷 Cartographer 🏷 kind 🏷 Tanzu 🏷 TAP 🏷 Knative 🏷 kapp-controller 🏷 ytt 🏷 GitOps 
🗓 Updated at 2022-12-19T04:08:43Z  🗓 Created at 2022-12-16T18:10:03Z   🌎 English Page

⚠️ 本記事の内容はVMwareによってサポートされていません。 記事の内容で生じた問題については自己責任で対応し、 VMwareサポート窓口には問い合わせないでください

TAPをGitOpsでインストールします。GitOpsにすることで、TAP自体のインストールを宣言的にでき、設定ファイルを管理でき、かつクラスタの操作ミスを防ぐことができます。 KubernetesでGitOpsを実現する方法はいくつかありますが、ここでは kapp-controller を使用します。 kapp-controllerはTAPのインストールの前提条件になるので、GitOps用に追加でソフトウェアをインストールする必要はありません。

kapp-controllerについてはCloud Native Operator Days 2022で紹介しましたので、詳細はスライドまたは動画を参考にしてください。

今回はこちらの記事で手動インストールしたTAPのGitOps版です。

目次

Kindクラスタの作成

TAPをインストールする環境としてkindを使用します。

Dockerには4 CPU, 4 GBメモリ以上を割り当ててください。

kindは次のバージョンを使用しています。古いkindではk8s 1.24のnodeが起動しませんでした。

$ kind version
kind v0.17.0 go1.19.2 darwin/amd64

k8s 1.24を使用します。

cat <<EOF > kind-expose-port.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
 - role: control-plane
   extraPortMappings:
   - containerPort: 31443 # expose port 31443 of the node to port 80 on the host for use later by Contour ingress (envoy)
     hostPort: 443
   - containerPort: 31080 # expose port 31080 of the node to port 80 on the host for use later by Contour ingress (envoy)
     hostPort: 80
EOF

kind create cluster --config kind-expose-port.yaml --image kindest/node:v1.24.7

kapp-controllerのインストール

TAPのドキュメントではCluster Essentials for VMware Tanzuでkapp-controllerをインストールしますが、 ここでは最低限の手順でkapp-controllerを導入するため、Github上のマニフェストを使用します。

kubectl apply -f https://github.com/vmware-tanzu/carvel-kapp-controller/releases/download/v0.44.1/release.yml

Service Accountの作成

kapp controllerが使用するService Accountを作成し、ClusterRoleBindingを設定します。 ここではcluster-adminをbindしますが、制限されたClusterRoleを使用しても良いです。

NAMESPACE=kapp
kubectl create ns ${NAMESPACE}
kubectl create -n ${NAMESPACE} sa kapp
kubectl create clusterrolebinding kapp-cluster-admin-${NAMESPACE} --clusterrole cluster-admin --serviceaccount=${NAMESPACE}:kapp

GitOps用のディレクトリ作成

kappディレクトリにはkapp-controllerのApp CRの定義を、configディレクトリにはデプロイされるk8sリソースの定義を格納します。 それを作成するクラスタ単位で管理します。今回はkind上にデプロイするiterater clusterを管理するためにkind-iterateディレクトリを作成します。 これらは後ほどgit pushします。

mkdir -p tap-install-gitops/kind-iterate/kapp
mkdir -p tap-install-gitops/kind-iterate/config

次のようなファイル階層になります。

$ tree tap-install-gitops 
tap-install-gitops
`-- kind-iterate
    |-- config
    `-- kapp

ここではマニフェストは https://github.com/making/tap-install-gitops で管理します。

App CRの定義

kapp-controllerの App CR の定義と、App CRからデプロイされるリソースの定義を行います。

secretgen-controllerインストール用のApp CR

まずはTAPの前提条件のもう一つであるsecretgen-controllerのインストールをApp CRで定義します。 ここではGithub上のマニフェストからsecretgen-controllerをデプロイするようにします。

cat <<EOF > tap-install-gitops/kind-iterate/kapp/secretgen-controller.yaml
apiVersion: kappctrl.k14s.io/v1alpha1
kind: App
metadata:
  name: secretgen-controller
  namespace: kapp
  annotations:
    kapp.k14s.io/change-group: "{name}"
spec:
  serviceAccountName: kapp
  fetch:
  - http:
      url: https://github.com/vmware-tanzu/carvel-secretgen-controller/releases/download/v0.13.0/release.yml
  syncPeriod: 6h
  template:
  - ytt: { }
  deploy:
  - kapp:
      rawOptions:
      - --wait-timeout=5m
      - --diff-changes=true
      - --diff-mask=true
EOF

次のようなファイル階層になります。

$ tree tap-install-gitops 
tap-install-gitops
`-- kind-iterate
    |-- config
    `-- kapp
        `-- secretgen-controller.yaml

TAPのPackageRepositry用のApp CR

TAPのPackageRepository及び、それを使用するのに必要なNamespaceとSecretをまとめてApp CRで定義します。

mkdir -p tap-install-gitops/kind-iterate/config/tap-repository

Namespaceの定義

cat <<EOF > tap-install-gitops/kind-iterate/config/tap-repository/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: tap-install
EOF

Secretの定義。レジストリの情報は外部化しており、最後に外から渡します。

cat <<EOF > tap-install-gitops/kind-iterate/config/tap-repository/secret.yaml
#@ load("@ytt:data", "data")
apiVersion: v1
kind: Secret
metadata:
  name: tap-registry
  namespace: tap-install
type: kubernetes.io/dockerconfigjson
stringData:
  #@yaml/text-templated-strings
  .dockerconfigjson: |-
    {
      "auths": {
        "(@= data.values.tap_registry.server @)": {
          "username": "(@= data.values.tap_registry.username @)",
          "password": "(@= data.values.tap_registry.password @)"
        }
      }
    }
EOF

上記のSecretを他のNamespaceにexportすることを許可するためのSecretExportの定義

cat <<EOF > tap-install-gitops/kind-iterate/config/tap-repository/secret-export.yaml
apiVersion: secretgen.carvel.dev/v1alpha1
kind: SecretExport
metadata:
  name: tap-registry
  namespace: tap-install
spec:
  toNamespaces:
  - '*'
EOF

PackageRepositoryの定義 (TAP 1.3.3用)

cat <<EOF > tap-install-gitops/kind-iterate/config/tap-repository/pkgr.yaml
#@ load("@ytt:data", "data")
apiVersion: packaging.carvel.dev/v1alpha1
kind: PackageRepository
metadata:
  name: tanzu-tap-repository-1.3.3
  namespace: tap-install
spec:
  fetch:
    imgpkgBundle:
      image: #@ "{}/tanzu-application-platform/tap-packages:1.3.3".format(data.values.tap_registry.server)
EOF

ここまで用意したリソースをGitOpsで管理するためのApp CRの定義。secretgen-controllerの後にインストールされるように設定します。 6時間間隔でgit pullします。

cat <<EOF > tap-install-gitops/kind-iterate/kapp/tap-repository.yaml
apiVersion: kappctrl.k14s.io/v1alpha1
kind: App
metadata:
  name: tap-repository
  namespace: kapp
  annotations:
    kapp.k14s.io/change-group: "{name}"
    kapp.k14s.io/change-rule.create-order.0: "upsert after upserting secretgen-controller"
    kapp.k14s.io/change-rule.delete-order.0: "delete before deleting secretgen-controller"
spec:
  syncPeriod: 6h
  serviceAccountName: kapp
  fetch:
  - git:
      url: https://github.com/making/tap-install-gitops.git
      ref: origin/main
      subPath: kind-iterate/config
  template:
  - ytt:
      paths:
      - tap-repository
      valuesFrom:
      - secretRef:
          name: tap-install-gitops
  deploy:
  - kapp:
      rawOptions:
      - --wait-timeout=5m
      - --diff-changes=false
      - --diff-mask=true
EOF

次のようなファイル階層になります。

$ tree tap-install-gitops 
tap-install-gitops
`-- kind-iterate
    |-- config
    |   `-- tap-repository
    |       |-- namespace.yaml
    |       |-- pkgr.yaml
    |       |-- secret-export.yaml
    |       `-- secret.yaml
    `-- kapp
        |-- secretgen-controller.yaml
        `-- tap-repository.yaml

TAPのPackageInstall用のApp CR

TAPのPackageInstall及びtap-values.yaml、及びoverlayのSecretをまとめてApp CRで定義します。

自己署名TLS証明書を発行するためCA証明書を作成します。

mkdir -p certs
rm -f certs/*
docker run --rm -v ${PWD}/certs:/certs hitch openssl req -new -nodes -out /certs/ca.csr -keyout /certs/ca.key -subj "/CN=default-ca/O=TAP/C=JP"
chmod og-rwx ca.key
docker run --rm -v ${PWD}/certs:/certs hitch openssl x509 -req -in /certs/ca.csr -days 3650 -extfile /etc/ssl/openssl.cnf -extensions v3_ca -signkey /certs/ca.key -out /certs/ca.crt
mkdir -p tap-install-gitops/kind-iterate/config/tap/overlays

ここではベースのドメイン名はKind用に127-0-0-1.sslip.ioを使用します。このドメイン及びサブドメインは全て127.0.0.1に解決されます。

export BASE_DOMAIN=127-0-0-1.sslip.io

まずはTAPのインストールで使用するoverlayのSecretを定義します。

  • デフォルトのTLS証明書を発行するためのoverlay
cat <<EOF > tap-install-gitops/kind-iterate/config/tap/overlays/contour-default-tls.yaml
#@ load("@ytt:data", "data")
apiVersion: v1
kind: Secret
metadata:
  name: contour-default-tls
  namespace: tap-install
  annotations:
    kapp.k14s.io/change-group: "tap-overlays"
type: Opaque
stringData:
  #@yaml/text-templated-strings
  contour-default-tls.yaml: |
    #@ load("@ytt:data", "data")
    #@ load("@ytt:overlay", "overlay")
    #@ namespace = data.values.namespace
    ---
    apiVersion: v1
    kind: Secret
    metadata:
      name: default-ca
      namespace: #@ namespace
    type: kubernetes.io/tls
    stringData:
      tls.crt: "(@= data.values.default_ca.crt.replace('\n', '\\n') @)"
      tls.key: "(@= data.values.default_ca.key.replace('\n', '\\n') @)"
    ---
    apiVersion: cert-manager.io/v1
    kind: Issuer
    metadata:
      name: default-ca-issuer
      namespace: #@ namespace
    spec:
      ca:
        secretName: default-ca
    ---
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      name: tap-default-tls
      namespace: #@ namespace
    spec:
      dnsNames:
      - #@ "*.${BASE_DOMAIN}"
      issuerRef:
        kind: Issuer
        name: default-ca-issuer
      secretName: tap-default-tls
    ---
    apiVersion: projectcontour.io/v1
    kind: TLSCertificateDelegation
    metadata:
      name: contour-delegation
      namespace: #@ namespace
    spec:
      delegations:
      - secretName: tap-default-tls
        targetNamespaces:
        - "*"
EOF
  • KnativeでHTTPSでデフォルトで使用するためのoverlay
cat <<EOF > tap-install-gitops/kind-iterate/config/tap/overlays/cnrs-https.yaml
apiVersion: v1
kind: Secret
metadata:
  name: cnrs-https
  namespace: tap-install
  annotations:
    kapp.k14s.io/change-group: "tap-overlays"
type: Opaque
stringData:
  cnrs-https.yaml: |
    #@ load("@ytt:overlay", "overlay")
    #@overlay/match by=overlay.subset({"metadata":{"name":"config-network"}, "kind": "ConfigMap"})
    ---
    data:
      #@overlay/match missing_ok=True
      default-external-scheme: https
      #@overlay/match missing_ok=True
      http-protocol: redirected      
EOF
  • TelemetryのPodを削除するためのoverlay
cat <<EOF > tap-install-gitops/kind-iterate/config/tap/overlays/tap-telemetry-remove.yaml
apiVersion: v1
kind: Secret
metadata:
  name: tap-telemetry-remove
  namespace: tap-install
  annotations:
    kapp.k14s.io/change-group: "tap-overlays"
type: Opaque
stringData:
  tap-telemetry-remove.yaml: |
    #@ load("@ytt:overlay", "overlay")
    #@overlay/match by=overlay.subset({"metadata":{"namespace":"tap-telemetry"}}), expects="1+"
    #@overlay/remove
    ---     
EOF

次に、tanzu package install tap -n tap-install -f tap-values.yamlと同等なインストールをYAMLで定義します。

tanzu CLIでPackageをインストールする場合とPackageInstallを作成してPackageをインストールする場合との違いはこちらの記事を参照してください。

tap-values.yamlを格納するSecretの定義

cat <<EOF > tap-install-gitops/kind-iterate/config/tap/values.yaml
#@ load("@ytt:data", "data")
#@ load("@ytt:yaml", "yaml")

#@ def tap_values():
shared:
  ingress_domain: ${BASE_DOMAIN}
  image_registry:
    project_path: #@ data.values.image_registry.project_path
    username: #@ data.values.image_registry.username
    password: #@ data.values.image_registry.password
  ca_cert_data: #@ data.values.default_ca.crt

ceip_policy_disclosed: true
profile: iterate

supply_chain: basic

contour:
  contour:
    replicas: 1
  envoy:
    service:
      type: NodePort
      nodePorts:
        http: 31080
        https: 31443
    hostPorts:
      enable: true

cnrs:
  domain_template: "{{.Name}}-{{.Namespace}}.{{.Domain}}"
  default_tls_secret: tanzu-system-ingress/tap-default-tls
  provider: local

package_overlays:
- name: contour
  secrets:
  - name: contour-default-tls
- name: cnrs
  secrets:
  - name: cnrs-https
- name: tap-telemetry
  secrets:
  - name: tap-telemetry-remove

excluded_packages:
- policy.apps.tanzu.vmware.com
- image-policy-webhook.signing.apps.tanzu.vmware.com
- eventing.tanzu.vmware.com
- sso.apps.tanzu.vmware.com
#@ end

apiVersion: v1
kind: Secret
metadata:
  name: tap-tap-install-values
  namespace: tap-install
  annotations:
    kapp.k14s.io/change-group: "tap-install-values"
type: Opaque
stringData:
  tap-values.yaml: #@ yaml.encode(tap_values())
EOF

PackageをインストールするためのRBACの定義

cat <<EOF > tap-install-gitops/kind-iterate/config/tap/rbac.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    tkg.tanzu.vmware.com/tanzu-package: tap-tap-install
    kapp.k14s.io/change-group: "tap-rbac"
  name: tap-tap-install-cluster-role
rules:
- apiGroups:
  - '*'
  resources:
  - '*'
  verbs:
  - '*'
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  annotations:
    tkg.tanzu.vmware.com/tanzu-package: tap-tap-install
    kapp.k14s.io/change-group: "tap-rbac"
  name: tap-tap-install-cluster-rolebinding
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: tap-tap-install-cluster-role
subjects:
- kind: ServiceAccount
  name: tap-tap-install-sa
  namespace: tap-install
---
apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    tkg.tanzu.vmware.com/tanzu-package: tap-tap-install
    kapp.k14s.io/change-group: "tap-rbac"
  name: tap-tap-install-sa
  namespace: tap-install 
EOF

PackageInstallの定義

cat <<EOF > tap-install-gitops/kind-iterate/config/tap/pkgi.yaml
apiVersion: packaging.carvel.dev/v1alpha1
kind: PackageInstall
metadata:
  name: tap
  namespace: tap-install
  annotations:
    tkg.tanzu.vmware.com/tanzu-package-ClusterRole: tap-tap-install-cluster-role
    tkg.tanzu.vmware.com/tanzu-package-ClusterRoleBinding: tap-tap-install-cluster-rolebinding
    tkg.tanzu.vmware.com/tanzu-package-Secret: tap-tap-install-values
    tkg.tanzu.vmware.com/tanzu-package-ServiceAccount: tap-tap-install-sa
    kapp.k14s.io/change-group: "{name}"
    kapp.k14s.io/change-rule.create-order.1: "upsert after upserting tap-rbac"
    kapp.k14s.io/change-rule.delete-order.1: "delete before deleting tap-rbac"
    kapp.k14s.io/change-rule.create-order.2: "upsert after upserting tap-values"
    kapp.k14s.io/change-rule.delete-order.2: "delete before deleting tap-values"
    kapp.k14s.io/change-rule.create-order.3: "upsert after upserting tap-overlays"
    kapp.k14s.io/change-rule.delete-order.3: "delete before deleting tap-overlays"
spec:
  syncPeriod: 3h
  serviceAccountName: tap-tap-install-sa
  packageRef:
    refName: tap.tanzu.vmware.com
    versionSelection:
      constraints: 1.3.3
      prereleases: { }
  values:
  - secretRef:
      name: tap-tap-install-values 
EOF

ここまで用意したリソースをGitOpsで管理するためのApp CRの定義。PackageRepositoryの後にインストールされるように設定します。 1時間間隔でgit pullします。

cat <<EOF > tap-install-gitops/kind-iterate/kapp/tap.yaml
apiVersion: kappctrl.k14s.io/v1alpha1
kind: App
metadata:
  name: tap
  namespace: kapp
  annotations:
    kapp.k14s.io/change-group: "{name}"
    kapp.k14s.io/change-rule.create-order.0: "upsert after upserting tap-repository"
    kapp.k14s.io/change-rule.delete-order.0: "delete before deleting tap-repository"
spec:
  syncPeriod: 1h
  serviceAccountName: kapp
  fetch:
  - git:
      url: https://github.com/making/tap-install-gitops.git
      ref: origin/main
      subPath: kind-iterate/config
  template:
  - ytt:
      paths:
      - tap
      valuesFrom:
      - secretRef:
          name: tap-install-gitops
  deploy:
  - kapp:
      rawOptions:
      - --wait-timeout=5m
      - --diff-changes=false
      - --diff-mask=true
EOF

次のようなファイル階層になります。

$ tree tap-install-gitops 
tap-install-gitops
`-- kind-iterate
    |-- config
    |   |-- tap
    |   |   |-- overlays
    |   |   |   |-- cnrs-https.yaml
    |   |   |   |-- contour-default-tls.yaml
    |   |   |   `-- tap-telemetry-remove.yaml
    |   |   |-- pkgi.yaml
    |   |   |-- rbac.yaml
    |   |   `-- values.yaml
    |   `-- tap-repository
    |       |-- namespace.yaml
    |       |-- pkgr.yaml
    |       |-- secret-export.yaml
    |       `-- secret.yaml
    `-- kapp
        |-- secretgen-controller.yaml
        |-- tap-repository.yaml
        `-- tap.yaml

App CR群をまとめて管理する親App CR

ここまで定義したApp CR群自体をGitOpsで管理するためのApp CRの定義。 10分間隔でgit pullします。

☝️ app of apps patternを実現します

cat <<EOF > tap-install-gitops/kind-iterate/apps.yaml
apiVersion: kappctrl.k14s.io/v1alpha1
kind: App
metadata:
  name: apps
  namespace: kapp
spec:
  serviceAccountName: kapp
  fetch:
  - git:
      url: https://github.com/making/tap-install-gitops.git
      ref: origin/main
      subPath: kind-iterate/kapp
  syncPeriod: 10m
  template:
  - ytt:
      paths:
      - '.'
  deploy:
  - kapp:
      rawOptions:
      - --wait-timeout=5m
      - --diff-changes=true
      - --diff-mask=false
EOF

次のようなファイル階層になります。

$ tree tap-install-gitops                              
tap-install-gitops
`-- kind-iterate
    |-- apps.yaml
    |-- config
    |   |-- tap
    |   |   |-- overlays
    |   |   |   |-- cnrs-https.yaml
    |   |   |   |-- contour-default-tls.yaml
    |   |   |   `-- tap-telemetry-remove.yaml
    |   |   |-- pkgi.yaml
    |   |   |-- rbac.yaml
    |   |   `-- values.yaml
    |   `-- tap-repository
    |       |-- namespace.yaml
    |       |-- pkgr.yaml
    |       |-- secret-export.yaml
    |       `-- secret.yaml
    `-- kapp
        |-- secretgen-controller.yaml
        |-- tap-repository.yaml
        `-- tap.yaml

マニフェストをgitにpush

作成したマニフェストを https://github.com/making/tap-install-gitops にpushします。

GITHUB_USERNAME=...

cd tap-install-gitops 
git init
git add -A
git commit -m "first commit"
git branch -M main
git remote add origin git@github.com:${GITHUB_USERNAME}/tap-install-gitops.git
git push -u origin main
cd ..

Credentials用Secretの作成

Gitで管理されるマニフェストにはCredentialsを含めず、外部化されたパラメータを参照するようにしていました。 外部化されたパラメータはSecretから参照するように設定されています。このSecretはGit管理外で、次のように作成します。

TANZUNET_USERNAME=...
TANZUNET_PASSWORD=...
GITHUB_USERNAME=...
GITHUB_API_TOKEN=...

kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: tap-install-gitops
  namespace: kapp
type: Opaque
stringData:
  credentials.yaml: |
    tap_registry:
      server: registry.tanzu.vmware.com
      username: ${TANZUNET_USERNAME}
      password: ${TANZUNET_PASSWORD}
    image_registry:
      project_path: ghcr.io/${GITHUB_USERNAME}
      username: ${GITHUB_USERNAME}
      password: ${GITHUB_API_TOKEN}
    default_ca:
      crt: |
$(cat certs/ca.crt | sed 's/^/        /g')
      key: |
$(cat certs/ca.key | sed 's/^/        /g')
EOF

CredentialsはGit管理外のSecretで管理する他にsopsで暗号化したファイルをGitで管理する方法もあります。 このやり方については https://carvel.dev/kapp-controller/docs/v0.43.2/sops/ を参照してください。

このブログの管理にはsopsを使用したGitOpsを採用しています。
本記事のファイル構成と若干異なりますが、 https://github.com/categolj/k8s-manifests が参考になるでしょう。

TAPのインストール

Gitレポジトリと、外部化されたパラメータができたのでいよいよApp CRでTAPをインストールします。 親App CRを作成するだけで全てがインストールされます。

kubectl apply -f tap-install-gitops/kind-iterate/apps.yaml

次のコマンドで完了するまで進捗を確認します。

while [ "$(kubectl -n kapp get app apps -o=jsonpath='{.status.friendlyDescription}')" != "Reconcile succeeded" ];do
  date
  kubectl get app -A
  echo "---------------------------------------------------------------------"
  sleep 10
done
echo "✅ Install succeeded"

インストールが成功した後、各AppはsyncPeriodの間隔でreconcileします。このsyncPeriodを待てない場合は

kctrl app kick -n kapp -a <App名>

で強制的にreconcileさせることができます。kctrl CLIは kapp-controllerのReleasesページ からダウンロードできます。

TAPのアンインストール

親App CRを削除するだけで全てがアンインストールされます。

kubectl delete -f tap-install-gitops/kind-iterate/apps.yaml

kapp-controllerでTAPをGitOpsする方法を紹介しました。

この方法を用いると、TAPをインストールするのに

  • kapp-controllerをインストール
  • Service Accountを作成
  • credentialsのSecretの登録 (sopsを使用する場合は、GPG Private Keyの登録)
  • apps App CRの作成

だけで済みます。tanzu CLIによる操作は不要です。

TAP以外のソフトウェア(Prometheusなど)も同時にインストール可能なので、環境構築の自動化も楽になります。 TAPの検証環境を構築・破棄を繰り返し行いたい場合にも役に立つでしょう。


✒️️ Edit  ⏰ History  🗑 Delete