Create and Deploy a Custom Add-On Pack

Custom add-on packs allow you to deploy Kubernetes applications in clusters and reuse them in multiple deployments. This ensures uniformity across your clusters. The primary use cases for creating custom packs are:

  • Aggregated configuration and application dependencies simplify deployment and consumption.

  • Open-source contributors can add new Kubernetes applications to a custom add-on pack for the community.

  • Enterprises can add proprietary Kubernetes applications to a custom add-on pack.

In this tutorial, you will create a custom add-on pack to package a sample Kubernetes application, Hello Universe, and deploy that application to a cluster. You will learn to create the pack in two ways, using manifest files and Helm charts.

After defining the custom pack, you will set up a registry server, publish the pack to that registry, and configure the registry server in Palette. Lastly, you will create a cluster profile that contains your custom pack and apply the profile to a cluster using either Palette or Terraform.


To complete the tutorial, you will need the following items:

  1. A Spectro Cloud account. Visit to create an account.
  1. Tenant admin access to Palette for the purpose of adding a new registry server.
  1. A cloud account, such as AWS, Azure, or GCP, added to your Palette project settings.
  1. An SSH key created in the region where you will deploy the cluster.
  1. Docker Desktop installed on your local machine to start the tutorials container.
  1. Basic knowledge of Docker containers and Kubernetes manifest file attributes.

Set Up the Tutorial Environment

You will work in a Docker container pre-configured with the necessary tools for this tutorial. However, you can practice this tutorial in any linux/amd64 or x86_64 environment by installing the necessary tools and cloning the GitHub repository that contains the tutorial files. Here are the steps to start the tutorials container.

Start the Docker Desktop on your local machine and ensure the daemon is available by issuing a command to list the currently active containers.

docker ps

Download the image to your local machine. The Docker image includes the necessary tools.

docker pull

Next, start the container, and open a bash session into it.

docker run --name tutorialContainer --publish 7000:5000 --interactive --tty bash

If port 7000 on your local machine is unavailable, you can use any other port of your choice.

Wait to exit the container until the tutorial is complete. Otherwise, you may lose your progress.

Tools and Starter Code

After opening a bash session in the active container, verify that the tools necessary for this tutorial are installed.

Check the Spectro CLI version.

spectro version

Check the Spectro registry server version.

registry --version

Check the Terraform version.

terraform --version

In addition to these tools, the tutorials container has other tools, such as ngrok, git, and nano.

Examine the directories that pertain to the current tutorial in the root directory.

├── packs
│ └── hello-universe-pack # Contains the pack files
└── terraform
└── pack-tf # Contains the .tf files for creating Spectro Cloud resources

The packs directory contains the pack files. The terraform directory contains the Terraform files used to create Spectro Cloud resources, which you will use later in this tutorial.

Build a Pack

Building a custom pack requires defining specific files. As outlined in the Adding Add-on Packs guide, you can define a custom pack in two ways: using manifest files or Helm charts. The file structure varies for manifest-based packs and Helm chart-based packs. Below is the reference file structure for each:

├── pack.json # Mandatory
├── values.yaml # Mandatory
├── manifests # Mandatory
├── manifest-1.yaml
├── manifest-2.yaml
│ └── manifest-3.yaml
├── logo.png # Mandatory
└── # Optional

To simplify this tutorial, we provide you with the manifest file for the Hello Universe application in the packs/hello-universe-pack folder. Change the directory to the packs/hello-universe-pack folder.

cd /packs/hello-universe-pack

Ensure you have the following files in the current directory.

├── pack.json # Mandatory
├── values.yaml # Mandatory
├── manifests # Mandatory
│ └── hello-universe.yaml
├── logo.png # Mandatory
└── # Optional

Pack File Structure

