Tanzu Community Edition

Documentation

Opinionated installation package

As a user, many times you will find yourself installing the same packages with similar configuration over and over. We call this an opinionated installation. The process, although simple, is still a few commands, and many times you will need to communicate these to your team in order to get similarly functional clusters. The more commands a user needs to type the more chances there are for error and the more complicated it gets to learn all the process.

If you don’t really care that much about all the necessary steps and configuration that is needed to provide you with your opinionated cluster, you can easily take advantage of the same mechanisms that are used in Tanzu Community Edition to provide capabilities onto a cluster: Carvel packages.

In this guide you’re going to learn the process of packaging an opinionated installation. As a base, we will use the configuration in the Secure/Automated Ingress on AWS guide. This guide will focus on packaging what is shown in that guide, but should be easy enough for you to modify to your needs.

You’re going to follow the same workflow as Tanzu Community Edition uses internally to create the packages it provides, but since you can’t easily use the scripts described in that doc, we will lay down all the commands you need. We will use a Linux shell convention for this, and it should be easy for you to adapt to your Operating System.

First thing you will do is to create a package that will contain all the additional resources that are created in your opinionated environment. This package will be named my-opinionated-config. Then, we will create a package that will instantiate the four packages used: contour, cert-manager, external-dns and my-opinionated-config. This is actually the one that will trigger all the installations on your environment. You will name this package my-opinionated-package.

Opinionated package

Opinionated configuration and additional resources

Go ahead and create a folder structure that you will use for the first package.

mkdir my-opinionated-config  
cd my-opinionated-config
mkdir -p config/overlays
mkdir -p config/additions
touch config/values.yaml

In our Secure automated Ingress on AWS guide, we created some additional resources to make things work collaboratively. These were the ClusterIssuer and Certificate for cert-manager and the TLSDelegation for contour. As these resources depend on the existence of the other packages, we need to provide them as an additional package to the final opinionated installation. For now, place these files in the config/additions folder.

We create a new namespace where all our additional resources will be created.

namespace.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: my-package-certs

We add the resources we created in the previous guide, making sure they will live in the my-package-certs namespace.

issuer.yaml

apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: wildcard-lets-encrypt
  namespace: my-package-certs
spec:
  acme:
    email: <EMAIL>
    privateKeySecretRef:
      name: issuer-account-key
    server: https://acme-v02.api.letsencrypt.org/directory
    solvers:
    - dns01:
        route53:
          region: <REGION>
          accessKeyID: <ACCESS_KEY_ID>
          secretAccessKeySecretRef:
            name: aws-creds
            key: secret-access-key
    - http01:
        ingress:
          class: contour

Note that this time, you’re setting up an Issuer and not a ClusterIssuer and placing it in the my-package-certs namespace. You will need to create the my-package-certs namespace as well. This is a convenience as this issuer is only used once.

certificate.yaml

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: wildcard
  namespace: my-package-certs
spec:
  secretName: wildcard
  issuerRef:
    name: wildcard-lets-encrypt
    kind: Issuer
  dnsNames:
  - <DNS_NAME>

tls-delegation.yaml

apiVersion: projectcontour.io/v1
kind: TLSCertificateDelegation
metadata:
  name: wildcards
  namespace: my-package-certs
spec:
  delegations:
  - secretName: wildcard
    targetNamespaces: ["*"]

You also need to provide AWS IAM credentials as secrets for cert-manager and external-dns. The former will be placed in the my-package-certs namespace, the latter will be placed in the external-dns namespace. Place both files also in config/additions:

aws-creds-cert-manager.yaml

apiVersion: v1
kind: Secret
metadata:
  name: aws-creds
  namespace: my-package-certs
type: Opaque
stringData:
  access-key-id: < ACCESS_KEY_ID >
  secret-access-key: < SECRET_ACCESS_KEY >

aws-creds-external-dns.yaml

apiVersion: v1
kind: Secret
metadata:
  name: aws-creds
  namespace: external-dns
type: Opaque
stringData:
  access-key-id: < ACCESS_KEY_ID >
  secret-access-key: < SECRET_ACCESS_KEY >

With all these in place, now we can proceed to configuring our package. Looking back to the files we just created, you will notice that there are some values that were defined between angle brackets and in capital letters. These are all configurations that the users of the package will need to provide as these are the things that can change between environments and installations for the opinionated installation.

We will create a values.yaml where you can define all of these, and you will place that file in the config folder. This file is a ytt data values file and will contain an annotation at the top of the file indicating that.

