Pre Helm Manifests

Table of contents

  1. Overview
  2. Configuration
  3. Configuration Format
    1. Supported URL Formats
    2. File URLs
    3. Directory URLs
    4. HTTP(S) URLs
    5. Mixed Configuration
  4. Examples
    1. Create a Namespace Before Installing a Chart
    2. Install CRDs Before a Chart That Requires Them
    3. Provide a Secret Consumed by a Chart
  5. Manifest Requirements
    1. YAML Format
    2. Namespaces
    3. Local File Accessibility
    4. Remote URL Accessibility
  6. Execution Order
    1. Full Execution Flow
  7. Important Notes
    1. Error Handling
    2. Validation Before Use
    3. Supported Formats
  8. Troubleshooting
    1. File Not Found
  9. Wrong
  10. Correct
    1. Application Failures
    2. Chart Still Fails After Adding a Prerequisite
    3. Best Practices
      1. Stage Namespaces and CRDs Here
      2. Pair with Post Install Manifests

Overview

BeKind can automatically apply Kubernetes YAML manifests before Helm charts are installed. This is useful for creating resources that your charts depend on, such as:

  • Namespaces
  • Custom Resource Definitions (CRDs)
  • Secrets and ConfigMaps consumed by charts
  • RBAC policies required during install
  • Any prerequisite resources a chart expects to already exist

This works just like Post Install Manifests, but the manifests are applied earlier in the setup flow, before any Helm chart is installed.


Configuration

Add manifest paths under the preHelmManifests key:

preHelmManifests:
  - "file:///home/user/k8s/namespace.yaml"
  - "file:///home/user/k8s/crds.yaml"
  - "https://example.com/configs/secret.yaml"

Configuration Format

Supported URL Formats

BeKind supports multiple ways to specify manifest locations:

  • Local files: file:// URLs with absolute paths
  • Local directories: dir:// URLs with absolute paths
  • HTTP(S) URLs: Direct links to manifests served as text/plain

You can mix and match both types in the same configuration.

File URLs

Local files must be specified as file:// URLs with absolute paths:

preHelmManifests:
  - "file:///home/user/manifests/namespace.yaml"
  - "file:///home/user/manifests/crds.yaml"

Relative paths are not supported. Always use absolute paths with the file:// prefix.

Linux/macOS:

preHelmManifests:
  - "file:///home/username/k8s/namespace.yaml"
  - "file:///Users/username/projects/k8s/crds.yaml"

Windows:

preHelmManifests:
  - "file:///C:/Users/username/k8s/namespace.yaml"

Directory URLs

A dir:// URL points at a local directory and applies every manifest inside it, working just like kubectl apply -f <dir>:

preHelmManifests:
  - "dir:///home/user/manifests/"

Only files ending in .yaml, .yml, or .json directly inside the directory are applied, and they are applied in alphabetical order. The directory is not traversed recursively. Use absolute paths with the dir:// prefix.

HTTP(S) URLs

Manifests can be fetched from remote URLs:

preHelmManifests:
  - "https://yoursite.example.org/manifests/crds.yaml"
  - "http://internal-server.local/configs/namespace.yaml"

Remote manifests must be served with the text/plain or application/yaml content type.

Mixed Configuration

You can combine local files and remote URLs:

preHelmManifests:
  - "file:///home/user/local/namespace.yaml"
  - "https://example.com/shared/crds.yaml"
  - "file:///home/user/local/secret.yaml"

Examples

Create a Namespace Before Installing a Chart

preHelmManifests:
  - "file:///home/user/k8s/monitoring-namespace.yaml"

helmCharts:
  - url: "https://prometheus-community.github.io/helm-charts"
    repo: "prometheus-community"
    chart: "kube-prometheus-stack"
    release: "monitoring"
    namespace: "monitoring"
    wait: true

Install CRDs Before a Chart That Requires Them

preHelmManifests:
  - "https://example.com/crds/my-operator-crds.yaml"

helmCharts:
  - url: "https://example.com/charts"
    repo: "myrepo"
    chart: "my-operator"
    release: "my-operator"
    namespace: "operators"
    wait: true

Provide a Secret Consumed by a Chart

preHelmManifests:
  - "file:///home/user/k8s/registry-credentials.yaml"

helmCharts:
  - url: "https://charts.example.com"
    repo: "example"
    chart: "private-app"
    release: "private-app"
    namespace: "default"
    wait: true

Manifest Requirements

YAML Format

Manifests must be valid Kubernetes YAML files. They can contain:

  • Single resources
  • Multiple resources separated by ---
  • Any valid Kubernetes resource type

Single resource:

apiVersion: v1
kind: Namespace
metadata:
  name: monitoring

Multiple resources:

apiVersion: v1
kind: Namespace
metadata:
  name: my-app
