What is a Pack?
A Pack is a Kubernetes custom resource for installing and managing a Helm chart. You define the chart, version, and values in a Pack manifest, and Pack Operator keeps the actual cluster state reconciled with that definition.
If you are new to Helm, read Helm and Helm charts in Kubernetes first.
Most users install and manage Packs from Kubchi > Packs in the Kubit panel. This page is the technical reference for the same resource when working with YAML, kubectl, GitOps, or kubit-cli. For panel installation, see Install a Pack in Kubchi.
Pack, chart, and operator relationship
A Helm chart contains an application's templates and default values. Pack selects the chart version and settings to install in a namespace. Pack Operator reads this definition, validates and applies the Helm output, and records the result in Pack status.
Each Pack corresponds to a Helm Release in the same namespace. A spec change may upgrade that release. Before applying a production change, inspect it with kubit helm-diff.
Prerequisites
To work directly with a Pack manifest, you need:
- Access to a cluster with Pack Operator installed.
- Permission to read or modify
Packresources in the target namespace. - An accessible
ClusterPackRepositorythat provides the chart. - Permission to read resources referenced by chart values.
When you use only Kubchi, Kubit prepares many of these prerequisites for the project.
Create a Pack manifest
This example installs the Redis chart from the cluster-wide kubit-paas repository in the my-project namespace. Match the version and values structure to the chart documentation.
apiVersion: k8s.kubit.ir/v1alpha1
kind: Pack
metadata:
name: redis
namespace: my-project
spec:
managed: true
chart:
repository:
kind: ClusterPackRepository
name: kubit-paas
name: redis
version: '0.1.6'
autoUpgrade: false
vars: {}
values: {}
spec.managed is optional. Omitting it is equivalent to spec.managed: true; Pack Operator manages the resource in both cases. Only an explicit spec.managed: false stops operator management. The example states managed: true explicitly.
The main manifest fields are:
| Field | Purpose |
|---|---|
metadata.name | Pack and Helm Release name |
metadata.namespace | Installation namespace |
spec.managed | Optional; omission means true, and only explicit false stops management |
spec.chart.repository.kind | Repository kind; ClusterPackRepository |
spec.chart.repository.name | Chart repository resource name |
spec.chart.name | Chart name in the repository |
spec.chart.version | Chart version or constraint; when omitted, the newest selectable version is used |
spec.chart.autoUpgrade | Enables automatic-upgrade checks for a non-exact version |
spec.chart.autoUpgradeDelay | Delay before automatic upgrade, such as 1h or 1d2h |
spec.vars | Variables available while rendering values |
spec.values | Values applied over chart defaults |
Choose the repository scope
PackRepository is namespaced, and only Packs in that namespace can use it. Choose it when a repository should be available to one project or environment.
ClusterPackRepository is cluster-scoped, so Packs in different namespaces can use it with the required permission. Cluster scope does not make repository credentials public; keep the username and password access-restricted.
Select a chart version
spec.chart.version accepts an exact version or a version constraint. Pack Operator filters repository versions with this constraint and selects the highest matching version. Quote the value so YAML treats it as a string.
version value | Allowed versions |
|---|---|
'0.1.6' | Only 0.1.6 |
'~=0.1.6' | At least 0.1.6 and below 0.2.0 |
'~=1.4' | At least 1.4 and below 2.0 |
'>=0.1.6,<0.2.0' | The intersection of both constraints |
'==0.1.*' | Every version in the 0.1 branch |
'>=0.1.6,!=0.1.8,<0.2.0' | The 0.1 branch from 0.1.6, excluding 0.1.8 |
Supported operators include ==, !=, ~=, <, <=, >, and >=. Comma-separated constraints must all match. Do not use syntax such as ^1.2.3 or 1.x || 2.x; those belong to other package managers.
If version is omitted, the highest selectable repository version is used. A range alone does not enable automatic upgrades. Automatic upgrade also requires autoUpgrade: true, a valid autoUpgradeDelay, and a non-exact version. An exact version such as '0.1.6' does not enter the automatic-upgrade queue.
Configure chart values
spec.values contains values applied over the chart defaults. Each key name and type must match the chart's values.yaml or documentation.
This example sets two nested chart values:
spec:
values:
replicaCount: 2
service:
port: 6379
Pack Operator first renders templates in spec.values, then passes the final values to Helm. Do not copy the complete values structure to change one option. Include only values that differ from chart defaults so changes and chart upgrades are easier to review.
Use templates in values
Strings in spec.values may use Jinja syntax. Expressions such as {{ ... }} produce values, and {% ... %} blocks provide template logic. The main render contexts are:
| Context | Available data |
|---|---|
vars | Effective organization, project, and Pack variables |
values | Other values in spec.values |
metadata | Pack name, namespace, labels, and annotations |
chart | Chart name, repository, version, and settings |
For example:
spec:
vars:
IMAGE_TAG: '7.4'
values:
replicaCount: 2
metrics:
enabled: true
image:
tag: '{{ vars.IMAGE_TAG }}'
instanceName: '{{ metadata.name }}'
service:
port: 6379
targetPort: '{{ values.service.port }}'
redisUrl: 'redis://{{ metadata.name }}:{{ values.service.port }}'
Here, image.tag comes from vars.IMAGE_TAG, while service.targetPort and part of redisUrl read values.service.port. Templates can therefore refer to other values as well as vars.
When the entire value is one template expression, the result type is preserved. For example, replicaCount remains a number and metrics.enabled remains a boolean. When the expression is part of a larger string, the result is a string.
Rendering is recursive, so one value may refer to another and key order does not matter. An undefined variable or a cycle such as a -> b -> a causes a validation error.
Useful filters include:
to_boolandto_strfor type conversion.splitto turn a string into a list.to_base64andfrom_base64.to_json,from_json,to_yaml, andfrom_yaml.ternaryto select a value from a condition.to_scalarto convert a Kubernetes quantity, such as CPU or memory, to a number.
For example, "true" can be converted to a boolean with '{{ vars.ENABLED | to_bool }}'.
Use vars
spec.vars separates template inputs from the chart structure. Defining a variable alone does not change Helm output; consume it from spec.values with an expression such as {{ vars.IMAGE_TAG }}.
spec:
vars:
IMAGE_TAG: '7.4'
values:
image:
tag: '{{ vars.IMAGE_TAG }}'
Pack Operator merges variables from the organization, project, and Pack. Precedence from lowest to highest is:
- Organization variables.
- Project variables.
- The Pack's
spec.vars.
When a name appears at several levels, the value closest to the Pack wins. Variable names are case-sensitive. Use organization or project variables for shared environment settings and spec.vars for installation-specific overrides.
Use Vault in vars and values
Vault encrypts sensitive text before it is stored in a manifest. During rendering, Pack Operator decrypts encrypted values in vars or values with a Vault key from the same namespace.
Create the Vault key in the Pack namespace and encrypt the sensitive value:
printf '%s' "$VAULT_PASSWORD" | kubit -n my-project vault create \
--vault-id app-vault \
--vault-password-stdin
printf '%s' "$REDIS_PASSWORD" | kubit -n my-project vault encrypt \
--vault-id app-vault
Place the complete output of the second command in a variable and use it from values. This example shows only the data shape; replace ENCRYPTED_PAYLOAD with the real command output:
spec:
vars:
REDIS_PASSWORD: |
$KUBIT_VAULT;1.2;AES256;app-vault
ENCRYPTED_PAYLOAD
values:
auth:
password: '{{ vars.REDIS_PASSWORD }}'
The Vault key must exist in the Pack namespace, and the executing identity or Pack Operator must be allowed to read it. Do not store decrypted text in a manifest, Git, CI logs, or support tickets. After rendering, Helm uses the value for installation, so also restrict access to Helm release Secrets and resources created by the chart.
Use Vault commands in kubit-cli to create, list, and encrypt values. For panel operations, see Manage Vault in Kubchi.
Control Pack management
When spec.managed is absent, Pack Operator treats it as true and manages the Pack. To pause reconciliation, set it explicitly to false:
spec:
managed: false
The operator then stops validation, apply, and automatic upgrades, and the Pack phase becomes Unmanaged. Running workloads and the existing Helm Release are not removed. Setting it back to true reconciles the Pack with spec again.
This option pauses management and does not fix errors. While management is disabled, manual changes outside Pack may drift from the manifest and be overwritten when management resumes. Pack deletion also behaves differently; read Delete a Pack first.
Pack exports
A chart author can define Pack outputs in pack-metadata.yaml. See Define Pack exports in a chart for the complete structure. Exports are not part of Pack spec; they may expose an application version, service address, image name, resource usage, or generated value. A chart may also read an export from a Secret, ConfigMap, or another resource in the same namespace.
Only outputs marked for status in chart metadata are stored in status.exports. Use kubit pack exports to read every defined output. The simple format is useful for quick inspection, while dict and list provide structured output.
Some outputs are sensitive. The sensitive flag tells consumers that the output is sensitive, but it does not replace access control. Do not store sensitive output in logs, pipelines, tickets, or Git.
Pack metadata and dependencies
metadata.name, metadata.namespace, labels, and annotations are available to templates and can be used to build environment-dependent names or settings. Keep operational names and annotations stable and documented to avoid unintended behavior.
If a Pack depends on a Secret or ConfigMap, declare the dependency with the restart-on-resource-change annotation so the operator can run the required rollout or restart. For manual operations, use force-upgrade and rollout-restart, and do not modify internal operator annotations directly.
Apply and inspect a Pack
Apply the manifest with kubectl:
kubectl apply -f redis.pack.yaml
Then inspect Pack status and events:
kubectl -n my-project get pack redis
kubectl -n my-project describe pack redis
A successful result uses the Applied phase. The main phases are:
Applied: the desired Pack state was applied.Failed: validation or apply failed.Unmanaged:spec.managedis disabled and the operator does not change the Pack.
The main status fields are:
| Field | Purpose |
|---|---|
status.current | Applied state, including exact chart version, chart and values digests, revision, Helm status, and last deployment time |
status.desired | Target state during processing or failure; cleared after a successful apply |
status.error | Latest reportable validation, migration, or apply error |
status.exports | Outputs selected by chart metadata for storage in status |
When status.desired remains beside a Failed phase, it shows the version and settings the operator attempted to reach. Compare it with status.current to diagnose the difference. All status fields are operator output and must not be edited manually.
Migrate between chart versions
A chart may provide migration rules in pack-migrations.yaml. To create this file, read Migrate Packs between chart versions. A migration is selected by repository, chart name, source version, and target version, and can convert the chart version, vars, or values to the new structure.
Before a manual upgrade, preview the result with kubit pack migrate, review the diff, and record the change only in the source manifest or Git repository. The --inline option changes the input file, so use it only on a versioned file or a recoverable copy.
During an automatic upgrade, the operator first checks for a matching migration. If none matches or execution fails, the normal automatic-upgrade path continues. Test migrations before publishing the chart; do not rely on migration failure to stop an upgrade.
Update a Pack
To change configuration, edit spec.vars or spec.values and apply the manifest again. Pack Operator validates the change, then updates the Helm release.
To record production changes in Git, store the manifest in a repository and use Kubchi GitOps. GitOps is optional and is not required to use Pack. Migration preview rules are covered in Migrate between chart versions.
Automatic upgrade runs only when the feature is enabled in the operator, autoUpgrade is true, autoUpgradeDelay is valid, and the chart version is not exact. After a compatible version is published and the delay passes, the operator checks migrations and runs the upgrade.
Delete a Pack
When spec.managed is true, deleting the Pack resource starts removal of the Helm release and its managed resources:
kubectl -n my-project delete pack redis
Check persistent data and chart volume-retention policies before deletion. When spec.managed is false, deleting the Pack does not uninstall its Helm Release or resources. For managed deletion, set managed back to true, wait for Applied, then delete the resource. Delete an unmanaged Pack directly only when you intend to manage the remaining release outside Pack.
Do not manually remove the Pack finalizer to force deletion; this can leave Helm resources without an owner. If deletion does not finish, inspect events and status.error, then contact Kubit support.
Related guides
- Helm and Helm charts in Kubernetes
- Add Pack capabilities to a Helm chart
- Create and test Pack migrations
- Install and manage a Pack in Kubchi
- Edit Pack configuration in Kubchi
- Manage Pack changes with GitOps
- Encrypt sensitive data with Vault
- Pack Operator behavior
- Restart a Pack after Secret or ConfigMap changes
- Read Pack exports with kubit-cli
- Use Pack through kubit-cli