values.yaml

#@data/values
---
domain:
email:
aws:
  region:
  credentials:
    access_key_id:
    secret_access_key:

Now, we need to pass this configuration down to the package. This will be done via ytt overlay files that allows us to apply overlaid information into the original yaml files without the need to modify them, although this is also an option.

For each of the configuration files we want to configure via this package (the ones with placeholders), we will create an overlay file. This is just a convenience for readability but one can choose to group overlays in a different way. We will place these files in the config/overlays folder.

overlay-creds-secret.yaml

#@ load("@ytt:overlay", "overlay")
#@ load("@ytt:data", "data")

#@overlay/match by=overlay.subset({"kind": "Secret", "metadata": {"name": "aws-creds"}}),expects=2
---
stringData:
  access-key-id: #@ data.values.aws.credentials.access_key_id
  secret-access-key: #@ data.values.aws.credentials.secret_access_key

This overlay will fill the AWS IAM credentials in the two aws-secrets the package uses.

overlay-issuer.yaml

#@ load("@ytt:overlay", "overlay")
#@ load("@ytt:data", "data")

#@overlay/match by=overlay.subset({"kind":"Issuer"})
---
spec:
  acme:
    email: #@ data.values.email
    solvers:
    #@overlay/match by=lambda _,l,r: "dns01" in l
    - dns01:
        route53:
          region: #@ data.values.aws.region
          accessKeyID: #@ data.values.aws.credentials.access_key_id

This overlay will modify the user-provided configuration into the issuer so that the placeholders we created are replaced with the values the user has provided.

overlay-certificate.yaml

#@ load("@ytt:overlay", "overlay")
#@ load("@ytt:data", "data")

#@overlay/match by=overlay.subset({"kind":"Certificate"})
---
spec:
  #@overlay/match
  #@overlay/replace
  dnsNames:
  - #@ "*.{}".format(data.values.domain)

This overlay will configure the dnsNames of the Certificate we will use.

We have finally created all the required files for our package. Well, not all really, but the ones that will be in the package bundle. We can test that everything works fine. For that, let’s create a test values file and invoke ytt manually. We will provide recognizable values in the sample file so that when we look into the output we can easily see what we have customized. Place this file in the root of your working directory, right outside the my-opinionated-config so that we don’t package it in later.

sample-values.yaml

#@data/values
---
domain: example.com
email: jorge@example.com
aws:
  region: MY_REGION
  credentials:
    access_key_id: AAAAAAAAAA
    secret_access_key: BBBBBBBBB

Now, to test the configuration we can just do:

ytt -f config -f ../sample-values.yaml

We will see the yaml resource files that the package will install on the cluster with the values we have provided. If you get a ytt error, review your files as you probably have missed something.

Now it’s time to package all the files up into a Carvel imgpkg bundle. For this we will still need to add some files, and we will need to have an OCI Registry (container registry) to push the generated bundle to, so that we can then test it in the cluster. For the purpose of this guide we will use an Anonymous & ephemeral Docker image registry called ttl.sh so that we don’t need to care about the registry. In a real world environment you should use your own registry.

