TAPをGitOpsでインストールします。GitOpsにすることで、TAP自体のインストールを宣言的にでき、設定ファイルを管理でき、かつクラスタの操作ミスを防ぐことができます。 KubernetesでGitOpsを実現する方法はいくつかありますが、ここでは kapp-controller を使用します。 kapp-controllerはTAPのインストールの前提条件になるので、GitOps用に追加でソフトウェアをインストールする必要はありません。
kapp-controllerについてはCloud Native Operator Days 2022で紹介しましたので、詳細はスライドまたは動画を参考にしてください。
今回はこちらの記事で手動インストールしたTAPのGitOps版です。
目次
- Kindクラスタの作成
- kapp-controllerのインストール
- Service Accountの作成
- GitOps用のディレクトリ作成
- App CRの定義
- マニフェストをgitにpush
- Credentials用Secretの作成
- TAPのインストール
- TAPのアンインストール
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の検証環境を構築・破棄を繰り返し行いたい場合にも役に立つでしょう。