Go ahead and review each of the following five files in the pack.

  • pack.json - This file contains the pack metadata such as addonType, cloudTypes, and the kubeManifests array that contains the list of manifest files: layer, name, and version. Refer to the JSON Schema for a list of attributes and respective data types. The schema validation will happen when you push a pack to the registry.

    "addonType":"app services",
    "cloudTypes": [ "all" ],
    "displayName": "Hello Universe",
    "kubeManifests": [
    "layer": "addon",
    "name": "hellouniverse",
    "version": "1.0.0"

  • values.yaml - This file contains configurable parameters you can define while adding the current pack to a cluster profile. In the values.yaml file for this tutorial, the pack/namespace attribute specifies the namespace on the target cluster to deploy the pack. If the values.yaml specifies a namespace value, then Palette first checks to see if the namespace has been created. If so, Palette uses the existing namespace. If the namespace has not been created, Palette creates a new one using the value specified in the YAML file.

    If the values.yaml does not specify a namespace value, Palette deploys the application to the default namespace.

    The manifests section exposes the configurable parameters for each manifest file listed in the manifests directory. For example, in the sample code snippet below, the hello-universe attribute exposes the registry, repository, and tag parameters.

    namespace: "hello-universe"
    repository: spectrocloud/hello-universe
    tag: 1.0.12

    You can optionally define presets, which are predefined values to use in the values.yaml. You define presets in a separate presets.yaml file. The presets become available when you create the cluster profile. Presets facilitate configuring the profile and avoid errors that can happen by manually editing the values.yaml file. Refer Pack Presets for details and examples of how to define presets.

    The example below shows the parameters you can configure in the values.yaml for the hello-universe manifest when you create the cluster profile.

    Screenshot of the configurable parameters in the values.yaml file.

  • manifests - This directory contains the manifest files for your Kubernetes application. This tutorial has only one file, hello-universe.yaml. Note that the values.yaml file has a corresponding manifests/hello-universe element with the same name as the YAML file.

  • logo.png - This file contains a logo that displays when you create a cluster profile.

  • - This file may contain the pack description, purpose, authors, and other relevant information. The README in the current example introduces the application used in the pack.

After finalizing all files in the pack directory, the next step is to set up a registry server and publish the pack to that registry, where you can access it directly from Palette.

Set Up the Registry Server

The tutorials environment already has the Spectro registry service and other necessary tools available. The following sections will guide you to start the registry server, expose the service to the external world using Ngrok reverse proxy, and log in to the registry server to push your custom add-on pack to it.

Start and Expose the Registry Server

Start the registry server by issuing the following command from the bash session you opened into the tutorials container.

registry serve /etc/spectro/config.yml > /var/log/registry.log 2>&1 &

The registry server will start in HTTP mode (not HTTPS). Refer to the Add a Custom Registry guide to learn more about deploying an HTTPS registry server.

Next, expose the registry server to the public so that you can configure it later in Palette. Use Ngrok reverse proxy to expose the registry server listening on port 5000 via an HTTP tunnel using the following command.

ngrok http 5000 --log-level debug

The command above will reserve the current bash session and display the status of each HTTP request made to the Ngrok server later in this tutorial. The screenshot below shows the registry server successfully exposed via Ngrok.

Screenshot of registry server exposed via ngrok

Verify the registry server is accessible from outside the tutorials container by visiting the /health endpoint. Access the https://Your-URL-Here/health in your host browser. Replace the base URL with the Ngrok URL output you received. You should receive a {"status":"UP"} response.

Log in to the Registry Server

Once the registry server's /health endpoint shows UP status, the next step is to log in and then push the pack to it. The pack you will push is in the tutorials container. Open another bash session into the tutorials container from your local terminal.

docker exec -it tutorialContainer bash

Log in to the registry server using Ngrok's public URL assigned to you. Issue the command below, but replace the URL with your Ngrok URL. The command below uses these credentials to log in to the registry server: {username: admin, password: admin}.

spectro registry login --insecure --default --username admin --password admin \

Do not use https:// or http:// keyword in the Ngrok URL. Using either of these keywords will result in an authorization issue.

You will receive a Login Succeeded response upon successful login.

# Output condensed for readability
WARNING! Your password will be stored unencrypted in /root/.spectro/config.json.
Login Succeeded

Push the Pack to the Registry Server

When you are logged in, push the pack to the registry server using the following command.

spectro pack push /packs/hello-universe-pack/

You can verify that the pack is in the registry by using the ls command. This command lists all packs in the registry.

spectro pack ls

Verify the pack you pushed is listed, as shown in the screenshot below.

Screenshot of spectro pack ls

If you need help with the Spectro CLI commands, such as deleting a pack, refer to the Spectro CLI commands guide.

Configure the Registry Server in Palette

After you push the pack to the registry server, log in to Palette and configure the registry service so that you can access it when you create your cluster profile.

Log in to Palette, and switch to the Tenant admin view.

Screenshot of Palette tenant settings.

Navigate to Tenant Settings > Registries > Pack Registries section. Click on Add New Pack Registry and enter the pack registry name, endpoint URL, and user credentials. For a consistent experience in this tutorial, we suggest using the name private-pack-registry, as shown in the screenshot below. Ensure you replace the URL with your Ngrok URL. Click on Validate to ensure the URL and credentials are correct, then click on Confirm to add the registry server.

Screenshot of registry server edit option in Palette tenant settings.

Palette syncs the registry server periodically. However, you can sync it manually the first time you add a server by clicking the three-dot Menu next to the registry server name and selecting Sync.

Screenshot of registry server sync in Palette

Create a Cluster Profile and Deploy a Cluster

This tutorial guides you to create a cluster profile for AWS. However, you can choose any other cloud service provider, provided you configure the following two items:

  • Cloud account: A cloud account added to your Palette project settings.

    The AWS cloud account name in this tutorial example is spectro-cloud. You can choose another name if desired. The screenshot below shows how to add and verify the AWS cloud account with your project. Navigate to Project Settings > Cloud Accounts > AWS > Add AWS Account in Palette. Check out the Register and Manage AWS Accounts guide for additional help.

    Screenshot of Cloud Accounts in Palette.

  • SSH key: An SSH key created in the region where you will deploy the cluster.

    This tutorial example will deploy the cluster in the us-east-2 region, and the SSH key name used in this example is aws_key_sk_us_east_2. You must choose the desired region and the available SSH key name from your AWS account.

Create a cluster profile and deploy it to a cluster using either Palette or Terraform code.

Create a Cluster Profile

Switch to the Default project scope for creating a cluster profile.

Screenshot of the Palette Default scope.

Select the Profile section in the left Main Menu to create a cluster profile that will combine the core infrastructure and add-on layers. Click on the Add Cluster Profile button, and provide the details in the wizard that follows. The wizard displays the following sections.

Basic Information

Use the following values in the Basic Information section.

DescriptionCluster profile as part of the pack tutorial.
Tagsspectro-cloud-education, app:hello-universe, terraform_managed:true

Click on Next to continue.

Cloud Type

In the Cloud Type section, choose AWS as the infrastructure provider for this tutorial, and click on Next at the bottom to move on to the next section.

If you choose a different cloud service provider, the core infrastructure layers options, as outlined in the Profile Layers section below, will differ from this tutorial.

Profile Layers

In the Profile Layers section, add the following core infrastructure layers if you have chosen the AWS cloud service provider. To deploy your resource to Azure or Google Cloud, use the core infrastructure layers outlined in Cloud Service Provider Configurations.

Pack TypeRegistryPack NamePack Version
OSPublic RepoUbuntuLTS__20.4.x
KubernetesPublic RepoKubernetes1.24.x
NetworkPublic RepoCalico3.25.x
StoragePublic RepoAmazon EBS CSI1.16.x

As you add each layer, click on the Next layer button. After you add the Storage layer, click on the Confirm button to complete the core infrastructure stack. Palette displays the newly created infrastructure profile as a layered diagram. You can select any layer to make further edits or change the version if desired.

Now you are ready to add the add-on layers. Click the Add New Pack button.

Add the Spectro Proxy pack to enable a reverse proxy to connect to the cluster's API. Adding this pack is optional, but it will help connect your local machine to the cluster's API for debugging. Refer to the Spectro Proxy guide for more details.

Pack TypeRegistryPack NamePack Version
AuthenticationPublic RepoSpectro Proxy1.3.x

Click on the Confirm & Create button to finish adding the Spectro Proxy pack. Also, add the following certificate Subject Alternative Name (SAN) value to the Kubernetes pack under the apiServer parameter section to configure the Spectro Proxy pack.

- "cluster-{{ .spectro.system.cluster.uid }}.{{ .spectro.system.reverseproxy.server }}"

Screenshot of the certificate Subject Alternative Name.

Next, add the following Hello Universe pack. This is the custom add-on pack you defined and pushed to the private-pack-registry earlier in this tutorial.

Pack TypeRegistryPack NamePack Version
App Servicesprivate-pack-registryHello Universe1.0.x

Click on the Confirm & Create button to finish adding the Hello Universe pack.

If there are no errors or compatibility issues, Palette displays the newly created full cluster profile. Verify the layers you added, and click Next.

Screenshot of the Profile Layers success.


Review once more and click Finish Configuration to create the cluster profile.

Create a Cluster

From the Profile page, click on the newly created cluster profile to view its details page. Palette displays all the layers and allows you to edit any of them.

Click the Deploy button to deploy a new cluster. The cluster deployment wizard will displays the following sections.

Basic Information

Use the following values in the first section, Basic Information.

Cluster namepack-tutorial-cluster
DescriptionCluster as part of the pack tutorial.
Tagsspectro-cloud-education, app:hello-universe, terraform_managed:true
Cloud Accountspectro-cloud

Note that the AWS cloud account name in this tutorial example is spectro-cloud. If you used a different cloud account name, choose the name configured in your Palette's project settings.

Click Next to continue.


The Parameters section allows you to change the profile configurations. For example, clicking on the Hello Universe 1.0.x layer allows you to configure the registry, repository, and tag parameters defined in the values.yaml file.

Screenshot of the Cluster layers.

Keep the default values and click Next.

Cluster config

In the Cluster config section, ensure the Static Placement field is unchecked. If checked, the Static Placement will deploy the cluster in an existing VPC, and you will need the Amazon Resource Names (ARNs) for the existing subnets, roles, and other resources. For this tutorial, we will use dynamic placement, where Palette creates a new VPC and all other resources needed for the cluster.

For the Region field, select the region of your choice. The tutorial example will deploy the cluster in the us-east-2 region. For the SSH Key Pair Name field, choose the SSH key pair name from the selected region. You must have an SSH key created already in the AWS region where you will deploy the cluster.

Click Next to continue.

Nodes config

In the Nodes config section, provide the details for the master and the worker pools. For this tutorial, you can use the following minimal configuration:

FieldValue for the master-poolValue for the worker-pool
Node pool namemaster-poolworker-pool
Number of nodes in the pool11
Allow worker capabilityCheckedNot applicable
Enable AutoscalerNot applicableNo
Rolling updateNot applicableExpand First.
Launch a new node first, then shut down the old one.

Keep the Cloud Configuration the same for the master and worker pools.

Instance TypeGeneral purpose m4.xlarge
A minimum allocation of four CPU cores are required for the master node.
Availability zonesChoose any one availability zone.
This tutorial example will deploy to the us-east-2a availability zone.
Disk size60 GiB

Click Next to continue.


The Settings section displays options for OS patching, scheduled scans, scheduled backups, and cluster role binding. Use the default values, and click on the Validate button.


Review all configurations in this section. The Review page displays the cluster name, tags, cloud account name, node pools, layers, and an estimated hourly cost. If everything looks good, click on the Finish Configuration button to finish deploying the cluster. Deployment may take up to 20 minutes to finish.

While deployment is in progress, Palette displays the cluster status as Provisioning. While you wait for the cluster to finish deploying, you can explore the various tabs on the cluster details page, such as Overview, Workloads, and Events.


In Palette, navigate to the left Main Menu and select Clusters. Next, select your cluster to display the cluster Overview page and monitor cluster provisioning progress.

Screenshot of the cluster health.

When cluster status displays Running and Healthy, you can access the application from the exposed service URL with the port number displayed. For the Hello Universe application, port 8080 is exposed. Click on the URL to access the application.

We recommend waiting to click on the service URL, as it takes one to three minutes for DNS to properly resolve the public load balancer URL. This prevents the browser from caching an unresolved DNS request.

Screenshot of the successful accessing the application using the load balancer URL.

You can also look at real-time metrics, such as CPU and memory consumption, in the cluster's Overview tab in Palette.

Screenshot of the cluster metrics.

Using your custom pack in the cluster, you have successfully deployed the Hello Universe application to the cluster.


Delete the cluster, cluster profile, and registry server, and remove the registry service configuration from Palette's settings.

The following steps will guide you in cleaning up your environment. Follow the steps for Palette if you used Palette to deploy the cluster. Use Terraform commands to delete the cluster if you used Terraform for deployment.

Delete the Cluster and Profile using Palette

Navigate to the Cluster section in Palette's left Main Menu, and view the details page of the pack-tutorial-cluster. To delete the cluster, click on the Settings button to expand the drop-down Menu, and select the Delete Cluster option. Palette prompts you to enter the cluster name and confirm the delete action. Type the cluster name to proceed with the delete step.

Screenshot of deleting the cluster in Palette.

The cluster status displays Deleting. Deletion takes up to 10 minutes.

If a cluster remains in the delete phase for over 15 minutes, it becomes eligible for force deletion. Navigate to the cluster's details page and click on Settings. Select Force Delete Cluster. Palette automatically removes clusters that are stuck in the cluster deletion phase for over 24 hours.

After you delete the cluster, go ahead and delete the profile. From the left Main Menu, click Profiles and select the profile to delete. Choose the Delete option in the three-dot Menu.

Screenshot of deleting the profile in Palette.

Wait for the resources to clean up and ensure they are successfully deleted.

Delete the Registry Server

After deleting the cluster and cluster profile, navigate to Tenant Settings > Registries > Pack Registries to delete the registry service configuration from Palette.

Screenshot of registry server delete in Palette

Stop the registry server by closing the tutorials container bash session that serves the Ngrok reverse proxy server. At this point, you can close all the bash sessions. To remove the container and the image from the local machine, issue the following commands:

docker container rm --force tutorialContainer
docker image rm --force


In this tutorial, you learned how to create a custom pack using manifest files. You packaged up an application in a custom pack that you pushed to a private registry server and added to Palette.

Next, you created a cluster profile that included all the core infrastructure layers, such as the OS, Kubernetes distribution, and more. You also added your custom pack to the cluster profile so your application could be deployed to a Kubernetes cluster.

Packs are the building blocks of cluster profiles, allowing you to customize your Kubernetes clusters. Palette enables you to use different packs to create multiple cluster profiles, each for specific purposes. As a result, you can ensure all Kubernetes deployments contain all the required dependencies and applications without developing complicated deployment scripts. All you need to do is maintain the cluster profiles.

To learn more about packs in Palette, we encourage you to check out the reference resources below.