---
apiVersion: v1
kind: Secret
metadata:
  name: my-secret
  namespace: my-app
type: Opaque
stringData:
  token: "example"

Namespaces

For namespace-scoped resources, BeKind honors the metadata.namespace field in the manifest. If a namespace-scoped resource omits metadata.namespace, BeKind applies it to the default namespace (mirroring kubectl behavior).

Cluster-scoped resources (such as Namespace, ClusterRole, or CRDs) are unaffected by this defaulting.

Local File Accessibility

Ensure BeKind can read the manifest files:

# Check file exists
ls -l /home/user/k8s/namespace.yaml

# Check file permissions
chmod 644 /home/user/k8s/namespace.yaml

Remote URL Accessibility

For HTTP(S) URLs, ensure:

  • The URL is accessible from where BeKind is running
  • The server returns text/plain or application/yaml content type
  • No authentication is required, or use a URL with embedded credentials (not recommended for production)
  • HTTPS certificates are valid (or use HTTP for internal/trusted networks)

Test URL accessibility:

# Test with curl
curl -I https://example.com/manifests/crds.yaml

# Should return 200 OK with text/plain or application/yaml content type

Execution Order

Manifests are applied in the order they appear in your configuration:

preHelmManifests:
  - "file:///path/to/namespace.yaml"      # Applied first
  - "file:///path/to/crds.yaml"           # Applied second
  - "file:///path/to/secret.yaml"         # Applied third

If resources have dependencies, list them in the correct order. For example, create namespaces before resources that use them.

Full Execution Flow

  1. KIND cluster is created
  2. Docker images are loaded (if configured)
  3. Pre-helm manifests are applied ← You are here
  4. Helm charts are installed (if configured)
  5. Post-install manifests are applied (if configured)
  6. Post-install patches are applied (if configured)
  7. Post-install actions are performed (if configured)

This ordering lets you stage prerequisite resources (namespaces, CRDs, secrets) so that Helm charts installed afterward can rely on them.


Important Notes

Error Handling

Pre-helm manifests are applied on a best-effort basis. If a manifest fails to apply:

  • BeKind logs a warning
  • Subsequent manifests are still attempted
  • Helm chart installation continues
  • The cluster setup is not aborted

Because application is best-effort, BeKind will continue even if a prerequisite manifest fails. If a chart strictly depends on a resource created here, verify it was applied successfully.

Validation Before Use

Always validate your manifests before using them with BeKind:

# Dry-run validation
kubectl apply -f manifest.yaml --dry-run=client

# Server-side validation
kubectl apply -f manifest.yaml --dry-run=server

Supported Formats

Currently, only YAML files are supported. JSON manifests are not supported.


Troubleshooting

File Not Found

If BeKind can’t find a manifest:

For local files:

  1. Check the path is absolute: ```yaml

    Wrong

    preHelmManifests:

    • ”./manifests/namespace.yaml”

    Correct

    preHelmManifests:

    • “file:///home/user/project/manifests/namespace.yaml” ```
  2. Verify the file exists:
    ls -l /home/user/project/manifests/namespace.yaml
    

For remote URLs:

  1. Test URL accessibility:
    curl -v https://example.com/manifests/crds.yaml
    
  2. Check content type:
    curl -I https://example.com/manifests/crds.yaml
    # Should see: Content-Type: text/plain or application/yaml
    

Application Failures

If a manifest fails to apply:

  1. Validate YAML syntax:
    yamllint manifest.yaml
    
  2. Check Kubernetes API version:
    kubectl api-versions
    
  3. Test manually:
    kubectl apply -f manifest.yaml
    

Chart Still Fails After Adding a Prerequisite

Because pre-helm manifests are best-effort, a failed prerequisite does not stop the chart install:

  1. Re-run BeKind with debug logging to see the warning:
    bekind start --config config.yaml -v
    
  2. Confirm the resource was created:
    kubectl get ns
    kubectl get crds
    

Best Practices

Stage Namespaces and CRDs Here

Use preHelmManifests for resources charts expect to already exist:

preHelmManifests:
  - "file:///home/user/k8s/namespaces.yaml"
  - "https://example.com/crds/operator-crds.yaml"

helmCharts:
  - url: "https://example.com/charts"
    repo: "example"
    chart: "operator"
    release: "operator"
    namespace: "operators"
    wait: true

Pair with Post Install Manifests

Use preHelmManifests for prerequisites and postInstallManifests for resources that depend on the installed charts:

preHelmManifests:
  - "file:///home/user/k8s/namespace.yaml"

helmCharts:
  - url: "https://argoproj.github.io/argo-helm"
    repo: "argo"
    chart: "argo-cd"
    release: "argocd"
    namespace: "argocd"
    wait: true

postInstallManifests:
  - "file:///home/user/argocd/app-of-apps.yaml"