The first step in creating the bundle is to make sure that it is complete which means that if it references images within the descriptors used, those images are properly defined in an imgpkg lock file. To do this, we need a folder .imgpkg in our package where that file will be generated. Create that folder and the run [kbld](/docs/designs/package-process/#5-resolve-and-reference-image-digests) to search on your files for images references to be inventoried.

kbld --file config --imgpkg-lock-output .imgpkg/images.yml

Since the configuration you are packaging up does not use any images, the file will be empty.

Next, you will create the package bundle. The bundle will be created and pushed into an OCI registry as a single operation.

imgpkg push --bundle ttl.sh/my-package-config:1d --file .

You should see a similar output like this:

dir: .
dir: .imgpkg
file: .imgpkg/images.yml
dir: config
dir: config/additions
file: config/additions/aws-creds-cert-manager.yaml
file: config/additions/aws-creds-external-dns.yaml
file: config/additions/cert.yaml
file: config/additions/issuer.yaml
file: config/additions/my-package-ns.yaml
file: config/additions/tls-delegation.yaml
dir: config/overlays
file: config/overlays/overlay-certificate.yaml
file: config/overlays/overlay-creds-secrets.yaml
file: config/overlays/overlay-issuer.yaml
file: config/values.yaml
Pushed 'ttl.sh/my-package-config@sha256:d066eb08e9783196e2348cd8da8e3d735d7e31e2cc076d94ce790ee73ca30cff'
Succeeded

ttl.sh will have this image in the ephemeral registry for one day. If you plan to use the package created here you should definitely use your own registry as otherwise the package will fail to install after 24 hours.

We can check that the image is there and look at the contents of the bundle with imgpkg.

imgpkg pull -b ttl.sh/my-package-config:1d -o /tmp/my-package-config
tree /tmp/my-package-config

Now it’s time for you to generate the PackageMetadata and Package resource definitions that define Carvel Packages. You can see in the previous links that there’s a lot of possible configuration, but we will use the simplest. Place these files in the working root folder, outside the my-package folder.

package-metadata.yaml

apiVersion: data.packaging.carvel.dev/v1alpha1
kind: PackageMetadata
metadata:
  name: config.my-opinionated.com
  namespace: default
spec:
  displayName: My opinionated config

NOTE: We are specifying the namespace where this package will live, but it’s up to you where you want to place it.

package.yaml

apiVersion: data.packaging.carvel.dev/v1alpha1
kind: Package
metadata:
  name: config.my-opinionated.com.0.0.1
  namespace: default
spec:
  refName: config.my-opinionated.com
  version: 0.0.1
  template:
    spec:
      deploy:
      - kapp: {}
      fetch:
      - imgpkgBundle:
          image: ttl.sh/my-package-config:1d
      template:
      - ytt:
          paths:
          - config/
      - kbld:
          paths:
          - '-'
          - .imgpkg/images.yml

As you can see, the Package resource references the imgpkg bundle we created. It is recommended that this image reference is resolved to it’s sha256 for reproducibility, so you will now run this command to lock the reference:

kbld --file package.yaml | sponge package.yaml

NOTE: We’re using sponge which is a command part of moreutils that can redirect the output of a command to the file used initially. You can use brew, apt or any other package manager to install sponge on your computer or redirect the output to a temporary file and then rename that temporary file back to the original.

You will now see a reference to the exact image the bundle uses, so that any update to the bundle will not mess things up.

apiVersion: data.packaging.carvel.dev/v1alpha1
kind: Package
metadata:
  annotations:
    kbld.k14s.io/images: |
      - origins:
        - resolved:
            tag: 1d
            url: ttl.sh/my-package-config:1d
        url: ttl.sh/my-package-config@sha256:d066eb08e9783196e2348cd8da8e3d735d7e31e2cc076d94ce790ee73ca30cff      
  name: config.my-opinionated.com.0.0.1
  namespace: default
spec:
  refName: config.my-opinionated.com
  version: 0.0.1
  template:
    spec:
      deploy:
      - kapp: {}
      fetch:
      - imgpkgBundle:
          image: ttl.sh/my-package-config@sha256:d066eb08e9783196e2348cd8da8e3d735d7e31e2cc076d94ce790ee73ca30cff
      template:
      - ytt:
          paths:
          - config/
      - kbld:
          paths:
          - '-'
          - .imgpkg/images.yml

Now you can proceed and install the Package (and PackageMetadata) in your cluster. If you’re going to be creating many packages, it’s recommended to create a PackageRepository which is a container for Packages.

To install the package on the cluster type:

kubectl apply -f package-metadata.yaml -f package.yaml

If the output from this command is successful, you should now be able to see the available packages with the tanzu CLI.

tanzu package available list config.my-opinionated.com

You have now created a package that provides your additional resources for the opinionated installation, but now we need to package this up with contour, cert-manager and external-dns packages as a single package that will provide the opinionated installation.

Opinionated installation package

Now that you have packages for the parts you want to install on your clusters, you’re going to create a package that will install all of them in one shot. The process and structure is almost identical to the one you followed in the previous section of this guide.

Go ahead and create a folder structure that you will use for this new package my-opinionated-package on the root of your working directory.

mkdir my-opinionated-package  
cd my-opinionated-package
mkdir -p config/overlays
mkdir -p config/additions
touch config/values.yaml

In our previous guide, we created some additional resources to install our packages. These were created under the hood by the tanzu CLI. These are the PackageInstall resources for Contour, external-dns and cert-manager and the configuration needed for every package that we provided in a file as argument to the tanzu package install command. We will also create a PackageInstall and configuration file for the package we just created in the previous section my-opinionated-config. You will place these files in config/additions directory you just created:

contour-packageinstall.yaml

apiVersion: packaging.carvel.dev/v1alpha1
kind: PackageInstall
metadata:
  name: contour
spec:
  packageRef:
    refName: contour.community.tanzu.vmware.com
    versionSelection:
      constraints: 1.17.1
      prereleases: {}
  serviceAccountName: my-package-default-sa
  values:
  - secretRef:
      name: contour-my-package-values

external-dns-packageinstall.yaml

apiVersion: packaging.carvel.dev/v1alpha1
kind: PackageInstall
metadata:
  name: external-dns
spec:
  packageRef:
    refName: external-dns.community.tanzu.vmware.com
    versionSelection:
      constraints: 0.8.0
      prereleases: {}
  serviceAccountName: my-package-default-sa
  values:
  - secretRef:
      name: external-dns-my-package-values

cert-manager-packageinstall.yaml

apiVersion: packaging.carvel.dev/v1alpha1
kind: PackageInstall
metadata:
  name: cert-manager
spec:
  packageRef:
    refName: cert-manager.community.tanzu.vmware.com
    versionSelection:
      constraints: 1.5.1
      prereleases: {}
  serviceAccountName: my-package-default-sa

my-opinionated-config-packageinstall.yaml

apiVersion: packaging.carvel.dev/v1alpha1
kind: PackageInstall
metadata:
  name: my-opinionated-config
spec:
  packageRef:
    refName: config.my-opinionated.com
    versionSelection:
      constraints: 0.0.1
      prereleases: {}
  serviceAccountName: my-package-default-sa
  values:
  - secretRef:
      name: my-opinionated-config-my-package-values

NOTE: The serviceAccountName and secretRef.name have been adapted to fit the name of the package.

There were some other configurations and files that were provided as part of the guide that would need to be created as well. We provided a configuration for contour and external-dns packages. We will create these files in the config/additions folder and we will use placeholders for values that are installation/environment specific.

external-dns-config.yaml

apiVersion: v1
kind: Secret
metadata:
  name: external-dns-my-package-values
type: Opaque
stringData:
  values.yml:

contour-config.yaml

apiVersion: v1
kind: Secret
metadata:
  name: contour-my-package-values
type: Opaque
stringData:
  values.yml:

my-opinionated-config-config.yaml

apiVersion: v1
kind: Secret
metadata:
  name: my-opinionated-config-my-package-values
type: Opaque
stringData:
  values.yml:

These configuration files are empty by default, as we will provide the values via overlay files. But first, you need to create a values.yaml where you can define all possible configuration that this package will use. As this file is a ytt data values file, it will contain an annotation at the top of the file indicating that.

values.yaml

#@data/values
---
domain:
email:
aws:
  region:
  credentials:
    access_key_id:
    secret_access_key:

Since this package will need to provide all the configuration downstream to the other four packages, it will require defining all the possible configurations. You will use the same values file structure as in the previous package for convenience.

Now, we need to pass this configuration down to the package. This will be done again via ytt overlay files. You will place these overlay files in the config/overlays folder. There will be one overlay per configuration file to be tuned.

overlay-contour-config.yaml

#@ load("@ytt:overlay", "overlay")
#@ load("@ytt:data", "data")
#@ load("@ytt:yaml", "yaml")

#@ def config():
envoy:
  service:
    annotations:
      external-dns.alpha.kubernetes.io/hostname: #@ "*.{}.".format(data.values.domain)
#@ end


#@overlay/match by=overlay.subset({"metadata":{"name": "contour-my-package-values"}})
---
stringData:
  values.yml: #@ yaml.encode(config())

This overlay does provide the correct values for the external-dns annotation of contour. This value is defined in the Secret contour-my-package-values that is passed to the Contour PackageInstall.

overlay-external-dns-config.yaml

#@ load("@ytt:overlay", "overlay")
#@ load("@ytt:data", "data")
#@ load("@ytt:yaml", "yaml")

#@ def config():
deployment:
  args:
    - --source=service
    - #@ "--domain-filter={}".format(data.values.domain)
    - --provider=aws
    - --policy=upsert-only
    - --aws-zone-type=public
    - --registry=txt
    - #@ "--txt-owner-id={}".format(data.values.domain)
  env:
    - name: AWS_ACCESS_KEY_ID
      valueFrom:
        secretKeyRef:
          name: aws-creds
          key: access-key-id
    - name: AWS_SECRET_ACCESS_KEY
      valueFrom:
        secretKeyRef:
          name: aws-creds
          key: secret-access-key
#@ end


#@overlay/match by=overlay.subset({"metadata":{"name": "external-dns-my-package-values"}})
---
stringData:
  values.yml: #@ yaml.encode(config())

This overlay provides the configuration for external-dns, as the secret that was created in config/additions was empty.

overlay-my-opinionated-config-config.yaml

#@ load("@ytt:overlay", "overlay")
#@ load("@ytt:data", "data")
#@ load("@ytt:yaml", "yaml")

#@ def config():
domain: #@ data.values.domain
email: #@ data.values.email
aws:
  region: #@ data.values.aws.region
  credentials:
    access_key_id: #@ data.values.aws.credentials.access_key_id
    secret_access_key: #@ data.values.aws.credentials.secret_access_key
#@ end


#@overlay/match by=overlay.subset({"metadata":{"name": "my-opinionated-config-my-package-values"}})
---
stringData:
  values.yml: #@ yaml.encode(config())

This overlay provides the values for the my-opinionated-config package. As noted before, you’re using the same values structure in both packages for convenience.

Using the same test file we used before we can verify that there’s no error in our ytt overlays. We test the configuration again with:

ytt -f config -f ../sample-values.yaml

If everything looks fine, you can move ahead to lock the images used in the package. Remember to create the .imgpkg folder before.

kbld --file config --imgpkg-lock-output .imgpkg/images.yml

Again, this package does not contain any direct image references so the file will be empty. In this case, the images used by contour, cert-manager and external-dns are all defined in the .imgpkg/images.yml file of those packages. The opinionated-config package you created in the previous section has locked the imgpkg bundle image used in the Package resource.

Next, you will create the package bundle. The bundle will be created and pushed into an OCI registry as a single operation. We use again ttl.sh as a convenience registry.

imgpkg push --bundle ttl.sh/my-package-bundle:1d --file .

You should see a similar output like this:

dir: .
dir: .imgpkg
file: .imgpkg/images.yml
dir: config
dir: config/additions
file: config/additions/cert-manager-packageinstall.yaml
file: config/additions/contour-config.yaml
file: config/additions/contour-packageinstall.yaml
file: config/additions/external-dns-config.yaml
file: config/additions/external-dns-packageinstall.yaml
file: config/additions/my-opinionated-config-config.yaml
file: config/additions/my-opinionated-config-packageinstall.yaml
dir: config/overlays
file: config/overlays/overlay-contour-config.yaml
file: config/overlays/overlay-external-dns-config.yaml
file: config/overlays/overlay-myopinionatedconfig-config.yaml
file: config/values.yaml
Pushed 'ttl.sh/my-package-bundle@sha256:e22decb7b0c5afb32dbf5c6fce98d6ea011881dafca365d61e8b907d8524e1dc'
Succeeded

Remember these images will only be available in that registry for 24 hours.

You will generate now the PackageMetadata and Package resources for this new package:

package-metadata.yaml

apiVersion: data.packaging.carvel.dev/v1alpha1
kind: PackageMetadata
metadata:
  name: my-package.my-opinionated.com
  namespace: default
spec:
  displayName: My opinionated install

NOTE: We are specifying the namespace where this package will live, but it’s up to you where you want to place it.

package.yaml

---
apiVersion: data.packaging.carvel.dev/v1alpha1
kind: Package
metadata:
  name: my-package.my-opinionated.com.0.0.1
  namespace: default
spec:
  refName: my-package.my-opinionated.com
  template:
    spec:
      deploy:
      - kapp: {}
      fetch:
      - imgpkgBundle:
          image: ttl.sh/my-package-bundle:1d
      template:
      - ytt:
          paths:
          - config/
      - kbld:
          paths:
          - '-'
          - .imgpkg/images.yml
  version: 0.0.1

We need to lock the image used for reproducibility.

kbld --file package.yaml | sponge package.yaml

You will now see a reference to the exact image the bundle uses, so that any update to the bundle will not mess things up.

apiVersion: data.packaging.carvel.dev/v1alpha1
kind: Package
metadata:
  annotations:
    kbld.k14s.io/images: |
      - origins:
        - resolved:
            tag: 1d
            url: ttl.sh/my-package-bundle:1d
        url: ttl.sh/my-package-bundle@sha256:e22decb7b0c5afb32dbf5c6fce98d6ea011881dafca365d61e8b907d8524e1dc      
  name: my-package.my-opinionated.com.0.0.1
  namespace: default
spec:
  refName: my-package.my-opinionated.com
  version: 0.0.1
  template:
    spec:
      deploy:
      - kapp: {}
      fetch:
      - imgpkgBundle:
          image: ttl.sh/my-package-bundle@sha256:e22decb7b0c5afb32dbf5c6fce98d6ea011881dafca365d61e8b907d8524e1dc
      template:
      - ytt:
          paths:
          - config/
      - kbld:
          paths:
          - '-'
          - .imgpkg/images.yml

What happens if you don’t lock this image? When you install the Package on the cluster it will have a reference to a rolling tag, this is a tag that can be reassigned. This means that if the imgpkg bundle is rebuilt and pushed again to that registry, all of the consumers of the package will get the latest version. This is ok while you’re developing your package, but once the package is ready to be released, if there’s a new version of the bits in the package, there should also be a new version of the Package definition, so this file would go from 0.0.1 to 0.0.2 or any other newer version.

Install the package metadata and package on the cluster:

kubectl apply -f package-metadata.yaml -f package.yaml

And now, you’re ready to create your installation of this opinionated installation package. We need a configuration file with our specific values. Let’s now create the values files for our cluster:

my-package-config.yaml

domain: example.com
email: jorge@none.com
aws:
  region: eu-west1
  credentials:
    access_key_id: AAAAAAAAAA
    secret_access_key: BBBBBBBBB

NOTE: Remember to use your own values when creating this file.

Verify that the package is available to install:

tanzu package available list my-package.my-opinionated.com

Install the package:

tanzu package install my-package --package-name my-package.my-opinionated.com --version 0.0.1 --values-file my-package-config.yaml

You will see the package being installed.

kubectl get pkgi
NAME                    PACKAGE NAME                              PACKAGE VERSION   DESCRIPTION           AGE
my-package              my-package.my-opinionated.com             0.0.1             Reconciling succeeded   10s

Soon after, this package will trigger the installation of the other four packages. Eventually all five packages will be installed on the cluster.

kubectl get pkgi
NAME                    PACKAGE NAME                              PACKAGE VERSION   DESCRIPTION           AGE
cert-manager            cert-manager.community.tanzu.vmware.com   1.5.1             Reconcile succeeded   2m
contour                 contour.community.tanzu.vmware.com        1.17.1            Reconcile succeeded   2m
external-dns            external-dns.community.tanzu.vmware.com   0.8.0             Reconcile succeeded   2m
my-opinionated-config   config.my-opinionated.com                 0.0.1             Reconcile succeeded   2m
my-package              my-package.my-opinionated.com             0.0.1             Reconcile succeeded   2m

You might have seen the package my-opinionated-config reporting a Reconcile failed error. This is expected, as it will fail until the other packages are fully installed. Carvel’s packaging controller (kapp-controller) will keep reconciling the packages every 2 minutes (by default), so the installation will eventually succeed.

You should be able to use the same application as before. The only difference is that in this installation the wildcard certificate will be installed in ​​my-package-certs namespace, so you will need to adjust the HTTPProxy accordingly.

One last reminder that since this guide uses ttl.sh as ephemeral registry, your packages will stop working after 24 hours. You will see something like this when doing kubectl get packageinstall:

my-package              my-package.my-opinionated.com             0.0.1             Reconcile failed: Error (see .status.usefulErrorMessage for details)   1d1h

You can get the detail of the error by doing:

kubectl get packageinstall my-package -n default -o jsonpath='{.status.usefulErrorMessage}'

The details, although not self explanatory, means that the image is not available or valid.

Error: Syncing directory '0': Syncing directory '.' with imgpkgBundle contents: Imgpkg: exit status 1 (stderr: Error: Checking if image is bundle: Collecting images: Working with ttl.sh/my-package-bundle@sha256:0524e5115cbb740c3f4226ab55c337a89fdaf207d84788d3b27b5a874adfe2c8: Encountered an error most likely because this image is in Docker Registry v1 format; only v2 or OCI image format is supported (underlying error: GET https://ttl.sh/v2/my-package-bundle/manifests/sha256:0524e5115cbb740c3f4226ab55c337a89fdaf207d84788d3b27b5a874adfe2c8: MANIFEST_UNKNOWN: manifest unknown; map[Name:my-package-bundle Revision:sha256:0524e5115cbb740c3f4226ab55c337a89fdaf207d84788d3b27b5a874adfe2c8])

Summary

This guide should have provided you with some details on how you can package up multiple packages and configuration into an opinionated package so that users of the clusters only need to deal with one single package installation and configuration.

There’s one last step left out of this guide which is to bundle your own packages into a PackageRepository of your own. You can find more information on PackageRepositories on our documentation.

Join us!

Our open community welcomes all users and contributors

Community