--- title: imgpkg bundle化したHelm ChartをCarvel Package化する tags: ["Kubernetes", "Carvle", "air-gapped", "kbld", "imgpkg", "Helm", "kapp-controller"] categories: ["Dev", "Carvel", "kapp-controller"] date: 2021-12-16T15:00:00Z updated: 2021-12-16T15:00:00Z --- > [TUNA-JP Advent Calendar 2021](https://qiita.com/advent-calendar/2021/tuna-jp) その2の17日目のエントリです。 [前の記事](/entries/679)で、imgpkg / kbldを使ったHelm Chartのimgpkg bundle化、及びair-gapped環境へのインストールができることを確認しました。 今回は前回作成したHelm Chartのimgpkg bundleを[Carvel Package](https://carvel.dev/kapp-controller/docs/latest/packaging/) 化し、PackageInstall CRを使ってair-gapped環境にinstallします。 Carvel Packageに関しては [CFCNのWebinar](https://www.youtube.com/watch?v=us3NhfUfIFk) がわかりやすいです。 Webinarで使われたサンプルのレポジトリは https://github.com/k14s/cncf-packaging-webinar です。 **目次** ### imgpkg bundle化したHelm ChartのCarvel Package作成 Webinarの [7-pkg-cr](https://github.com/k14s/cncf-packaging-webinar/tree/develop/7-pkg-cr) と [8-pkg-cr-helm-chart](https://github.com/k14s/cncf-packaging-webinar/tree/develop/8-pkg-cr-helm-chart) の内容を組み合わせます。 Webinarでは作成されませんでしたが、[PackageMetadata CR](https://carvel.dev/kapp-controller/docs/latest/packaging/#package-metadata) を作っておきます。 `pkg-metadata.yaml`に次の内容を記述します。 ```yaml apiVersion: data.packaging.carvel.dev/v1alpha1 kind: PackageMetadata metadata: name: nginx.chart.pkg.maki.lol namespace: default spec: displayName: "Nginx" longDescription: "Nginx Bitnami Helm Chart" shortDescription: "Nginx Bitnami Helm Chart" categories: - nginx - bitnami - helm ``` 次に [Package CR](https://carvel.dev/kapp-controller/docs/latest/packaging/#package) を作成します。 `fetch`に`imgpkgBundle`を`template`に`helmTemplate` + `kbld`を指定します。 `pkg.yaml`に次の内容を記述します。 ```yaml apiVersion: data.packaging.carvel.dev/v1alpha1 kind: Package metadata: name: nginx.chart.pkg.maki.lol.9.5.7 namespace: default spec: refName: nginx.chart.pkg.maki.lol version: 9.5.7 releaseNotes: | Supprt nginx bitnami helm chart 9.5.7 template: spec: fetch: - imgpkgBundle: image: harbor-10-213-232-22.sslip.io/library/nginx-chart-bundle:9.5.7 template: - helmTemplate: {} - kbld: paths: - "-" - ".imgpkg/images.yml" deploy: - kapp: {} ``` > ちなみに既存のHelm ChartをCarvel Package化したいだけであれば、imgpkg bundleを作る必要はなく、次のYAMLのように`fetch`に`helmChart`を指定すれば良いです。air-gapped環境にインストールしたい場合は、imgpkg bundle化する > ```yaml > apiVersion: data.packaging.carvel.dev/v1alpha1 > kind: Package > metadata: > name: nginx.chart.pkg.maki.lol.9.5.7 > annotations: > kapp.k14s.io/change-group: pkg > spec: > refName: nginx.chart.pkg.maki.lol > version: 9.5.7 > releaseNotes: | > Supprt nginx bitnami helm chart 9.5.7 > template: > spec: > fetch: > - helmChart: > name: nginx > version: 9.5.7 > repository: > url: https://charts.bitnami.com/bitnami > template: > - helmTemplate: {} > - kbld: > paths: > - "-" > - ".imgpkg/images.yml" > deploy: > - kapp: {} > ``` `pkg-metadata.yaml`と`pkg.yaml`をapplyします。 ``` kubectl apply -f pkg-metadata.yaml -f pkg.yaml ``` PackageとPackageMetadata一覧に`nginx.chart.pkg.maki.lol`が現れることを確認します。 ``` $ kubectl get package NAME PACKAGEMETADATA NAME VERSION AGE cert-manager.tanzu.vmware.com.1.1.0+vmware.1-tkg.2 cert-manager.tanzu.vmware.com 1.1.0+vmware.1-tkg.2 79h34m56s contour.tanzu.vmware.com.1.17.1+vmware.1-tkg.1 contour.tanzu.vmware.com 1.17.1+vmware.1-tkg.1 79h34m56s external-dns.tanzu.vmware.com.0.8.0+vmware.1-tkg.1 external-dns.tanzu.vmware.com 0.8.0+vmware.1-tkg.1 79h34m56s fluent-bit.tanzu.vmware.com.1.7.5+vmware.1-tkg.1 fluent-bit.tanzu.vmware.com 1.7.5+vmware.1-tkg.1 79h34m56s grafana.tanzu.vmware.com.7.5.7+vmware.1-tkg.1 grafana.tanzu.vmware.com 7.5.7+vmware.1-tkg.1 79h34m56s harbor.tanzu.vmware.com.2.2.3+vmware.1-tkg.1 harbor.tanzu.vmware.com 2.2.3+vmware.1-tkg.1 79h34m56s multus-cni.tanzu.vmware.com.3.7.1+vmware.1-tkg.1 multus-cni.tanzu.vmware.com 3.7.1+vmware.1-tkg.1 79h34m56s prometheus.tanzu.vmware.com.2.27.0+vmware.1-tkg.1 prometheus.tanzu.vmware.com 2.27.0+vmware.1-tkg.1 79h34m55s nginx.chart.pkg.maki.lol.9.5.7 nginx.chart.pkg.maki.lol 9.5.7 1m6s $ kubectl get packagemetadata NAME DISPLAY NAME CATEGORIES SHORT DESCRIPTION AGE cert-manager.tanzu.vmware.com cert-manager certificate management Certificate management 79h34m58s contour.tanzu.vmware.com Contour ingress An ingress controller 79h34m58s external-dns.tanzu.vmware.com external-dns dns This package provides DNS synchronization funct... 79h34m58s fluent-bit.tanzu.vmware.com fluent-bit logging,observability Fluent Bit is a fast Log Processor and Forwarder 79h34m58s grafana.tanzu.vmware.com grafana monitoring,observability Visualization and analytics software 79h34m58s harbor.tanzu.vmware.com Harbor OCI registry OCI Registry 79h34m57s multus-cni.tanzu.vmware.com multus-cni networking This package provides the ability for enabling ... 79h34m57s prometheus.tanzu.vmware.com prometheus monitoring,observability A time series database for your metrics 79h34m58s nginx.chart.pkg.maki.lol Nginx nginx,bitnami,helm Nginx Bitnami Helm Chart 1m9s ``` > 【補足情報】
> PackageもPackageMetadataも**Namespaced**なリソースです。上記の例ではnginxは`default` namespaceにインストールされました。 > しかし、一覧表示には`tanzu-package-repo-global`にインストールされたPackageとPackageMetadataも出力されています。
> kapp controllerの`-packaging-global-namespace`オプションに指定されたnamespaceは他のnamespaceからもアクセスできるようになります。
> TKGのkapp-controllerに`-packaging-global-namespace=tanzu-package-repo-global`オプションが指定されているため、このnamespaceにインストールされたPackageやPackageMetadataは他のnamespaceからも見えるようになっています。
> 詳細は [ドキュメント](https://carvel.dev/kapp-controller/docs/latest/package-consumer-concepts/) に記載されています。 ### PackageInstall CRの作成 インストールしたPackage CRはPackageInstall CRを作成することで [App CR](https://carvel.dev/kapp-controller/docs/latest/app-overview/) が作成され、Deploymentなどの実際のリソースが作成されます。 PackageInstallの作り方は、YAMLを`kubectl`で作成する方法と`tanzu` CLIを使用する方法があります。 #### kubectlでPackageInstall CRを作成 まずはYAMLでPackageInstall CRを作成します。インストールするPackageの指定と、Packageに渡すパラメータ(ここではhelm templateに渡すvalues.yamlそのもの)をSecret経由で指定します。 `pkg-install.yaml`に次の内容を記述します。 ```yaml apiVersion: packaging.carvel.dev/v1alpha1 kind: PackageInstall metadata: name: nginx namespace: default spec: serviceAccountName: default-ns-sa packageRef: refName: nginx.chart.pkg.maki.lol versionSelection: constraints: 9.5.7 values: - secretRef: name: nginx-values --- apiVersion: v1 kind: Secret metadata: name: nginx-values namespace: default stringData: data.yml: | serverBlock: |- server { listen 0.0.0.0:8080; location / { return 200 "hello from kapp-controller!"; } } ``` ここで指定した`secretRef`はPackage CRの`template`の一つ目(ここでは`helmTemplate`)に渡されます。 以下のコマンドでPackageInstall CRを作成します。その前にPackageInstall CRが使用するService AccountとそのRBACを作成します。 ``` kubectl apply -f https://github.com/k14s/cncf-packaging-webinar/raw/develop/3-app-cr-config-map/rbac/default-ns.yml kubectl apply -f pkg-install.yaml ``` nginxのPackage Install CRとそれによって作成されるApp CRを確認します。 ``` $ kubectl get packageinstall,app NAME PACKAGE NAME PACKAGE VERSION DESCRIPTION AGE packageinstall.packaging.carvel.dev/nginx nginx.chart.pkg.maki.lol 9.5.7 Reconcile succeeded 71s NAME DESCRIPTION SINCE-DEPLOY AGE app.kappctrl.k14s.io/nginx Reconcile succeeded 55s 71s ``` 実際にどのようなリソースが作成されたかは次のようにApp CRのstatusで確認できます。 ```yaml $ kubectl get app nginx -oyaml apiVersion: kappctrl.k14s.io/v1alpha1 kind: App metadata: creationTimestamp: "2021-12-14T11:39:07Z" finalizers: - finalizers.kapp-ctrl.k14s.io/delete generation: 1 name: nginx namespace: default ownerReferences: - apiVersion: packaging.carvel.dev/v1alpha1 blockOwnerDeletion: true controller: true kind: PackageInstall name: nginx uid: 2aa16ab1-0637-4584-b952-9c2f8d16cf78 resourceVersion: "970989" uid: f35ddafe-858a-415c-bc74-bffa42a5799f spec: deploy: - kapp: {} fetch: - imgpkgBundle: image: harbor-10-213-232-22.sslip.io/library/nginx-chart-bundle:9.5.7 serviceAccountName: default-ns-sa template: - helmTemplate: valuesFrom: - secretRef: name: nginx-values - kbld: paths: - '-' - .imgpkg/images.yml status: conditions: - status: "True" type: ReconcileSucceeded consecutiveReconcileSuccesses: 3 deploy: exitCode: 0 finished: true startedAt: "2021-12-14T11:40:30Z" stdout: |- Target cluster 'https://100.64.0.1:443' 11:40:30AM: info: Resources: Ignoring group version: schema.GroupVersionResource{Group:"stats.antrea.tanzu.vmware.com", Version:"v1alpha1", Resource:"networkpolicystats"} 11:40:30AM: info: Resources: Ignoring group version: schema.GroupVersionResource{Group:"stats.antrea.tanzu.vmware.com", Version:"v1alpha1", Resource:"antreanetworkpolicystats"} Changes Namespace Name Kind Conds. Age Op Op st. Wait to Rs Ri Op: 0 create, 0 delete, 0 update, 0 noop Wait to: 0 reconcile, 0 delete, 0 noop Succeeded updatedAt: "2021-12-14T11:40:31Z" fetch: exitCode: 0 startedAt: "2021-12-14T11:40:28Z" stdout: | apiVersion: vendir.k14s.io/v1alpha1 directories: - contents: - imgpkgBundle: image: harbor-10-213-232-22.sslip.io/library/nginx-chart-bundle@sha256:d9ef393cf39246e623e833581f7fb9dbf8547b610152da958d80221a23899a84 path: . path: "0" kind: LockConfig updatedAt: "2021-12-14T11:40:29Z" friendlyDescription: Reconcile succeeded inspect: exitCode: 0 stdout: |- Target cluster 'https://100.64.0.1:443' 11:40:31AM: info: Resources: Ignoring group version: schema.GroupVersionResource{Group:"stats.antrea.tanzu.vmware.com", Version:"v1alpha1", Resource:"antreanetworkpolicystats"} 11:40:31AM: info: Resources: Ignoring group version: schema.GroupVersionResource{Group:"stats.antrea.tanzu.vmware.com", Version:"v1alpha1", Resource:"networkpolicystats"} Resources in app 'nginx-ctrl' Namespace Name Kind Owner Conds. Rs Ri Age default nginx Deployment kapp 2/2 t ok - 1m ^ nginx Endpoints cluster - ok - 1m ^ nginx Service kapp - ok - 1m ^ nginx-6d58d959c7 ReplicaSet cluster - ok - 1m ^ nginx-6d58d959c7-sbs8f Pod cluster 4/4 t ok - 1m ^ nginx-ltxf4 EndpointSlice cluster - ok - 1m ^ nginx-server-block ConfigMap kapp - ok - 1m Rs: Reconcile state Ri: Reconcile information 7 resources Succeeded updatedAt: "2021-12-14T11:40:31Z" observedGeneration: 1 template: exitCode: 0 stderr: | resolve | final: docker.io/bitnami/nginx:1.21.3-debian-10-r29 -> harbor-10-213-232-22.sslip.io/library/nginx-chart-bundle@sha256:f21acb4cd83d4b55930d8e290ebd3064fb0e019b0f06cd10ebc297cd67901747 updatedAt: "2021-12-14T11:40:30Z" ``` `helmTemplate`に`secretRef`が設定されていることも確認できました。 デプロイされたNginxにアクセスし、`data.yaml`で設定した内容が反映されていることを確認します。 ``` $ curl $(kubectl get svc nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}') hello from kapp-controller! ``` 確認できたら、PackageInstallとRBACの設定を削除します。 ``` kubectl delete -f pkg-install.yaml kubectl delete -f https://github.com/k14s/cncf-packaging-webinar/raw/develop/3-app-cr-config-map/rbac/default-ns.yml ``` #### Tanzu CLIでPackageInstall CRを作成 PackageInstall CRは`tanzu` CLIを使うことでも作成できます。この場合PackageInstall CRのYAMLは不要です。 また、RBACの設定も自動で行われます。 次のコマンドで対象のnamespaceにインストール可能なPackage一覧を取得します、 ``` $ tanzu package available list \ Retrieving available packages... NAME DISPLAY-NAME SHORT-DESCRIPTION LATEST-VERSION cert-manager.tanzu.vmware.com cert-manager Certificate management 1.1.0+vmware.1-tkg.2 contour.tanzu.vmware.com Contour An ingress controller 1.17.1+vmware.1-tkg.1 external-dns.tanzu.vmware.com external-dns This package provides DNS synchronization functionality. 0.8.0+vmware.1-tkg.1 fluent-bit.tanzu.vmware.com fluent-bit Fluent Bit is a fast Log Processor and Forwarder 1.7.5+vmware.1-tkg.1 grafana.tanzu.vmware.com grafana Visualization and analytics software 7.5.7+vmware.1-tkg.1 harbor.tanzu.vmware.com Harbor OCI Registry 2.2.3+vmware.1-tkg.1 multus-cni.tanzu.vmware.com multus-cni This package provides the ability for enabling attaching multiple network interfaces to pods in Kubernetes 3.7.1+vmware.1-tkg.1 prometheus.tanzu.vmware.com prometheus A time series database for your metrics 2.27.0+vmware.1-tkg.1 nginx.chart.pkg.maki.lol Nginx Nginx Bitnami Helm Chart 9.5.7 ``` Packageに渡すパラメータ(ここではhelm templateに渡すvalues.yamlそのもの)のみYAMLで次のように作成します。 ```yaml cat < data.yml serverBlock: |- server { listen 0.0.0.0:8080; location / { return 200 "hello from kapp-controller!"; } } EOF ``` 次のコマンドでPackageをインストールします。 ``` tanzu package install nginx -p nginx.chart.pkg.maki.lol -v 9.5.7 -f data.yml -n default ``` 次のようなログが出力され、RBACの設定やPackageInstall CRが作成されていることがわかります。 ``` | Installing package 'nginx.chart.pkg.maki.lol' | Getting package metadata for 'nginx.chart.pkg.maki.lol' / Creating service account 'nginx-default-sa' / Creating cluster admin role 'nginx-default-cluster-role' / Creating cluster role binding 'nginx-default-cluster-rolebinding' / Creating secret 'nginx-default-values' / Creating package resource \ Waiting for 'PackageInstall' reconciliation for 'nginx' | 'PackageInstall' resource install status: Reconciling Added installed package 'nginx' ``` `tanzu` CLIでインストールされたPackage一覧を確認します。 ``` $ tanzu package installed list / Retrieving installed packages... NAME PACKAGE-NAME PACKAGE-VERSION STATUS nginx nginx.chart.pkg.maki.lol 9.5.7 Reconcile succeeded ``` `kubectl`でPackageInstall CRとApp CRを確認します。 ``` $ kubectl get packageinstall,app NAME PACKAGE NAME PACKAGE VERSION DESCRIPTION AGE packageinstall.packaging.carvel.dev/nginx nginx.chart.pkg.maki.lol 9.5.7 Reconcile succeeded 3m53s NAME DESCRIPTION SINCE-DEPLOY AGE app.kappctrl.k14s.io/nginx Reconcile succeeded 13s 3m53s ``` 実際にどのようなリソースが作成されたかは次のようにApp CRのstatusで確認できます。 ```yaml $ kubectl get app nginx -oyaml apiVersion: kappctrl.k14s.io/v1alpha1 kind: App metadata: creationTimestamp: "2021-12-14T11:47:28Z" finalizers: - finalizers.kapp-ctrl.k14s.io/delete generation: 1 name: nginx namespace: default ownerReferences: - apiVersion: packaging.carvel.dev/v1alpha1 blockOwnerDeletion: true controller: true kind: PackageInstall name: nginx uid: 0aa10a91-7134-4564-85a3-243d2456f51b resourceVersion: "973411" uid: d776a09d-0acf-4c0e-a0a0-0dffd49ae719 spec: deploy: - kapp: {} fetch: - imgpkgBundle: image: harbor-10-213-232-22.sslip.io/library/nginx-chart-bundle:9.5.7 serviceAccountName: nginx-default-sa template: - helmTemplate: valuesFrom: - secretRef: name: nginx-default-values - kbld: paths: - '-' - .imgpkg/images.yml status: conditions: - status: "True" type: ReconcileSucceeded consecutiveReconcileSuccesses: 8 deploy: exitCode: 0 finished: true startedAt: "2021-12-14T11:51:42Z" stdout: |- Target cluster 'https://100.64.0.1:443' (nodes: cheetah-control-plane-xtwcj, 1+) 11:51:43AM: info: Resources: Ignoring group version: schema.GroupVersionResource{Group:"stats.antrea.tanzu.vmware.com", Version:"v1alpha1", Resource:"antreaclusternetworkpolicystats"} 11:51:43AM: info: Resources: Ignoring group version: schema.GroupVersionResource{Group:"stats.antrea.tanzu.vmware.com", Version:"v1alpha1", Resource:"antreanetworkpolicystats"} 11:51:43AM: info: Resources: Ignoring group version: schema.GroupVersionResource{Group:"stats.antrea.tanzu.vmware.com", Version:"v1alpha1", Resource:"networkpolicystats"} Changes Namespace Name Kind Conds. Age Op Op st. Wait to Rs Ri Op: 0 create, 0 delete, 0 update, 0 noop Wait to: 0 reconcile, 0 delete, 0 noop Succeeded updatedAt: "2021-12-14T11:51:43Z" fetch: exitCode: 0 startedAt: "2021-12-14T11:51:41Z" stdout: | apiVersion: vendir.k14s.io/v1alpha1 directories: - contents: - imgpkgBundle: image: harbor-10-213-232-22.sslip.io/library/nginx-chart-bundle@sha256:d9ef393cf39246e623e833581f7fb9dbf8547b610152da958d80221a23899a84 path: . path: "0" kind: LockConfig updatedAt: "2021-12-14T11:51:42Z" friendlyDescription: Reconcile succeeded inspect: exitCode: 0 stdout: |- Target cluster 'https://100.64.0.1:443' (nodes: cheetah-control-plane-xtwcj, 1+) 11:51:43AM: info: Resources: Ignoring group version: schema.GroupVersionResource{Group:"stats.antrea.tanzu.vmware.com", Version:"v1alpha1", Resource:"antreaclusternetworkpolicystats"} 11:51:43AM: info: Resources: Ignoring group version: schema.GroupVersionResource{Group:"stats.antrea.tanzu.vmware.com", Version:"v1alpha1", Resource:"networkpolicystats"} 11:51:43AM: info: Resources: Ignoring group version: schema.GroupVersionResource{Group:"stats.antrea.tanzu.vmware.com", Version:"v1alpha1", Resource:"antreanetworkpolicystats"} Resources in app 'nginx-ctrl' Namespace Name Kind Owner Conds. Rs Ri Age default nginx Deployment kapp 2/2 t ok - 4m ^ nginx Endpoints cluster - ok - 4m ^ nginx Service kapp - ok - 4m ^ nginx-59b74db6b ReplicaSet cluster - ok - 4m ^ nginx-59b74db6b-wsh68 Pod cluster 4/4 t ok - 4m ^ nginx-j9wh8 EndpointSlice cluster - ok - 4m ^ nginx-server-block ConfigMap kapp - ok - 4m Rs: Reconcile state Ri: Reconcile information 7 resources Succeeded updatedAt: "2021-12-14T11:51:43Z" observedGeneration: 1 template: exitCode: 0 stderr: | resolve | final: docker.io/bitnami/nginx:1.21.3-debian-10-r29 -> harbor-10-213-232-22.sslip.io/library/nginx-chart-bundle@sha256:f21acb4cd83d4b55930d8e290ebd3064fb0e019b0f06cd10ebc297cd67901747 updatedAt: "2021-12-14T11:51:42Z" ``` デプロイされたNginxにアクセスし、`data.yaml`で設定した内容が反映されていることを確認します。 ``` $ curl $(kubectl get svc nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}') hello from kapp-controller! ``` 確認できたら、PackageInstallとRBACの設定を`tanzu` CLIで削除します。 ``` tanzu package installed delete nginx -y ``` --- imgpkg bundle化したHelmChartをCarvel Package化しました。 このPackageはair-gapped環境でもインストール可能です。