Documentation Index Fetch the complete documentation index at: https://docs.pangolin.net/llms.txt
Use this file to discover all available pages before exploring further.
Try free on Pangolin Cloud Fastest way to get started with Pangolin using the hosted control plane. No credit card required.
Use Kustomize when you want to manage Pangolin with rendered manifests, environment-specific overlays, and explicit patches in Git.
For Pangolin, the supported Kustomize workflow is:
Render the Pangolin Helm chart to manifests.
Use the rendered output as the Kustomize base.
Create overlays per environment.
Apply the overlay with kubectl apply -k or reconcile it with Argo CD or Flux.
When to use Kustomize for Pangolin
Use Kustomize if you:
want environment-specific overlays for dev, staging, or production
need explicit patches committed to Git
prefer reviewing rendered Kubernetes manifests before applying them
use Argo CD or Flux with Kustomize sources
want to customize Helm-rendered output without forking the chart
For a simpler single-environment setup, use Pangolin Helm .
Version context
This page is aligned with the Pangolin Helm chart 0.1.0-alpha.0.
Item Value Chart version 0.1.0-alpha.0Pangolin app version 1.18.2Kubernetes version >=1.30.14-0Gerbil image tag 1.3.1pangolin-kube-controller image tag 0.1.0-alpha.1Traefik image tag v3.6.15
Supported approach
The Pangolin chart does not provide native Kustomize bases. Render the Helm chart first, then use Kustomize on the rendered manifests.
Do not manage the same Pangolin resources with both a live Helm release and Kustomize. Pick one ownership model per environment.
Recommended ownership model:
Use Helm only to render the Pangolin chart.
Use Kustomize, Argo CD, or Flux to apply and reconcile the rendered manifests.
Re-render the base when upgrading the chart or changing Helm values.
Example directory structure
pangolin-deployment/
├── base/
│ ├── kustomization.yaml
│ └── pangolin.yaml
├── overlays/
│ ├── dev/
│ │ ├── kustomization.yaml
│ │ └── patches/
│ │ └── pangolin-resources.patch.yaml
│ ├── staging/
│ │ ├── kustomization.yaml
│ │ └── patches/
│ │ └── pangolin-resources.patch.yaml
│ └── prod/
│ ├── kustomization.yaml
│ └── patches/
│ ├── pangolin-resources.patch.yaml
│ └── ingressroute-host.patch.yaml
└── values/
├── values-base.yaml
├── values-dev.yaml
├── values-staging.yaml
└── values-prod.yaml
Step 1: Create the namespace
Create the namespace before applying rendered manifests:
kubectl create namespace pangolin
Gerbil requires NET_ADMIN for WireGuard interface management. If your cluster enforces Pod Security Admission, label the namespace before creating workloads:
kubectl label namespace pangolin \
pod-security.kubernetes.io/enforce=privileged \
pod-security.kubernetes.io/warn=baseline \
pod-security.kubernetes.io/audit=restricted \
--overwrite
Do not use a restricted Pod Security profile for a namespace running Gerbil unless you have validated the selected chart mode. Gerbil requires NET_ADMIN.
Step 2: Create the Pangolin app Secret
Create a Secret for SERVER_SECRET:
kubectl create secret generic pangolin-app-secret \
--namespace pangolin \
--from-literal=SERVER_SECRET= '<strong-random-secret>'
Do not commit this Secret to Git.
Step 3: Create base values
Create values/values-base.yaml:
deployment :
type : controller
mode : multi
installTraefikController : false
database :
mode : cloudnativepg
cloudnativepg :
cluster :
name : pangolin-db
cnpg-operator :
enabled : true
cnpg-cluster :
enabled : true
fullnameOverride : pangolin-db
cluster :
instances : 1
storage :
size : 8Gi
pangolin :
secret :
existingSecretName : pangolin-app-secret
existingSecretKey : SERVER_SECRET
config :
app :
dashboard_url : https://pangolin.example.com
domains :
domain1 :
base_domain : example.com
cert_resolver : letsencrypt
gerbil :
base_endpoint : vpn.example.com
start_port : 51820
clients_start_port : 21820
traefik :
enabled : true
http_entrypoint : web
https_entrypoint : websecure
cert_resolver : letsencrypt
ingressRoute :
dashboard :
enabled : true
host : pangolin.example.com
entryPoints :
- websecure
tls :
enabled : true
certResolver : letsencrypt
secretName : ""
gerbil :
enabled : true
startupMode : delayed
persistence :
enabled : true
size : 1Gi
Replace:
pangolin.example.com
example.com
vpn.example.com
TLS resolver names
storage settings
Use gerbil.startupMode=delayed for the first install if Gerbil should not start before the initial Pangolin setup is complete. Switch it to normal after setup.
Step 4: Render Pangolin to the base
Add and update the Helm repository:
helm repo add fossorial https://charts.fossorial.io
helm repo update fossorial
Create directories:
mkdir -p base overlays/dev/patches overlays/staging/patches overlays/prod/patches values
Render the Pangolin chart:
helm template pangolin fossorial/pangolin \
--namespace pangolin \
--values values/values-base.yaml \
> base/pangolin.yaml
You can also render from the GHCR OCI chart:
helm template pangolin oci://ghcr.io/fosrl/helm-charts/pangolin \
--version 0.1.0-alpha.0 \
--namespace pangolin \
--values values/values-base.yaml \
> base/pangolin.yaml
Step 5: Create the base kustomization
# base/kustomization.yaml
apiVersion : kustomize.config.k8s.io/v1beta1
kind : Kustomization
resources :
- pangolin.yaml
The namespace is already rendered by Helm through --namespace pangolin. You can also set namespace: pangolin in Kustomize, but avoid changing namespaces in overlays unless you have verified all rendered resources and references.
Step 6: Inspect rendered resource names
Before writing patches, inspect the generated resource names:
kustomize build base | grep -E "^(kind:| name:)"
Or list the main resource names with yq:
kustomize build base | yq '. | select(.kind == "Deployment" or .kind == "StatefulSet" or .kind == "IngressRoute" or .kind == "Service") | .kind + " " + .metadata.name'
Do not assume generated resource names. Helm names can change with the release name, chart name, nameOverride, or fullnameOverride.
Use the actual rendered names in your patch targets.
Step 7: Create a production overlay
Example overlays/prod/kustomization.yaml:
apiVersion : kustomize.config.k8s.io/v1beta1
kind : Kustomization
resources :
- ../../base
labels :
- pairs :
app.kubernetes.io/environment : production
app.kubernetes.io/managed-by : kustomize
patches :
- path : patches/pangolin-resources.patch.yaml
target :
group : apps
version : v1
kind : Deployment
name : pangolin
- path : patches/ingressroute-host.patch.yaml
target :
group : traefik.io
version : v1alpha1
kind : IngressRoute
name : pangolin-dashboard
Replace pangolin and pangolin-dashboard with the actual names from your rendered manifests.
Step 8: Add patches
Patch Pangolin resources
# overlays/prod/patches/pangolin-resources.patch.yaml
apiVersion : apps/v1
kind : Deployment
metadata :
name : pangolin
spec :
template :
spec :
containers :
- name : pangolin
resources :
requests :
cpu : 500m
memory : 512Mi
limits :
memory : 1Gi
CPU limits are rendered by default through the chart’s resourcesPolicy.cpuLimits.enabled=true. If you disable CPU limits in chart values, keep your Kustomize patches consistent with that policy.
Patch dashboard IngressRoute host
The Pangolin chart uses Traefik IngressRoute for the dashboard and API in controller mode, not a standard Kubernetes Ingress.
# overlays/prod/patches/ingressroute-host.patch.yaml
apiVersion : traefik.io/v1alpha1
kind : IngressRoute
metadata :
name : pangolin-dashboard
spec :
routes :
- kind : Rule
match : Host(`pangolin-prod.example.com`) && PathPrefix(`/api/v1`)
- kind : Rule
match : Host(`pangolin-prod.example.com`)
Patch the rendered IngressRoute only after checking the route order and match rules. The API route and dashboard route target different service ports.
Patch node affinity
# overlays/prod/patches/pangolin-node-affinity.patch.yaml
apiVersion : apps/v1
kind : Deployment
metadata :
name : pangolin
spec :
template :
spec :
affinity :
nodeAffinity :
requiredDuringSchedulingIgnoredDuringExecution :
nodeSelectorTerms :
- matchExpressions :
- key : node-type
operator : In
values :
- production
Reference it in overlays/prod/kustomization.yaml:
patches :
- path : patches/pangolin-node-affinity.patch.yaml
target :
group : apps
version : v1
kind : Deployment
name : pangolin
Patch Gerbil startup mode
For first install, this should usually be handled in Helm values before rendering. If you still need to patch rendered manifests, inspect the generated Deployment first.
To switch Gerbil from delayed to normal mode, prefer updating values and re-rendering:
gerbil :
startupMode : normal
Then re-render:
helm template pangolin fossorial/pangolin \
--namespace pangolin \
--values values/values-base.yaml \
> base/pangolin.yaml
Do not rename rendered Helm resources by default
Avoid Kustomize options such as namePrefix and nameSuffix for Helm-rendered bases unless you have verified every generated reference.
Renaming rendered resources can break:
Service selectors
Secret references
ConfigMap references
ServiceAccount references
NetworkPolicy selectors
Traefik IngressRoute service references
Prometheus monitor selectors
CloudNativePG references
If you need different resource names, prefer changing the Helm release name or chart naming values before rendering.
Apply the overlay
Preview the rendered output:
kustomize build overlays/prod
Compare with the live cluster:
kustomize build overlays/prod | kubectl diff -f -
Apply the overlay:
kubectl apply -k overlays/prod
Verify workloads:
kubectl get pods --namespace pangolin
kubectl get deploy,statefulset --namespace pangolin
kubectl get svc --namespace pangolin
Verify Traefik resources:
kubectl get ingressroute --namespace pangolin
Check events:
kubectl get events --namespace pangolin --sort-by=.lastTimestamp
Updating the rendered base
When upgrading the Pangolin chart or changing Helm values, re-render the base and review the changes.
Update the Helm repository:
helm repo update fossorial
Render the updated chart output:
helm template pangolin fossorial/pangolin \
--namespace pangolin \
--values values/values-base.yaml \
> base/pangolin.yaml
Or with OCI:
helm template pangolin oci://ghcr.io/fosrl/helm-charts/pangolin \
--version 0.1.0-alpha.0 \
--namespace pangolin \
--values values/values-base.yaml \
> base/pangolin.yaml
Validate the overlay:
kustomize build overlays/prod
Review the diff:
git diff
kustomize build overlays/prod | kubectl diff -f -
Commit the updated base and overlays:
git add base/ overlays/ values/
git commit -m "Update Pangolin rendered manifests"
Apply after review:
kubectl apply -k overlays/prod
Ownership model
Do not run helm upgrade against a release that is managed by Kustomize.
Avoid this pattern:
helm upgrade pangolin fossorial/pangolin --namespace pangolin
kubectl apply -k overlays/prod
Use one of these models instead:
Model Description Helm-managed Helm installs and upgrades the live release. Kustomize is not used for the same resources. Kustomize-managed Helm renders manifests only. Kustomize applies and owns the live resources. GitOps-managed Argo CD or Flux applies the Kustomize overlay and owns reconciliation.
Common Kustomize patches for Pangolin
Patch resource requests and limits
patches :
- path : patches/pangolin-resources.patch.yaml
target :
group : apps
version : v1
kind : Deployment
name : pangolin
Patch IngressRoute host
patches :
- path : patches/ingressroute-host.patch.yaml
target :
group : traefik.io
version : v1alpha1
kind : IngressRoute
name : pangolin-dashboard
Add annotations
patches :
- target :
group : apps
version : v1
kind : Deployment
name : pangolin
patch : | -
- op: add
path: /metadata/annotations
value:
example.com/owner: platform
Patch Gerbil Service type
Patch the Gerbil Service only after checking the rendered Service name.
patches :
- target :
version : v1
kind : Service
name : pangolin-gerbil
patch : | -
- op: replace
path: /spec/type
value: LoadBalancer
For important topology settings such as database mode, Gerbil ports, startupMode, Traefik mode, and CloudNativePG settings, prefer changing Helm values and re-rendering instead of patching rendered YAML.
Validation
Validate Kustomize output:
kustomize build overlays/prod
Run a server-side dry run:
kustomize build overlays/prod | kubectl apply -f - --dry-run=server
Preview live changes:
kustomize build overlays/prod | kubectl diff -f -
If a patch does not apply, inspect generated resource names:
kustomize build base | grep -E "^(kind:| name:)"
Troubleshooting
The patch does not apply
Check the rendered resource name and kind:
kustomize build base | grep -E "^(kind:| name:)"
Then verify the patch target in your overlay.
The pod does not start
Check pod status and events:
kubectl get pods --namespace pangolin
kubectl describe pod < pod-nam e> --namespace pangolin
kubectl get events --namespace pangolin --sort-by=.lastTimestamp
Dashboard routing does not work
Check the rendered and applied IngressRoute:
kubectl get ingressroute --namespace pangolin
kubectl describe ingressroute < nam e> --namespace pangolin
Verify:
Traefik CRDs are installed.
A Traefik controller is watching the namespace and labels.
pangolin.ingressRoute.dashboard.host or the patched host matches DNS.
The API route still contains PathPrefix(/api/v1).
TLS settings match your Traefik setup.
Gerbil does not start
Check Gerbil resources:
kubectl get pods,svc,pvc --namespace pangolin \
-l app.kubernetes.io/name=gerbil
Verify:
namespace allows NET_ADMIN
gerbil.startupMode is set correctly
Gerbil persistence is enabled or intentionally disabled
pangolin.config.gerbil.start_port matches gerbil.ports.wg1
pangolin.config.gerbil.clients_start_port matches gerbil.ports.wg2
Next steps
Helm Install Install Pangolin with Helm.
Configuration Review Pangolin chart options.
Troubleshooting Debug Pangolin deployment and routing issues.
GitOps Deploy Pangolin with Argo CD or Flux.