mirror of
https://github.com/fosrl/docs-v2.git
synced 2026-07-16 19:09:55 +00:00
docs(self-host/kubernetes): add Kubernetes deployment guides with Helm, Kustomize, Helmfile, and GitOps for Newt and Pangolin
Signed-off-by: Marc Schäfer <git@marcschaeferger.de>
This commit is contained in:
39
docs.json
39
docs.json
@@ -175,7 +175,44 @@
|
||||
"group": "Manual Installation",
|
||||
"pages": [
|
||||
"self-host/manual/docker-compose",
|
||||
"self-host/manual/unraid"
|
||||
"self-host/manual/unraid",
|
||||
{
|
||||
"group": "Kubernetes",
|
||||
"pages": [
|
||||
"self-host/manual/kubernetes/overview",
|
||||
"self-host/manual/kubernetes/choose-method",
|
||||
"self-host/manual/kubernetes/prerequisites",
|
||||
"self-host/manual/kubernetes/helm",
|
||||
"self-host/manual/kubernetes/kustomize",
|
||||
"self-host/manual/kubernetes/helmfile",
|
||||
{
|
||||
"group": "GitOps",
|
||||
"pages": [
|
||||
"self-host/manual/kubernetes/gitops/overview",
|
||||
"self-host/manual/kubernetes/gitops/argocd",
|
||||
"self-host/manual/kubernetes/gitops/flux"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Newt",
|
||||
"pages": [
|
||||
"self-host/manual/kubernetes/newt/helm",
|
||||
"self-host/manual/kubernetes/newt/kustomize",
|
||||
"self-host/manual/kubernetes/newt/configuration",
|
||||
"self-host/manual/kubernetes/newt/troubleshooting"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Pangolin",
|
||||
"pages": [
|
||||
"self-host/manual/kubernetes/pangolin/helm",
|
||||
"self-host/manual/kubernetes/pangolin/kustomize",
|
||||
"self-host/manual/kubernetes/pangolin/configuration",
|
||||
"self-host/manual/kubernetes/pangolin/troubleshooting"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"self-host/dns-and-networking",
|
||||
|
||||
180
self-host/manual/kubernetes/choose-method.mdx
Normal file
180
self-host/manual/kubernetes/choose-method.mdx
Normal file
@@ -0,0 +1,180 @@
|
||||
---
|
||||
title: "Choose a Method"
|
||||
description: "Choose the right Kubernetes installation workflow for Pangolin and Newt."
|
||||
---
|
||||
|
||||
import PangolinCloudTocCta from "/snippets/pangolin-cloud-toc-cta.mdx";
|
||||
|
||||
<PangolinCloudTocCta />
|
||||
|
||||
|
||||
This page helps you choose the right Kubernetes workflow for installing and managing Pangolin and related components.
|
||||
|
||||
## Quick decision table
|
||||
|
||||
| If you... | Use | Why |
|
||||
| --- | --- | --- |
|
||||
| Want the recommended Kubernetes install path | **Helm** | Standard chart-based workflow for installing, upgrading, and uninstalling releases |
|
||||
| Need environment-specific overlays or manifest customization | **Kustomize** | Patch and reuse Kubernetes manifests without a separate templating language |
|
||||
| Already use Argo CD or want GitOps with a web UI | **Argo CD** | Git-driven reconciliation, sync status, drift detection, and optional auto-sync |
|
||||
| Already use Flux or want GitOps defined through Kubernetes CRDs | **Flux** | Declarative reconciliation with resources such as `HelmRelease` and `Kustomization` |
|
||||
| Need to manage several Helm releases together | **Helmfile** | Declarative orchestration for multiple Helm releases and shared values |
|
||||
|
||||
## Detailed method descriptions
|
||||
|
||||
### Use Helm if...
|
||||
|
||||
- You want the recommended Kubernetes install workflow for Pangolin or Newt.
|
||||
- You want a straightforward chart-based install.
|
||||
- You manage releases manually or through CI/CD.
|
||||
- You want normal Helm release operations such as install, upgrade, rollback, and uninstall.
|
||||
- You are comfortable managing configuration through `values.yaml`.
|
||||
|
||||
Helm is the default choice for most Kubernetes installations. It packages Kubernetes resources into versioned charts and manages releases in the cluster.
|
||||
|
||||
**Get started**: [Helm Quick-Start](/self-host/manual/kubernetes/helm)
|
||||
|
||||
### Use Kustomize if...
|
||||
|
||||
- You need environment-specific overlays for dev, staging, or production.
|
||||
- You want to patch Kubernetes manifests without using a templating language.
|
||||
- You prefer a manifest-driven workflow.
|
||||
- You want to keep rendered or curated manifests in Git.
|
||||
- You are comfortable with `kubectl apply -k` or `kustomize build`.
|
||||
|
||||
Kustomize works well when you want a shared base with small environment-specific changes. It can be used with curated manifests, generated manifests, or GitOps tools.
|
||||
|
||||
**Common scenario**: Keep a base deployment and apply overlays for each environment.
|
||||
|
||||
**Get started**: [Kustomize Quick-Start](/self-host/manual/kubernetes/kustomize)
|
||||
|
||||
### Use Argo CD if...
|
||||
|
||||
- Your Git repository should be the source of truth.
|
||||
- You want a web UI for application status, sync state, and troubleshooting.
|
||||
- You want drift detection when the live cluster state differs from the desired state.
|
||||
- You want manual sync, automated sync, or self-healing behavior.
|
||||
- You already use Argo CD for other applications.
|
||||
|
||||
Argo CD reconciles applications from a declared source into the cluster. It can use Helm charts, Kustomize overlays, plain YAML, Jsonnet, or configured plugins as sources.
|
||||
|
||||
When Argo CD deploys a Helm chart, Helm is used to render the manifests. The application lifecycle is then managed by Argo CD, not by the local `helm` CLI.
|
||||
|
||||
**Argo CD can deploy**:
|
||||
|
||||
- Helm charts
|
||||
- Kustomize overlays
|
||||
- Plain YAML manifests
|
||||
- Jsonnet or custom config-management plugin output
|
||||
|
||||
**Get started**: [Argo CD Guide](/self-host/manual/kubernetes/gitops/argocd)
|
||||
|
||||
### Use Flux if...
|
||||
|
||||
- You want GitOps managed through Kubernetes custom resources.
|
||||
- You already use Flux for other workloads.
|
||||
- You want Helm releases reconciled by a controller.
|
||||
- You want Kustomize overlays reconciled from Git.
|
||||
- You prefer a lightweight workflow without depending on a central web UI.
|
||||
|
||||
Flux defines sources and desired state as Kubernetes resources. Typical resources include `GitRepository`, `HelmRepository`, `OCIRepository`, `Kustomization`, and `HelmRelease`.
|
||||
|
||||
**Flux can deploy**:
|
||||
|
||||
- Helm charts with `HelmRepository` and `HelmRelease`
|
||||
- OCI-based Helm charts with `OCIRepository` and `HelmRelease`
|
||||
- Kustomize overlays with `GitRepository` and `Kustomization`
|
||||
- Plain manifests through a Flux `Kustomization`
|
||||
|
||||
**Get started**: [Flux Guide](/self-host/manual/kubernetes/gitops/flux)
|
||||
|
||||
### Use Helmfile if...
|
||||
|
||||
- You need to manage multiple Helm releases as one deployment stack.
|
||||
- You want to install Pangolin together with supporting components.
|
||||
- You want one declarative file for releases, values files, and release ordering.
|
||||
- You prefer running one controlled workflow instead of several manual `helm upgrade --install` commands.
|
||||
|
||||
Helmfile is a declarative wrapper around Helm. It does not replace Helm; it calls Helm to apply the declared releases.
|
||||
|
||||
**Common scenario**: One Helmfile manages supporting components such as an ingress controller, certificate management, database components, Pangolin, and Newt.
|
||||
|
||||
**Get started**: [Helmfile Guide](/self-host/manual/kubernetes/helmfile)
|
||||
|
||||
## Important clarifications
|
||||
|
||||
### Argo CD and Flux are not Helm replacements
|
||||
|
||||
Argo CD and Flux are delivery and reconciliation tools. They do not replace Helm or Kustomize.
|
||||
|
||||
- **Helm** packages and renders Kubernetes resources from charts.
|
||||
- **Kustomize** customizes Kubernetes manifests through bases, overlays, and patches.
|
||||
- **Argo CD** reconciles applications from Git, Helm repositories, OCI registries, or other configured sources.
|
||||
- **Flux** reconciles sources and workloads through Kubernetes custom resources such as `HelmRelease` and `Kustomization`.
|
||||
|
||||
You can use Argo CD or Flux with Helm charts, Kustomize overlays, or plain manifests.
|
||||
|
||||
### OCI is not a separate install method
|
||||
|
||||
OCI (Open Container Initiative) describes a chart distribution format, not a separate deployment workflow.
|
||||
|
||||
For Pangolin and Newt, OCI chart publishing is available in GHCR:
|
||||
|
||||
- Newt: `oci://ghcr.io/fosrl/helm-charts/newt` (for example `1.4.0`)
|
||||
- Pangolin: `oci://ghcr.io/fosrl/helm-charts/pangolin` (for example `0.1.0-alpha.0`)
|
||||
|
||||
You still choose the same deployment method (Helm directly, or GitOps with Argo CD/Flux). OCI only changes where charts are pulled from.
|
||||
|
||||
Classic Helm repository flow is still valid:
|
||||
|
||||
```bash
|
||||
helm repo add fossorial https://charts.fossorial.io
|
||||
helm repo update fossorial
|
||||
helm install my-newt fossorial/newt
|
||||
helm install my-pangolin fossorial/pangolin
|
||||
```
|
||||
|
||||
OCI workflow with Helm:
|
||||
|
||||
```bash
|
||||
helm pull oci://ghcr.io/fosrl/helm-charts/newt --version 1.4.0
|
||||
helm pull oci://ghcr.io/fosrl/helm-charts/pangolin --version 0.1.0-alpha.0
|
||||
```
|
||||
|
||||
```bash
|
||||
helm install my-newt oci://ghcr.io/fosrl/helm-charts/newt \
|
||||
--version 1.4.0
|
||||
|
||||
helm install my-pangolin oci://ghcr.io/fosrl/helm-charts/pangolin \
|
||||
--version 0.1.0-alpha.0
|
||||
```
|
||||
|
||||
### Raw YAML is not a separate primary workflow
|
||||
|
||||
This documentation does not provide a dedicated raw-YAML installation path.
|
||||
|
||||
Raw manifests are still possible:
|
||||
|
||||
- Render a Helm chart with `helm template`.
|
||||
- Render Kustomize overlays with `kustomize build` or `kubectl kustomize`.
|
||||
- Apply generated manifests with `kubectl apply -f`.
|
||||
- Reconcile plain manifests with Argo CD or Flux.
|
||||
|
||||
For most users, Helm, Kustomize, Argo CD, or Flux is easier to maintain than applying standalone YAML files manually.
|
||||
|
||||
## Next steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Prerequisites" href="/self-host/manual/kubernetes/prerequisites" icon="list-check">
|
||||
Review cluster, tooling, ingress, DNS, storage, and secret requirements.
|
||||
</Card>
|
||||
<Card title="Helm Quick-Start" href="/self-host/manual/kubernetes/helm" icon="box">
|
||||
Install Pangolin or Newt with the recommended chart-based workflow.
|
||||
</Card>
|
||||
<Card title="Kustomize Quick-Start" href="/self-host/manual/kubernetes/kustomize" icon="layer-group">
|
||||
Use bases, overlays, and patches for manifest-driven deployments.
|
||||
</Card>
|
||||
<Card title="GitOps Overview" href="/self-host/manual/kubernetes/gitops/overview" icon="code-branch">
|
||||
Deploy and reconcile Pangolin or Newt with Argo CD or Flux.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
468
self-host/manual/kubernetes/gitops/argocd.mdx
Normal file
468
self-host/manual/kubernetes/gitops/argocd.mdx
Normal file
@@ -0,0 +1,468 @@
|
||||
---
|
||||
title: "Argo CD"
|
||||
description: "Deploy Pangolin and Newt using Argo CD for Git-driven GitOps reconciliation."
|
||||
---
|
||||
|
||||
import PangolinCloudTocCta from "/snippets/pangolin-cloud-toc-cta.mdx";
|
||||
|
||||
<PangolinCloudTocCta />
|
||||
|
||||
|
||||
Argo CD is a declarative GitOps tool that continuously syncs your cluster state to your Git repository. This guide covers installing Pangolin and Newt using Argo CD.
|
||||
|
||||
## Argo CD overview
|
||||
|
||||
Argo CD watches your Git repository (or Helm chart repository) and automatically reconciles Kubernetes resources to match the desired state defined in Git.
|
||||
|
||||
**Key concepts**:
|
||||
|
||||
- **Application**: Argo CD custom resource that defines what to deploy, where, and how
|
||||
- **Helm source**: Argo CD uses Helm to render charts; you provide values
|
||||
- **Kustomize source**: Argo CD uses Kustomize to build manifests
|
||||
- **Sync**: Process of applying desired state to the cluster
|
||||
- **Drift**: When cluster state diverges from Git (Argo CD can detect and correct)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Argo CD installed in your cluster (in `argocd` namespace, typically)
|
||||
- Helm repo configured: `helm repo add fossorial https://charts.fossorial.io`
|
||||
- Git repository with Argo CD configuration (optional, can use chart repo as source)
|
||||
- Newt auth secret (if installing Newt)
|
||||
|
||||
## Install Argo CD
|
||||
|
||||
If you don't have Argo CD yet:
|
||||
|
||||
```bash
|
||||
# Create namespace
|
||||
kubectl create namespace argocd
|
||||
|
||||
# Install Argo CD
|
||||
helm repo add argo https://argoproj.github.io/argo-helm
|
||||
helm repo update argo
|
||||
helm install argocd argo/argo-cd -n argocd
|
||||
```
|
||||
|
||||
Access the Argo CD UI:
|
||||
|
||||
```bash
|
||||
# Port-forward
|
||||
kubectl port-forward -n argocd svc/argocd-server 8080:443
|
||||
|
||||
# Visit https://localhost:8080
|
||||
# Default username: admin
|
||||
# Password: kubectl get secret -n argocd argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
|
||||
```
|
||||
|
||||
## Install Pangolin with Argo CD using Helm
|
||||
|
||||
### Step 1: Create Pangolin namespace
|
||||
|
||||
```bash
|
||||
kubectl create namespace pangolin
|
||||
```
|
||||
|
||||
### Step 2: Create Application
|
||||
|
||||
Create an Argo CD Application resource that tells Argo CD to deploy Pangolin using the Helm chart:
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: pangolin
|
||||
namespace: argocd
|
||||
spec:
|
||||
project: default
|
||||
|
||||
source:
|
||||
repoURL: https://charts.fossorial.io
|
||||
chart: pangolin
|
||||
targetRevision: 0.1.0-alpha.0 # or use ~0.1.0 for range
|
||||
helm:
|
||||
values: |
|
||||
deployment:
|
||||
type: controller
|
||||
mode: multi
|
||||
|
||||
database:
|
||||
mode: cloudnativepg
|
||||
|
||||
pangolin:
|
||||
config:
|
||||
app:
|
||||
dashboard_url: https://pangolin.example.com
|
||||
domains:
|
||||
domain1:
|
||||
base_domain: example.com
|
||||
gerbil:
|
||||
base_endpoint: vpn.example.com
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: traefik
|
||||
hosts:
|
||||
- host: pangolin.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: pangolin-tls
|
||||
hosts:
|
||||
- pangolin.example.com
|
||||
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: pangolin
|
||||
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
```
|
||||
|
||||
Apply the Application:
|
||||
|
||||
```bash
|
||||
kubectl apply -f pangolin-app.yaml
|
||||
```
|
||||
|
||||
### Step 3: Monitor in Argo CD
|
||||
|
||||
In the Argo CD UI, you should see the `pangolin` application. Argo CD will:
|
||||
|
||||
1. Fetch the Helm chart from `https://charts.fossorial.io`
|
||||
2. Render the chart with your inline `values`
|
||||
3. Create all resources in the `pangolin` namespace
|
||||
4. Continuously monitor for drift
|
||||
|
||||
### Step 4: Verify deployment
|
||||
|
||||
```bash
|
||||
# Check Argo CD status
|
||||
kubectl describe app -n argocd pangolin
|
||||
|
||||
# Check pod status
|
||||
kubectl get pods -n pangolin
|
||||
```
|
||||
|
||||
## Install Newt with Argo CD using Helm
|
||||
|
||||
### Step 1: Create Newt auth secret
|
||||
|
||||
```bash
|
||||
kubectl create secret generic newt-auth \
|
||||
-n pangolin \
|
||||
--from-literal=PANGOLIN_ENDPOINT=https://pangolin.example.com \
|
||||
--from-literal=NEWT_ID=<your-newt-id> \
|
||||
--from-literal=NEWT_SECRET=<your-newt-secret>
|
||||
```
|
||||
|
||||
### Step 2: Create Newt Application
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: newt
|
||||
namespace: argocd
|
||||
spec:
|
||||
project: default
|
||||
|
||||
source:
|
||||
repoURL: https://charts.fossorial.io
|
||||
chart: newt
|
||||
targetRevision: 1.4.0
|
||||
helm:
|
||||
values: |
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
auth:
|
||||
existingSecretName: newt-auth
|
||||
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: pangolin
|
||||
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
```
|
||||
|
||||
Apply:
|
||||
|
||||
```bash
|
||||
kubectl apply -f newt-app.yaml
|
||||
```
|
||||
|
||||
## Using Argo CD with Git repository
|
||||
|
||||
Instead of inline values, you can store configuration in Git and have Argo CD deploy from there:
|
||||
|
||||
### Repository structure
|
||||
|
||||
```
|
||||
infrastructure/
|
||||
├── apps/
|
||||
│ ├── pangolin/
|
||||
│ │ ├── values-base.yaml
|
||||
│ │ ├── values-prod.yaml
|
||||
│ │ └── app.yaml (Argo CD Application CRD)
|
||||
│ └── newt/
|
||||
│ ├── values.yaml
|
||||
│ └── app.yaml
|
||||
└── clusters/
|
||||
└── production/
|
||||
├── pangolin.yaml (reference to app)
|
||||
└── newt.yaml
|
||||
```
|
||||
|
||||
### Git-based Application
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: pangolin
|
||||
namespace: argocd
|
||||
spec:
|
||||
project: default
|
||||
|
||||
source:
|
||||
repoURL: https://github.com/my-org/infrastructure
|
||||
path: apps/pangolin
|
||||
targetRevision: main
|
||||
helm:
|
||||
valuesObject:
|
||||
deployment:
|
||||
type: controller
|
||||
mode: multi
|
||||
releaseName: pangolin
|
||||
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: pangolin
|
||||
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
```
|
||||
|
||||
Argo CD will watch the Git repository and auto-sync on changes to `apps/pangolin`.
|
||||
|
||||
## Using Argo CD with Kustomize
|
||||
|
||||
Deploy Pangolin using Kustomize overlays:
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: pangolin
|
||||
namespace: argocd
|
||||
spec:
|
||||
project: default
|
||||
|
||||
source:
|
||||
repoURL: https://github.com/my-org/infrastructure
|
||||
path: overlays/production
|
||||
targetRevision: main
|
||||
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: pangolin
|
||||
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
```
|
||||
|
||||
## Sync policies
|
||||
|
||||
### Automated sync
|
||||
|
||||
**prune: true**: Deletes resources in cluster that are no longer in Git
|
||||
|
||||
**selfHeal: true**: Resyncs if cluster drifts from Git (e.g., manual `kubectl apply`)
|
||||
|
||||
```yaml
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
allowEmpty: false # prevent accidental deletion of all resources
|
||||
```
|
||||
|
||||
### Manual sync
|
||||
|
||||
Sync only when you explicitly trigger it:
|
||||
|
||||
```yaml
|
||||
syncPolicy:
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
```
|
||||
|
||||
Manually sync:
|
||||
|
||||
```bash
|
||||
argocd app sync pangolin
|
||||
# or use UI
|
||||
```
|
||||
|
||||
## Advanced: ApplicationSet for multi-environment
|
||||
|
||||
Deploy Pangolin and Newt across multiple clusters or environments:
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: ApplicationSet
|
||||
metadata:
|
||||
name: pangolin-multienv
|
||||
namespace: argocd
|
||||
spec:
|
||||
generators:
|
||||
- list:
|
||||
elements:
|
||||
- cluster: production
|
||||
env: prod
|
||||
- cluster: staging
|
||||
env: staging
|
||||
template:
|
||||
metadata:
|
||||
name: pangolin-{{ .cluster }}
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://github.com/my-org/infrastructure
|
||||
path: clusters/{{ .cluster }}/pangolin
|
||||
targetRevision: main
|
||||
destination:
|
||||
name: '{{ .cluster }}'
|
||||
namespace: pangolin
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
```
|
||||
|
||||
## OCI Helm sources (if available)
|
||||
|
||||
If the Helm chart is available in an OCI registry:
|
||||
|
||||
```yaml
|
||||
source:
|
||||
repoURL: oci://registry.example.com/fossorial
|
||||
chart: pangolin
|
||||
targetRevision: 0.1.0-alpha.0
|
||||
helm:
|
||||
values: |
|
||||
# ... values ...
|
||||
```
|
||||
|
||||
OCI chart references work the same as traditional Helm repository references in Argo CD.
|
||||
|
||||
## Troubleshooting Argo CD deployments
|
||||
|
||||
### Check Application status
|
||||
|
||||
```bash
|
||||
kubectl describe app -n argocd pangolin
|
||||
kubectl get app -n argocd pangolin -o yaml
|
||||
```
|
||||
|
||||
### Check sync status
|
||||
|
||||
```bash
|
||||
argocd app get pangolin
|
||||
argocd app logs pangolin
|
||||
```
|
||||
|
||||
### Manual sync
|
||||
|
||||
```bash
|
||||
argocd app sync pangolin --force
|
||||
```
|
||||
|
||||
### Refresh from repository
|
||||
|
||||
```bash
|
||||
argocd app diff pangolin
|
||||
```
|
||||
|
||||
### Delete Application
|
||||
|
||||
```bash
|
||||
kubectl delete app -n argocd pangolin
|
||||
```
|
||||
|
||||
## Common patterns
|
||||
|
||||
### Different values per environment
|
||||
|
||||
Use multiple Applications:
|
||||
|
||||
```yaml
|
||||
# production/pangolin-app.yaml
|
||||
spec:
|
||||
source:
|
||||
helm:
|
||||
values: |
|
||||
resources:
|
||||
limits:
|
||||
cpu: 2000m
|
||||
memory: 2Gi
|
||||
replicas: 3
|
||||
|
||||
# staging/pangolin-app.yaml
|
||||
spec:
|
||||
source:
|
||||
helm:
|
||||
values: |
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
replicas: 1
|
||||
```
|
||||
|
||||
### Secrets with sealed-secrets
|
||||
|
||||
Use sealed-secrets to safely store secrets in Git:
|
||||
|
||||
```yaml
|
||||
# In Git
|
||||
apiVersion: bitnami.com/v1alpha1
|
||||
kind: SealedSecret
|
||||
metadata:
|
||||
name: newt-auth
|
||||
namespace: pangolin
|
||||
spec:
|
||||
encryptedData:
|
||||
PANGOLIN_ENDPOINT: AgC4F5qd...
|
||||
NEWT_ID: AgB9l2pK...
|
||||
NEWT_SECRET: AgDq3jX...
|
||||
```
|
||||
|
||||
Argo CD applies the sealed secret; the cluster decrypts it.
|
||||
|
||||
## Next steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="GitOps Overview" href="/self-host/manual/kubernetes/gitops/overview" icon="code-branch" />
|
||||
<Card title="Flux" href="/self-host/manual/kubernetes/gitops/flux" icon="code-branch" />
|
||||
<Card title="Pangolin Configuration" href="/self-host/manual/kubernetes/pangolin/configuration" icon="sliders" />
|
||||
<Card title="Troubleshooting" href="/self-host/manual/kubernetes/pangolin/troubleshooting" icon="circle-question" />
|
||||
</CardGroup>
|
||||
559
self-host/manual/kubernetes/gitops/flux.mdx
Normal file
559
self-host/manual/kubernetes/gitops/flux.mdx
Normal file
@@ -0,0 +1,559 @@
|
||||
---
|
||||
title: "Flux"
|
||||
description: "Deploy Pangolin and Newt using Flux for Git-driven GitOps reconciliation."
|
||||
---
|
||||
|
||||
import PangolinCloudTocCta from "/snippets/pangolin-cloud-toc-cta.mdx";
|
||||
|
||||
<PangolinCloudTocCta />
|
||||
|
||||
|
||||
Flux is a declarative GitOps tool that uses Kubernetes-native Custom Resources to manage deployments. This guide covers installing Pangolin and Newt using Flux.
|
||||
|
||||
## Flux overview
|
||||
|
||||
Flux watches your Git repository and continuous reconciles cluster state using Kubernetes CRDs:
|
||||
|
||||
- **HelmRepository**: Defines a Helm chart repository
|
||||
- **HelmRelease**: Declaratively manages a Helm chart deployment
|
||||
- **GitRepository**: References a Git repository
|
||||
- **Kustomization**: Reconciles Kustomize overlays
|
||||
- **OCIRepository**: References an OCI-based container registry (for Helm charts)
|
||||
|
||||
**Key benefits**:
|
||||
|
||||
- Native Kubernetes reconciliation (no separate UI needed, though one exists)
|
||||
- Lightweight footprint
|
||||
- Excellent for multi-cluster deployments
|
||||
- Declarative everything: sources, releases, dependencies
|
||||
|
||||
## Flux prerequisites
|
||||
|
||||
- Kubernetes 1.25+
|
||||
- `flux` CLI installed: [Flux install guide](https://fluxcd.io/flux/installation/)
|
||||
- Git repository for configuration (optional, can use built-in sources)
|
||||
- GitHub, GitLab, or other Git provider account (optional)
|
||||
|
||||
Install Flux CLI:
|
||||
|
||||
```bash
|
||||
# macOS/Linux with brew
|
||||
brew install flux
|
||||
|
||||
# or curl
|
||||
curl -s https://fluxcd.io/install.sh | sudo bash
|
||||
|
||||
# Verify
|
||||
flux --version
|
||||
```
|
||||
|
||||
## Install Flux on your cluster
|
||||
|
||||
### Option 1: Bootstrap Flux from GitHub
|
||||
|
||||
Flux `bootstrap` automatically installs Flux and configures Git sync:
|
||||
|
||||
```bash
|
||||
flux bootstrap github \
|
||||
--owner=my-org \
|
||||
--repo=infrastructure \
|
||||
--personal \
|
||||
--path=clusters/production
|
||||
```
|
||||
|
||||
This creates the Git repository structure and installs Flux components.
|
||||
|
||||
### Option 2: Manual Flux installation
|
||||
|
||||
```bash
|
||||
# Create flux-system namespace and install Flux
|
||||
flux install --namespace=flux-system --network-policy=true
|
||||
```
|
||||
|
||||
## Install Pangolin with Flux using HelmRelease
|
||||
|
||||
### Step 1: Create HelmRepository
|
||||
|
||||
Define the Fossorial Helm chart repository:
|
||||
|
||||
```yaml
|
||||
apiVersion: source.toolkit.fluxcd.io/v1beta2
|
||||
kind: HelmRepository
|
||||
metadata:
|
||||
name: fossorial
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 5m
|
||||
url: https://charts.fossorial.io
|
||||
```
|
||||
|
||||
Apply:
|
||||
|
||||
```bash
|
||||
kubectl apply -f helmrepo.yaml
|
||||
|
||||
# Verify
|
||||
kubectl get helmrepo -n flux-system
|
||||
```
|
||||
|
||||
### Step 2: Create Pangolin HelmRelease
|
||||
|
||||
```yaml
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: pangolin
|
||||
namespace: pangolin
|
||||
spec:
|
||||
interval: 10m
|
||||
chart:
|
||||
spec:
|
||||
chart: pangolin
|
||||
version: 0.1.0-alpha.0 # or use ~0.1.0 for auto-upgrades
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: fossorial
|
||||
namespace: flux-system
|
||||
|
||||
install:
|
||||
crds: Create
|
||||
upgrade:
|
||||
crds: CreateReplace
|
||||
|
||||
values:
|
||||
deployment:
|
||||
type: controller
|
||||
mode: multi
|
||||
|
||||
database:
|
||||
mode: cloudnativepg
|
||||
|
||||
pangolin:
|
||||
config:
|
||||
app:
|
||||
dashboard_url: https://pangolin.example.com
|
||||
domains:
|
||||
domain1:
|
||||
base_domain: example.com
|
||||
gerbil:
|
||||
base_endpoint: vpn.example.com
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: traefik
|
||||
hosts:
|
||||
- host: pangolin.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: pangolin-tls
|
||||
hosts:
|
||||
- pangolin.example.com
|
||||
```
|
||||
|
||||
Create namespace:
|
||||
|
||||
```bash
|
||||
kubectl create namespace pangolin
|
||||
```
|
||||
|
||||
Apply:
|
||||
|
||||
```bash
|
||||
kubectl apply -f pangolin-helmrelease.yaml
|
||||
```
|
||||
|
||||
### Step 3: Monitor reconciliation
|
||||
|
||||
```bash
|
||||
# Check HelmRelease status
|
||||
kubectl get helmrelease -n pangolin
|
||||
|
||||
# Watch live
|
||||
kubectl get helmrelease -n pangolin -w
|
||||
|
||||
# Describe for details
|
||||
kubectl describe helmrelease pangolin -n pangolin
|
||||
|
||||
# Check Flux logs
|
||||
flux logs --all-namespaces --follow
|
||||
```
|
||||
|
||||
## Install Newt with Flux using HelmRelease
|
||||
|
||||
### Step 1: Create Newt auth secret
|
||||
|
||||
```bash
|
||||
kubectl create secret generic newt-auth \
|
||||
-n pangolin \
|
||||
--from-literal=PANGOLIN_ENDPOINT=https://pangolin.example.com \
|
||||
--from-literal=NEWT_ID=<your-newt-id> \
|
||||
--from-literal=NEWT_SECRET=<your-newt-secret>
|
||||
```
|
||||
|
||||
### Step 2: Create Newt HelmRelease
|
||||
|
||||
```yaml
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: newt
|
||||
namespace: pangolin
|
||||
spec:
|
||||
interval: 10m
|
||||
chart:
|
||||
spec:
|
||||
chart: newt
|
||||
version: 1.4.0
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: fossorial
|
||||
namespace: flux-system
|
||||
|
||||
values:
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
auth:
|
||||
existingSecretName: newt-auth
|
||||
```
|
||||
|
||||
Apply:
|
||||
|
||||
```bash
|
||||
kubectl apply -f newt-helmrelease.yaml
|
||||
```
|
||||
|
||||
### Step 3: Verify
|
||||
|
||||
```bash
|
||||
kubectl get helmrelease -n pangolin
|
||||
kubectl describe helmrelease newt -n pangolin
|
||||
```
|
||||
|
||||
## Using Flux with Git repository (GitOps)
|
||||
|
||||
Store Flux configuration in Git and have Flux automatically reconcile changes:
|
||||
|
||||
### Repository structure
|
||||
|
||||
```
|
||||
infrastructure/
|
||||
├── clusters/
|
||||
│ └── production/
|
||||
│ ├── flux-system/
|
||||
│ │ └── gotk-components.yaml (auto-generated)
|
||||
│ ├── pangolin/
|
||||
│ │ ├── helmrepo.yaml
|
||||
│ │ ├── pangolin-helmrelease.yaml
|
||||
│ │ └── newt-helmrelease.yaml
|
||||
│ └── kustomization.yaml
|
||||
└── apps/
|
||||
├── pangolin/
|
||||
│ └── values.yaml
|
||||
└── newt/
|
||||
└── values.yaml
|
||||
```
|
||||
|
||||
### GitRepository for configuration
|
||||
|
||||
```yaml
|
||||
apiVersion: source.toolkit.fluxcd.io/v1beta2
|
||||
kind: GitRepository
|
||||
metadata:
|
||||
name: infrastructure
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 1m
|
||||
url: https://github.com/my-org/infrastructure
|
||||
ref:
|
||||
branch: main
|
||||
```
|
||||
|
||||
### Kustomization for syncing
|
||||
|
||||
```yaml
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: production
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: infrastructure
|
||||
path: ./clusters/production
|
||||
prune: true
|
||||
wait: true
|
||||
```
|
||||
|
||||
Flux watches `clusters/production` in Git and auto-applies all resources.
|
||||
|
||||
## Using Flux with Kustomize overlays
|
||||
|
||||
Manage environment-specific overlays with Flux:
|
||||
|
||||
### Repository structure
|
||||
|
||||
```
|
||||
overlays/
|
||||
├── dev/
|
||||
│ ├── kustomization.yaml
|
||||
│ └── pangolin-patch.yaml
|
||||
├── staging/
|
||||
│ └── kustomization.yaml
|
||||
└── prod/
|
||||
├── kustomization.yaml
|
||||
└── pangolin-patch.yaml
|
||||
```
|
||||
|
||||
### Kustomization resource
|
||||
|
||||
```yaml
|
||||
apiVersion: kustomize.toolkit.fluxcd.io/v1
|
||||
kind: Kustomization
|
||||
metadata:
|
||||
name: pangolin-prod
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 10m
|
||||
sourceRef:
|
||||
kind: GitRepository
|
||||
name: infrastructure
|
||||
path: ./overlays/prod
|
||||
prune: true
|
||||
wait: true
|
||||
```
|
||||
|
||||
Flux builds and applies the Kustomize overlay automatically.
|
||||
|
||||
## Using Flux with OCI Helm charts
|
||||
|
||||
If Helm charts are available in an OCI registry:
|
||||
|
||||
```yaml
|
||||
apiVersion: source.toolkit.fluxcd.io/v1beta2
|
||||
kind: OCIRepository
|
||||
metadata:
|
||||
name: fossorial-oci
|
||||
namespace: flux-system
|
||||
spec:
|
||||
interval: 5m
|
||||
url: oci://registry.example.com/fossorial
|
||||
|
||||
---
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: pangolin
|
||||
namespace: pangolin
|
||||
spec:
|
||||
interval: 10m
|
||||
chart:
|
||||
spec:
|
||||
chart: pangolin
|
||||
version: 0.1.0-alpha.0
|
||||
sourceRef:
|
||||
kind: OCIRepository
|
||||
name: fossorial-oci
|
||||
namespace: flux-system
|
||||
values:
|
||||
# ... values ...
|
||||
```
|
||||
|
||||
## Advanced: Dependency ordering
|
||||
|
||||
Order HelmReleases to install dependencies first:
|
||||
|
||||
```yaml
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: cert-manager
|
||||
namespace: cert-manager
|
||||
spec:
|
||||
interval: 10m
|
||||
chart:
|
||||
spec:
|
||||
chart: cert-manager
|
||||
# ...
|
||||
|
||||
---
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: pangolin
|
||||
namespace: pangolin
|
||||
spec:
|
||||
interval: 10m
|
||||
dependsOn:
|
||||
- name: cert-manager
|
||||
namespace: cert-manager
|
||||
chart:
|
||||
spec:
|
||||
chart: pangolin
|
||||
# ...
|
||||
```
|
||||
|
||||
Flux ensures `cert-manager` reconciles before `pangolin`.
|
||||
|
||||
## Advanced: valuesFrom ConfigMap/Secret
|
||||
|
||||
Store values in ConfigMaps or Secrets, referenced from HelmRelease:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: pangolin-values
|
||||
namespace: pangolin
|
||||
data:
|
||||
values.yaml: |
|
||||
deployment:
|
||||
type: controller
|
||||
mode: multi
|
||||
|
||||
---
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: pangolin
|
||||
namespace: pangolin
|
||||
spec:
|
||||
interval: 10m
|
||||
chart:
|
||||
spec:
|
||||
chart: pangolin
|
||||
# ...
|
||||
valuesFrom:
|
||||
- kind: ConfigMap
|
||||
name: pangolin-values
|
||||
```
|
||||
|
||||
Flux extracts values from the ConfigMap and applies them to the HelmRelease.
|
||||
|
||||
## Troubleshooting Flux
|
||||
|
||||
### Check Flux components
|
||||
|
||||
```bash
|
||||
kubectl get deployments -n flux-system
|
||||
flux check --all-namespaces
|
||||
```
|
||||
|
||||
### Check HelmRelease status
|
||||
|
||||
```bash
|
||||
kubectl get helmrelease -n pangolin
|
||||
kubectl describe helmrelease pangolin -n pangolin
|
||||
kubectl get helmrelease pangolin -n pangolin -o yaml
|
||||
```
|
||||
|
||||
### View reconciliation logs
|
||||
|
||||
```bash
|
||||
flux logs --all-namespaces --follow
|
||||
|
||||
# Specific resource
|
||||
kubectl logs -n pangolin deployment/helm-operator -f
|
||||
```
|
||||
|
||||
### Manual reconciliation
|
||||
|
||||
```bash
|
||||
flux reconcile helmrelease pangolin -n pangolin
|
||||
flux reconcile kustomization production -n flux-system
|
||||
```
|
||||
|
||||
### Suspend reconciliation
|
||||
|
||||
```bash
|
||||
flux suspend helmrelease pangolin -n pangolin
|
||||
```
|
||||
|
||||
### Resume reconciliation
|
||||
|
||||
```bash
|
||||
flux resume helmrelease pangolin -n pangolin
|
||||
```
|
||||
|
||||
## Multi-environment example
|
||||
|
||||
### Bootstrap multiple clusters
|
||||
|
||||
```bash
|
||||
# Production cluster
|
||||
flux bootstrap github \
|
||||
--owner=my-org \
|
||||
--repo=infrastructure \
|
||||
--personal \
|
||||
--path=clusters/production
|
||||
|
||||
# Staging cluster (from different checkout)
|
||||
flux bootstrap github \
|
||||
--owner=my-org \
|
||||
--repo=infrastructure \
|
||||
--personal \
|
||||
--path=clusters/staging
|
||||
```
|
||||
|
||||
Each cluster reconciles its own `clusters/*/` directory.
|
||||
|
||||
### Repository structure
|
||||
|
||||
```
|
||||
clusters/
|
||||
├── production/
|
||||
│ ├── kustomization.yaml
|
||||
│ └── pangolin/
|
||||
│ ├── helmrepo.yaml
|
||||
│ └── helmrelease.yaml (prod values)
|
||||
├── staging/
|
||||
│ ├── kustomization.yaml
|
||||
│ └── pangolin/
|
||||
│ ├── helmrepo.yaml
|
||||
│ └── helmrelease.yaml (staging values)
|
||||
└── dev/
|
||||
├── kustomization.yaml
|
||||
└── pangolin/
|
||||
└── helmrelease.yaml (dev values)
|
||||
```
|
||||
|
||||
Each environment's HelmRelease uses environment-specific values.
|
||||
|
||||
## Important notes
|
||||
|
||||
### CRD management
|
||||
|
||||
When using Flux with Helm charts that include CRDs:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
install:
|
||||
crds: Create # Create CRDs on first install
|
||||
upgrade:
|
||||
crds: CreateReplace # Update CRDs on upgrade
|
||||
```
|
||||
|
||||
### Namespace creation
|
||||
|
||||
Flux automatically creates namespaces if they don't exist. Ensure appropriate RBAC.
|
||||
|
||||
### GitOps best practices
|
||||
|
||||
- Use branches for different environments
|
||||
- Protect production branches with review requirements
|
||||
- Store secrets using sealed-secrets or external-secrets
|
||||
- Track all changes in Git
|
||||
- Use consistent naming conventions
|
||||
|
||||
## Next steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="GitOps Overview" href="/self-host/manual/kubernetes/gitops/overview" icon="code-branch" />
|
||||
<Card title="Argo CD" href="/self-host/manual/kubernetes/gitops/argocd" icon="code-branch" />
|
||||
<Card title="Pangolin Configuration" href="/self-host/manual/kubernetes/pangolin/configuration" icon="sliders" />
|
||||
<Card title="Troubleshooting" href="/self-host/manual/kubernetes/pangolin/troubleshooting" icon="circle-question" />
|
||||
</CardGroup>
|
||||
351
self-host/manual/kubernetes/gitops/overview.mdx
Normal file
351
self-host/manual/kubernetes/gitops/overview.mdx
Normal file
@@ -0,0 +1,351 @@
|
||||
---
|
||||
title: "GitOps Overview"
|
||||
description: "Git-driven Kubernetes deployments for Pangolin and Newt using Argo CD or Flux."
|
||||
---
|
||||
|
||||
import PangolinCloudTocCta from "/snippets/pangolin-cloud-toc-cta.mdx";
|
||||
|
||||
<PangolinCloudTocCta />
|
||||
|
||||
|
||||
GitOps is a declarative approach to infrastructure management where your Git repository is the single source of truth for cluster state. Changes go through Git; the GitOps tool automatically reconciles the cluster to match.
|
||||
|
||||
## What is GitOps?
|
||||
|
||||
GitOps reconciliation loop:
|
||||
|
||||
<Steps>
|
||||
<Step title="Declare desired state in Git">
|
||||
**Git repository** contains desired state (manifests, Helm values, Kustomize overlays).
|
||||
</Step>
|
||||
<Step title="GitOps controller watches source">
|
||||
**GitOps tool** (Argo CD or Flux) watches the Git repository.
|
||||
</Step>
|
||||
<Step title="Detect changes and drift">
|
||||
The controller detects new commits or drift between Git and the live cluster.
|
||||
</Step>
|
||||
<Step title="Reconcile cluster">
|
||||
The controller syncs cluster state to match Git state.
|
||||
</Step>
|
||||
<Step title="Continuous convergence">
|
||||
**Result**: Cluster stays aligned with the declared Git configuration.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Benefits
|
||||
|
||||
- **Version control**: All infrastructure changes tracked in Git
|
||||
- **Audit trail**: See who changed what and when
|
||||
- **Rollback**: Revert to previous state by reverting Git commits
|
||||
- **Automation**: No manual `kubectl apply` commands needed
|
||||
- **Drift detection**: Automatic alerts if cluster diverges from Git
|
||||
|
||||
## GitOps tools for Kubernetes
|
||||
|
||||
### Argo CD
|
||||
|
||||
- **UI**: Web-based dashboard for monitoring and manual syncs
|
||||
- **Approach**: External reconciler (watches Git, applies to cluster)
|
||||
- **Supports**: Helm charts, Kustomize overlays, raw YAML
|
||||
- **Best for**: Teams who want GitOps with a UI, hybrid manual/automated workflows
|
||||
|
||||
**Use Argo CD if**:
|
||||
- You want a visual dashboard
|
||||
- You need frequent manual sync capabilities
|
||||
- You're already using Argo CD for other workloads
|
||||
|
||||
See: [Argo CD Install Guide](/self-host/manual/kubernetes/gitops/argocd)
|
||||
|
||||
### Flux
|
||||
|
||||
- **CRDs**: Kubernetes-native Custom Resources (HelmRelease, Kustomization, GitRepository)
|
||||
- **Approach**: Declarative reconciliation using Kubernetes resources
|
||||
- **Supports**: Helm charts, Kustomize overlays, raw YAML, OCI registries
|
||||
- **Best for**: Teams who want declarative Kubernetes-way GitOps, lightweight controllers
|
||||
|
||||
**Use Flux if**:
|
||||
- You prefer Kubernetes-native CRDs
|
||||
- You want a lightweight, modern GitOps tool
|
||||
- You're already using Flux for other workloads
|
||||
|
||||
See: [Flux Install Guide](/self-host/manual/kubernetes/gitops/flux)
|
||||
|
||||
## Recommended repository structure
|
||||
|
||||
For multi-environment Pangolin/Newt deployments, organize your Git repository like this:
|
||||
|
||||
```
|
||||
my-org/infrastructure/
|
||||
├── clusters/
|
||||
│ ├── production/
|
||||
│ │ ├── pangolin/
|
||||
│ │ │ ├── values.yaml
|
||||
│ │ │ └── kustomization.yaml (if using Kustomize)
|
||||
│ │ └── newt/
|
||||
│ │ ├── values.yaml
|
||||
│ │ └── kustomization.yaml
|
||||
│ ├── staging/
|
||||
│ │ ├── pangolin/
|
||||
│ │ └── newt/
|
||||
│ └── dev/
|
||||
│ ├── pangolin/
|
||||
│ └── newt/
|
||||
├── apps/
|
||||
│ ├── pangolin/
|
||||
│ │ ├── helm/
|
||||
│ │ │ ├── values-base.yaml
|
||||
│ │ │ ├── values-prod.yaml
|
||||
│ │ │ └── values-staging.yaml
|
||||
│ │ └── kustomize/
|
||||
│ │ ├── base/
|
||||
│ │ └── overlays/
|
||||
│ └── newt/
|
||||
│ ├── helm/
|
||||
│ └── kustomize/
|
||||
└── .gitignore
|
||||
```
|
||||
|
||||
**Pattern**:
|
||||
- `clusters/` → environment-specific configuration
|
||||
- `apps/` → shared, reusable application configuration
|
||||
- Environment overlays layer on top of app definitions
|
||||
|
||||
## Secrets in GitOps
|
||||
|
||||
<Warning>
|
||||
**Never commit plaintext secrets to Git.** Use secret management tools instead.
|
||||
</Warning>
|
||||
|
||||
Options for managing secrets in GitOps:
|
||||
|
||||
### Sealed Secrets
|
||||
|
||||
- **Tool**: [sealed-secrets](https://github.com/bitnami-labs/sealed-secrets)
|
||||
- **How**: Encrypt secrets with cluster-specific key; safe to commit encrypted secrets
|
||||
- **Decrypt**: Only the cluster can decrypt (uses private key)
|
||||
|
||||
```bash
|
||||
# Encrypt a secret
|
||||
echo -n mypassword | kubeseal -f - > secret.yaml
|
||||
|
||||
# Git tracks encrypted secret.yaml
|
||||
# Cluster auto-decrypts on apply
|
||||
```
|
||||
|
||||
### External Secrets Operator
|
||||
|
||||
- **Tool**: [external-secrets](https://external-secrets.io/)
|
||||
- **How**: Reference secrets stored in external vault (AWS Secrets Manager, Azure Key Vault, HashiCorp Vault)
|
||||
- **Git**: Stores reference only, not secret values
|
||||
|
||||
```yaml
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: SecretStore
|
||||
metadata:
|
||||
name: vault-backend
|
||||
spec:
|
||||
provider:
|
||||
vault:
|
||||
server: "https://vault.example.com"
|
||||
```
|
||||
|
||||
### SOPS (Secrets Operations)
|
||||
|
||||
- **Tool**: [SOPS](https://github.com/mozilla/sops)
|
||||
- **How**: Encrypt YAML files; decrypt at deploy time
|
||||
- **Git**: Stores encrypted files
|
||||
|
||||
```bash
|
||||
sops --encrypt secrets.yaml > secrets.enc.yaml
|
||||
# Commit secrets.enc.yaml; tool decrypts on apply
|
||||
```
|
||||
|
||||
### Cloud Provider Secrets
|
||||
|
||||
- **AWS**: Use AWS Secrets Manager or Parameter Store with IRSA (IAM Roles for Service Accounts)
|
||||
- **Azure**: Use Azure Key Vault with pod identity
|
||||
- **GCP**: Use Google Secret Manager with workload identity
|
||||
|
||||
<Tip>
|
||||
Choose a secret management strategy **before** setting up GitOps. Seal secrets once; keep approach consistent.
|
||||
</Tip>
|
||||
|
||||
## GitOps workflow example
|
||||
|
||||
### 1. Set up Git repository
|
||||
|
||||
```bash
|
||||
git clone https://github.com/my-org/infrastructure.git
|
||||
cd infrastructure
|
||||
mkdir -p clusters/production/pangolin
|
||||
cd clusters/production/pangolin
|
||||
```
|
||||
|
||||
### 2. Create configuration
|
||||
|
||||
```bash
|
||||
# values.yaml with Pangolin config
|
||||
cat > values.yaml <<EOF
|
||||
deployment:
|
||||
type: controller
|
||||
mode: multi
|
||||
database:
|
||||
mode: cloudnativepg
|
||||
pangolin:
|
||||
config:
|
||||
app:
|
||||
dashboard_url: https://pangolin.example.com
|
||||
domains:
|
||||
domain1:
|
||||
base_domain: example.com
|
||||
gerbil:
|
||||
base_endpoint: vpn.example.com
|
||||
EOF
|
||||
|
||||
git add values.yaml
|
||||
git commit -m "Add production Pangolin config"
|
||||
git push
|
||||
```
|
||||
|
||||
### 3. Install GitOps tool
|
||||
|
||||
```bash
|
||||
# For Argo CD
|
||||
kubectl create namespace argocd
|
||||
helm repo add argo https://argoproj.github.io/argo-helm
|
||||
helm install argocd argo/argo-cd -n argocd
|
||||
|
||||
# For Flux
|
||||
flux bootstrap github \
|
||||
--owner=my-org \
|
||||
--repo=infrastructure \
|
||||
--personal \
|
||||
--path=clusters/production
|
||||
```
|
||||
|
||||
### 4. Create Application/HelmRelease
|
||||
|
||||
**With Argo CD**:
|
||||
|
||||
```yaml
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: pangolin
|
||||
namespace: argocd
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: https://github.com/my-org/infrastructure
|
||||
targetRevision: main
|
||||
path: clusters/production/pangolin
|
||||
helm:
|
||||
values: values.yaml
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: pangolin
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
```
|
||||
|
||||
**With Flux**:
|
||||
|
||||
```yaml
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: pangolin
|
||||
namespace: pangolin
|
||||
spec:
|
||||
interval: 10m
|
||||
chart:
|
||||
spec:
|
||||
chart: pangolin
|
||||
sourceRef:
|
||||
kind: HelmRepository
|
||||
name: fossorial
|
||||
namespace: flux-system
|
||||
values:
|
||||
deployment:
|
||||
type: controller
|
||||
mode: multi
|
||||
```
|
||||
|
||||
### 5. Push to Git
|
||||
|
||||
```bash
|
||||
git add pangolin-app.yaml
|
||||
git commit -m "Add Argo CD Application for Pangolin"
|
||||
git push
|
||||
```
|
||||
|
||||
**Result**: GitOps tool automatically detects the new Application and begins reconciliation.
|
||||
|
||||
### 6. Monitor
|
||||
|
||||
**Argo CD**:
|
||||
|
||||
```bash
|
||||
# Port-forward to UI
|
||||
kubectl port-forward -n argocd svc/argocd-server 8080:443
|
||||
|
||||
# Visit https://localhost:8080
|
||||
```
|
||||
|
||||
**Flux**:
|
||||
|
||||
```bash
|
||||
# Check reconciliation status
|
||||
flux get all
|
||||
|
||||
# View logs
|
||||
flux logs --all-namespaces --follow
|
||||
```
|
||||
|
||||
## Common use cases
|
||||
|
||||
### Multi-environment deployments
|
||||
|
||||
Use Git branches, directories, or environments to manage dev, staging, production:
|
||||
|
||||
```
|
||||
clusters/dev/pangolin → helm values for dev
|
||||
clusters/staging/pangolin → helm values for staging
|
||||
clusters/production/pangolin → helm values for production
|
||||
```
|
||||
|
||||
Each environment syncs independently.
|
||||
|
||||
### Automatic deployments on chart update
|
||||
|
||||
Flux or Argo CD can watch a Helm repository and auto-update when a new chart version is released:
|
||||
|
||||
```yaml
|
||||
apiVersion: helm.toolkit.fluxcd.io/v2
|
||||
kind: HelmRelease
|
||||
metadata:
|
||||
name: pangolin
|
||||
spec:
|
||||
chart:
|
||||
spec:
|
||||
chart: pangolin
|
||||
version: ">=0.1.0" # auto-upgrade to latest 0.1.x
|
||||
```
|
||||
|
||||
### Drift detection and remediation
|
||||
|
||||
Argo CD and Flux both support continuous drift detection:
|
||||
|
||||
- **Argo CD**: Detects drift on demand or continuously; can auto-sync on drift
|
||||
- **Flux**: Reconciles on interval; rolls back manual cluster changes
|
||||
|
||||
## Next steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Argo CD Install" href="/self-host/manual/kubernetes/gitops/argocd" icon="code-branch" />
|
||||
<Card title="Flux Install" href="/self-host/manual/kubernetes/gitops/flux" icon="code-branch" />
|
||||
<Card title="Helm Quick-Start" href="/self-host/manual/kubernetes/helm" icon="box" />
|
||||
<Card title="Kustomize Quick-Start" href="/self-host/manual/kubernetes/kustomize" icon="layer-group" />
|
||||
</CardGroup>
|
||||
399
self-host/manual/kubernetes/helm.mdx
Normal file
399
self-host/manual/kubernetes/helm.mdx
Normal file
@@ -0,0 +1,399 @@
|
||||
---
|
||||
title: "Helm"
|
||||
description: "Kubernetes installation using Helm charts for Pangolin and Newt."
|
||||
---
|
||||
|
||||
import PangolinCloudTocCta from "/snippets/pangolin-cloud-toc-cta.mdx";
|
||||
|
||||
<PangolinCloudTocCta />
|
||||
|
||||
|
||||
Helm is the recommended method for standard Kubernetes installations of Pangolin and Newt.
|
||||
|
||||
Use Helm when you want a chart-based workflow for installing, upgrading, rolling back, and removing releases from your cluster.
|
||||
|
||||
## Helm repository setup
|
||||
|
||||
Add the Fossorial Helm chart repository:
|
||||
|
||||
```bash
|
||||
helm repo add fossorial https://charts.fossorial.io
|
||||
helm repo update fossorial
|
||||
```
|
||||
|
||||
Search for available charts:
|
||||
|
||||
```bash
|
||||
helm search repo fossorial
|
||||
```
|
||||
|
||||
The classic Helm repository flow is the default path for most installations:
|
||||
|
||||
```bash
|
||||
helm install my-newt fossorial/newt
|
||||
helm install my-pangolin fossorial/pangolin
|
||||
```
|
||||
|
||||
## Installation overview
|
||||
|
||||
A typical Helm installation flow looks like this:
|
||||
|
||||
<Steps>
|
||||
<Step title="Create namespace and labels">
|
||||
Create the namespace manually and apply required labels or annotations.
|
||||
</Step>
|
||||
<Step title="Prepare values files">
|
||||
Create a `values.yaml` file for each release (`values-pangolin.yaml`, `values-newt.yaml`).
|
||||
</Step>
|
||||
<Step title="Install with Helm">
|
||||
Install with `helm upgrade --install` to support first install and future updates with the same command.
|
||||
</Step>
|
||||
<Step title="Verify release and resources">
|
||||
Confirm Helm release status and Kubernetes resources after deployment.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Info>
|
||||
It is recommended to create the namespace explicitly before installation. This allows you to apply Pod Security Admission labels, policy labels, annotations, or other cluster-specific metadata before the chart creates workloads.
|
||||
</Info>
|
||||
|
||||
For detailed installation steps, see:
|
||||
|
||||
* [Pangolin Helm Quick-Start](/self-host/manual/kubernetes/pangolin/helm) — Install Pangolin
|
||||
* [Newt Helm Quick-Start](/self-host/manual/kubernetes/newt/helm) — Install Newt
|
||||
|
||||
## Install command patterns
|
||||
|
||||
<CodeGroup>
|
||||
```bash Classic Helm repository
|
||||
helm upgrade --install pangolin fossorial/pangolin \
|
||||
--namespace pangolin \
|
||||
--values values-pangolin.yaml
|
||||
|
||||
helm upgrade --install newt fossorial/newt \
|
||||
--namespace pangolin \
|
||||
--values values-newt.yaml
|
||||
```
|
||||
|
||||
```bash OCI (GHCR)
|
||||
helm upgrade --install pangolin oci://ghcr.io/fosrl/helm-charts/pangolin \
|
||||
--version 0.1.0-alpha.0 \
|
||||
--namespace pangolin \
|
||||
--values values-pangolin.yaml
|
||||
|
||||
helm upgrade --install newt oci://ghcr.io/fosrl/helm-charts/newt \
|
||||
--version 1.4.0 \
|
||||
--namespace pangolin \
|
||||
--values values-newt.yaml
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Namespace preparation
|
||||
|
||||
Create the namespace before installing the chart:
|
||||
|
||||
```bash
|
||||
kubectl create namespace pangolin
|
||||
```
|
||||
|
||||
If your cluster uses Pod Security Admission or namespace-based policies, apply the required labels before installation.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
kubectl label namespace pangolin \
|
||||
pod-security.kubernetes.io/enforce=baseline \
|
||||
pod-security.kubernetes.io/audit=restricted \
|
||||
pod-security.kubernetes.io/warn=restricted
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Pangolin deployments that include Gerbil require permissions that are not compatible with a restricted namespace profile, because Gerbil manages WireGuard and requires capabilities such as `NET_ADMIN`.
|
||||
</Warning>
|
||||
|
||||
For more details, see [Prerequisites](/self-host/manual/kubernetes/prerequisites).
|
||||
|
||||
## Install with a values file
|
||||
|
||||
Both charts use values files for configuration.
|
||||
|
||||
Pangolin example:
|
||||
|
||||
```bash
|
||||
helm upgrade --install pangolin fossorial/pangolin \
|
||||
--namespace pangolin \
|
||||
--values values-pangolin.yaml
|
||||
```
|
||||
|
||||
Newt example:
|
||||
|
||||
```bash
|
||||
helm upgrade --install newt fossorial/newt \
|
||||
--namespace pangolin \
|
||||
--values values-newt.yaml
|
||||
```
|
||||
|
||||
Using `helm upgrade --install` keeps the command usable for both the first installation and later configuration changes.
|
||||
|
||||
<Note>
|
||||
Do not use `--create-namespace` if you need custom namespace labels or annotations. Create the namespace first and then run Helm against that namespace.
|
||||
</Note>
|
||||
|
||||
## Values and configuration
|
||||
|
||||
Keep reusable configuration in a values file:
|
||||
|
||||
```bash
|
||||
helm upgrade --install pangolin fossorial/pangolin \
|
||||
--namespace pangolin \
|
||||
--values values-pangolin.yaml
|
||||
```
|
||||
|
||||
Use `--set` only for small tests or temporary overrides:
|
||||
|
||||
```bash
|
||||
helm upgrade --install pangolin fossorial/pangolin \
|
||||
--namespace pangolin \
|
||||
--set example.key=value
|
||||
```
|
||||
|
||||
Common value sources:
|
||||
|
||||
* `values-pangolin.yaml` for Pangolin.
|
||||
* `values-newt.yaml` for Newt.
|
||||
* Kubernetes Secrets for credentials.
|
||||
* Existing cluster resources such as TLS secrets, StorageClasses, or ingress controllers.
|
||||
|
||||
Full configuration options are documented here:
|
||||
|
||||
* [Pangolin Configuration](/self-host/manual/kubernetes/pangolin/configuration)
|
||||
* [Newt Configuration](/self-host/manual/kubernetes/newt/configuration)
|
||||
|
||||
## Artifact Hub and chart discovery
|
||||
|
||||
The Fossorial charts can be installed from the Fossorial Helm repository:
|
||||
|
||||
```bash
|
||||
helm repo add fossorial https://charts.fossorial.io
|
||||
helm repo update fossorial
|
||||
helm search repo fossorial
|
||||
```
|
||||
|
||||
Artifact Hub can also be used to discover published chart metadata, available versions, install commands, and repository information.
|
||||
|
||||
<Note>
|
||||
Always verify the chart name, chart version, and repository URL before copying install commands into production.
|
||||
</Note>
|
||||
|
||||
## OCI-based charts
|
||||
|
||||
OCI is not a separate installation method. It only changes where Helm pulls the chart from.
|
||||
|
||||
For Pangolin and Newt, OCI chart publishing is available in GHCR:
|
||||
|
||||
* Newt: `oci://ghcr.io/fosrl/helm-charts/newt`
|
||||
* Pangolin: `oci://ghcr.io/fosrl/helm-charts/pangolin`
|
||||
|
||||
You still use Helm in the same way: choose a chart, select a version, provide values, and install the release.
|
||||
|
||||
### Pull OCI charts
|
||||
|
||||
Newt example:
|
||||
|
||||
```bash
|
||||
helm pull oci://ghcr.io/fosrl/helm-charts/newt \
|
||||
--version 1.4.0
|
||||
```
|
||||
|
||||
Pangolin example:
|
||||
|
||||
```bash
|
||||
helm pull oci://ghcr.io/fosrl/helm-charts/pangolin \
|
||||
--version 0.1.0-alpha.0
|
||||
```
|
||||
|
||||
### Install from OCI
|
||||
|
||||
Newt example:
|
||||
|
||||
```bash
|
||||
helm upgrade --install newt oci://ghcr.io/fosrl/helm-charts/newt \
|
||||
--version 1.4.0 \
|
||||
--namespace pangolin \
|
||||
--values values-newt.yaml
|
||||
```
|
||||
|
||||
Pangolin example:
|
||||
|
||||
```bash
|
||||
helm upgrade --install pangolin oci://ghcr.io/fosrl/helm-charts/pangolin \
|
||||
--version 0.1.0-alpha.0 \
|
||||
--namespace pangolin \
|
||||
--values values-pangolin.yaml
|
||||
```
|
||||
|
||||
<Info>
|
||||
Use the classic Helm repository when you want the normal `helm repo add` and `helm search repo` workflow. Use OCI when you want to pull charts directly from GHCR or when your deployment tooling expects OCI chart references.
|
||||
</Info>
|
||||
|
||||
## Upgrade and maintenance
|
||||
|
||||
### Update the classic Helm repository
|
||||
|
||||
```bash
|
||||
helm repo update fossorial
|
||||
```
|
||||
|
||||
This step is only needed when using the classic Helm repository. OCI installs pull the chart by OCI reference and version.
|
||||
|
||||
### Upgrade Pangolin
|
||||
|
||||
Classic Helm repository:
|
||||
|
||||
```bash
|
||||
helm upgrade pangolin fossorial/pangolin \
|
||||
--namespace pangolin \
|
||||
--values values-pangolin.yaml
|
||||
```
|
||||
|
||||
OCI:
|
||||
|
||||
```bash
|
||||
helm upgrade pangolin oci://ghcr.io/fosrl/helm-charts/pangolin \
|
||||
--version 0.1.0-alpha.0 \
|
||||
--namespace pangolin \
|
||||
--values values-pangolin.yaml
|
||||
```
|
||||
|
||||
### Upgrade Newt
|
||||
|
||||
Classic Helm repository:
|
||||
|
||||
```bash
|
||||
helm upgrade newt fossorial/newt \
|
||||
--namespace pangolin \
|
||||
--values values-newt.yaml
|
||||
```
|
||||
|
||||
OCI:
|
||||
|
||||
```bash
|
||||
helm upgrade newt oci://ghcr.io/fosrl/helm-charts/newt \
|
||||
--version 1.4.0 \
|
||||
--namespace pangolin \
|
||||
--values values-newt.yaml
|
||||
```
|
||||
|
||||
### Check release status
|
||||
|
||||
```bash
|
||||
helm status pangolin --namespace pangolin
|
||||
helm history pangolin --namespace pangolin
|
||||
```
|
||||
|
||||
```bash
|
||||
helm status newt --namespace pangolin
|
||||
helm history newt --namespace pangolin
|
||||
```
|
||||
|
||||
### View rendered manifests
|
||||
|
||||
```bash
|
||||
helm get manifest pangolin --namespace pangolin
|
||||
```
|
||||
|
||||
```bash
|
||||
helm get manifest newt --namespace pangolin
|
||||
```
|
||||
|
||||
### View applied values
|
||||
|
||||
```bash
|
||||
helm get values pangolin --namespace pangolin
|
||||
```
|
||||
|
||||
```bash
|
||||
helm get values newt --namespace pangolin
|
||||
```
|
||||
|
||||
### Roll back a release
|
||||
|
||||
```bash
|
||||
helm rollback pangolin <revision> --namespace pangolin
|
||||
```
|
||||
|
||||
```bash
|
||||
helm rollback newt <revision> --namespace pangolin
|
||||
```
|
||||
|
||||
### Uninstall a release
|
||||
|
||||
```bash
|
||||
helm uninstall pangolin --namespace pangolin
|
||||
```
|
||||
|
||||
```bash
|
||||
helm uninstall newt --namespace pangolin
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Uninstalling a Helm release does not always remove persistent volumes, externally managed secrets, DNS records, certificates, or cloud load balancers. Review the namespace and related cluster resources before deleting data.
|
||||
</Warning>
|
||||
|
||||
## Using Helm with GitOps
|
||||
|
||||
Helm charts can also be installed and reconciled through GitOps tools.
|
||||
|
||||
* [Argo CD](/self-host/manual/kubernetes/gitops/argocd) can deploy Helm charts from a Helm repository, Git repository, or OCI source.
|
||||
* [Flux](/self-host/manual/kubernetes/gitops/flux) can reconcile Helm charts through `HelmRepository`, `OCIRepository`, and `HelmRelease`.
|
||||
|
||||
In these workflows, Helm is the chart format. The GitOps controller manages reconciliation.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
For component-specific troubleshooting, see:
|
||||
|
||||
* [Pangolin Troubleshooting](/self-host/manual/kubernetes/pangolin/troubleshooting)
|
||||
* [Newt Troubleshooting](/self-host/manual/kubernetes/newt/troubleshooting)
|
||||
|
||||
Useful Helm commands:
|
||||
|
||||
```bash
|
||||
helm list --all-namespaces
|
||||
helm status <release-name> --namespace <namespace>
|
||||
helm history <release-name> --namespace <namespace>
|
||||
helm get values <release-name> --namespace <namespace>
|
||||
helm get manifest <release-name> --namespace <namespace>
|
||||
```
|
||||
|
||||
Useful Kubernetes commands:
|
||||
|
||||
```bash
|
||||
kubectl get pods -n pangolin
|
||||
kubectl get events -n pangolin --sort-by=.lastTimestamp
|
||||
kubectl describe pod <pod-name> -n pangolin
|
||||
kubectl logs <pod-name> -n pangolin
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Pangolin Helm Install" href="/self-host/manual/kubernetes/pangolin/helm" icon="server">
|
||||
Install Pangolin with the Helm chart.
|
||||
</Card>
|
||||
<Card title="Newt Helm Install" href="/self-host/manual/kubernetes/newt/helm" icon="globe">
|
||||
Install Newt with the Helm chart.
|
||||
</Card>
|
||||
<Card title="Pangolin Configuration" href="/self-host/manual/kubernetes/pangolin/configuration" icon="sliders">
|
||||
Configure Pangolin chart values for your cluster.
|
||||
</Card>
|
||||
<Card title="Newt Configuration" href="/self-host/manual/kubernetes/newt/configuration" icon="sliders">
|
||||
Configure Newt chart values and credentials.
|
||||
</Card>
|
||||
<Card title="Argo CD" href="/self-host/manual/kubernetes/gitops/argocd" icon="code-branch">
|
||||
Deploy the charts with Argo CD.
|
||||
</Card>
|
||||
<Card title="Flux" href="/self-host/manual/kubernetes/gitops/flux" icon="code-branch">
|
||||
Deploy the charts with Flux.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
386
self-host/manual/kubernetes/helmfile.mdx
Normal file
386
self-host/manual/kubernetes/helmfile.mdx
Normal file
@@ -0,0 +1,386 @@
|
||||
---
|
||||
title: "Helmfile"
|
||||
description: "Advanced Kubernetes installation using Helmfile for multi-release orchestration."
|
||||
---
|
||||
|
||||
import PangolinCloudTocCta from "/snippets/pangolin-cloud-toc-cta.mdx";
|
||||
|
||||
<PangolinCloudTocCta />
|
||||
|
||||
|
||||
Helmfile is a declarative way to manage multiple Helm releases in a single workflow. Use Helmfile when you need to install Pangolin and/or Newt alongside other Kubernetes components or manage multiple releases together.
|
||||
|
||||
## When to use Helmfile
|
||||
|
||||
Use Helmfile if you want to:
|
||||
|
||||
- **Orchestrate multiple Helm releases** in a single file (Pangolin + Newt + dependencies).
|
||||
- **Manage dependencies** between releases (e.g., install cert-manager before Pangolin).
|
||||
- **Keep release definitions** in version control and synchronized.
|
||||
- **Avoid repeated `helm install` commands** for complex multi-release setups.
|
||||
|
||||
**Not using Helmfile?** If you're installing only Pangolin or only Newt without additional services, [Helm quick-start](/self-host/manual/kubernetes/helm) is simpler.
|
||||
|
||||
## Helm vs. Helmfile
|
||||
|
||||
| Aspect | Helm | Helmfile |
|
||||
| --- | --- | --- |
|
||||
| **Purpose** | Install/manage a single Helm chart release | Orchestrate multiple Helm chart releases |
|
||||
| **Command** | `helm install`, `helm upgrade` | `helmfile sync`, `helmfile apply` |
|
||||
| **Use case** | Quick install, single app | Multi-release, dependencies, fleet management |
|
||||
| **Complexity** | Low | Medium |
|
||||
|
||||
## Helmfile prerequisites
|
||||
|
||||
- Helm 3.10+
|
||||
- `helmfile` CLI installed: [Helmfile GitHub](https://github.com/roboll/helmfile)
|
||||
- Basic knowledge of Helm values and YAML
|
||||
|
||||
Install helmfile:
|
||||
|
||||
```bash
|
||||
# macOS/Linux with brew
|
||||
brew install helmfile
|
||||
|
||||
# or download from releases
|
||||
wget https://github.com/roboll/helmfile/releases/download/v<version>/helmfile_<os>_<arch>
|
||||
chmod +x helmfile
|
||||
sudo mv helmfile /usr/local/bin/
|
||||
```
|
||||
|
||||
Verify:
|
||||
|
||||
```bash
|
||||
helmfile --version
|
||||
```
|
||||
|
||||
## Basic Helmfile structure
|
||||
|
||||
A Helmfile is a YAML file (typically named `helmfile.yaml`) that declares multiple releases:
|
||||
|
||||
```yaml
|
||||
# helmfile.yaml
|
||||
releases:
|
||||
- name: cert-manager
|
||||
namespace: cert-manager
|
||||
createNamespace: true
|
||||
chart: jetstack/cert-manager
|
||||
version: v1.14.0
|
||||
|
||||
- name: pangolin
|
||||
namespace: pangolin
|
||||
createNamespace: true
|
||||
chart: fossorial/pangolin
|
||||
version: 0.1.0-alpha.0
|
||||
values:
|
||||
- pangolin-values.yaml
|
||||
|
||||
- name: newt
|
||||
namespace: pangolin
|
||||
chart: fossorial/newt
|
||||
version: 1.4.0
|
||||
values:
|
||||
- newt-values.yaml
|
||||
dependsOn:
|
||||
- pangolin
|
||||
```
|
||||
|
||||
## Helmfile with Pangolin and Newt
|
||||
|
||||
### 1. Add Helm repositories
|
||||
|
||||
```bash
|
||||
helm repo add jetstack https://charts.jetstack.io
|
||||
helm repo add fossorial https://charts.fossorial.io
|
||||
helm repo update
|
||||
```
|
||||
|
||||
### 2. Create Helmfile
|
||||
|
||||
Create `helmfile.yaml`:
|
||||
|
||||
```yaml
|
||||
helmDefaults:
|
||||
atomic: true
|
||||
cleanupOnFail: true
|
||||
wait: true
|
||||
timeout: 600
|
||||
recreatePods: true
|
||||
force: false
|
||||
|
||||
repositories:
|
||||
- name: jetstack
|
||||
url: https://charts.jetstack.io
|
||||
- name: fossorial
|
||||
url: https://charts.fossorial.io
|
||||
|
||||
releases:
|
||||
- name: cert-manager
|
||||
namespace: cert-manager
|
||||
createNamespace: true
|
||||
chart: jetstack/cert-manager
|
||||
version: v1.14.0
|
||||
set:
|
||||
installCRDs: true
|
||||
|
||||
- name: pangolin
|
||||
namespace: pangolin
|
||||
createNamespace: true
|
||||
chart: fossorial/pangolin
|
||||
version: 0.1.0-alpha.0
|
||||
values:
|
||||
- ./values/pangolin.yaml
|
||||
dependsOn:
|
||||
- cert-manager
|
||||
|
||||
- name: newt
|
||||
namespace: pangolin
|
||||
chart: fossorial/newt
|
||||
version: 1.4.0
|
||||
values:
|
||||
- ./values/newt.yaml
|
||||
dependsOn:
|
||||
- pangolin
|
||||
```
|
||||
|
||||
### 3. Create values files
|
||||
|
||||
Create `values/pangolin.yaml`:
|
||||
|
||||
```yaml
|
||||
deployment:
|
||||
type: controller
|
||||
mode: multi
|
||||
|
||||
database:
|
||||
mode: cloudnativepg
|
||||
|
||||
pangolin:
|
||||
config:
|
||||
app:
|
||||
dashboard_url: https://pangolin.example.com
|
||||
domains:
|
||||
domain1:
|
||||
base_domain: example.com
|
||||
gerbil:
|
||||
base_endpoint: vpn.example.com
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: traefik
|
||||
hosts:
|
||||
- host: pangolin.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: pangolin-tls
|
||||
hosts:
|
||||
- pangolin.example.com
|
||||
```
|
||||
|
||||
Create `values/newt.yaml`:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
auth:
|
||||
existingSecretName: newt-auth
|
||||
```
|
||||
|
||||
### 4. Create Newt auth secret
|
||||
|
||||
Before applying Helmfile:
|
||||
|
||||
```bash
|
||||
kubectl create namespace pangolin
|
||||
kubectl create secret generic newt-auth \
|
||||
-n pangolin \
|
||||
--from-literal=PANGOLIN_ENDPOINT=https://pangolin.example.com \
|
||||
--from-literal=NEWT_ID=<your-newt-id> \
|
||||
--from-literal=NEWT_SECRET=<your-newt-secret>
|
||||
```
|
||||
|
||||
### 5. Deploy with Helmfile
|
||||
|
||||
```bash
|
||||
# Preview changes
|
||||
helmfile diff
|
||||
|
||||
# Apply releases
|
||||
helmfile sync
|
||||
|
||||
# or
|
||||
helmfile apply
|
||||
```
|
||||
|
||||
### 6. Verify deployment
|
||||
|
||||
```bash
|
||||
helmfile status
|
||||
|
||||
# Check individual releases
|
||||
helm status cert-manager -n cert-manager
|
||||
helm status pangolin -n pangolin
|
||||
helm status newt -n pangolin
|
||||
|
||||
# Check pods
|
||||
kubectl get pods -n pangolin
|
||||
kubectl get pods -n cert-manager
|
||||
```
|
||||
|
||||
## Advanced: Helmfile with environments
|
||||
|
||||
For multi-environment setups (dev, staging, prod), use Helmfile environments:
|
||||
|
||||
```yaml
|
||||
environments:
|
||||
dev:
|
||||
values:
|
||||
environment: dev
|
||||
domain: dev.example.com
|
||||
replicaCount: 1
|
||||
prod:
|
||||
values:
|
||||
environment: prod
|
||||
domain: pangolin.example.com
|
||||
replicaCount: 3
|
||||
|
||||
helmDefaults:
|
||||
atomic: true
|
||||
wait: true
|
||||
|
||||
repositories:
|
||||
- name: fossorial
|
||||
url: https://charts.fossorial.io
|
||||
|
||||
releases:
|
||||
- name: pangolin
|
||||
namespace: pangolin
|
||||
createNamespace: true
|
||||
chart: fossorial/pangolin
|
||||
version: 0.1.0-alpha.0
|
||||
values:
|
||||
- ./values/pangolin-{{ .Environment.Values.environment }}.yaml
|
||||
```
|
||||
|
||||
Deploy to specific environment:
|
||||
|
||||
```bash
|
||||
helmfile -e dev sync
|
||||
helmfile -e prod sync
|
||||
```
|
||||
|
||||
## Helmfile with GitOps
|
||||
|
||||
### Using Helmfile with FluxCD
|
||||
|
||||
FluxCD can reconcile Helmfile declarations using the `helmfile-controller`. This allows Git-driven Helmfile updates:
|
||||
|
||||
1. Commit Helmfile and values to Git
|
||||
2. Create HelmRelease for each release in your Helmfile
|
||||
3. Flux reconciles and applies changes
|
||||
|
||||
See [Flux Guide](/self-host/manual/kubernetes/gitops/flux) for details.
|
||||
|
||||
### Using Helmfile with Argo CD
|
||||
|
||||
While Argo CD has native Helm and Kustomize support, you can:
|
||||
|
||||
1. Use Helmfile to render manifests: `helmfile template > manifests.yaml`
|
||||
2. Commit manifests to Git
|
||||
3. Have Argo CD manage the raw YAML
|
||||
|
||||
Alternatively, use Helm source in Argo CD (simpler than Helmfile for single releases).
|
||||
|
||||
## Troubleshooting Helmfile
|
||||
|
||||
### Check syntax
|
||||
|
||||
```bash
|
||||
helmfile lint
|
||||
```
|
||||
|
||||
### Debug release dependencies
|
||||
|
||||
```bash
|
||||
helmfile template
|
||||
```
|
||||
|
||||
### See what will be deployed
|
||||
|
||||
```bash
|
||||
helmfile diff
|
||||
```
|
||||
|
||||
### Remove releases
|
||||
|
||||
```bash
|
||||
helmfile destroy
|
||||
```
|
||||
|
||||
<Warning>
|
||||
`helmfile destroy` uninstalls all releases and may delete data (e.g., databases). Use with caution in production.
|
||||
</Warning>
|
||||
|
||||
## Common patterns
|
||||
|
||||
### Helmfile with local chart overrides
|
||||
|
||||
```yaml
|
||||
releases:
|
||||
- name: pangolin
|
||||
namespace: pangolin
|
||||
chart: ./charts/pangolin # local path
|
||||
values:
|
||||
- values.yaml
|
||||
```
|
||||
|
||||
### Helmfile with inline values
|
||||
|
||||
```yaml
|
||||
releases:
|
||||
- name: pangolin
|
||||
namespace: pangolin
|
||||
chart: fossorial/pangolin
|
||||
set:
|
||||
deployment.type: controller
|
||||
deployment.mode: multi
|
||||
```
|
||||
|
||||
### Helmfile with conditional releases
|
||||
|
||||
```yaml
|
||||
releases:
|
||||
- name: cert-manager
|
||||
namespace: cert-manager
|
||||
createNamespace: true
|
||||
chart: jetstack/cert-manager
|
||||
installed: {{ .Environment.Values.installCertManager | default true }}
|
||||
```
|
||||
|
||||
## Important notes
|
||||
|
||||
### Official support
|
||||
|
||||
Helmfile for Pangolin/Newt Kubernetes deployments is **advanced/community-supported**. The primary supported methods are:
|
||||
|
||||
- Helm directly
|
||||
- Kustomize overlays
|
||||
- GitOps tools (Argo CD, Flux)
|
||||
|
||||
If you encounter Helmfile-specific issues, refer to the [Helmfile documentation](https://github.com/roboll/helmfile) and community.
|
||||
|
||||
### Helm chart dependencies
|
||||
|
||||
The Pangolin Helm chart includes optional sub-chart dependencies (e.g., CloudNativePG operator). Helmfile does not manage these—they're handled by Helm. Ensure chart dependencies are available when installing.
|
||||
|
||||
## Next steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Helm Quick-Start" href="/self-host/manual/kubernetes/helm" icon="box" />
|
||||
<Card title="Pangolin Configuration" href="/self-host/manual/kubernetes/pangolin/configuration" icon="sliders" />
|
||||
<Card title="GitOps with Flux" href="/self-host/manual/kubernetes/gitops/flux" icon="code-branch" />
|
||||
<Card title="Troubleshooting" href="/self-host/manual/kubernetes/pangolin/troubleshooting" icon="circle-question" />
|
||||
</CardGroup>
|
||||
403
self-host/manual/kubernetes/kustomize.mdx
Normal file
403
self-host/manual/kubernetes/kustomize.mdx
Normal file
@@ -0,0 +1,403 @@
|
||||
---
|
||||
title: "Kustomize"
|
||||
description: "Customize Helm-rendered Kubernetes manifests with Kustomize overlays."
|
||||
---
|
||||
|
||||
import PangolinCloudTocCta from "/snippets/pangolin-cloud-toc-cta.mdx";
|
||||
|
||||
<PangolinCloudTocCta />
|
||||
|
||||
|
||||
Kustomize can be used to customize Kubernetes manifests with bases, overlays, and patches.
|
||||
|
||||
For Pangolin and Newt, the supported Kustomize workflow is to render the Helm charts into manifests and use those rendered manifests as the Kustomize base.
|
||||
|
||||
Use Kustomize when you need:
|
||||
|
||||
- environment-specific overlays for dev, staging, or production
|
||||
- explicit manifest patches in Git
|
||||
- a manifest-driven workflow for GitOps tools
|
||||
- small changes on top of a shared base without maintaining separate full manifests
|
||||
|
||||
## When to use Kustomize
|
||||
|
||||
Use Kustomize if:
|
||||
|
||||
- you want to manage rendered Pangolin or Newt manifests in Git
|
||||
- you need different overlays for different environments
|
||||
- your team prefers reviewing concrete Kubernetes manifests
|
||||
- you use Argo CD or Flux with Kustomize sources
|
||||
- you want to patch generated manifests without forking the Helm chart
|
||||
|
||||
For a single environment or a first installation, [Helm](/self-host/manual/kubernetes/helm) is usually simpler.
|
||||
|
||||
## Supported workflow
|
||||
|
||||
The chart repository does not provide native Kustomize bases. Use this workflow instead:
|
||||
|
||||
<Steps>
|
||||
<Step title="Render chart manifests">
|
||||
Render the Helm chart with your values file and save the output as base manifests.
|
||||
</Step>
|
||||
<Step title="Commit base manifests">
|
||||
Commit rendered manifests as the Kustomize base in Git.
|
||||
</Step>
|
||||
<Step title="Create environment overlays">
|
||||
Create overlays for each environment (for example dev, staging, production).
|
||||
</Step>
|
||||
<Step title="Apply or reconcile">
|
||||
Apply overlays manually or reconcile them with Argo CD or Flux.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
<Warning>
|
||||
Do not manage the same resources with both a live Helm release and Kustomize. Pick one ownership model per environment.
|
||||
</Warning>
|
||||
|
||||
Recommended ownership model:
|
||||
|
||||
- Use Helm only to render manifests.
|
||||
- Use Kustomize, Argo CD, or Flux to apply and reconcile the rendered manifests.
|
||||
- Re-render the base when upgrading the chart version.
|
||||
|
||||
## Example repository layout
|
||||
|
||||
```text
|
||||
my-pangolin-k8s/
|
||||
├── base/
|
||||
│ ├── kustomization.yaml
|
||||
│ ├── pangolin.yaml
|
||||
│ └── newt.yaml
|
||||
├── overlays/
|
||||
│ ├── dev/
|
||||
│ │ ├── kustomization.yaml
|
||||
│ │ └── pangolin-resources.patch.yaml
|
||||
│ ├── staging/
|
||||
│ │ ├── kustomization.yaml
|
||||
│ │ └── pangolin-resources.patch.yaml
|
||||
│ └── prod/
|
||||
│ ├── kustomization.yaml
|
||||
│ └── pangolin-resources.patch.yaml
|
||||
└── values/
|
||||
├── values-pangolin.yaml
|
||||
└── values-newt.yaml
|
||||
```
|
||||
|
||||
## Step 1: Render manifests from Helm
|
||||
|
||||
Create a base directory:
|
||||
|
||||
```bash
|
||||
mkdir -p base overlays/dev overlays/staging overlays/prod
|
||||
```
|
||||
|
||||
Render Pangolin:
|
||||
|
||||
<CodeGroup>
|
||||
```bash Classic Helm repository
|
||||
helm template pangolin fossorial/pangolin \
|
||||
--namespace pangolin \
|
||||
--values values/values-pangolin.yaml \
|
||||
> base/pangolin.yaml
|
||||
```
|
||||
|
||||
```bash OCI (GHCR)
|
||||
helm template pangolin oci://ghcr.io/fosrl/helm-charts/pangolin \
|
||||
--version 0.1.0-alpha.0 \
|
||||
--namespace pangolin \
|
||||
--values values/values-pangolin.yaml \
|
||||
> base/pangolin.yaml
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
Render Newt:
|
||||
|
||||
<CodeGroup>
|
||||
```bash Classic Helm repository
|
||||
helm template newt fossorial/newt \
|
||||
--namespace pangolin \
|
||||
--values values/values-newt.yaml \
|
||||
> base/newt.yaml
|
||||
```
|
||||
|
||||
```bash OCI (GHCR)
|
||||
helm template newt oci://ghcr.io/fosrl/helm-charts/newt \
|
||||
--version 1.4.0 \
|
||||
--namespace pangolin \
|
||||
--values values/values-newt.yaml \
|
||||
> base/newt.yaml
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
## Step 2: Create the base kustomization
|
||||
|
||||
```yaml
|
||||
# base/kustomization.yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- pangolin.yaml
|
||||
- newt.yaml
|
||||
```
|
||||
|
||||
## Step 3: Create an overlay
|
||||
|
||||
Use `resources` to reference the base.
|
||||
|
||||
```yaml
|
||||
# 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: pangolin-resources.patch.yaml
|
||||
target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
name: pangolin
|
||||
```
|
||||
|
||||
<Note>
|
||||
Avoid `namePrefix` and `nameSuffix` for Helm-rendered bases unless you have verified every generated reference. Renaming chart-generated resources can break service names, selectors, secret references, and workload dependencies.
|
||||
</Note>
|
||||
|
||||
## Step 4: Add patches
|
||||
|
||||
Example Strategic Merge patch for container resources:
|
||||
|
||||
```yaml
|
||||
# overlays/prod/pangolin-resources.patch.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: pangolin
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: pangolin
|
||||
resources:
|
||||
requests:
|
||||
cpu: 1000m
|
||||
memory: 1Gi
|
||||
limits:
|
||||
memory: 2Gi
|
||||
```
|
||||
|
||||
Example JSON6902-style inline patch:
|
||||
|
||||
```yaml
|
||||
# overlays/prod/kustomization.yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- ../../base
|
||||
|
||||
patches:
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
name: pangolin
|
||||
patch: |-
|
||||
- op: replace
|
||||
path: /spec/template/spec/containers/0/resources/requests/cpu
|
||||
value: "1000m"
|
||||
```
|
||||
|
||||
<Note>
|
||||
Modern Kustomize uses the `patches` field for both Strategic Merge and JSON6902-style patches. Avoid `patchesStrategicMerge`, `patchesJson6902`, and `bases` in new examples.
|
||||
</Note>
|
||||
|
||||
## Apply an overlay
|
||||
|
||||
Preview the rendered output:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/prod
|
||||
```
|
||||
|
||||
Compare with the live cluster:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/prod | kubectl diff -f -
|
||||
```
|
||||
|
||||
Apply the overlay:
|
||||
|
||||
```bash
|
||||
kubectl apply -k overlays/prod
|
||||
```
|
||||
|
||||
Or apply the rendered output:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/prod | kubectl apply -f -
|
||||
```
|
||||
|
||||
## Updating the base
|
||||
|
||||
When upgrading chart versions or changing Helm values, re-render the base and review the diff.
|
||||
|
||||
```bash
|
||||
helm repo update fossorial
|
||||
```
|
||||
|
||||
Render the updated chart output:
|
||||
|
||||
```bash
|
||||
helm template pangolin fossorial/pangolin \
|
||||
--namespace pangolin \
|
||||
--values values/values-pangolin.yaml \
|
||||
> base/pangolin.yaml
|
||||
```
|
||||
|
||||
```bash
|
||||
helm template newt fossorial/newt \
|
||||
--namespace pangolin \
|
||||
--values values/values-newt.yaml \
|
||||
> base/newt.yaml
|
||||
```
|
||||
|
||||
Then validate the overlay:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/prod
|
||||
```
|
||||
|
||||
Review changes before applying:
|
||||
|
||||
```bash
|
||||
git diff
|
||||
kustomize build overlays/prod | kubectl diff -f -
|
||||
```
|
||||
|
||||
Apply after review:
|
||||
|
||||
```bash
|
||||
kubectl apply -k overlays/prod
|
||||
```
|
||||
|
||||
## Kustomize with GitOps
|
||||
|
||||
Kustomize overlays work well with GitOps tools.
|
||||
|
||||
* [Argo CD](/self-host/manual/kubernetes/gitops/argocd) can reconcile a Kustomize overlay path directly.
|
||||
* [Flux](/self-host/manual/kubernetes/gitops/flux) can reconcile a Kustomize overlay with a `Kustomization` resource.
|
||||
|
||||
In GitOps workflows, the controller applies the overlay. Do not also apply the same overlay manually unless you are debugging.
|
||||
|
||||
## Important considerations
|
||||
|
||||
### Namespace handling
|
||||
|
||||
Render the charts with the namespace you intend to use:
|
||||
|
||||
```bash
|
||||
helm template pangolin fossorial/pangolin \
|
||||
--namespace pangolin \
|
||||
--values values/values-pangolin.yaml \
|
||||
> base/pangolin.yaml
|
||||
```
|
||||
|
||||
Create the namespace before applying the overlay:
|
||||
|
||||
```bash
|
||||
kubectl create namespace pangolin
|
||||
```
|
||||
|
||||
Apply any required Pod Security Admission labels or cluster-policy labels before workloads are created.
|
||||
|
||||
### Secrets
|
||||
|
||||
Do not commit plaintext secrets into rendered manifests.
|
||||
|
||||
Use one of these approaches instead:
|
||||
|
||||
* reference existing Kubernetes Secrets in the values file before rendering
|
||||
* create secrets separately with your secret-management workflow
|
||||
* use Sealed Secrets, External Secrets Operator, SOPS, or another GitOps-safe secret solution
|
||||
|
||||
### Do not mix ownership models
|
||||
|
||||
Avoid this pattern:
|
||||
|
||||
```text
|
||||
helm upgrade pangolin fossorial/pangolin
|
||||
kubectl apply -k overlays/prod
|
||||
```
|
||||
|
||||
This creates two tools managing the same objects.
|
||||
|
||||
Use one of these models instead:
|
||||
|
||||
| Model | Description |
|
||||
| ----------------- | ---------------------------------------------------------------------------------------- |
|
||||
| Helm-managed | Helm installs and upgrades the live release. Kustomize is not used for the same objects. |
|
||||
| Kustomize-managed | Helm only renders the base. Kustomize applies and owns the live objects. |
|
||||
| GitOps-managed | Argo CD or Flux applies the Kustomize overlay and owns reconciliation. |
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
Validate the overlay:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/prod
|
||||
```
|
||||
|
||||
Check the generated YAML:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/prod > manifests.yaml
|
||||
```
|
||||
|
||||
Run a server-side dry run:
|
||||
|
||||
```bash
|
||||
kubectl apply -f manifests.yaml --dry-run=server
|
||||
```
|
||||
|
||||
Preview live changes:
|
||||
|
||||
```bash
|
||||
kubectl diff -f manifests.yaml
|
||||
```
|
||||
|
||||
Check live resources:
|
||||
|
||||
```bash
|
||||
kubectl get all -n pangolin
|
||||
kubectl get events -n pangolin --sort-by=.lastTimestamp
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Pangolin Kustomize Install" href="/self-host/manual/kubernetes/pangolin/kustomize" icon="server">
|
||||
Install Pangolin with rendered manifests and Kustomize overlays.
|
||||
</Card>
|
||||
<Card title="Newt Kustomize Install" href="/self-host/manual/kubernetes/newt/kustomize" icon="globe">
|
||||
Install Newt with rendered manifests and Kustomize overlays.
|
||||
</Card>
|
||||
<Card title="Argo CD" href="/self-host/manual/kubernetes/gitops/argocd" icon="code-branch">
|
||||
Reconcile Kustomize overlays with Argo CD.
|
||||
</Card>
|
||||
<Card title="Flux" href="/self-host/manual/kubernetes/gitops/flux" icon="code-branch">
|
||||
Reconcile Kustomize overlays with Flux.
|
||||
</Card>
|
||||
<Card title="Troubleshooting" href="/self-host/manual/kubernetes/pangolin/troubleshooting" icon="circle-question">
|
||||
Troubleshoot Pangolin deployments on Kubernetes.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
```
|
||||
811
self-host/manual/kubernetes/newt/configuration.mdx
Normal file
811
self-host/manual/kubernetes/newt/configuration.mdx
Normal file
@@ -0,0 +1,811 @@
|
||||
---
|
||||
title: "Newt Configuration"
|
||||
description: "Configuration reference for Newt Kubernetes deployments."
|
||||
---
|
||||
|
||||
import PangolinCloudTocCta from "/snippets/pangolin-cloud-toc-cta.mdx";
|
||||
|
||||
<PangolinCloudTocCta />
|
||||
|
||||
|
||||
This page covers the main Newt Kubernetes configuration options for Helm and Kustomize workflows.
|
||||
|
||||
For exhaustive option coverage, refer to the chart resources:
|
||||
|
||||
<CardGroup cols={3}>
|
||||
<Card title="README" href="https://github.com/fosrl/helm-charts/blob/main/charts/newt/README.md" />
|
||||
<Card title="values.yaml" href="https://github.com/fosrl/helm-charts/blob/main/charts/newt/values.yaml" />
|
||||
<Card title="values.schema.json" href="https://github.com/fosrl/helm-charts/blob/main/charts/newt/values.schema.json" />
|
||||
</CardGroup>
|
||||
|
||||
## Version context
|
||||
|
||||
This page is aligned with the Newt Helm chart `1.4.0`.
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Chart version | `1.4.0` |
|
||||
| App version | `1.12.3` |
|
||||
| Kubernetes version | `>=1.30.14-0` |
|
||||
| Default image | `docker.io/fosrl/newt:1.12.3` |
|
||||
|
||||
Chart `1.4.0` also publishes the Newt image metadata for Docker Hub and GHCR and includes Artifact Hub signing metadata.
|
||||
|
||||
## Configuration sections
|
||||
|
||||
<AccordionGroup>
|
||||
|
||||
<Accordion title="Image and global defaults" defaultOpen>
|
||||
|
||||
Use `global.image` to control the Newt container image used by all instances.
|
||||
|
||||
```yaml
|
||||
global:
|
||||
image:
|
||||
registry: docker.io
|
||||
repository: fosrl/newt
|
||||
tag: ""
|
||||
digest: ""
|
||||
imagePullPolicy: IfNotPresent
|
||||
imagePullSecrets: []
|
||||
|
||||
logLevel: INFO
|
||||
```
|
||||
|
||||
Recommendations:
|
||||
|
||||
- Leave `tag` empty to use the chart `appVersion`.
|
||||
- Use `digest` when you need immutable image pinning.
|
||||
- Use `imagePullSecrets` when pulling from a private registry.
|
||||
- Use per-instance overrides only when `allowGlobalOverride` is enabled for that instance.
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Namespace and Pod Security Admission">
|
||||
|
||||
The chart can render Namespace resources, including Pod Security Admission labels.
|
||||
|
||||
```yaml
|
||||
namespace:
|
||||
create: false
|
||||
name: ""
|
||||
labels: {}
|
||||
podSecurity:
|
||||
enforce: ""
|
||||
warn: ""
|
||||
audit: ""
|
||||
```
|
||||
|
||||
Recommended production pattern:
|
||||
|
||||
1. Create the namespace manually.
|
||||
2. Apply required Pod Security Admission labels or policy labels.
|
||||
3. Install the chart into that namespace.
|
||||
|
||||
```bash
|
||||
kubectl create namespace pangolin
|
||||
```
|
||||
|
||||
Example namespace labels:
|
||||
|
||||
```bash
|
||||
kubectl label namespace pangolin \
|
||||
pod-security.kubernetes.io/enforce=baseline \
|
||||
pod-security.kubernetes.io/audit=restricted \
|
||||
pod-security.kubernetes.io/warn=restricted
|
||||
```
|
||||
|
||||
Per-instance namespace overrides are available when `allowGlobalOverride: true` is set:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
allowGlobalOverride: true
|
||||
namespace:
|
||||
name: pangolin
|
||||
create: false
|
||||
labels: {}
|
||||
podSecurity:
|
||||
enforce: ""
|
||||
warn: ""
|
||||
audit: ""
|
||||
```
|
||||
|
||||
<Note>
|
||||
Creating the namespace manually is recommended when your cluster uses Pod Security Admission, policy labels, admission webhooks, or namespace annotations.
|
||||
</Note>
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Credentials and authentication">
|
||||
|
||||
For production, use an existing Kubernetes Secret.
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
auth:
|
||||
existingSecretName: newt-auth
|
||||
```
|
||||
|
||||
Create the Secret before installing the chart:
|
||||
|
||||
```bash
|
||||
kubectl create secret generic newt-auth \
|
||||
--namespace pangolin \
|
||||
--from-literal=PANGOLIN_ENDPOINT=https://pangolin.example.com \
|
||||
--from-literal=NEWT_ID=<newt-id> \
|
||||
--from-literal=NEWT_SECRET=<newt-secret>
|
||||
```
|
||||
|
||||
The default Secret keys are:
|
||||
|
||||
```yaml
|
||||
PANGOLIN_ENDPOINT
|
||||
NEWT_ID
|
||||
NEWT_SECRET
|
||||
```
|
||||
|
||||
Use `auth.keys.*` only when your Secret uses different key names:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
auth:
|
||||
existingSecretName: newt-auth
|
||||
keys:
|
||||
endpointKey: PANGOLIN_ENDPOINT
|
||||
idKey: NEWT_ID
|
||||
secretKey: NEWT_SECRET
|
||||
```
|
||||
|
||||
`auth.keys.*` are Secret key names, not credential values.
|
||||
|
||||
Inline credentials are supported, but should only be used for local testing:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
auth:
|
||||
pangolinEndpoint: "https://pangolin.example.com"
|
||||
id: "<newt-id>"
|
||||
secret: "<newt-secret>"
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Inline credentials can appear in rendered manifests and Helm release history. Use `auth.existingSecretName` for production.
|
||||
</Warning>
|
||||
|
||||
<Warning>
|
||||
Do not commit plaintext credentials to Git. For GitOps workflows, use encrypted or external secret backends such as SOPS, Sealed Secrets, External Secrets Operator, Vault, or Infisical.
|
||||
</Warning>
|
||||
|
||||
Chart `1.4.0` also includes `auth.createSecret` and `auth.envVarsDirect` modes for generated Secret and direct environment-variable workflows. Use these only when they match your operational model.
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Provisioning">
|
||||
|
||||
Newt 1.11+ supports provisioning-based installs.
|
||||
|
||||
Use provisioning when Newt should bootstrap credentials from a provisioning key instead of using a static `NEWT_ID` and `NEWT_SECRET`.
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
auth:
|
||||
pangolinEndpoint: https://pangolin.example.com
|
||||
provisioningKey: "<provisioning-key>"
|
||||
newtName: "my-site"
|
||||
configPersistence:
|
||||
enabled: true
|
||||
type: emptyDir
|
||||
mountPath: /var/lib/newt
|
||||
fileName: config.json
|
||||
```
|
||||
|
||||
Provisioning requires writable config persistence so Newt can store the generated configuration.
|
||||
|
||||
For durable storage, use an existing PVC:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
auth:
|
||||
pangolinEndpoint: https://pangolin.example.com
|
||||
provisioningKey: "<provisioning-key>"
|
||||
newtName: "my-site"
|
||||
configPersistence:
|
||||
enabled: true
|
||||
type: persistentVolumeClaim
|
||||
existingClaim: my-newt-config
|
||||
mountPath: /var/lib/newt
|
||||
fileName: config.json
|
||||
```
|
||||
|
||||
You can also provide a provisioning blueprint:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
auth:
|
||||
pangolinEndpoint: https://pangolin.example.com
|
||||
provisioningKey: "<provisioning-key>"
|
||||
newtName: "my-site"
|
||||
configPersistence:
|
||||
enabled: true
|
||||
type: emptyDir
|
||||
provisioningBlueprintFile: /etc/newt/provisioning-blueprint.yaml
|
||||
provisioningBlueprintData: |
|
||||
version: 1
|
||||
routes: []
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Instance runtime settings">
|
||||
|
||||
Each Newt instance is configured under `newtInstances[]`.
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
replicas: 1
|
||||
logLevel: INFO
|
||||
mtu: 1280
|
||||
dns: ""
|
||||
pingInterval: ""
|
||||
pingTimeout: ""
|
||||
acceptClients: false
|
||||
useNativeInterface: false
|
||||
interface: newt
|
||||
keepInterface: false
|
||||
noCloud: false
|
||||
disableClients: false
|
||||
```
|
||||
|
||||
Key settings:
|
||||
|
||||
| Setting | Purpose |
|
||||
| ------------------------------ | ----------------------------------------------------------- |
|
||||
| `replicas` | Number of replicas for this Newt instance |
|
||||
| `mtu` | WireGuard interface MTU |
|
||||
| `dns` | Optional DNS server address pushed to the client |
|
||||
| `pingInterval` / `pingTimeout` | Optional Newt ping timing overrides |
|
||||
| `acceptClients` | Allows client connections at runtime |
|
||||
| `useNativeInterface` | Uses native WireGuard interface when native mode is enabled |
|
||||
| `noCloud` | Disables cloud connectivity |
|
||||
| `disableClients` | Disables client connections |
|
||||
|
||||
<Note>
|
||||
Newt 1.11 changed upstream ping defaults. Set `pingInterval` and `pingTimeout` explicitly if you need older timing behavior.
|
||||
</Note>
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Service and connectivity">
|
||||
|
||||
Service exposure is controlled separately from `acceptClients`.
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
service:
|
||||
enabled: false
|
||||
type: ClusterIP
|
||||
port: 51820
|
||||
testerPort: ""
|
||||
externalTrafficPolicy: ""
|
||||
loadBalancerSourceRanges: []
|
||||
```
|
||||
|
||||
Important behavior:
|
||||
|
||||
- `acceptClients` does not create a Service.
|
||||
- `newtInstances[].service.enabled` controls whether a Service is created.
|
||||
- Tester port exposure is disabled by default unless enabled through test settings or explicit legacy tester-port configuration.
|
||||
|
||||
Common Service types:
|
||||
|
||||
| Type | Use case |
|
||||
| -------------- | --------------------------------------------- |
|
||||
| `ClusterIP` | Internal cluster access |
|
||||
| `LoadBalancer` | External exposure through cloud load balancer |
|
||||
| `NodePort` | Node-level port exposure |
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Configuration persistence">
|
||||
|
||||
Use `configPersistence` when Newt needs writable configuration storage.
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
configPersistence:
|
||||
enabled: false
|
||||
type: emptyDir
|
||||
mountPath: /var/lib/newt
|
||||
fileName: config.json
|
||||
existingClaim: ""
|
||||
```
|
||||
|
||||
Storage types:
|
||||
|
||||
| Type | Behavior |
|
||||
| ----------------------- | ----------------------------------------- |
|
||||
| `emptyDir` | Ephemeral storage, recreated with the pod |
|
||||
| `persistentVolumeClaim` | Durable storage using an existing PVC |
|
||||
|
||||
Provisioning-based installs should enable config persistence. For production provisioning, prefer a PVC over `emptyDir`.
|
||||
|
||||
<Warning>
|
||||
`emptyDir` is recreated when a pod is replaced. Newt can require a reconnect and handshake after restart, which may briefly interrupt active traffic.
|
||||
</Warning>
|
||||
|
||||
<Tip>
|
||||
For production, prefer an existing PersistentVolumeClaim to keep writable Newt configuration across restarts and rescheduling.
|
||||
</Tip>
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Blueprints, mTLS, and scripts">
|
||||
|
||||
The chart supports blueprints, provisioning blueprints, mTLS certificate mounts, Docker socket mounts, and up/down scripts.
|
||||
|
||||
Blueprint example:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
blueprintFile: /etc/newt/blueprint.yaml
|
||||
blueprintData: |
|
||||
version: 1
|
||||
routes: []
|
||||
```
|
||||
|
||||
Provisioning blueprint example:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
provisioningBlueprintFile: /etc/newt/provisioning-blueprint.yaml
|
||||
provisioningBlueprintData: |
|
||||
version: 1
|
||||
routes: []
|
||||
```
|
||||
|
||||
mTLS using an existing PEM Secret:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
mtls:
|
||||
enabled: true
|
||||
mode: pem
|
||||
pem:
|
||||
secretName: newt-mtls
|
||||
clientCertPath: /certs/client.crt
|
||||
clientKeyPath: /certs/client.key
|
||||
caPath: /certs/ca.crt
|
||||
```
|
||||
|
||||
Up/down scripts:
|
||||
|
||||
```yaml
|
||||
global:
|
||||
updownScripts:
|
||||
route.sh: |
|
||||
#!/bin/sh
|
||||
echo "Newt interface changed"
|
||||
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
updown:
|
||||
enabled: true
|
||||
mountPath: /opt/newt/updown
|
||||
```
|
||||
|
||||
<Note>
|
||||
Use Secrets for certificates and sensitive script inputs. Avoid inline private keys or credentials in values files.
|
||||
</Note>
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Native WireGuard mode">
|
||||
|
||||
By default, Newt runs without native WireGuard mode.
|
||||
|
||||
```yaml
|
||||
global:
|
||||
nativeMode:
|
||||
enabled: false
|
||||
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
useNativeInterface: false
|
||||
```
|
||||
|
||||
Native mode requires elevated privileges.
|
||||
|
||||
When native mode or `useNativeInterface` is enabled, Newt runs as root with privileged settings and capabilities such as `NET_ADMIN` and `SYS_MODULE`.
|
||||
|
||||
<Warning>
|
||||
Only enable native WireGuard mode if your cluster policy allows privileged workloads and you understand the security impact.
|
||||
</Warning>
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Service accounts and RBAC">
|
||||
|
||||
ServiceAccount creation is enabled by default.
|
||||
|
||||
```yaml
|
||||
serviceAccount:
|
||||
create: true
|
||||
name: ""
|
||||
automountServiceAccountToken: false
|
||||
```
|
||||
|
||||
RBAC is disabled by default in chart `1.4.0`:
|
||||
|
||||
```yaml
|
||||
rbac:
|
||||
create: false
|
||||
clusterRole: false
|
||||
```
|
||||
|
||||
Enable RBAC only when your selected configuration needs Kubernetes API permissions:
|
||||
|
||||
```yaml
|
||||
rbac:
|
||||
create: true
|
||||
clusterRole: false
|
||||
```
|
||||
|
||||
Per-instance ServiceAccount overrides are available when `allowGlobalOverride: true` is set:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
allowGlobalOverride: true
|
||||
serviceAccount:
|
||||
create: true
|
||||
name: newt-main-tunnel
|
||||
automountServiceAccountToken: false
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Chart `1.4.0` changed the RBAC default to `rbac.create=false`. Existing installations that relied on auto-created RBAC must opt in explicitly during upgrade.
|
||||
</Warning>
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Resources and scheduling">
|
||||
|
||||
Global resource requests and limits apply to Newt workloads.
|
||||
|
||||
```yaml
|
||||
global:
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
ephemeral-storage: 128Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
ephemeral-storage: 256Mi
|
||||
```
|
||||
|
||||
Scheduling defaults:
|
||||
|
||||
```yaml
|
||||
global:
|
||||
priorityClassName: ""
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity:
|
||||
nodeAffinity: {}
|
||||
podAffinity: {}
|
||||
podAntiAffinity: {}
|
||||
topologySpreadConstraints: []
|
||||
```
|
||||
|
||||
Pod Disruption Budget:
|
||||
|
||||
```yaml
|
||||
global:
|
||||
podDisruptionBudget:
|
||||
enabled: false
|
||||
minAvailable: 1
|
||||
maxUnavailable: ""
|
||||
```
|
||||
|
||||
Recommendations:
|
||||
|
||||
- Start with the chart defaults.
|
||||
- Increase requests and limits based on traffic volume.
|
||||
- Use node selectors, tolerations, affinity, or topology spread constraints when you need placement control.
|
||||
- Enable a PodDisruptionBudget only when your replica count and maintenance policy support it.
|
||||
|
||||
<Warning>
|
||||
Avoid CPU limits unless you explicitly need hard caps. CPU limits can trigger throttling even when spare node CPU exists. For most deployments, use CPU requests and memory limits as the starting point.
|
||||
</Warning>
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Health probes and Helm tests">
|
||||
|
||||
Health probes are disabled by default.
|
||||
|
||||
```yaml
|
||||
global:
|
||||
health:
|
||||
enabled: false
|
||||
path: /tmp/healthy
|
||||
readinessFailureThreshold: 3
|
||||
```
|
||||
|
||||
Per-instance health options:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
healthFile: /tmp/healthy
|
||||
enforceHcCert: false
|
||||
```
|
||||
|
||||
Helm test jobs are disabled by default:
|
||||
|
||||
```yaml
|
||||
global:
|
||||
tests:
|
||||
enabled: false
|
||||
image:
|
||||
repository: registry.k8s.io/kubectl
|
||||
tag: "1.30.14"
|
||||
pullPolicy: IfNotPresent
|
||||
```
|
||||
|
||||
Enable tests only when you want chart test jobs and tester-port related resources.
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Metrics and monitoring">
|
||||
|
||||
Metrics are disabled by default.
|
||||
|
||||
```yaml
|
||||
global:
|
||||
metrics:
|
||||
enabled: false
|
||||
port: 9090
|
||||
path: /metrics
|
||||
adminAddr: ":2112"
|
||||
asyncBytes: false
|
||||
region: ""
|
||||
otlpEnabled: false
|
||||
pprofEnabled: false
|
||||
```
|
||||
|
||||
The default `adminAddr` is `:2112`, which listens on all interfaces and allows in-cluster scraping. Use `127.0.0.1:2112` only when scraping from other pods is not required.
|
||||
|
||||
Metrics Service:
|
||||
|
||||
```yaml
|
||||
global:
|
||||
metrics:
|
||||
service:
|
||||
enabled: false
|
||||
type: ClusterIP
|
||||
port: 2112
|
||||
portName: metrics
|
||||
```
|
||||
|
||||
Prometheus Operator resources:
|
||||
|
||||
```yaml
|
||||
global:
|
||||
metrics:
|
||||
podMonitor:
|
||||
enabled: false
|
||||
serviceMonitor:
|
||||
enabled: false
|
||||
prometheusRule:
|
||||
enabled: false
|
||||
```
|
||||
|
||||
Example with ServiceMonitor:
|
||||
|
||||
```yaml
|
||||
global:
|
||||
metrics:
|
||||
enabled: true
|
||||
service:
|
||||
enabled: true
|
||||
serviceMonitor:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
Optional pprof endpoint:
|
||||
|
||||
```yaml
|
||||
global:
|
||||
metrics:
|
||||
pprofEnabled: true
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Network policy">
|
||||
|
||||
NetworkPolicy rendering is disabled by default.
|
||||
|
||||
```yaml
|
||||
global:
|
||||
networkPolicy:
|
||||
enabled: false
|
||||
defaultMode: merge
|
||||
components:
|
||||
defaultApp:
|
||||
enabled: true
|
||||
dns:
|
||||
enabled: false
|
||||
kubeApi:
|
||||
enabled: false
|
||||
custom:
|
||||
enabled: false
|
||||
ruleSets: {}
|
||||
```
|
||||
|
||||
Per-instance NetworkPolicy overrides:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
networkPolicy:
|
||||
enabled: null
|
||||
mode: merge
|
||||
useGlobalComponents:
|
||||
defaultApp: true
|
||||
dns: false
|
||||
kubeApi: false
|
||||
custom: true
|
||||
components:
|
||||
dns:
|
||||
enabled: false
|
||||
custom:
|
||||
enabled: false
|
||||
includeRuleSets: []
|
||||
```
|
||||
|
||||
Modes:
|
||||
|
||||
| Mode | Behavior |
|
||||
| --------- | ------------------------------------------------- |
|
||||
| `inherit` | Use global components and rule sets only |
|
||||
| `merge` | Combine global and instance-level policy settings |
|
||||
| `replace` | Use only the instance-level policy settings |
|
||||
|
||||
Enable DNS egress rules if your default network policy blocks DNS.
|
||||
|
||||
</Accordion>
|
||||
|
||||
</AccordionGroup>
|
||||
|
||||
## Configuration by install method
|
||||
|
||||
### Helm
|
||||
|
||||
Use a values file:
|
||||
|
||||
```bash
|
||||
helm upgrade --install newt fossorial/newt \
|
||||
--namespace pangolin \
|
||||
--values values-newt.yaml
|
||||
```
|
||||
|
||||
Use inline values only for small tests:
|
||||
|
||||
```bash
|
||||
helm upgrade --install newt fossorial/newt \
|
||||
--namespace pangolin \
|
||||
--set 'newtInstances[0].name=main-tunnel' \
|
||||
--set 'newtInstances[0].auth.existingSecretName=newt-auth'
|
||||
```
|
||||
|
||||
See [Newt Helm](/self-host/manual/kubernetes/newt/helm) for the installation flow.
|
||||
|
||||
### Kustomize
|
||||
|
||||
Render the chart with Helm, then use Kustomize overlays:
|
||||
|
||||
```bash
|
||||
helm template newt fossorial/newt \
|
||||
--namespace pangolin \
|
||||
--values values-newt.yaml \
|
||||
> base/newt.yaml
|
||||
```
|
||||
|
||||
Then apply an overlay:
|
||||
|
||||
```bash
|
||||
kubectl apply -k overlays/site-a
|
||||
```
|
||||
|
||||
See [Newt Kustomize](/self-host/manual/kubernetes/newt/kustomize) for the Kustomize workflow.
|
||||
|
||||
### GitOps
|
||||
|
||||
Store Helm values or Kustomize overlays in Git. Argo CD or Flux reconciles the desired state.
|
||||
|
||||
Argo CD Helm example:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
source:
|
||||
helm:
|
||||
values: |
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
auth:
|
||||
existingSecretName: newt-auth
|
||||
```
|
||||
|
||||
Flux HelmRelease example:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
values:
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
auth:
|
||||
existingSecretName: newt-auth
|
||||
```
|
||||
|
||||
See [GitOps](/self-host/manual/kubernetes/gitops/overview) for GitOps guidance.
|
||||
|
||||
## Production checklist
|
||||
|
||||
Before deploying Newt to production:
|
||||
|
||||
- [ ] Create the namespace before installation and apply required labels or annotations.
|
||||
- [ ] Store credentials in Kubernetes Secrets.
|
||||
- [ ] Avoid inline plaintext credentials.
|
||||
- [ ] Use provisioning only with writable config persistence.
|
||||
- [ ] Use a PVC for durable provisioning state.
|
||||
- [ ] Keep native WireGuard mode disabled unless privileged workloads are allowed.
|
||||
- [ ] Confirm the Pangolin endpoint is reachable from the Newt pod.
|
||||
- [ ] Confirm TLS certificates are valid for the Pangolin endpoint.
|
||||
- [ ] Set resources based on expected traffic.
|
||||
- [ ] Configure NetworkPolicy rules if your cluster enforces network isolation.
|
||||
- [ ] Enable metrics only when you have a scraping path.
|
||||
- [ ] Review RBAC settings before upgrading from older chart versions.
|
||||
|
||||
## Next steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Helm Install" href="/self-host/manual/kubernetes/newt/helm" icon="box">
|
||||
Install Newt with Helm.
|
||||
</Card>
|
||||
<Card title="Kustomize Install" href="/self-host/manual/kubernetes/newt/kustomize" icon="layer-group">
|
||||
Install Newt with rendered manifests and Kustomize overlays.
|
||||
</Card>
|
||||
<Card title="Troubleshooting" href="/self-host/manual/kubernetes/newt/troubleshooting" icon="circle-question">
|
||||
Debug Newt deployment and connection issues.
|
||||
</Card>
|
||||
<Card title="GitOps" href="/self-host/manual/kubernetes/gitops/overview" icon="code-branch">
|
||||
Deploy Newt with Argo CD or Flux.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
437
self-host/manual/kubernetes/newt/helm.mdx
Normal file
437
self-host/manual/kubernetes/newt/helm.mdx
Normal file
@@ -0,0 +1,437 @@
|
||||
---
|
||||
title: "Newt Helm"
|
||||
description: "Quick-start guide for installing Newt on Kubernetes using Helm."
|
||||
---
|
||||
|
||||
import PangolinCloudTocCta from "/snippets/pangolin-cloud-toc-cta.mdx";
|
||||
|
||||
<PangolinCloudTocCta />
|
||||
|
||||
|
||||
Newt is the site connector used to expose private resources through Pangolin. It runs close to the resources you want to publish and connects back to Pangolin.
|
||||
|
||||
Newt is a user-space WireGuard tunnel client and TCP/UDP proxy. It does not require users to manage WireGuard tunnels or NAT rules manually. :contentReference[oaicite:1]{index=1}
|
||||
|
||||
## Version matrix
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Chart version | `1.4.0` |
|
||||
| App version | `1.12.3` |
|
||||
| Kubernetes version | `>=1.30.14-0` |
|
||||
| Default image tag | `1.12.3` |
|
||||
|
||||
Newt chart `1.4.0` includes Newt `1.12.3` and supports Kubernetes `>=1.30.14-0`. :contentReference[oaicite:2]{index=2}
|
||||
|
||||
## What the chart supports
|
||||
|
||||
The Newt chart can deploy one or more Newt instances through `newtInstances[]`.
|
||||
|
||||
Newt chart `1.4.0` includes support for:
|
||||
|
||||
- Newt 1.11+ provisioning with `NEWT_PROVISIONING_KEY` and `NEWT_NAME`
|
||||
- legacy credential installs with `NEWT_ID` and `NEWT_SECRET`
|
||||
- existing Kubernetes Secrets for production credentials
|
||||
- writable config persistence with `emptyDir` or an existing PVC
|
||||
- optional metrics, PodMonitor, ServiceMonitor, and PrometheusRule
|
||||
- optional NetworkPolicy
|
||||
- optional native WireGuard mode
|
||||
- multi-instance deployments with per-instance overrides
|
||||
|
||||
The chart README lists these features for version `1.4.0`. :contentReference[oaicite:3]{index=3}
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before installing Newt, you need:
|
||||
|
||||
- Kubernetes `1.30.14` or newer
|
||||
- Helm 3.x
|
||||
- `kubectl` access to the target cluster
|
||||
- a reachable Pangolin instance
|
||||
- either:
|
||||
- Newt credentials from Pangolin: `NEWT_ID` and `NEWT_SECRET`
|
||||
- or a provisioning key for Newt 1.11+ provisioning
|
||||
|
||||
The chart quickstart lists Kubernetes `>=1.30.14`, Helm 3.x, configured `kubectl`, and Newt credentials from Pangolin as prerequisites. :contentReference[oaicite:4]{index=4}
|
||||
|
||||
See [Prerequisites](/self-host/manual/kubernetes/prerequisites) for cluster, namespace, storage, networking, and security planning.
|
||||
|
||||
## Authentication options
|
||||
|
||||
Newt chart `1.4.0` supports three credential patterns:
|
||||
|
||||
| Method | Recommended for | Notes |
|
||||
| --- | --- | --- |
|
||||
| Existing Secret | Production | Credentials are stored in a Kubernetes Secret created outside Helm |
|
||||
| Provisioning key | Newt 1.11+ provisioning | Requires writable config persistence |
|
||||
| Inline values | Local testing only | Credentials may be stored in Helm release history |
|
||||
|
||||
For production, use `auth.existingSecretName` or a GitOps-safe secret workflow. The chart values explicitly warn that inline credentials can be stored in Helm release history and recommend existing Secrets for production. :contentReference[oaicite:5]{index=5}
|
||||
|
||||
## Quick install with existing Secret
|
||||
|
||||
This is the recommended simple production pattern.
|
||||
|
||||
### Step 1: Create the namespace
|
||||
|
||||
Create the namespace before installing the chart:
|
||||
|
||||
```bash
|
||||
kubectl create namespace pangolin
|
||||
```
|
||||
|
||||
If your cluster uses Pod Security Admission labels, namespace labels, or policy annotations, apply them before installing Newt.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
kubectl label namespace pangolin \
|
||||
pod-security.kubernetes.io/enforce=baseline \
|
||||
pod-security.kubernetes.io/audit=restricted \
|
||||
pod-security.kubernetes.io/warn=restricted
|
||||
```
|
||||
|
||||
<Note>
|
||||
The chart can create namespaces through `namespace.create`, but creating the namespace explicitly is recommended when your cluster uses Pod Security Admission, namespace labels, or policy annotations.
|
||||
</Note>
|
||||
|
||||
### Step 2: Create the Newt Secret
|
||||
|
||||
Create a Secret with the credentials from Pangolin:
|
||||
|
||||
```bash
|
||||
kubectl create secret generic newt-auth \
|
||||
--namespace pangolin \
|
||||
--from-literal=PANGOLIN_ENDPOINT=https://pangolin.example.com \
|
||||
--from-literal=NEWT_ID=<your-newt-id> \
|
||||
--from-literal=NEWT_SECRET=<your-newt-secret>
|
||||
```
|
||||
|
||||
<Tip>
|
||||
Get the Newt credentials from the Pangolin dashboard for the site you want this Newt instance to connect to.
|
||||
</Tip>
|
||||
|
||||
### Step 3: Create a values file
|
||||
|
||||
Create `values-newt.yaml`:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
auth:
|
||||
existingSecretName: newt-auth
|
||||
replicas: 1
|
||||
```
|
||||
|
||||
The default Secret keys are:
|
||||
|
||||
```yaml
|
||||
PANGOLIN_ENDPOINT
|
||||
NEWT_ID
|
||||
NEWT_SECRET
|
||||
```
|
||||
|
||||
You only need to set `auth.keys.*` if your Secret uses different key names.
|
||||
|
||||
Example with custom Secret keys:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
auth:
|
||||
existingSecretName: newt-auth
|
||||
keys:
|
||||
endpointKey: PANGOLIN_ENDPOINT
|
||||
idKey: NEWT_ID
|
||||
secretKey: NEWT_SECRET
|
||||
replicas: 1
|
||||
```
|
||||
|
||||
`auth.keys.*` are key names inside the Kubernetes Secret, not the credential values themselves. ([GitHub][2])
|
||||
|
||||
### Step 4: Install Newt
|
||||
|
||||
Add the Helm repository:
|
||||
|
||||
```bash
|
||||
helm repo add fossorial https://charts.fossorial.io
|
||||
helm repo update fossorial
|
||||
```
|
||||
|
||||
Install Newt:
|
||||
|
||||
```bash
|
||||
helm upgrade --install newt fossorial/newt \
|
||||
--namespace pangolin \
|
||||
--values values-newt.yaml
|
||||
```
|
||||
|
||||
Do not use `--create-namespace` here if you created and labeled the namespace manually.
|
||||
|
||||
### Step 5: Verify the deployment
|
||||
|
||||
Check the Helm release:
|
||||
|
||||
```bash
|
||||
helm status newt --namespace pangolin
|
||||
```
|
||||
|
||||
Check the pods:
|
||||
|
||||
```bash
|
||||
kubectl get pods --namespace pangolin \
|
||||
-l app.kubernetes.io/name=newt
|
||||
```
|
||||
|
||||
Check the logs:
|
||||
|
||||
```bash
|
||||
kubectl logs --namespace pangolin \
|
||||
-l app.kubernetes.io/name=newt \
|
||||
--tail=50
|
||||
```
|
||||
|
||||
Wait for the Newt pod to become ready:
|
||||
|
||||
```bash
|
||||
kubectl wait --for=condition=ready pod \
|
||||
-l app.kubernetes.io/name=newt \
|
||||
--namespace pangolin \
|
||||
--timeout=60s
|
||||
```
|
||||
|
||||
## Quick install with provisioning key
|
||||
|
||||
Newt 1.11+ supports provisioning-based installs. Use this when you want Newt to bootstrap credentials from a provisioning key.
|
||||
|
||||
Provisioning requires writable config persistence so Newt can store the generated configuration. The chart quickstart explicitly notes that provisioning requires a writable `CONFIG_FILE` target and that the chart provides this through `newtInstances[x].configPersistence`. ([GitHub][3])
|
||||
|
||||
Create `values-newt.yaml`:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
pangolinEndpoint: https://pangolin.example.com
|
||||
provisioningKey: "<your-provisioning-key>"
|
||||
newtName: "my-site"
|
||||
configPersistence:
|
||||
enabled: true
|
||||
type: emptyDir
|
||||
mountPath: /var/lib/newt
|
||||
fileName: config.json
|
||||
```
|
||||
|
||||
Install Newt:
|
||||
|
||||
```bash
|
||||
helm upgrade --install newt fossorial/newt \
|
||||
--namespace pangolin \
|
||||
--values values-newt.yaml
|
||||
```
|
||||
|
||||
<Note>
|
||||
`emptyDir` is enough for testing, but it is ephemeral. For durable provisioning state, use `type: persistentVolumeClaim` with an existing PVC.
|
||||
</Note>
|
||||
|
||||
Example with an existing PVC:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
pangolinEndpoint: https://pangolin.example.com
|
||||
provisioningKey: "<your-provisioning-key>"
|
||||
newtName: "my-site"
|
||||
configPersistence:
|
||||
enabled: true
|
||||
type: persistentVolumeClaim
|
||||
existingClaim: my-newt-config
|
||||
mountPath: /var/lib/newt
|
||||
fileName: config.json
|
||||
```
|
||||
|
||||
The Newt README includes both `emptyDir` and existing PVC provisioning examples. ([GitHub][4])
|
||||
|
||||
## Verifying connectivity
|
||||
|
||||
Follow the Newt logs:
|
||||
|
||||
```bash
|
||||
kubectl logs --namespace pangolin \
|
||||
-l app.kubernetes.io/name=newt \
|
||||
--follow
|
||||
```
|
||||
|
||||
In the Pangolin dashboard, verify that the site connected by this Newt instance is online.
|
||||
|
||||
If the pod is running but the site does not connect, check:
|
||||
|
||||
* `PANGOLIN_ENDPOINT`
|
||||
* Newt credentials or provisioning key
|
||||
* DNS resolution from inside the cluster
|
||||
* outbound network access from the Newt pod
|
||||
* TLS validity for the Pangolin endpoint
|
||||
|
||||
## Upgrade
|
||||
|
||||
Update the Helm repository:
|
||||
|
||||
```bash
|
||||
helm repo update fossorial
|
||||
```
|
||||
|
||||
Upgrade the release:
|
||||
|
||||
```bash
|
||||
helm upgrade newt fossorial/newt \
|
||||
--namespace pangolin \
|
||||
--values values-newt.yaml
|
||||
```
|
||||
|
||||
Check upgrade status:
|
||||
|
||||
```bash
|
||||
helm status newt --namespace pangolin
|
||||
helm history newt --namespace pangolin
|
||||
```
|
||||
|
||||
Rollback to a previous revision if needed:
|
||||
|
||||
```bash
|
||||
helm rollback newt <revision> --namespace pangolin
|
||||
```
|
||||
|
||||
## Multiple Newt instances
|
||||
|
||||
You can deploy multiple Newt instances with one chart release.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: site-a
|
||||
enabled: true
|
||||
auth:
|
||||
existingSecretName: newt-auth-site-a
|
||||
replicas: 1
|
||||
|
||||
- name: site-b
|
||||
enabled: true
|
||||
auth:
|
||||
existingSecretName: newt-auth-site-b
|
||||
replicas: 1
|
||||
```
|
||||
|
||||
Create a separate Secret for each site:
|
||||
|
||||
```bash
|
||||
kubectl create secret generic newt-auth-site-a \
|
||||
--namespace pangolin \
|
||||
--from-literal=PANGOLIN_ENDPOINT=https://pangolin.example.com \
|
||||
--from-literal=NEWT_ID=<site-a-newt-id> \
|
||||
--from-literal=NEWT_SECRET=<site-a-newt-secret>
|
||||
|
||||
kubectl create secret generic newt-auth-site-b \
|
||||
--namespace pangolin \
|
||||
--from-literal=PANGOLIN_ENDPOINT=https://pangolin.example.com \
|
||||
--from-literal=NEWT_ID=<site-b-newt-id> \
|
||||
--from-literal=NEWT_SECRET=<site-b-newt-secret>
|
||||
```
|
||||
|
||||
## Architecture notes
|
||||
|
||||
### Instance-based deployment
|
||||
|
||||
* `newtInstances[]` defines the Newt instances rendered by the chart.
|
||||
* Each enabled instance creates its own workload.
|
||||
* Each instance can use its own Secret, provisioning settings, resources, service settings, and network policy settings.
|
||||
* Per-instance namespace and service account overrides require `allowGlobalOverride: true`.
|
||||
|
||||
The chart values include `newtInstances[]`, per-instance namespace settings, and per-instance service account overrides. ([GitHub][2])
|
||||
|
||||
### Security defaults
|
||||
|
||||
By default, Newt runs without native WireGuard mode.
|
||||
|
||||
The chart values describe the default non-native mode as non-root with privilege escalation disabled, read-only root filesystem, and dropped capabilities. Native WireGuard mode requires a privileged container with capabilities such as `NET_ADMIN` and `SYS_MODULE`. ([GitHub][2])
|
||||
|
||||
<Warning>
|
||||
Only enable native WireGuard mode if you understand the required privileges and your cluster policy allows them.
|
||||
</Warning>
|
||||
|
||||
### RBAC
|
||||
|
||||
Newt chart `1.4.0` defaults `rbac.create` to `false`. Enable RBAC only when your selected Newt configuration requires Kubernetes API permissions.
|
||||
|
||||
```yaml
|
||||
rbac:
|
||||
create: true
|
||||
```
|
||||
|
||||
The chart changelog for `1.4.0` marks this as a breaking change: installations that relied on auto-created RBAC must explicitly enable `rbac.create=true` during upgrade. ([GitHub][1])
|
||||
|
||||
### Helm tests
|
||||
|
||||
Helm test Jobs are disabled by default.
|
||||
|
||||
Enable them only when you want to run chart test jobs:
|
||||
|
||||
```yaml
|
||||
global:
|
||||
tests:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
The chart quickstart notes that test Jobs are gated behind `global.tests.enabled`, which defaults to `false`. ([GitHub][3])
|
||||
|
||||
## OCI install
|
||||
|
||||
The Newt chart is also published as an OCI chart in GHCR.
|
||||
|
||||
Pull the chart:
|
||||
|
||||
```bash
|
||||
helm pull oci://ghcr.io/fosrl/helm-charts/newt \
|
||||
--version 1.4.0
|
||||
```
|
||||
|
||||
Install from OCI:
|
||||
|
||||
```bash
|
||||
helm upgrade --install newt oci://ghcr.io/fosrl/helm-charts/newt \
|
||||
--version 1.4.0 \
|
||||
--namespace pangolin \
|
||||
--values values-newt.yaml
|
||||
```
|
||||
|
||||
OCI changes where Helm pulls the chart from. It does not change the values file or the release behavior.
|
||||
|
||||
## References
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Chart README" href="https://github.com/fosrl/helm-charts/blob/main/charts/newt/README.md" icon="book" />
|
||||
<Card title="values.yaml" href="https://github.com/fosrl/helm-charts/blob/main/charts/newt/values.yaml" icon="file-code" />
|
||||
<Card title="values.schema.json" href="https://github.com/fosrl/helm-charts/blob/main/charts/newt/values.schema.json" icon="file-code" />
|
||||
<Card title="Artifact Hub" href="https://artifacthub.io/packages/helm/fosrl/newt" icon="box" />
|
||||
<Card title="Issues" href="https://github.com/fosrl/helm-charts/issues" icon="circle-question" />
|
||||
</CardGroup>
|
||||
|
||||
## Next steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Full Configuration" href="/self-host/manual/kubernetes/newt/configuration" icon="sliders">
|
||||
Review all Newt chart options.
|
||||
</Card>
|
||||
<Card title="Troubleshooting" href="/self-host/manual/kubernetes/newt/troubleshooting" icon="circle-question">
|
||||
Debug Newt deployment and connection issues.
|
||||
</Card>
|
||||
<Card title="Kustomize Install" href="/self-host/manual/kubernetes/newt/kustomize" icon="layer-group">
|
||||
Install Newt with rendered manifests and Kustomize overlays.
|
||||
</Card>
|
||||
<Card title="Pangolin Helm" href="/self-host/manual/kubernetes/pangolin/helm" icon="server">
|
||||
Install the Pangolin control plane.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
626
self-host/manual/kubernetes/newt/kustomize.mdx
Normal file
626
self-host/manual/kubernetes/newt/kustomize.mdx
Normal file
@@ -0,0 +1,626 @@
|
||||
---
|
||||
title: "Newt Kustomize"
|
||||
description: "Deploy Newt on Kubernetes using Helm-rendered manifests and Kustomize overlays."
|
||||
---
|
||||
|
||||
import PangolinCloudTocCta from "/snippets/pangolin-cloud-toc-cta.mdx";
|
||||
|
||||
<PangolinCloudTocCta />
|
||||
|
||||
|
||||
Use Kustomize when you want to manage Newt with rendered manifests, environment-specific overlays, and explicit patches in Git.
|
||||
|
||||
For Newt, the supported Kustomize workflow is:
|
||||
|
||||
1. Render the Newt Helm chart to manifests.
|
||||
2. Use the rendered output as the Kustomize base.
|
||||
3. Create overlays per site, cluster, or environment.
|
||||
4. Apply the overlay with `kubectl apply -k` or reconcile it with Argo CD or Flux.
|
||||
|
||||
## When to use Kustomize for Newt
|
||||
|
||||
Use Kustomize if you:
|
||||
|
||||
- want site-specific or environment-specific overlays
|
||||
- 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-site setup, use [Newt Helm](/self-host/manual/kubernetes/newt/helm).
|
||||
|
||||
## Supported approach
|
||||
|
||||
The Newt chart does not provide native Kustomize bases. Render the Helm chart first, then use Kustomize on the rendered manifests.
|
||||
|
||||
<Warning>
|
||||
Do not manage the same Newt resources with both a live Helm release and Kustomize. Pick one ownership model per environment.
|
||||
</Warning>
|
||||
|
||||
Recommended ownership model:
|
||||
|
||||
- Use Helm only to render the Newt 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
|
||||
|
||||
```text
|
||||
newt-deployment/
|
||||
├── base/
|
||||
│ ├── kustomization.yaml
|
||||
│ └── newt.yaml
|
||||
├── overlays/
|
||||
│ ├── site-a/
|
||||
│ │ ├── kustomization.yaml
|
||||
│ │ └── patches/
|
||||
│ │ └── deployment-resources.patch.yaml
|
||||
│ └── site-b/
|
||||
│ ├── kustomization.yaml
|
||||
│ └── patches/
|
||||
│ └── deployment-resources.patch.yaml
|
||||
└── values/
|
||||
├── values-base.yaml
|
||||
├── values-site-a.yaml
|
||||
└── values-site-b.yaml
|
||||
```
|
||||
|
||||
## Step 1: Create the namespace
|
||||
|
||||
Create the namespace before applying rendered manifests:
|
||||
|
||||
```bash
|
||||
kubectl create namespace pangolin
|
||||
```
|
||||
|
||||
If your cluster uses Pod Security Admission, namespace labels, or other policy labels, apply them before creating workloads.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
kubectl label namespace pangolin \
|
||||
pod-security.kubernetes.io/enforce=baseline \
|
||||
pod-security.kubernetes.io/audit=restricted \
|
||||
pod-security.kubernetes.io/warn=restricted
|
||||
```
|
||||
|
||||
## Step 2: Create Newt credentials
|
||||
|
||||
Create a Kubernetes Secret for each Newt site or instance.
|
||||
|
||||
```bash
|
||||
kubectl create secret generic newt-auth-site-a \
|
||||
--namespace pangolin \
|
||||
--from-literal=PANGOLIN_ENDPOINT=https://pangolin.example.com \
|
||||
--from-literal=NEWT_ID=<site-a-newt-id> \
|
||||
--from-literal=NEWT_SECRET=<site-a-newt-secret>
|
||||
```
|
||||
|
||||
For a second site:
|
||||
|
||||
```bash
|
||||
kubectl create secret generic newt-auth-site-b \
|
||||
--namespace pangolin \
|
||||
--from-literal=PANGOLIN_ENDPOINT=https://pangolin.example.com \
|
||||
--from-literal=NEWT_ID=<site-b-newt-id> \
|
||||
--from-literal=NEWT_SECRET=<site-b-newt-secret>
|
||||
```
|
||||
|
||||
<Note>
|
||||
Use existing Kubernetes Secrets for production. Do not commit Newt credentials into Helm values, rendered manifests, or Kustomize patches.
|
||||
</Note>
|
||||
|
||||
## Step 3: Create base values
|
||||
|
||||
Create `values/values-base.yaml`:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
replicas: 1
|
||||
auth:
|
||||
existingSecretName: newt-auth-site-a
|
||||
```
|
||||
|
||||
This values file uses an existing Secret. The default Secret keys are:
|
||||
|
||||
```text
|
||||
PANGOLIN_ENDPOINT
|
||||
NEWT_ID
|
||||
NEWT_SECRET
|
||||
```
|
||||
|
||||
Use `auth.keys.*` only when your Secret uses different key names.
|
||||
|
||||
## Step 4: Render Newt to the base
|
||||
|
||||
Add and update the Helm repository:
|
||||
|
||||
```bash
|
||||
helm repo add fossorial https://charts.fossorial.io
|
||||
helm repo update fossorial
|
||||
```
|
||||
|
||||
Render the Newt chart:
|
||||
|
||||
```bash
|
||||
mkdir -p base overlays/site-a/patches overlays/site-b/patches values
|
||||
|
||||
helm template newt fossorial/newt \
|
||||
--namespace pangolin \
|
||||
--values values/values-base.yaml \
|
||||
> base/newt.yaml
|
||||
```
|
||||
|
||||
You can also render from the GHCR OCI chart:
|
||||
|
||||
```bash
|
||||
helm template newt oci://ghcr.io/fosrl/helm-charts/newt \
|
||||
--version 1.4.0 \
|
||||
--namespace pangolin \
|
||||
--values values/values-base.yaml \
|
||||
> base/newt.yaml
|
||||
```
|
||||
|
||||
## Step 5: Create the base kustomization
|
||||
|
||||
```yaml
|
||||
# base/kustomization.yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- newt.yaml
|
||||
```
|
||||
|
||||
<Note>
|
||||
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.
|
||||
</Note>
|
||||
|
||||
## Step 6: Inspect the rendered resource names
|
||||
|
||||
Before writing patches, check the generated names:
|
||||
|
||||
```bash
|
||||
kustomize build base | grep -E "^(kind:| name:)"
|
||||
```
|
||||
|
||||
Or list the deployments:
|
||||
|
||||
```bash
|
||||
kustomize build base | yq '. | select(.kind == "Deployment") | .metadata.name'
|
||||
```
|
||||
|
||||
Use the actual rendered Deployment name in your patch targets.
|
||||
|
||||
<Warning>
|
||||
Do not assume the rendered Deployment name without checking the generated manifests. Helm naming can change with release name, chart name, `nameOverride`, or `fullnameOverride`.
|
||||
</Warning>
|
||||
|
||||
## Step 7: Create site-specific overlays
|
||||
|
||||
Example overlay for Site A:
|
||||
|
||||
```yaml
|
||||
# overlays/site-a/kustomization.yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- ../../base
|
||||
|
||||
labels:
|
||||
- pairs:
|
||||
app.kubernetes.io/site: site-a
|
||||
app.kubernetes.io/environment: production
|
||||
|
||||
patches:
|
||||
- path: patches/deployment-resources.patch.yaml
|
||||
target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
name: newt-main-tunnel
|
||||
```
|
||||
|
||||
Example resource patch:
|
||||
|
||||
```yaml
|
||||
# overlays/site-a/patches/deployment-resources.patch.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: newt-main-tunnel
|
||||
spec:
|
||||
replicas: 1
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: newt
|
||||
resources:
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
limits:
|
||||
memory: 256Mi
|
||||
```
|
||||
|
||||
<Note>
|
||||
Replace `newt-main-tunnel` with the actual Deployment name from your rendered manifests.
|
||||
</Note>
|
||||
|
||||
Example overlay for Site B with a different Secret is usually better handled by rendering a second base with a different values file.
|
||||
|
||||
Create `values/values-site-b.yaml`:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
replicas: 1
|
||||
auth:
|
||||
existingSecretName: newt-auth-site-b
|
||||
```
|
||||
|
||||
Then render a separate base for Site B:
|
||||
|
||||
```bash
|
||||
mkdir -p site-b/base
|
||||
|
||||
helm template newt-site-b fossorial/newt \
|
||||
--namespace pangolin \
|
||||
--values values/values-site-b.yaml \
|
||||
> site-b/base/newt.yaml
|
||||
```
|
||||
|
||||
<Info>
|
||||
For different credentials, endpoints, provisioning keys, or instance names, prefer separate Helm-rendered bases. Use Kustomize patches for environment-level changes such as labels, annotations, resources, scheduling, or NetworkPolicy adjustments.
|
||||
</Info>
|
||||
|
||||
## Common Kustomize patches for Newt
|
||||
|
||||
### Patch resource requests and limits
|
||||
|
||||
```yaml
|
||||
# overlays/site-a/kustomization.yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- ../../base
|
||||
|
||||
patches:
|
||||
- path: patches/resources.patch.yaml
|
||||
target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
name: newt-main-tunnel
|
||||
```
|
||||
|
||||
```yaml
|
||||
# overlays/site-a/patches/resources.patch.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: newt-main-tunnel
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: newt
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
memory: 512Mi
|
||||
```
|
||||
|
||||
### Patch log level
|
||||
|
||||
Prefer configuring log level through Helm values before rendering. If you still need a manifest patch, patch the generated environment variable carefully after inspecting the rendered Deployment.
|
||||
|
||||
Example JSON6902-style patch:
|
||||
|
||||
```yaml
|
||||
# overlays/site-a/kustomization.yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- ../../base
|
||||
|
||||
patches:
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
name: newt-main-tunnel
|
||||
patch: |-
|
||||
- op: add
|
||||
path: /spec/template/spec/containers/0/env/-
|
||||
value:
|
||||
name: LOG_LEVEL
|
||||
value: DEBUG
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Only use index-based JSON patches after checking the rendered manifest. Container order and environment variable layout can change between chart versions.
|
||||
</Warning>
|
||||
|
||||
### Add node affinity
|
||||
|
||||
```yaml
|
||||
# overlays/site-a/patches/node-affinity.patch.yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: newt-main-tunnel
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
affinity:
|
||||
nodeAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
nodeSelectorTerms:
|
||||
- matchExpressions:
|
||||
- key: site
|
||||
operator: In
|
||||
values:
|
||||
- site-a
|
||||
```
|
||||
|
||||
Reference the patch:
|
||||
|
||||
```yaml
|
||||
# overlays/site-a/kustomization.yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- ../../base
|
||||
|
||||
patches:
|
||||
- path: patches/node-affinity.patch.yaml
|
||||
target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
name: newt-main-tunnel
|
||||
```
|
||||
|
||||
### Add annotations
|
||||
|
||||
```yaml
|
||||
# overlays/site-a/kustomization.yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- ../../base
|
||||
|
||||
patches:
|
||||
- target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
name: newt-main-tunnel
|
||||
patch: |-
|
||||
- op: add
|
||||
path: /metadata/annotations
|
||||
value:
|
||||
example.com/owner: platform
|
||||
```
|
||||
|
||||
## Do not rename rendered Helm resources by default
|
||||
|
||||
Avoid Kustomize options such as `namePrefix` and `nameSuffix` for Helm-rendered bases unless you have validated every generated reference.
|
||||
|
||||
Renaming rendered resources can break:
|
||||
|
||||
* Service selectors
|
||||
* Secret references
|
||||
* ConfigMap references
|
||||
* ServiceAccount references
|
||||
* NetworkPolicy selectors
|
||||
* Prometheus monitor selectors
|
||||
|
||||
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:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/site-a
|
||||
```
|
||||
|
||||
Compare with the live cluster:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/site-a | kubectl diff -f -
|
||||
```
|
||||
|
||||
Apply the overlay:
|
||||
|
||||
```bash
|
||||
kubectl apply -k overlays/site-a
|
||||
```
|
||||
|
||||
Verify the deployment:
|
||||
|
||||
```bash
|
||||
kubectl get pods --namespace pangolin \
|
||||
-l app.kubernetes.io/name=newt
|
||||
|
||||
kubectl logs --namespace pangolin \
|
||||
-l app.kubernetes.io/name=newt \
|
||||
--tail=50
|
||||
```
|
||||
|
||||
## Updating the rendered base
|
||||
|
||||
When upgrading the Newt chart, re-render the base and review the changes.
|
||||
|
||||
```bash
|
||||
helm repo update fossorial
|
||||
```
|
||||
|
||||
Render the updated chart output:
|
||||
|
||||
```bash
|
||||
helm template newt fossorial/newt \
|
||||
--namespace pangolin \
|
||||
--values values/values-base.yaml \
|
||||
> base/newt.yaml
|
||||
```
|
||||
|
||||
Or with OCI:
|
||||
|
||||
```bash
|
||||
helm template newt oci://ghcr.io/fosrl/helm-charts/newt \
|
||||
--version 1.4.0 \
|
||||
--namespace pangolin \
|
||||
--values values/values-base.yaml \
|
||||
> base/newt.yaml
|
||||
```
|
||||
|
||||
Validate the overlay:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/site-a
|
||||
```
|
||||
|
||||
Review the diff:
|
||||
|
||||
```bash
|
||||
git diff
|
||||
kustomize build overlays/site-a | kubectl diff -f -
|
||||
```
|
||||
|
||||
Commit the updated base and overlays:
|
||||
|
||||
```bash
|
||||
git add base/ overlays/ values/
|
||||
git commit -m "Update Newt rendered manifests"
|
||||
```
|
||||
|
||||
Apply after review:
|
||||
|
||||
```bash
|
||||
kubectl apply -k overlays/site-a
|
||||
```
|
||||
|
||||
## Ownership model
|
||||
|
||||
Do not run `helm upgrade` against a release that is managed by Kustomize.
|
||||
|
||||
Avoid this pattern:
|
||||
|
||||
```bash
|
||||
helm upgrade newt fossorial/newt --namespace pangolin
|
||||
kubectl apply -k overlays/site-a
|
||||
```
|
||||
|
||||
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. |
|
||||
|
||||
## Validation
|
||||
|
||||
Validate Kustomize output:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/site-a
|
||||
```
|
||||
|
||||
Run a server-side dry run:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/site-a | kubectl apply -f - --dry-run=server
|
||||
```
|
||||
|
||||
Preview live changes:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/site-a | kubectl diff -f -
|
||||
```
|
||||
|
||||
Check live resources:
|
||||
|
||||
```bash
|
||||
kubectl get all --namespace pangolin
|
||||
kubectl get events --namespace pangolin --sort-by=.lastTimestamp
|
||||
```
|
||||
|
||||
## Kustomize with GitOps
|
||||
|
||||
Kustomize overlays work well with GitOps tools.
|
||||
|
||||
* [Argo CD](/self-host/manual/kubernetes/gitops/argocd) can reconcile a Kustomize overlay path directly.
|
||||
* [Flux](/self-host/manual/kubernetes/gitops/flux) can reconcile a Kustomize overlay with a `Kustomization` resource.
|
||||
|
||||
In GitOps workflows, the controller owns the apply operation. Do not also apply the same overlay manually unless you are debugging.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### The patch does not apply
|
||||
|
||||
Check the rendered resource name and kind:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
kubectl get pods --namespace pangolin
|
||||
kubectl describe pod <pod-name> --namespace pangolin
|
||||
kubectl get events --namespace pangolin --sort-by=.lastTimestamp
|
||||
```
|
||||
|
||||
### Newt does not connect
|
||||
|
||||
Check logs:
|
||||
|
||||
```bash
|
||||
kubectl logs --namespace pangolin \
|
||||
-l app.kubernetes.io/name=newt \
|
||||
--tail=100
|
||||
```
|
||||
|
||||
Verify:
|
||||
|
||||
* the Secret exists in the same namespace
|
||||
* `PANGOLIN_ENDPOINT` is reachable from the pod
|
||||
* `NEWT_ID` and `NEWT_SECRET` are correct
|
||||
* outbound DNS and HTTPS are allowed
|
||||
* TLS certificates for the Pangolin endpoint are valid
|
||||
|
||||
## Next steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Helm Install" href="/self-host/manual/kubernetes/newt/helm" icon="box">
|
||||
Install Newt with Helm.
|
||||
</Card>
|
||||
<Card title="Configuration" href="/self-host/manual/kubernetes/newt/configuration" icon="sliders">
|
||||
Review Newt chart options.
|
||||
</Card>
|
||||
<Card title="Troubleshooting" href="/self-host/manual/kubernetes/newt/troubleshooting" icon="circle-question">
|
||||
Debug Newt deployment and connection issues.
|
||||
</Card>
|
||||
<Card title="GitOps" href="/self-host/manual/kubernetes/gitops/overview" icon="code-branch">
|
||||
Deploy Kustomize overlays with Argo CD or Flux.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
752
self-host/manual/kubernetes/newt/troubleshooting.mdx
Normal file
752
self-host/manual/kubernetes/newt/troubleshooting.mdx
Normal file
@@ -0,0 +1,752 @@
|
||||
---
|
||||
title: "Newt Troubleshooting"
|
||||
description: "Diagnose and resolve common Newt Kubernetes deployment issues."
|
||||
---
|
||||
|
||||
import PangolinCloudTocCta from "/snippets/pangolin-cloud-toc-cta.mdx";
|
||||
|
||||
<PangolinCloudTocCta />
|
||||
|
||||
|
||||
Use this guide to troubleshoot Newt Kubernetes deployments installed with Helm, Kustomize, Argo CD, or Flux.
|
||||
|
||||
Start with the basic checks, then move to the section that matches the symptom.
|
||||
|
||||
## Quick checks
|
||||
|
||||
Set the namespace and release name used by your installation:
|
||||
|
||||
```bash
|
||||
export NEWT_NAMESPACE=pangolin
|
||||
export NEWT_RELEASE=newt
|
||||
```
|
||||
|
||||
Check the Helm release:
|
||||
|
||||
```bash
|
||||
helm status "$NEWT_RELEASE" --namespace "$NEWT_NAMESPACE"
|
||||
helm history "$NEWT_RELEASE" --namespace "$NEWT_NAMESPACE"
|
||||
```
|
||||
|
||||
Check Newt pods:
|
||||
|
||||
```bash
|
||||
kubectl get pods --namespace "$NEWT_NAMESPACE" \
|
||||
-l app.kubernetes.io/name=newt
|
||||
```
|
||||
|
||||
Check recent events:
|
||||
|
||||
```bash
|
||||
kubectl get events --namespace "$NEWT_NAMESPACE" \
|
||||
--sort-by=.lastTimestamp
|
||||
```
|
||||
|
||||
Check logs:
|
||||
|
||||
```bash
|
||||
kubectl logs --namespace "$NEWT_NAMESPACE" \
|
||||
-l app.kubernetes.io/name=newt \
|
||||
--tail=100
|
||||
```
|
||||
|
||||
Check the applied Helm values:
|
||||
|
||||
```bash
|
||||
helm get values "$NEWT_RELEASE" --namespace "$NEWT_NAMESPACE"
|
||||
```
|
||||
|
||||
<Note>
|
||||
Do not assume the pod or Deployment name. Chart-generated names can change with the Helm release name, instance name, `nameOverride`, or `fullnameOverride`.
|
||||
</Note>
|
||||
|
||||
## Get the generated resource names
|
||||
|
||||
List Newt resources:
|
||||
|
||||
```bash
|
||||
kubectl get deploy,sts,svc,secret,cm --namespace "$NEWT_NAMESPACE" \
|
||||
-l app.kubernetes.io/name=newt
|
||||
```
|
||||
|
||||
List pods with labels:
|
||||
|
||||
```bash
|
||||
kubectl get pods --namespace "$NEWT_NAMESPACE" \
|
||||
-l app.kubernetes.io/name=newt \
|
||||
--show-labels
|
||||
```
|
||||
|
||||
Store the first Newt pod name:
|
||||
|
||||
```bash
|
||||
export NEWT_POD="$(kubectl get pod --namespace "$NEWT_NAMESPACE" \
|
||||
-l app.kubernetes.io/name=newt \
|
||||
-o jsonpath='{.items[0].metadata.name}')"
|
||||
```
|
||||
|
||||
Then use:
|
||||
|
||||
```bash
|
||||
echo "$NEWT_POD"
|
||||
```
|
||||
|
||||
## Pod fails to start
|
||||
|
||||
### Symptoms
|
||||
|
||||
```text
|
||||
STATUS RESTARTS
|
||||
CrashLoopBackOff 5
|
||||
Error 3
|
||||
CreateContainerConfigError
|
||||
ImagePullBackOff
|
||||
```
|
||||
|
||||
### Check pod details
|
||||
|
||||
```bash
|
||||
kubectl describe pod "$NEWT_POD" --namespace "$NEWT_NAMESPACE"
|
||||
```
|
||||
|
||||
Check logs:
|
||||
|
||||
```bash
|
||||
kubectl logs "$NEWT_POD" --namespace "$NEWT_NAMESPACE" --tail=100
|
||||
```
|
||||
|
||||
If the container restarts quickly, check the previous logs:
|
||||
|
||||
```bash
|
||||
kubectl logs "$NEWT_POD" --namespace "$NEWT_NAMESPACE" --previous --tail=100
|
||||
```
|
||||
|
||||
### Common causes
|
||||
|
||||
| Symptom | Likely cause | Check |
|
||||
| ----------------------------------- | ------------------------------------------------------ | ---------------------------------------------------------- |
|
||||
| `Secret "..." not found` | Secret name does not match `auth.existingSecretName` | `kubectl get secret -n "$NEWT_NAMESPACE"` |
|
||||
| Missing env var or empty credential | Secret exists but key names do not match `auth.keys.*` | `kubectl describe secret <secret> -n "$NEWT_NAMESPACE"` |
|
||||
| Authentication failure | Wrong `NEWT_ID`, `NEWT_SECRET`, or provisioning key | Check credentials in Pangolin |
|
||||
| Endpoint connection errors | `PANGOLIN_ENDPOINT` is wrong or unreachable | Test DNS and HTTPS from the pod |
|
||||
| Image pull failure | Registry or image settings are wrong | `kubectl describe pod` |
|
||||
| Permission error with native mode | Native WireGuard mode requires privileged settings | Check `global.nativeMode.enabled` and `useNativeInterface` |
|
||||
|
||||
## Secret issues
|
||||
|
||||
### Verify the Secret exists
|
||||
|
||||
```bash
|
||||
kubectl get secret newt-auth --namespace "$NEWT_NAMESPACE"
|
||||
```
|
||||
|
||||
### Check Secret keys
|
||||
|
||||
```bash
|
||||
kubectl describe secret newt-auth --namespace "$NEWT_NAMESPACE"
|
||||
```
|
||||
|
||||
The default keys are:
|
||||
|
||||
```text
|
||||
PANGOLIN_ENDPOINT
|
||||
NEWT_ID
|
||||
NEWT_SECRET
|
||||
```
|
||||
|
||||
If your Secret uses different key names, map them in values:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
auth:
|
||||
existingSecretName: newt-auth
|
||||
keys:
|
||||
endpointKey: PANGOLIN_ENDPOINT
|
||||
idKey: NEWT_ID
|
||||
secretKey: NEWT_SECRET
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Do not paste decoded secrets into issue reports, logs, screenshots, or public repositories.
|
||||
</Warning>
|
||||
|
||||
### Check which Secret the pod uses
|
||||
|
||||
```bash
|
||||
kubectl get pod "$NEWT_POD" --namespace "$NEWT_NAMESPACE" \
|
||||
-o jsonpath='{range .spec.containers[*].envFrom[*]}{.secretRef.name}{"\n"}{end}'
|
||||
```
|
||||
|
||||
Also inspect explicit Secret references:
|
||||
|
||||
```bash
|
||||
kubectl get pod "$NEWT_POD" --namespace "$NEWT_NAMESPACE" -o yaml | grep -A5 -B2 secretKeyRef
|
||||
```
|
||||
|
||||
## Newt cannot reach Pangolin
|
||||
|
||||
### Test DNS from the Newt pod
|
||||
|
||||
```bash
|
||||
kubectl exec "$NEWT_POD" --namespace "$NEWT_NAMESPACE" -- \
|
||||
nslookup pangolin.example.com
|
||||
```
|
||||
|
||||
### Test HTTPS from the Newt pod
|
||||
|
||||
```bash
|
||||
kubectl exec "$NEWT_POD" --namespace "$NEWT_NAMESPACE" -- \
|
||||
wget -S -O- https://pangolin.example.com 2>&1 | head -40
|
||||
```
|
||||
|
||||
Depending on the image, `curl`, `wget`, `nc`, or `nslookup` may not be available. If needed, run a temporary debug pod in the same namespace:
|
||||
|
||||
```bash
|
||||
kubectl run net-debug \
|
||||
--namespace "$NEWT_NAMESPACE" \
|
||||
--rm -it \
|
||||
--image=curlimages/curl:latest \
|
||||
--restart=Never \
|
||||
-- sh
|
||||
```
|
||||
|
||||
Then test:
|
||||
|
||||
```bash
|
||||
curl -vk https://pangolin.example.com
|
||||
```
|
||||
|
||||
### Common causes
|
||||
|
||||
| Problem | What to check |
|
||||
| -------------------------------- | --------------------------------------------------------- |
|
||||
| DNS fails | CoreDNS, NetworkPolicy egress to DNS, wrong hostname |
|
||||
| HTTPS fails | ingress, TLS certificate, firewall, proxy, wrong endpoint |
|
||||
| TLS verification fails | certificate chain, hostname mismatch, private CA |
|
||||
| Works locally but not in cluster | egress policies, proxy settings, DNS split-horizon |
|
||||
|
||||
## Newt pod is running but site is offline
|
||||
|
||||
Check logs:
|
||||
|
||||
```bash
|
||||
kubectl logs "$NEWT_POD" --namespace "$NEWT_NAMESPACE" --tail=200
|
||||
```
|
||||
|
||||
Check the site in the Pangolin dashboard.
|
||||
|
||||
Verify:
|
||||
|
||||
* the site credentials belong to the same site
|
||||
* the site was not deleted or regenerated in Pangolin
|
||||
* `PANGOLIN_ENDPOINT` points to the correct Pangolin URL
|
||||
* the cluster can resolve and reach the Pangolin endpoint
|
||||
* outbound HTTPS is allowed from the Newt namespace
|
||||
* the Secret is in the same namespace as the Newt workload
|
||||
|
||||
If you use provisioning, also verify:
|
||||
|
||||
* `provisioningKey` is valid
|
||||
* `newtName` is set as expected
|
||||
* `configPersistence.enabled=true`
|
||||
* the configured `CONFIG_FILE` path is writable
|
||||
|
||||
## Provisioning issues
|
||||
|
||||
Newt 1.11+ provisioning requires writable config persistence.
|
||||
|
||||
### Symptoms
|
||||
|
||||
* Newt starts but does not keep generated credentials after restart.
|
||||
* Newt provisions repeatedly.
|
||||
* Logs mention config file or write errors.
|
||||
* Pod restarts cause the site to appear as a new or unconfigured instance.
|
||||
|
||||
### Check values
|
||||
|
||||
```bash
|
||||
helm get values "$NEWT_RELEASE" --namespace "$NEWT_NAMESPACE"
|
||||
```
|
||||
|
||||
Provisioning example:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
auth:
|
||||
pangolinEndpoint: https://pangolin.example.com
|
||||
provisioningKey: "<provisioning-key>"
|
||||
newtName: "my-site"
|
||||
configPersistence:
|
||||
enabled: true
|
||||
type: emptyDir
|
||||
mountPath: /var/lib/newt
|
||||
fileName: config.json
|
||||
```
|
||||
|
||||
For durable state, use an existing PVC:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
enabled: true
|
||||
auth:
|
||||
pangolinEndpoint: https://pangolin.example.com
|
||||
provisioningKey: "<provisioning-key>"
|
||||
newtName: "my-site"
|
||||
configPersistence:
|
||||
enabled: true
|
||||
type: persistentVolumeClaim
|
||||
existingClaim: my-newt-config
|
||||
mountPath: /var/lib/newt
|
||||
fileName: config.json
|
||||
```
|
||||
|
||||
<Note>
|
||||
`emptyDir` is recreated when the pod is recreated. Use a PVC if the generated configuration must survive pod replacement.
|
||||
</Note>
|
||||
|
||||
## Native WireGuard permission issues
|
||||
|
||||
By default, Newt does not require native WireGuard privileges.
|
||||
|
||||
Only check this section if you enabled native WireGuard mode:
|
||||
|
||||
```yaml
|
||||
global:
|
||||
nativeMode:
|
||||
enabled: true
|
||||
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
useNativeInterface: true
|
||||
```
|
||||
|
||||
### Symptoms
|
||||
|
||||
```text
|
||||
operation not permitted
|
||||
cannot create interface
|
||||
permission denied
|
||||
```
|
||||
|
||||
### Check security context
|
||||
|
||||
```bash
|
||||
kubectl get pod "$NEWT_POD" --namespace "$NEWT_NAMESPACE" -o yaml | grep -A30 securityContext
|
||||
```
|
||||
|
||||
Native mode requires privileged workload settings and capabilities such as `NET_ADMIN` and `SYS_MODULE`.
|
||||
|
||||
<Warning>
|
||||
Only enable native WireGuard mode if your cluster policy allows privileged workloads. Do not add `NET_ADMIN` to the default non-native deployment unless you know it is required.
|
||||
</Warning>
|
||||
|
||||
### Check namespace policy
|
||||
|
||||
```bash
|
||||
kubectl get namespace "$NEWT_NAMESPACE" --show-labels
|
||||
```
|
||||
|
||||
A namespace with a restricted Pod Security Admission profile may block native mode.
|
||||
|
||||
## Service not created or not reachable
|
||||
|
||||
### Important behavior
|
||||
|
||||
`acceptClients` does not create a Service.
|
||||
|
||||
A Service is created through:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
service:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
The chart also has `service.enabledWhenAcceptClients`, but runtime client behavior and Service rendering should still be verified in the rendered manifests.
|
||||
|
||||
### Check Services
|
||||
|
||||
```bash
|
||||
kubectl get svc --namespace "$NEWT_NAMESPACE" \
|
||||
-l app.kubernetes.io/name=newt
|
||||
```
|
||||
|
||||
Describe the Service:
|
||||
|
||||
```bash
|
||||
kubectl describe svc <service-name> --namespace "$NEWT_NAMESPACE"
|
||||
```
|
||||
|
||||
### LoadBalancer stuck in pending
|
||||
|
||||
```text
|
||||
EXTERNAL-IP <pending>
|
||||
```
|
||||
|
||||
Common causes:
|
||||
|
||||
* the cluster has no cloud load balancer integration
|
||||
* bare-metal cluster without MetalLB or equivalent
|
||||
* cloud provider quota or permission issue
|
||||
* invalid `loadBalancerClass`
|
||||
* invalid `loadBalancerSourceRanges`
|
||||
|
||||
For bare-metal clusters, use MetalLB or another load balancer implementation, or use `NodePort` if appropriate.
|
||||
|
||||
## Metrics scraping does not work
|
||||
|
||||
Metrics are disabled by default.
|
||||
|
||||
Enable metrics:
|
||||
|
||||
```yaml
|
||||
global:
|
||||
metrics:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
The chart default admin address is:
|
||||
|
||||
```yaml
|
||||
global:
|
||||
metrics:
|
||||
adminAddr: ":2112"
|
||||
```
|
||||
|
||||
This listens on all interfaces and allows in-cluster scraping. Do not set it to `127.0.0.1:2112` if Prometheus scrapes from another pod.
|
||||
|
||||
### Metrics Service
|
||||
|
||||
Enable the metrics Service:
|
||||
|
||||
```yaml
|
||||
global:
|
||||
metrics:
|
||||
enabled: true
|
||||
service:
|
||||
enabled: true
|
||||
port: 2112
|
||||
```
|
||||
|
||||
### ServiceMonitor
|
||||
|
||||
If you use Prometheus Operator:
|
||||
|
||||
```yaml
|
||||
global:
|
||||
metrics:
|
||||
enabled: true
|
||||
service:
|
||||
enabled: true
|
||||
serviceMonitor:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
Check resources:
|
||||
|
||||
```bash
|
||||
kubectl get svc,podmonitor,servicemonitor,prometheusrule \
|
||||
--namespace "$NEWT_NAMESPACE" \
|
||||
-l app.kubernetes.io/name=newt
|
||||
```
|
||||
|
||||
<Note>
|
||||
The chart has separate metrics values for container port, admin address, and metrics Service port. Check the rendered manifest when changing these values.
|
||||
</Note>
|
||||
|
||||
## NetworkPolicy blocks traffic
|
||||
|
||||
If NetworkPolicy is enabled, check that the policy allows required egress.
|
||||
|
||||
Newt usually needs egress to:
|
||||
|
||||
* DNS
|
||||
* Pangolin endpoint over HTTPS
|
||||
* any tunnel or connectivity endpoints used by your deployment
|
||||
|
||||
Check policies:
|
||||
|
||||
```bash
|
||||
kubectl get networkpolicy --namespace "$NEWT_NAMESPACE"
|
||||
kubectl describe networkpolicy --namespace "$NEWT_NAMESPACE"
|
||||
```
|
||||
|
||||
If DNS is blocked, enable or add DNS egress rules.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
global:
|
||||
networkPolicy:
|
||||
enabled: true
|
||||
components:
|
||||
dns:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
If HTTPS egress is blocked, add an appropriate custom egress rule for your environment.
|
||||
|
||||
## Multiple Newt instances conflict
|
||||
|
||||
### Symptoms
|
||||
|
||||
* Multiple pods run, but only one site connects.
|
||||
* Both instances use the same credentials.
|
||||
* A site appears to flap between instances.
|
||||
* Logs show authentication or registration conflicts.
|
||||
|
||||
### Check values
|
||||
|
||||
```bash
|
||||
helm get values "$NEWT_RELEASE" --namespace "$NEWT_NAMESPACE"
|
||||
```
|
||||
|
||||
Each instance should use its own credentials or provisioning identity:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: site-a
|
||||
enabled: true
|
||||
auth:
|
||||
existingSecretName: newt-auth-site-a
|
||||
|
||||
- name: site-b
|
||||
enabled: true
|
||||
auth:
|
||||
existingSecretName: newt-auth-site-b
|
||||
```
|
||||
|
||||
Create separate Secrets:
|
||||
|
||||
```bash
|
||||
kubectl create secret generic newt-auth-site-a \
|
||||
--namespace "$NEWT_NAMESPACE" \
|
||||
--from-literal=PANGOLIN_ENDPOINT=https://pangolin.example.com \
|
||||
--from-literal=NEWT_ID=<site-a-newt-id> \
|
||||
--from-literal=NEWT_SECRET=<site-a-newt-secret>
|
||||
|
||||
kubectl create secret generic newt-auth-site-b \
|
||||
--namespace "$NEWT_NAMESPACE" \
|
||||
--from-literal=PANGOLIN_ENDPOINT=https://pangolin.example.com \
|
||||
--from-literal=NEWT_ID=<site-b-newt-id> \
|
||||
--from-literal=NEWT_SECRET=<site-b-newt-secret>
|
||||
```
|
||||
|
||||
## RBAC or service account issues
|
||||
|
||||
Chart `1.4.0` disables RBAC creation by default.
|
||||
|
||||
Check service account and RBAC:
|
||||
|
||||
```bash
|
||||
kubectl get serviceaccount,role,rolebinding \
|
||||
--namespace "$NEWT_NAMESPACE" \
|
||||
-l app.kubernetes.io/name=newt
|
||||
```
|
||||
|
||||
If your configuration requires Kubernetes API access, enable RBAC:
|
||||
|
||||
```yaml
|
||||
rbac:
|
||||
create: true
|
||||
clusterRole: false
|
||||
```
|
||||
|
||||
For most Newt deployments, RBAC is not required.
|
||||
|
||||
## High CPU or memory usage
|
||||
|
||||
Check resource usage:
|
||||
|
||||
```bash
|
||||
kubectl top pod --namespace "$NEWT_NAMESPACE" \
|
||||
-l app.kubernetes.io/name=newt
|
||||
```
|
||||
|
||||
Check current resource settings:
|
||||
|
||||
```bash
|
||||
kubectl get pod "$NEWT_POD" --namespace "$NEWT_NAMESPACE" \
|
||||
-o jsonpath='{.spec.containers[0].resources}'
|
||||
```
|
||||
|
||||
Tune resources in values:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
resources:
|
||||
requests:
|
||||
cpu: 200m
|
||||
memory: 256Mi
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 512Mi
|
||||
```
|
||||
|
||||
Then upgrade:
|
||||
|
||||
```bash
|
||||
helm upgrade "$NEWT_RELEASE" fossorial/newt \
|
||||
--namespace "$NEWT_NAMESPACE" \
|
||||
--values values-newt.yaml
|
||||
```
|
||||
|
||||
Common causes of high usage:
|
||||
|
||||
* high tunnel traffic
|
||||
* too low resource limits
|
||||
* repeated reconnect loops
|
||||
* excessive debug logging
|
||||
* MTU or network path issues
|
||||
|
||||
## MTU issues
|
||||
|
||||
### Symptoms
|
||||
|
||||
* Connections establish but large transfers fail.
|
||||
* Some websites or services work, others hang.
|
||||
* Logs show repeated reconnects.
|
||||
* Throughput is much lower than expected.
|
||||
|
||||
Newt defaults to MTU `1280`.
|
||||
|
||||
Try another MTU only after confirming basic connectivity:
|
||||
|
||||
```yaml
|
||||
newtInstances:
|
||||
- name: main-tunnel
|
||||
mtu: 1280
|
||||
```
|
||||
|
||||
Upgrade after changing values:
|
||||
|
||||
```bash
|
||||
helm upgrade "$NEWT_RELEASE" fossorial/newt \
|
||||
--namespace "$NEWT_NAMESPACE" \
|
||||
--values values-newt.yaml
|
||||
```
|
||||
|
||||
## Helm debugging
|
||||
|
||||
Preview an upgrade:
|
||||
|
||||
```bash
|
||||
helm upgrade "$NEWT_RELEASE" fossorial/newt \
|
||||
--namespace "$NEWT_NAMESPACE" \
|
||||
--values values-newt.yaml \
|
||||
--dry-run
|
||||
```
|
||||
|
||||
Render the chart locally:
|
||||
|
||||
```bash
|
||||
helm template "$NEWT_RELEASE" fossorial/newt \
|
||||
--namespace "$NEWT_NAMESPACE" \
|
||||
--values values-newt.yaml
|
||||
```
|
||||
|
||||
Show rendered manifests from the live release:
|
||||
|
||||
```bash
|
||||
helm get manifest "$NEWT_RELEASE" --namespace "$NEWT_NAMESPACE"
|
||||
```
|
||||
|
||||
Show values from the live release:
|
||||
|
||||
```bash
|
||||
helm get values "$NEWT_RELEASE" --namespace "$NEWT_NAMESPACE"
|
||||
```
|
||||
|
||||
Rollback:
|
||||
|
||||
```bash
|
||||
helm rollback "$NEWT_RELEASE" <revision> --namespace "$NEWT_NAMESPACE"
|
||||
```
|
||||
|
||||
## Kustomize debugging
|
||||
|
||||
Validate the overlay:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/site-a
|
||||
```
|
||||
|
||||
Run a server-side dry run:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/site-a | kubectl apply -f - --dry-run=server
|
||||
```
|
||||
|
||||
Preview live changes:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/site-a | kubectl diff -f -
|
||||
```
|
||||
|
||||
If a patch does not apply, inspect generated resource names:
|
||||
|
||||
```bash
|
||||
kustomize build base | grep -E "^(kind:| name:)"
|
||||
```
|
||||
|
||||
## Collect diagnostics
|
||||
|
||||
Collect logs and resource information:
|
||||
|
||||
```bash
|
||||
kubectl logs --namespace "$NEWT_NAMESPACE" \
|
||||
-l app.kubernetes.io/name=newt \
|
||||
--tail=200 > newt-logs.txt
|
||||
|
||||
kubectl get pods --namespace "$NEWT_NAMESPACE" \
|
||||
-l app.kubernetes.io/name=newt \
|
||||
-o yaml > newt-pods.yaml
|
||||
|
||||
kubectl get events --namespace "$NEWT_NAMESPACE" \
|
||||
--sort-by=.lastTimestamp > newt-events.txt
|
||||
|
||||
helm get values "$NEWT_RELEASE" \
|
||||
--namespace "$NEWT_NAMESPACE" > newt-helm-values.yaml
|
||||
|
||||
helm get manifest "$NEWT_RELEASE" \
|
||||
--namespace "$NEWT_NAMESPACE" > newt-helm-manifest.yaml
|
||||
```
|
||||
|
||||
If using Kustomize:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/site-a > newt-kustomize-output.yaml
|
||||
```
|
||||
|
||||
Before sharing diagnostics, remove:
|
||||
|
||||
* Newt credentials
|
||||
* provisioning keys
|
||||
* TLS private keys
|
||||
* tokens
|
||||
* passwords
|
||||
* internal hostnames if sensitive
|
||||
|
||||
## Next steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Configuration" href="/self-host/manual/kubernetes/newt/configuration" icon="sliders">
|
||||
Review Newt chart options.
|
||||
</Card>
|
||||
<Card title="Helm Install" href="/self-host/manual/kubernetes/newt/helm" icon="box">
|
||||
Install Newt with Helm.
|
||||
</Card>
|
||||
<Card title="Kustomize Install" href="/self-host/manual/kubernetes/newt/kustomize" icon="layer-group">
|
||||
Install Newt with rendered manifests and Kustomize overlays.
|
||||
</Card>
|
||||
<Card title="GitOps" href="/self-host/manual/kubernetes/gitops/overview" icon="code-branch">
|
||||
Deploy Newt with Argo CD or Flux.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
108
self-host/manual/kubernetes/overview.mdx
Normal file
108
self-host/manual/kubernetes/overview.mdx
Normal file
@@ -0,0 +1,108 @@
|
||||
---
|
||||
title: "Overview"
|
||||
description: "Deploy Pangolin, Newt, and related components on Kubernetes with Helm, Kustomize, GitOps, or Helmfile."
|
||||
---
|
||||
|
||||
import PangolinCloudTocCta from "/snippets/pangolin-cloud-toc-cta.mdx";
|
||||
|
||||
<PangolinCloudTocCta />
|
||||
|
||||
|
||||
## Kubernetes deployment options
|
||||
|
||||
Kubernetes is a good fit for running Pangolin-related components when you need repeatable deployments, workload isolation, rolling updates, and integration with existing cluster services such as ingress, storage, monitoring, and network policy.
|
||||
|
||||
This section covers the main Kubernetes workflows:
|
||||
|
||||
- **Helm** for the recommended chart-based installation and upgrade workflow.
|
||||
- **Kustomize** for overlay-based customization and manifest-driven deployments.
|
||||
- **GitOps** with Argo CD or Flux for reconciling Helm charts, Kustomize overlays, or manifests from Git.
|
||||
- **Helmfile** for advanced setups that manage multiple Helm releases together.
|
||||
|
||||
## What this section covers
|
||||
|
||||
- Kubernetes prerequisites and cluster requirements.
|
||||
- Installation workflows for Helm, Kustomize, GitOps, and Helmfile.
|
||||
- Pangolin installation, configuration, and troubleshooting.
|
||||
- Newt installation, configuration, and troubleshooting.
|
||||
- How Pangolin, Gerbil, Traefik, Newt and Pangolin-Kube-Controller fit together in tunneled deployments.
|
||||
|
||||
## Components
|
||||
|
||||
| Component | Role |
|
||||
| --- | --- |
|
||||
| Pangolin | Main application and control plane for the dashboard, API, authentication, configuration, and database-backed state. |
|
||||
| Gerbil | WireGuard interface management service used as part of the Pangolin tunnel stack. |
|
||||
| Newt | Site connector used to expose private resources through Pangolin. Newt runs as a user-space WireGuard tunnel client and TCP/UDP proxy. |
|
||||
| Traefik | Reverse proxy and router for ingress traffic. |
|
||||
| PostgreSQL / SQlite | Database options for Pangolin deployments, depending on the selected installation workflow and chart configuration. |
|
||||
| Controller | Kubernetes controller for integration with Traefik cluster resources, replacing single Traefik instances with Traefik ingress controllers. |
|
||||
|
||||
<Info>
|
||||
For local reverse proxy deployments, the full tunnel stack may not be required. Tunneled sites require the components needed for Newt and WireGuard-based connectivity.
|
||||
</Info>
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
U[Users] --> T[Traefik]
|
||||
T --> P[Pangolin]
|
||||
P --> G[Gerbil]
|
||||
N[Newt] --> G
|
||||
P --> D[(Database)]
|
||||
```
|
||||
|
||||
## Method comparison
|
||||
|
||||
Choose the workflow that matches how you already manage Kubernetes applications:
|
||||
|
||||
| Method | Best for | Complexity | GitOps fit |
|
||||
| --- | --- | --- | --- |
|
||||
| **Helm** | Standard Kubernetes installs and upgrades | Low | Works with Argo CD and Flux |
|
||||
| **Kustomize** | Environment-specific overlays and manifest customization | Medium | Works with Argo CD and Flux |
|
||||
| **Argo CD** | Git-driven reconciliation with a web UI and sync status | Medium | Native GitOps workflow |
|
||||
| **Flux** | Declarative GitOps using Kubernetes custom resources | Medium | Native GitOps workflow |
|
||||
| **Helmfile** | Managing multiple Helm releases as one deployment stack | Medium | Usually used from CI/CD or a controlled automation workflow |
|
||||
|
||||
<Tip>
|
||||
Argo CD and Flux are delivery and reconciliation tools. They do not replace Helm or Kustomize. They can deploy Helm charts, Kustomize overlays, and other Kubernetes manifests.
|
||||
</Tip>
|
||||
|
||||
## Recommended starting points
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Choose a Method" href="/self-host/manual/kubernetes/choose-method" icon="code-branch">
|
||||
Compare Helm, Kustomize, GitOps, and Helmfile before choosing a workflow.
|
||||
</Card>
|
||||
<Card title="Prerequisites" href="/self-host/manual/kubernetes/prerequisites" icon="list-check">
|
||||
Review the cluster, ingress, storage, DNS, and tooling requirements.
|
||||
</Card>
|
||||
<Card title="Helm" href="/self-host/manual/kubernetes/helm" icon="layer-group">
|
||||
Start with the recommended chart-based Kubernetes workflow.
|
||||
</Card>
|
||||
<Card title="Kustomize" href="/self-host/manual/kubernetes/kustomize" icon="layer-group">
|
||||
Use overlays and patches for manifest-based deployments.
|
||||
</Card>
|
||||
<Card title="GitOps" href="/self-host/manual/kubernetes/gitops/overview" icon="code-branch">
|
||||
Deploy with Argo CD or Flux from Git.
|
||||
</Card>
|
||||
<Card title="Helmfile" href="/self-host/manual/kubernetes/helmfile" icon="scroll">
|
||||
Manage Pangolin, Newt, and supporting Helm releases together.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
## Component quick links
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Pangolin with Helm" href="/self-host/manual/kubernetes/pangolin/helm" icon="server">
|
||||
Install Pangolin with the Helm chart.
|
||||
</Card>
|
||||
<Card title="Pangolin Configuration" href="/self-host/manual/kubernetes/pangolin/configuration" icon="sliders">
|
||||
Configure Pangolin for your Kubernetes environment.
|
||||
</Card>
|
||||
<Card title="Newt with Helm" href="/self-host/manual/kubernetes/newt/helm" icon="server">
|
||||
Install Newt in a Kubernetes cluster.
|
||||
</Card>
|
||||
<Card title="Newt Configuration" href="/self-host/manual/kubernetes/newt/configuration" icon="sliders">
|
||||
Configure Newt credentials, endpoints, resources, and runtime settings.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
1016
self-host/manual/kubernetes/pangolin/configuration.mdx
Normal file
1016
self-host/manual/kubernetes/pangolin/configuration.mdx
Normal file
File diff suppressed because it is too large
Load Diff
408
self-host/manual/kubernetes/pangolin/helm.mdx
Normal file
408
self-host/manual/kubernetes/pangolin/helm.mdx
Normal file
@@ -0,0 +1,408 @@
|
||||
---
|
||||
title: "Pangolin Helm"
|
||||
description: "Quick-start guide for installing Pangolin on Kubernetes using Helm."
|
||||
---
|
||||
|
||||
import PangolinCloudTocCta from "/snippets/pangolin-cloud-toc-cta.mdx";
|
||||
|
||||
<PangolinCloudTocCta />
|
||||
|
||||
|
||||
<Warning>
|
||||
The Pangolin Helm chart is currently alpha (`0.1.0-alpha.0`). Test installs and upgrades in a non-production environment before using the chart for production traffic.
|
||||
</Warning>
|
||||
|
||||
## What Pangolin deploys
|
||||
|
||||
The Pangolin Helm chart deploys the Pangolin control plane and related Kubernetes components.
|
||||
|
||||
Depending on the selected values, the chart can deploy:
|
||||
|
||||
- **Pangolin application**: dashboard, API, authentication, configuration, and application state.
|
||||
- **pangolin-kube-controller**: Kubernetes controller used in controller mode.
|
||||
- **Gerbil**: WireGuard tunnel manager used by the Pangolin tunnel stack.
|
||||
- **Traefik integration**: Traefik CRD-based routing in controller mode, bundled Traefik controller when enabled, or standalone Traefik mode.
|
||||
- **Database backend**: CloudNativePG, external PostgreSQL, embedded PostgreSQL, or SQLite.
|
||||
|
||||
## Version matrix
|
||||
|
||||
| Item | Value |
|
||||
| --- | --- |
|
||||
| Chart version | `0.1.0-alpha.0` |
|
||||
| Kubernetes version | `>=1.30.14-0` |
|
||||
| Pangolin appVersion | `1.18.2` |
|
||||
| Pangolin default image tag | `1.18.2` |
|
||||
| Pangolin PostgreSQL image tag | `postgresql-1.18.2` |
|
||||
| pangolin-kube-controller tag | `0.1.0-alpha.1` |
|
||||
| Gerbil tag | `1.3.1` |
|
||||
| Traefik tag | `v3.6.15` |
|
||||
|
||||
The current chart metadata defines chart version `0.1.0-alpha.0`, app version `1.18.2`, Kubernetes `>=1.30.14-0`, and the component image metadata listed above. :contentReference[oaicite:0]{index=0}
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before installing Pangolin, you need:
|
||||
|
||||
- Kubernetes `1.30.14` or newer.
|
||||
- Helm 3.x.
|
||||
- `kubectl` access to the target cluster.
|
||||
- A namespace prepared for the install.
|
||||
- A StorageClass if you use chart-managed persistent storage.
|
||||
- DNS records for the Pangolin dashboard and tunnel endpoint.
|
||||
- Traefik CRDs and a Traefik controller when using `deployment.type=controller`.
|
||||
- A database plan: CloudNativePG, external PostgreSQL, embedded PostgreSQL, or SQLite.
|
||||
|
||||
See [Prerequisites](/self-host/manual/kubernetes/prerequisites) for detailed cluster, namespace, storage, networking, and security requirements.
|
||||
|
||||
## Recommended quick install
|
||||
|
||||
This quick install uses:
|
||||
|
||||
- `deployment.type=controller`
|
||||
- `deployment.mode=multi`
|
||||
- `database.mode=cloudnativepg`
|
||||
- chart-managed CloudNativePG operator and cluster
|
||||
- chart-managed dashboard `IngressRoute`
|
||||
- Traefik cert resolver for TLS
|
||||
|
||||
<Note>
|
||||
This example assumes a Traefik controller is available and can process the chart-managed `IngressRoute`. If you want the chart to install the bundled Traefik controller, set `deployment.installTraefikController=true`.
|
||||
</Note>
|
||||
|
||||
### Step 1: Create the namespace
|
||||
|
||||
Create the namespace before installing the chart:
|
||||
|
||||
```bash
|
||||
kubectl create namespace pangolin
|
||||
```
|
||||
|
||||
Gerbil requires `NET_ADMIN` for WireGuard interface management. If your cluster enforces Pod Security Admission, label the namespace accordingly:
|
||||
|
||||
```bash
|
||||
kubectl label namespace pangolin \
|
||||
pod-security.kubernetes.io/enforce=privileged \
|
||||
pod-security.kubernetes.io/warn=baseline \
|
||||
pod-security.kubernetes.io/audit=restricted \
|
||||
--overwrite
|
||||
```
|
||||
|
||||
<Warning>
|
||||
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` for WireGuard.
|
||||
</Warning>
|
||||
|
||||
### Step 2: Create a Pangolin app secret
|
||||
|
||||
Create a Secret for `SERVER_SECRET`:
|
||||
|
||||
```bash
|
||||
kubectl create secret generic pangolin-app-secret \
|
||||
--namespace pangolin \
|
||||
--from-literal=SERVER_SECRET='<strong-random-secret>'
|
||||
```
|
||||
|
||||
Use a long random value. Do not commit this secret to Git.
|
||||
|
||||
### Step 3: Create a values file
|
||||
|
||||
Create `values-pangolin.yaml`:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
Important points:
|
||||
|
||||
* Replace `pangolin.example.com`, `example.com`, and `vpn.example.com`.
|
||||
* Keep `pangolin.config.gerbil.start_port` aligned with `gerbil.ports.wg1`.
|
||||
* Keep `pangolin.config.gerbil.clients_start_port` aligned with `gerbil.ports.wg2`.
|
||||
* Use `gerbil.startupMode=delayed` for the first install if Gerbil should not start before the initial Pangolin setup is complete.
|
||||
|
||||
The chart defaults to `deployment.type=controller`, `deployment.mode=multi`, `database.mode=cloudnativepg`, and NetworkPolicy rendering enabled. Gerbil `startupMode` supports `normal`, `delayed`, and `disabledUntilSetup`. ([GitHub][1])
|
||||
|
||||
### Step 4: Install Pangolin
|
||||
|
||||
Add the Helm repository:
|
||||
|
||||
```bash
|
||||
helm repo add fossorial https://charts.fossorial.io
|
||||
helm repo update fossorial
|
||||
```
|
||||
|
||||
Install Pangolin:
|
||||
|
||||
```bash
|
||||
helm upgrade --install pangolin fossorial/pangolin \
|
||||
--namespace pangolin \
|
||||
--values values-pangolin.yaml
|
||||
```
|
||||
|
||||
Do not use `--create-namespace` here. The namespace was created and labeled before installation.
|
||||
|
||||
### Step 5: Verify the deployment
|
||||
|
||||
Check Helm release status:
|
||||
|
||||
```bash
|
||||
helm status pangolin --namespace pangolin
|
||||
helm history pangolin --namespace pangolin
|
||||
```
|
||||
|
||||
Check workloads:
|
||||
|
||||
```bash
|
||||
kubectl get pods --namespace pangolin
|
||||
kubectl get deploy,statefulset --namespace pangolin
|
||||
```
|
||||
|
||||
Check Services:
|
||||
|
||||
```bash
|
||||
kubectl get svc --namespace pangolin
|
||||
```
|
||||
|
||||
Check Traefik `IngressRoute` resources:
|
||||
|
||||
```bash
|
||||
kubectl get ingressroute --namespace pangolin
|
||||
```
|
||||
|
||||
If Traefik CRDs are not installed, this command will fail. In that case, install Traefik CRDs or enable/install the Traefik controller path required by your selected deployment mode.
|
||||
|
||||
Wait for the Pangolin pod to become ready:
|
||||
|
||||
```bash
|
||||
kubectl wait --for=condition=ready pod \
|
||||
-l app.kubernetes.io/name=pangolin \
|
||||
--namespace pangolin \
|
||||
--timeout=300s
|
||||
```
|
||||
|
||||
## Accessing the dashboard
|
||||
|
||||
After DNS and Traefik routing are configured, access Pangolin through the dashboard URL:
|
||||
|
||||
```text
|
||||
https://pangolin.example.com
|
||||
```
|
||||
|
||||
The API route is exposed under:
|
||||
|
||||
```text
|
||||
https://pangolin.example.com/api/v1
|
||||
```
|
||||
|
||||
<Tip>
|
||||
For a temporary local check, port-forward the dashboard/UI port:
|
||||
|
||||
```bash
|
||||
kubectl port-forward --namespace pangolin svc/pangolin 8080:3002
|
||||
```
|
||||
|
||||
Then open:
|
||||
|
||||
```text
|
||||
http://localhost:8080
|
||||
```
|
||||
|
||||
</Tip>
|
||||
|
||||
The chart routes `/api/v1` to the Pangolin external/API port and the dashboard route to the Next/UI port. The default service ports are `3000` for external/API and `3002` for the dashboard/UI. ([GitHub][1])
|
||||
|
||||
## Switch Gerbil to normal startup
|
||||
|
||||
If you installed with `gerbil.startupMode=delayed`, switch Gerbil to normal mode after the initial setup is complete:
|
||||
|
||||
```bash
|
||||
helm upgrade pangolin fossorial/pangolin \
|
||||
--namespace pangolin \
|
||||
--reuse-values \
|
||||
--set gerbil.startupMode=normal
|
||||
```
|
||||
|
||||
Check Gerbil resources:
|
||||
|
||||
```bash
|
||||
kubectl get pods,svc,pvc --namespace pangolin \
|
||||
-l app.kubernetes.io/name=gerbil
|
||||
```
|
||||
|
||||
## Upgrade
|
||||
|
||||
Update the Helm repository:
|
||||
|
||||
```bash
|
||||
helm repo update fossorial
|
||||
```
|
||||
|
||||
Upgrade the release:
|
||||
|
||||
```bash
|
||||
helm upgrade pangolin fossorial/pangolin \
|
||||
--namespace pangolin \
|
||||
--values values-pangolin.yaml
|
||||
```
|
||||
|
||||
Check upgrade status:
|
||||
|
||||
```bash
|
||||
helm status pangolin --namespace pangolin
|
||||
helm history pangolin --namespace pangolin
|
||||
```
|
||||
|
||||
Rollback if needed:
|
||||
|
||||
```bash
|
||||
helm rollback pangolin <revision> --namespace pangolin
|
||||
```
|
||||
|
||||
## OCI install
|
||||
|
||||
The Pangolin chart is also published as an OCI chart in GHCR.
|
||||
|
||||
Pull the chart:
|
||||
|
||||
```bash
|
||||
helm pull oci://ghcr.io/fosrl/helm-charts/pangolin \
|
||||
--version 0.1.0-alpha.0
|
||||
```
|
||||
|
||||
Install from OCI:
|
||||
|
||||
```bash
|
||||
helm upgrade --install pangolin oci://ghcr.io/fosrl/helm-charts/pangolin \
|
||||
--version 0.1.0-alpha.0 \
|
||||
--namespace pangolin \
|
||||
--values values-pangolin.yaml
|
||||
```
|
||||
|
||||
OCI changes where Helm pulls the chart from. It does not change the values file or the release behavior.
|
||||
|
||||
## Architecture overview
|
||||
|
||||
Recommended deployment mode:
|
||||
|
||||
```yaml
|
||||
deployment:
|
||||
type: controller
|
||||
mode: multi
|
||||
```
|
||||
|
||||
In this topology:
|
||||
|
||||
| Component | Role |
|
||||
| -------------------------- | -------------------------------------------------------------------- |
|
||||
| Pangolin | Main application, dashboard, API, authentication, and configuration. |
|
||||
| pangolin-kube-controller | Reconciles dynamic Kubernetes and Traefik CRD configuration. |
|
||||
| Gerbil | WireGuard tunnel manager for Pangolin sites. |
|
||||
| Traefik | Routes dashboard, API, and site traffic. |
|
||||
| CloudNativePG / PostgreSQL | Stores Pangolin application state. |
|
||||
|
||||
Database modes:
|
||||
|
||||
| Mode | Use case |
|
||||
| --------------- | --------------------------------------------------- |
|
||||
| `cloudnativepg` | Recommended Kubernetes production path. |
|
||||
| `external` | Production path with externally managed PostgreSQL. |
|
||||
| `embedded` | Lab or test setups. |
|
||||
| `sqlite` | Development or CI only. |
|
||||
|
||||
The chart supports `cloudnativepg`, `external`, `embedded`, and `sqlite` database modes. The chart comments mark `cloudnativepg` as the preferred production mode and SQLite as development/test only. ([GitHub][1])
|
||||
|
||||
## Chart signing
|
||||
|
||||
The chart metadata includes Artifact Hub signing information:
|
||||
|
||||
```text
|
||||
Fingerprint: 48E7F670FCC13645FC48B08D587294B228C2EC2C
|
||||
Public key: https://charts.fossorial.io/pgp_keys.asc
|
||||
```
|
||||
|
||||
Use this metadata when verifying signed chart releases. The signing key and fingerprint are published in the chart annotations. ([GitHub][2])
|
||||
|
||||
## References
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Chart README" href="https://github.com/fosrl/helm-charts/blob/main/charts/pangolin/README.md" icon="book" />
|
||||
<Card title="values.yaml" href="https://github.com/fosrl/helm-charts/blob/main/charts/pangolin/values.yaml" icon="file-code" />
|
||||
<Card title="values.schema.json" href="https://github.com/fosrl/helm-charts/blob/main/charts/pangolin/values.schema.json" icon="file-code" />
|
||||
<Card title="Examples" href="https://github.com/fosrl/helm-charts/tree/main/charts/pangolin/examples" icon="list-check" />
|
||||
<Card title="Issues" href="https://github.com/fosrl/helm-charts/issues" icon="circle-question" />
|
||||
</CardGroup>
|
||||
|
||||
## Next steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Full Configuration" href="/self-host/manual/kubernetes/pangolin/configuration" icon="sliders">
|
||||
Review Pangolin chart options.
|
||||
</Card>
|
||||
<Card title="Troubleshooting" href="/self-host/manual/kubernetes/pangolin/troubleshooting" icon="circle-question">
|
||||
Debug Pangolin deployment and routing issues.
|
||||
</Card>
|
||||
<Card title="Kustomize Install" href="/self-host/manual/kubernetes/pangolin/kustomize" icon="layer-group">
|
||||
Install Pangolin with rendered manifests and Kustomize overlays.
|
||||
</Card>
|
||||
<Card title="GitOps" href="/self-host/manual/kubernetes/gitops/overview" icon="code-branch">
|
||||
Deploy Pangolin with Argo CD or Flux.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
708
self-host/manual/kubernetes/pangolin/kustomize.mdx
Normal file
708
self-host/manual/kubernetes/pangolin/kustomize.mdx
Normal file
@@ -0,0 +1,708 @@
|
||||
---
|
||||
title: "Pangolin Kustomize"
|
||||
description: "Deploy Pangolin on Kubernetes using Helm-rendered manifests and Kustomize overlays."
|
||||
---
|
||||
|
||||
import PangolinCloudTocCta from "/snippets/pangolin-cloud-toc-cta.mdx";
|
||||
|
||||
<PangolinCloudTocCta />
|
||||
|
||||
|
||||
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:
|
||||
|
||||
1. Render the Pangolin Helm chart to manifests.
|
||||
2. Use the rendered output as the Kustomize base.
|
||||
3. Create overlays per environment.
|
||||
4. 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](/self-host/manual/kubernetes/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.0` |
|
||||
| Pangolin app version | `1.18.2` |
|
||||
| Kubernetes version | `>=1.30.14-0` |
|
||||
| Gerbil image tag | `1.3.1` |
|
||||
| pangolin-kube-controller image tag | `0.1.0-alpha.1` |
|
||||
| Traefik 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.
|
||||
|
||||
<Warning>
|
||||
Do not manage the same Pangolin resources with both a live Helm release and Kustomize. Pick one ownership model per environment.
|
||||
</Warning>
|
||||
|
||||
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
|
||||
|
||||
```text
|
||||
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:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
kubectl label namespace pangolin \
|
||||
pod-security.kubernetes.io/enforce=privileged \
|
||||
pod-security.kubernetes.io/warn=baseline \
|
||||
pod-security.kubernetes.io/audit=restricted \
|
||||
--overwrite
|
||||
```
|
||||
|
||||
<Warning>
|
||||
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`.
|
||||
</Warning>
|
||||
|
||||
## Step 2: Create the Pangolin app Secret
|
||||
|
||||
Create a Secret for `SERVER_SECRET`:
|
||||
|
||||
```bash
|
||||
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`:
|
||||
|
||||
```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
|
||||
|
||||
<Note>
|
||||
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.
|
||||
</Note>
|
||||
|
||||
## Step 4: Render Pangolin to the base
|
||||
|
||||
Add and update the Helm repository:
|
||||
|
||||
```bash
|
||||
helm repo add fossorial https://charts.fossorial.io
|
||||
helm repo update fossorial
|
||||
```
|
||||
|
||||
Create directories:
|
||||
|
||||
```bash
|
||||
mkdir -p base overlays/dev/patches overlays/staging/patches overlays/prod/patches values
|
||||
```
|
||||
|
||||
Render the Pangolin chart:
|
||||
|
||||
```bash
|
||||
helm template pangolin fossorial/pangolin \
|
||||
--namespace pangolin \
|
||||
--values values/values-base.yaml \
|
||||
> base/pangolin.yaml
|
||||
```
|
||||
|
||||
You can also render from the GHCR OCI chart:
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```yaml
|
||||
# base/kustomization.yaml
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- pangolin.yaml
|
||||
```
|
||||
|
||||
<Note>
|
||||
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.
|
||||
</Note>
|
||||
|
||||
## Step 6: Inspect rendered resource names
|
||||
|
||||
Before writing patches, inspect the generated resource names:
|
||||
|
||||
```bash
|
||||
kustomize build base | grep -E "^(kind:| name:)"
|
||||
```
|
||||
|
||||
Or list the main resource names with `yq`:
|
||||
|
||||
```bash
|
||||
kustomize build base | yq '. | select(.kind == "Deployment" or .kind == "StatefulSet" or .kind == "IngressRoute" or .kind == "Service") | .kind + " " + .metadata.name'
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Do not assume generated resource names. Helm names can change with the release name, chart name, `nameOverride`, or `fullnameOverride`.
|
||||
</Warning>
|
||||
|
||||
Use the actual rendered names in your patch targets.
|
||||
|
||||
## Step 7: Create a production overlay
|
||||
|
||||
Example `overlays/prod/kustomization.yaml`:
|
||||
|
||||
```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
|
||||
```
|
||||
|
||||
<Note>
|
||||
Replace `pangolin` and `pangolin-dashboard` with the actual names from your rendered manifests.
|
||||
</Note>
|
||||
|
||||
## Step 8: Add patches
|
||||
|
||||
### Patch Pangolin resources
|
||||
|
||||
```yaml
|
||||
# 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
|
||||
```
|
||||
|
||||
<Note>
|
||||
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.
|
||||
</Note>
|
||||
|
||||
### Patch dashboard IngressRoute host
|
||||
|
||||
The Pangolin chart uses Traefik `IngressRoute` for the dashboard and API in controller mode, not a standard Kubernetes `Ingress`.
|
||||
|
||||
```yaml
|
||||
# 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`)
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Patch the rendered `IngressRoute` only after checking the route order and match rules. The API route and dashboard route target different service ports.
|
||||
</Warning>
|
||||
|
||||
### Patch node affinity
|
||||
|
||||
```yaml
|
||||
# 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`:
|
||||
|
||||
```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:
|
||||
|
||||
```yaml
|
||||
gerbil:
|
||||
startupMode: normal
|
||||
```
|
||||
|
||||
Then re-render:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/prod
|
||||
```
|
||||
|
||||
Compare with the live cluster:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/prod | kubectl diff -f -
|
||||
```
|
||||
|
||||
Apply the overlay:
|
||||
|
||||
```bash
|
||||
kubectl apply -k overlays/prod
|
||||
```
|
||||
|
||||
Verify workloads:
|
||||
|
||||
```bash
|
||||
kubectl get pods --namespace pangolin
|
||||
kubectl get deploy,statefulset --namespace pangolin
|
||||
kubectl get svc --namespace pangolin
|
||||
```
|
||||
|
||||
Verify Traefik resources:
|
||||
|
||||
```bash
|
||||
kubectl get ingressroute --namespace pangolin
|
||||
```
|
||||
|
||||
Check events:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
helm repo update fossorial
|
||||
```
|
||||
|
||||
Render the updated chart output:
|
||||
|
||||
```bash
|
||||
helm template pangolin fossorial/pangolin \
|
||||
--namespace pangolin \
|
||||
--values values/values-base.yaml \
|
||||
> base/pangolin.yaml
|
||||
```
|
||||
|
||||
Or with OCI:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/prod
|
||||
```
|
||||
|
||||
Review the diff:
|
||||
|
||||
```bash
|
||||
git diff
|
||||
kustomize build overlays/prod | kubectl diff -f -
|
||||
```
|
||||
|
||||
Commit the updated base and overlays:
|
||||
|
||||
```bash
|
||||
git add base/ overlays/ values/
|
||||
git commit -m "Update Pangolin rendered manifests"
|
||||
```
|
||||
|
||||
Apply after review:
|
||||
|
||||
```bash
|
||||
kubectl apply -k overlays/prod
|
||||
```
|
||||
|
||||
## Ownership model
|
||||
|
||||
Do not run `helm upgrade` against a release that is managed by Kustomize.
|
||||
|
||||
Avoid this pattern:
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```yaml
|
||||
patches:
|
||||
- path: patches/pangolin-resources.patch.yaml
|
||||
target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
name: pangolin
|
||||
```
|
||||
|
||||
### Patch IngressRoute host
|
||||
|
||||
```yaml
|
||||
patches:
|
||||
- path: patches/ingressroute-host.patch.yaml
|
||||
target:
|
||||
group: traefik.io
|
||||
version: v1alpha1
|
||||
kind: IngressRoute
|
||||
name: pangolin-dashboard
|
||||
```
|
||||
|
||||
### Add annotations
|
||||
|
||||
```yaml
|
||||
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.
|
||||
|
||||
```yaml
|
||||
patches:
|
||||
- target:
|
||||
version: v1
|
||||
kind: Service
|
||||
name: pangolin-gerbil
|
||||
patch: |-
|
||||
- op: replace
|
||||
path: /spec/type
|
||||
value: LoadBalancer
|
||||
```
|
||||
|
||||
<Note>
|
||||
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.
|
||||
</Note>
|
||||
|
||||
## Validation
|
||||
|
||||
Validate Kustomize output:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/prod
|
||||
```
|
||||
|
||||
Run a server-side dry run:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/prod | kubectl apply -f - --dry-run=server
|
||||
```
|
||||
|
||||
Preview live changes:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/prod | kubectl diff -f -
|
||||
```
|
||||
|
||||
If a patch does not apply, inspect generated resource names:
|
||||
|
||||
```bash
|
||||
kustomize build base | grep -E "^(kind:| name:)"
|
||||
```
|
||||
|
||||
## Kustomize with GitOps
|
||||
|
||||
Kustomize overlays work well with GitOps tools.
|
||||
|
||||
* [Argo CD](/self-host/manual/kubernetes/gitops/argocd) can reconcile a Kustomize overlay path directly.
|
||||
* [Flux](/self-host/manual/kubernetes/gitops/flux) can reconcile a Kustomize overlay with a `Kustomization` resource.
|
||||
|
||||
In GitOps workflows, the controller owns the apply operation. Do not also apply the same overlay manually unless you are debugging.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### The patch does not apply
|
||||
|
||||
Check the rendered resource name and kind:
|
||||
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
kubectl get pods --namespace pangolin
|
||||
kubectl describe pod <pod-name> --namespace pangolin
|
||||
kubectl get events --namespace pangolin --sort-by=.lastTimestamp
|
||||
```
|
||||
|
||||
### Dashboard routing does not work
|
||||
|
||||
Check the rendered and applied `IngressRoute`:
|
||||
|
||||
```bash
|
||||
kubectl get ingressroute --namespace pangolin
|
||||
kubectl describe ingressroute <name> --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:
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Helm Install" href="/self-host/manual/kubernetes/pangolin/helm" icon="box">
|
||||
Install Pangolin with Helm.
|
||||
</Card>
|
||||
<Card title="Configuration" href="/self-host/manual/kubernetes/pangolin/configuration" icon="sliders">
|
||||
Review Pangolin chart options.
|
||||
</Card>
|
||||
<Card title="Troubleshooting" href="/self-host/manual/kubernetes/pangolin/troubleshooting" icon="circle-question">
|
||||
Debug Pangolin deployment and routing issues.
|
||||
</Card>
|
||||
<Card title="GitOps" href="/self-host/manual/kubernetes/gitops/overview" icon="code-branch">
|
||||
Deploy Pangolin with Argo CD or Flux.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
888
self-host/manual/kubernetes/pangolin/troubleshooting.mdx
Normal file
888
self-host/manual/kubernetes/pangolin/troubleshooting.mdx
Normal file
@@ -0,0 +1,888 @@
|
||||
---
|
||||
title: "Pangolin Troubleshooting"
|
||||
description: "Diagnose and resolve Pangolin Kubernetes deployment issues."
|
||||
---
|
||||
|
||||
import PangolinCloudTocCta from "/snippets/pangolin-cloud-toc-cta.mdx";
|
||||
|
||||
<PangolinCloudTocCta />
|
||||
|
||||
|
||||
This page covers troubleshooting Pangolin Kubernetes deployments across Helm, Kustomize, Argo CD, and Flux workflows.
|
||||
|
||||
Start with the core checks, then use the section that matches the symptom.
|
||||
|
||||
## Core diagnostics
|
||||
|
||||
Set the namespace and release name used by your installation:
|
||||
|
||||
```bash
|
||||
export PANGOLIN_NAMESPACE=pangolin
|
||||
export PANGOLIN_RELEASE=pangolin
|
||||
```
|
||||
|
||||
### Helm diagnostics
|
||||
|
||||
Check the release:
|
||||
|
||||
```bash
|
||||
helm status "$PANGOLIN_RELEASE" --namespace "$PANGOLIN_NAMESPACE"
|
||||
helm history "$PANGOLIN_RELEASE" --namespace "$PANGOLIN_NAMESPACE"
|
||||
helm get values "$PANGOLIN_RELEASE" --namespace "$PANGOLIN_NAMESPACE" --all
|
||||
```
|
||||
|
||||
Render the chart locally with your values file:
|
||||
|
||||
```bash
|
||||
helm repo update fossorial
|
||||
|
||||
helm template "$PANGOLIN_RELEASE" fossorial/pangolin \
|
||||
--namespace "$PANGOLIN_NAMESPACE" \
|
||||
--values values-pangolin.yaml
|
||||
```
|
||||
|
||||
Preview an upgrade:
|
||||
|
||||
```bash
|
||||
helm upgrade "$PANGOLIN_RELEASE" fossorial/pangolin \
|
||||
--namespace "$PANGOLIN_NAMESPACE" \
|
||||
--values values-pangolin.yaml \
|
||||
--dry-run
|
||||
```
|
||||
|
||||
<Note>
|
||||
`helm lint charts/pangolin` is only useful when you are working inside the Helm chart repository. For normal installs, use `helm template` and `helm upgrade --dry-run`.
|
||||
</Note>
|
||||
|
||||
### Kubernetes diagnostics
|
||||
|
||||
Check workloads and events:
|
||||
|
||||
```bash
|
||||
kubectl get pods --namespace "$PANGOLIN_NAMESPACE"
|
||||
kubectl get deploy,statefulset,job,cronjob --namespace "$PANGOLIN_NAMESPACE"
|
||||
kubectl get events --namespace "$PANGOLIN_NAMESPACE" --sort-by=.lastTimestamp
|
||||
```
|
||||
|
||||
Inspect a pod:
|
||||
|
||||
```bash
|
||||
kubectl describe pod <pod-name> --namespace "$PANGOLIN_NAMESPACE"
|
||||
kubectl logs <pod-name> --namespace "$PANGOLIN_NAMESPACE" --all-containers --tail=200
|
||||
```
|
||||
|
||||
Check services, PVCs, and policies:
|
||||
|
||||
```bash
|
||||
kubectl get svc,pvc,secret,configmap --namespace "$PANGOLIN_NAMESPACE"
|
||||
kubectl get networkpolicy --namespace "$PANGOLIN_NAMESPACE"
|
||||
```
|
||||
|
||||
### Traefik diagnostics
|
||||
|
||||
In controller mode, the chart uses Traefik CRDs such as `IngressRoute`.
|
||||
|
||||
Check whether Traefik CRDs are installed:
|
||||
|
||||
```bash
|
||||
kubectl get crd | grep traefik
|
||||
```
|
||||
|
||||
Check rendered or applied Traefik resources:
|
||||
|
||||
```bash
|
||||
kubectl get ingressroute --namespace "$PANGOLIN_NAMESPACE"
|
||||
kubectl describe ingressroute <name> --namespace "$PANGOLIN_NAMESPACE"
|
||||
```
|
||||
|
||||
Depending on your Traefik setup, also check:
|
||||
|
||||
```bash
|
||||
kubectl get middleware,tlsoption,traefikservice --namespace "$PANGOLIN_NAMESPACE"
|
||||
```
|
||||
|
||||
<Note>
|
||||
`kubectl get ingress` is only useful if your selected deployment mode renders standard Kubernetes Ingress resources. In controller mode, use `IngressRoute`.
|
||||
</Note>
|
||||
|
||||
### Database diagnostics
|
||||
|
||||
If you use CloudNativePG, first check that the CRD exists:
|
||||
|
||||
```bash
|
||||
kubectl get crd | grep postgresql.cnpg.io
|
||||
```
|
||||
|
||||
Then check CNPG resources:
|
||||
|
||||
```bash
|
||||
kubectl get cluster --namespace "$PANGOLIN_NAMESPACE"
|
||||
kubectl describe cluster <cluster-name> --namespace "$PANGOLIN_NAMESPACE"
|
||||
kubectl get pods --namespace "$PANGOLIN_NAMESPACE" | grep -E 'pangolin-db|postgres'
|
||||
kubectl get secret --namespace "$PANGOLIN_NAMESPACE" | grep -E 'pangolin-db|postgres'
|
||||
```
|
||||
|
||||
If you use external PostgreSQL, verify the connection Secret:
|
||||
|
||||
```bash
|
||||
kubectl get secret <connection-secret-name> --namespace "$PANGOLIN_NAMESPACE"
|
||||
kubectl describe secret <connection-secret-name> --namespace "$PANGOLIN_NAMESPACE"
|
||||
```
|
||||
|
||||
Do not decode and paste database credentials into logs, screenshots, or issue reports.
|
||||
|
||||
## Common issues and solutions
|
||||
|
||||
<AccordionGroup>
|
||||
|
||||
<Accordion title="Gerbil fails during the first install">
|
||||
|
||||
**Symptoms**
|
||||
|
||||
* Gerbil pod crashes during a fresh install.
|
||||
* Logs mention missing setup data, missing exit node, or tunnel configuration not being ready.
|
||||
* Pangolin itself is not initialized yet.
|
||||
|
||||
**Cause**
|
||||
|
||||
On first install, Gerbil may start before Pangolin has completed the initial setup. The chart supports `gerbil.startupMode` for this case.
|
||||
|
||||
**Resolution**
|
||||
|
||||
Use delayed startup for the first install:
|
||||
|
||||
```yaml
|
||||
gerbil:
|
||||
startupMode: delayed
|
||||
```
|
||||
|
||||
Install or upgrade with the values file:
|
||||
|
||||
```bash
|
||||
helm upgrade --install "$PANGOLIN_RELEASE" fossorial/pangolin \
|
||||
--namespace "$PANGOLIN_NAMESPACE" \
|
||||
--values values-pangolin.yaml
|
||||
```
|
||||
|
||||
After Pangolin setup is complete, switch Gerbil to normal startup:
|
||||
|
||||
```bash
|
||||
helm upgrade "$PANGOLIN_RELEASE" fossorial/pangolin \
|
||||
--namespace "$PANGOLIN_NAMESPACE" \
|
||||
--reuse-values \
|
||||
--set gerbil.startupMode=normal
|
||||
```
|
||||
|
||||
Check Gerbil resources:
|
||||
|
||||
```bash
|
||||
kubectl get pods,svc,pvc --namespace "$PANGOLIN_NAMESPACE" \
|
||||
-l app.kubernetes.io/name=gerbil
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Gerbil is blocked by Pod Security Admission">
|
||||
|
||||
**Symptoms**
|
||||
|
||||
* Gerbil pod does not start.
|
||||
* Events mention Pod Security Admission.
|
||||
* Events mention forbidden capabilities.
|
||||
* Logs or events mention `NET_ADMIN`.
|
||||
|
||||
**Cause**
|
||||
|
||||
Gerbil requires the `NET_ADMIN` Linux capability for WireGuard interface management. A namespace using a restricted Pod Security profile can block this.
|
||||
|
||||
**Resolution**
|
||||
|
||||
Check namespace labels:
|
||||
|
||||
```bash
|
||||
kubectl get namespace "$PANGOLIN_NAMESPACE" --show-labels
|
||||
```
|
||||
|
||||
For a namespace running Gerbil, use a policy profile that allows the required capability. Example:
|
||||
|
||||
```bash
|
||||
kubectl label namespace "$PANGOLIN_NAMESPACE" \
|
||||
pod-security.kubernetes.io/enforce=privileged \
|
||||
pod-security.kubernetes.io/warn=baseline \
|
||||
pod-security.kubernetes.io/audit=restricted \
|
||||
--overwrite
|
||||
```
|
||||
|
||||
Then restart the affected pods:
|
||||
|
||||
```bash
|
||||
kubectl rollout restart deploy --namespace "$PANGOLIN_NAMESPACE"
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Do not use a restricted Pod Security profile for Gerbil unless you have validated the selected chart mode and security context. Removing `NET_ADMIN` breaks WireGuard management.
|
||||
</Warning>
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Dashboard is not reachable through IngressRoute">
|
||||
|
||||
**Symptoms**
|
||||
|
||||
* The dashboard URL does not load.
|
||||
* Browser shows timeout, bad gateway, 404, or TLS error.
|
||||
* API path `/api/v1` fails while the dashboard path works, or the reverse.
|
||||
|
||||
**Common causes**
|
||||
|
||||
* DNS points to the wrong load balancer or ingress endpoint.
|
||||
* Traefik CRDs are missing.
|
||||
* Traefik controller is not watching the namespace or selector labels.
|
||||
* `IngressRoute` host does not match the dashboard URL.
|
||||
* API route was changed and no longer matches `PathPrefix(/api/v1)`.
|
||||
* TLS resolver or TLS Secret is misconfigured.
|
||||
|
||||
**Checks**
|
||||
|
||||
Check DNS:
|
||||
|
||||
```bash
|
||||
nslookup pangolin.example.com
|
||||
```
|
||||
|
||||
Check Traefik CRDs:
|
||||
|
||||
```bash
|
||||
kubectl get crd | grep traefik
|
||||
```
|
||||
|
||||
Check IngressRoute resources:
|
||||
|
||||
```bash
|
||||
kubectl get ingressroute --namespace "$PANGOLIN_NAMESPACE"
|
||||
kubectl describe ingressroute <name> --namespace "$PANGOLIN_NAMESPACE"
|
||||
```
|
||||
|
||||
Check the rendered values:
|
||||
|
||||
```bash
|
||||
helm get values "$PANGOLIN_RELEASE" --namespace "$PANGOLIN_NAMESPACE" --all | grep -A30 ingressRoute
|
||||
```
|
||||
|
||||
Check Traefik logs. Adjust the namespace and label selector to your Traefik installation:
|
||||
|
||||
```bash
|
||||
kubectl logs --namespace traefik -l app.kubernetes.io/name=traefik --tail=100
|
||||
```
|
||||
|
||||
Temporary local check for the dashboard/UI service port:
|
||||
|
||||
```bash
|
||||
kubectl port-forward --namespace "$PANGOLIN_NAMESPACE" svc/pangolin 8080:3002
|
||||
```
|
||||
|
||||
Then open:
|
||||
|
||||
```text
|
||||
http://localhost:8080
|
||||
```
|
||||
|
||||
<Note>
|
||||
The dashboard/UI port is `3002`. The API/external port is `3000`. Port-forward `3002` when checking the dashboard locally.
|
||||
</Note>
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="TLS certResolver and secretName conflict">
|
||||
|
||||
**Symptoms**
|
||||
|
||||
* `IngressRoute` is created but TLS does not work.
|
||||
* Traefik logs mention TLS configuration problems.
|
||||
* Certificate is not issued or the TLS Secret is not found.
|
||||
|
||||
**Cause**
|
||||
|
||||
The dashboard `IngressRoute` TLS configuration should use either a Traefik certificate resolver or an existing TLS Secret.
|
||||
|
||||
**Resolution**
|
||||
|
||||
Use Traefik ACME certificate resolver:
|
||||
|
||||
```yaml
|
||||
pangolin:
|
||||
ingressRoute:
|
||||
dashboard:
|
||||
tls:
|
||||
enabled: true
|
||||
certResolver: letsencrypt
|
||||
secretName: ""
|
||||
```
|
||||
|
||||
Or use an existing TLS Secret:
|
||||
|
||||
```yaml
|
||||
pangolin:
|
||||
ingressRoute:
|
||||
dashboard:
|
||||
tls:
|
||||
enabled: true
|
||||
certResolver: ""
|
||||
secretName: pangolin-dashboard-tls
|
||||
```
|
||||
|
||||
Verify the Secret if using `secretName`:
|
||||
|
||||
```bash
|
||||
kubectl get secret pangolin-dashboard-tls --namespace "$PANGOLIN_NAMESPACE"
|
||||
```
|
||||
|
||||
<Note>
|
||||
`certResolver` is a Traefik ACME resolver setting. It is not a cert-manager issuer reference.
|
||||
</Note>
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Newt cannot reach Gerbil WireGuard ports">
|
||||
|
||||
**Symptoms**
|
||||
|
||||
* Newt shows repeated connection or tunnel errors.
|
||||
* Tunnel traffic does not pass.
|
||||
* WireGuard UDP ports are unreachable from the Newt location.
|
||||
|
||||
**Common causes**
|
||||
|
||||
* `pangolin.config.gerbil.base_endpoint` points to the wrong host.
|
||||
* Gerbil Service is not exposed as expected.
|
||||
* External firewall blocks UDP traffic.
|
||||
* NetworkPolicy blocks the required traffic.
|
||||
* `pangolin.config.gerbil.start_port` and `gerbil.ports.wg1` are not aligned.
|
||||
* `pangolin.config.gerbil.clients_start_port` and `gerbil.ports.wg2` are not aligned.
|
||||
|
||||
**Checks**
|
||||
|
||||
Check Gerbil Service:
|
||||
|
||||
```bash
|
||||
kubectl get svc --namespace "$PANGOLIN_NAMESPACE" \
|
||||
-l app.kubernetes.io/name=gerbil
|
||||
|
||||
kubectl describe svc <gerbil-service-name> --namespace "$PANGOLIN_NAMESPACE"
|
||||
```
|
||||
|
||||
Check Gerbil values:
|
||||
|
||||
```bash
|
||||
helm get values "$PANGOLIN_RELEASE" --namespace "$PANGOLIN_NAMESPACE" --all | grep -A30 gerbil
|
||||
```
|
||||
|
||||
Check NetworkPolicies:
|
||||
|
||||
```bash
|
||||
kubectl get networkpolicy --namespace "$PANGOLIN_NAMESPACE"
|
||||
kubectl describe networkpolicy --namespace "$PANGOLIN_NAMESPACE"
|
||||
```
|
||||
|
||||
Verify external firewall rules for the configured UDP ports.
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="External database mode missing or invalid Secret">
|
||||
|
||||
**Symptoms**
|
||||
|
||||
* Pangolin pod crashes.
|
||||
* Logs mention database connection errors.
|
||||
* Events mention missing Secret or missing Secret key.
|
||||
|
||||
**Cause**
|
||||
|
||||
`database.mode=external` needs a valid database connection Secret unless the chart is configured to generate one from values.
|
||||
|
||||
**Resolution**
|
||||
|
||||
Create a connection Secret:
|
||||
|
||||
```bash
|
||||
kubectl create secret generic pangolin-db-connection \
|
||||
--namespace "$PANGOLIN_NAMESPACE" \
|
||||
--from-literal=connectionString='postgresql://pangolin:password@postgres.example.com:5432/pangolin?sslmode=require'
|
||||
```
|
||||
|
||||
Reference it in values:
|
||||
|
||||
```yaml
|
||||
database:
|
||||
mode: external
|
||||
connection:
|
||||
existingSecretName: pangolin-db-connection
|
||||
existingSecretKey: connectionString
|
||||
```
|
||||
|
||||
Check the Secret:
|
||||
|
||||
```bash
|
||||
kubectl describe secret pangolin-db-connection --namespace "$PANGOLIN_NAMESPACE"
|
||||
```
|
||||
|
||||
<Warning>
|
||||
Do not put database passwords directly in values files for production. Use an existing Secret or your normal secret-management workflow.
|
||||
</Warning>
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="CloudNativePG cluster does not provision">
|
||||
|
||||
**Symptoms**
|
||||
|
||||
* CNPG Cluster resource is missing.
|
||||
* CNPG pods do not start.
|
||||
* Pangolin cannot connect to the generated CNPG database.
|
||||
* Secret such as `pangolin-db-app` is missing.
|
||||
|
||||
**Common causes**
|
||||
|
||||
* CloudNativePG CRDs/operator are not installed.
|
||||
* `cnpg-cluster.enabled` is false when you expected the chart to create a cluster.
|
||||
* `cnpg-operator.enabled` is false and no operator exists.
|
||||
* `database.cloudnativepg.cluster.name` does not match the CNPG cluster name.
|
||||
* StorageClass or PVC provisioning fails.
|
||||
|
||||
**Checks**
|
||||
|
||||
Check CRDs:
|
||||
|
||||
```bash
|
||||
kubectl get crd | grep postgresql.cnpg.io
|
||||
```
|
||||
|
||||
Check CNPG operator pods:
|
||||
|
||||
```bash
|
||||
kubectl get pods --all-namespaces | grep -i cnpg
|
||||
```
|
||||
|
||||
Check CNPG Cluster:
|
||||
|
||||
```bash
|
||||
kubectl get cluster --namespace "$PANGOLIN_NAMESPACE"
|
||||
kubectl describe cluster pangolin-db --namespace "$PANGOLIN_NAMESPACE"
|
||||
```
|
||||
|
||||
Check PVCs and Secrets:
|
||||
|
||||
```bash
|
||||
kubectl get pvc --namespace "$PANGOLIN_NAMESPACE"
|
||||
kubectl get secret --namespace "$PANGOLIN_NAMESPACE" | grep pangolin-db
|
||||
```
|
||||
|
||||
Expected naming when using the default example:
|
||||
|
||||
```yaml
|
||||
database:
|
||||
cloudnativepg:
|
||||
cluster:
|
||||
name: pangolin-db
|
||||
|
||||
cnpg-cluster:
|
||||
enabled: true
|
||||
fullnameOverride: pangolin-db
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="NetworkPolicy blocks DNS, database, controller, or tunnel traffic">
|
||||
|
||||
**Symptoms**
|
||||
|
||||
* DNS lookups fail.
|
||||
* Pangolin cannot connect to the database.
|
||||
* Controller cannot reach the Kubernetes API.
|
||||
* Gerbil or Newt traffic does not work.
|
||||
* External services such as SMTP, OIDC, or webhooks time out.
|
||||
|
||||
**Cause**
|
||||
|
||||
The chart can render NetworkPolicies. If your CNI enforces them, missing egress or ingress rules can break required paths.
|
||||
|
||||
**Checks**
|
||||
|
||||
```bash
|
||||
kubectl get networkpolicy --namespace "$PANGOLIN_NAMESPACE"
|
||||
kubectl describe networkpolicy --namespace "$PANGOLIN_NAMESPACE"
|
||||
```
|
||||
|
||||
Check whether DNS is allowed:
|
||||
|
||||
```yaml
|
||||
networkPolicy:
|
||||
dns:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
Check database egress:
|
||||
|
||||
```yaml
|
||||
networkPolicy:
|
||||
database:
|
||||
enabled: true
|
||||
port: 5432
|
||||
```
|
||||
|
||||
Check controller API access:
|
||||
|
||||
```yaml
|
||||
networkPolicy:
|
||||
controller:
|
||||
egress:
|
||||
enabled: true
|
||||
kubernetesApi:
|
||||
enabled: true
|
||||
port: 443
|
||||
```
|
||||
|
||||
For external integrations, add scoped egress rules for the required services instead of allowing broad egress.
|
||||
|
||||
For a temporary isolation test, disable NetworkPolicy and re-apply:
|
||||
|
||||
```yaml
|
||||
networkPolicy:
|
||||
enabled: false
|
||||
```
|
||||
|
||||
If this fixes the issue, re-enable policies and add the missing rules.
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Pangolin pod is CrashLoopBackOff or Pending">
|
||||
|
||||
**Symptoms**
|
||||
|
||||
* Pangolin pod restarts repeatedly.
|
||||
* Pod stays Pending.
|
||||
* Readiness never becomes true.
|
||||
|
||||
**Checks**
|
||||
|
||||
Find the pod:
|
||||
|
||||
```bash
|
||||
kubectl get pods --namespace "$PANGOLIN_NAMESPACE" \
|
||||
-l app.kubernetes.io/name=pangolin
|
||||
```
|
||||
|
||||
Inspect it:
|
||||
|
||||
```bash
|
||||
kubectl describe pod <pod-name> --namespace "$PANGOLIN_NAMESPACE"
|
||||
kubectl logs <pod-name> --namespace "$PANGOLIN_NAMESPACE" --tail=200
|
||||
kubectl logs <pod-name> --namespace "$PANGOLIN_NAMESPACE" --previous --tail=200
|
||||
```
|
||||
|
||||
Check PVCs:
|
||||
|
||||
```bash
|
||||
kubectl get pvc --namespace "$PANGOLIN_NAMESPACE"
|
||||
kubectl describe pvc <pvc-name> --namespace "$PANGOLIN_NAMESPACE"
|
||||
```
|
||||
|
||||
Common causes:
|
||||
|
||||
| Status | Common causes |
|
||||
| ------------------ | ----------------------------------------------------------------------------------------------------- |
|
||||
| `CrashLoopBackOff` | Database connection issue, missing Secret, invalid config, startup dependency not ready |
|
||||
| `Pending` | PVC not bound, insufficient resources, node selector/affinity mismatch, Pod Security policy rejection |
|
||||
| `ImagePullBackOff` | Wrong image override, registry access issue, missing imagePullSecret |
|
||||
|
||||
<Note>
|
||||
Do not assume tools such as `psql`, `curl`, or `dig` are available inside the Pangolin container. Use logs, Events, or a temporary debug pod when needed.
|
||||
</Note>
|
||||
|
||||
Run a temporary debug pod for network tests:
|
||||
|
||||
```bash
|
||||
kubectl run net-debug \
|
||||
--namespace "$PANGOLIN_NAMESPACE" \
|
||||
--rm -it \
|
||||
--image=curlimages/curl:latest \
|
||||
--restart=Never \
|
||||
-- sh
|
||||
```
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Traefik CRDs or resources are missing">
|
||||
|
||||
**Symptoms**
|
||||
|
||||
* Helm template or install succeeds, but Traefik resources are not reconciled.
|
||||
* `kubectl get ingressroute` fails with unknown resource type.
|
||||
* Argo CD or Flux reports missing kind `IngressRoute`.
|
||||
|
||||
**Cause**
|
||||
|
||||
Controller mode expects Traefik CRDs and a Traefik controller. They must be installed separately or through the bundled dependency when enabled.
|
||||
|
||||
**Checks**
|
||||
|
||||
```bash
|
||||
kubectl get crd | grep traefik
|
||||
kubectl get pods --all-namespaces | grep -i traefik
|
||||
```
|
||||
|
||||
If you want the chart to install the bundled Traefik controller, enable it:
|
||||
|
||||
```yaml
|
||||
deployment:
|
||||
type: controller
|
||||
installTraefikController: true
|
||||
```
|
||||
|
||||
If Traefik is already installed elsewhere, keep it disabled and make sure the controller watches the namespace and labels used by the Pangolin `IngressRoute`.
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Helm upgrade fails or rendered output is unexpected">
|
||||
|
||||
**Symptoms**
|
||||
|
||||
* `helm upgrade` fails.
|
||||
* Rendered resources changed unexpectedly.
|
||||
* Existing resources conflict with chart-managed resources.
|
||||
* GitOps reports immutable field changes or ownership conflicts.
|
||||
|
||||
**Checks**
|
||||
|
||||
Render before upgrading:
|
||||
|
||||
```bash
|
||||
helm template "$PANGOLIN_RELEASE" fossorial/pangolin \
|
||||
--namespace "$PANGOLIN_NAMESPACE" \
|
||||
--values values-pangolin.yaml > rendered.yaml
|
||||
```
|
||||
|
||||
Run a server-side dry run:
|
||||
|
||||
```bash
|
||||
kubectl apply -f rendered.yaml --dry-run=server
|
||||
```
|
||||
|
||||
Compare the current live release:
|
||||
|
||||
```bash
|
||||
helm get manifest "$PANGOLIN_RELEASE" --namespace "$PANGOLIN_NAMESPACE" > live-release.yaml
|
||||
diff -u live-release.yaml rendered.yaml
|
||||
```
|
||||
|
||||
Check ownership conflicts:
|
||||
|
||||
```bash
|
||||
kubectl get all --namespace "$PANGOLIN_NAMESPACE" -o yaml | grep -E "meta.helm.sh|app.kubernetes.io/managed-by"
|
||||
```
|
||||
|
||||
Avoid `--force` unless you understand which resources will be recreated.
|
||||
|
||||
<Warning>
|
||||
`helm upgrade --force` can delete and recreate resources. That can interrupt traffic and may affect persistent workloads depending on the resource type.
|
||||
</Warning>
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Kustomize patches do not apply">
|
||||
|
||||
**Symptoms**
|
||||
|
||||
* Kustomize build succeeds but changes are missing.
|
||||
* Patch target does not match any resource.
|
||||
* Patch breaks after chart upgrade.
|
||||
|
||||
**Checks**
|
||||
|
||||
List generated resource names:
|
||||
|
||||
```bash
|
||||
kustomize build base | grep -E "^(kind:| name:)"
|
||||
```
|
||||
|
||||
Validate the overlay:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/prod
|
||||
```
|
||||
|
||||
Run a server-side dry run:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/prod | kubectl apply -f - --dry-run=server
|
||||
```
|
||||
|
||||
Preview live changes:
|
||||
|
||||
```bash
|
||||
kustomize build overlays/prod | kubectl diff -f -
|
||||
```
|
||||
|
||||
Use modern Kustomize `patches` syntax:
|
||||
|
||||
```yaml
|
||||
patches:
|
||||
- path: patches/pangolin-resources.patch.yaml
|
||||
target:
|
||||
group: apps
|
||||
version: v1
|
||||
kind: Deployment
|
||||
name: pangolin
|
||||
```
|
||||
|
||||
<Note>
|
||||
For Helm-rendered bases, do not assume resource names. Check the rendered manifests after each chart upgrade.
|
||||
</Note>
|
||||
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="GitOps deployment does not sync">
|
||||
|
||||
**Symptoms**
|
||||
|
||||
* Argo CD Application is OutOfSync or Degraded.
|
||||
* Flux HelmRelease or Kustomization is not Ready.
|
||||
* Resources are missing or constantly reverted.
|
||||
|
||||
**Argo CD checks**
|
||||
|
||||
```bash
|
||||
kubectl describe application pangolin --namespace argocd
|
||||
kubectl logs --namespace argocd deployment/argocd-application-controller --tail=100
|
||||
argocd app diff pangolin
|
||||
argocd app sync pangolin
|
||||
```
|
||||
|
||||
**Flux checks**
|
||||
|
||||
```bash
|
||||
flux get sources all --all-namespaces
|
||||
flux get helmreleases --all-namespaces
|
||||
flux get kustomizations --all-namespaces
|
||||
flux logs --all-namespaces --follow
|
||||
```
|
||||
|
||||
Reconcile manually:
|
||||
|
||||
```bash
|
||||
flux reconcile helmrelease pangolin --namespace "$PANGOLIN_NAMESPACE"
|
||||
flux reconcile kustomization pangolin --namespace flux-system
|
||||
```
|
||||
|
||||
Common causes:
|
||||
|
||||
- chart repository or OCI source not reachable
|
||||
- wrong chart version
|
||||
- missing CRDs
|
||||
- invalid values
|
||||
- rendered resource ownership conflict
|
||||
- Secret not available in the expected namespace
|
||||
|
||||
</Accordion>
|
||||
|
||||
</AccordionGroup>
|
||||
|
||||
## Routing issues to the right repository
|
||||
|
||||
Use the repository that matches the failing area:
|
||||
|
||||
| Area | Repository |
|
||||
| ----------------------------------------------------- | ------------------- |
|
||||
| Chart templates, values, examples, rendered manifests | `fosrl/helm-charts` |
|
||||
| Pangolin runtime, API, UI, auth, application behavior | `fosrl/pangolin` |
|
||||
| Newt client behavior or connectivity | `fosrl/newt` |
|
||||
| Documentation | `fosrl/docs-v2` |
|
||||
|
||||
## Before opening an issue, collect
|
||||
|
||||
Collect this information before opening an issue:
|
||||
|
||||
* chart version
|
||||
* Pangolin app version
|
||||
* Kubernetes version
|
||||
* Helm version
|
||||
* deployment method: Helm, Kustomize, Argo CD, or Flux
|
||||
* sanitized values file
|
||||
* pod logs
|
||||
* namespace events
|
||||
* Traefik logs, if routing is involved
|
||||
* rendered manifests from `helm template` or `kustomize build`
|
||||
* Helm release status or GitOps sync status
|
||||
* reproduction steps
|
||||
|
||||
Collect basic diagnostics:
|
||||
|
||||
```bash
|
||||
kubectl version
|
||||
helm version
|
||||
|
||||
helm status "$PANGOLIN_RELEASE" --namespace "$PANGOLIN_NAMESPACE"
|
||||
helm get values "$PANGOLIN_RELEASE" --namespace "$PANGOLIN_NAMESPACE" --all > pangolin-values.yaml
|
||||
helm get manifest "$PANGOLIN_RELEASE" --namespace "$PANGOLIN_NAMESPACE" > pangolin-manifest.yaml
|
||||
|
||||
kubectl get pods --namespace "$PANGOLIN_NAMESPACE" -o wide > pangolin-pods.txt
|
||||
kubectl get events --namespace "$PANGOLIN_NAMESPACE" --sort-by=.lastTimestamp > pangolin-events.txt
|
||||
```
|
||||
|
||||
Before sharing diagnostics, remove:
|
||||
|
||||
* database passwords
|
||||
* `SERVER_SECRET`
|
||||
* API keys
|
||||
* OAuth/OIDC client secrets
|
||||
* TLS private keys
|
||||
* internal hostnames, if sensitive
|
||||
|
||||
## Useful command reference
|
||||
|
||||
```bash
|
||||
# General cluster info
|
||||
kubectl cluster-info
|
||||
kubectl version
|
||||
|
||||
# Namespace overview
|
||||
kubectl get all --namespace "$PANGOLIN_NAMESPACE"
|
||||
kubectl get pvc,secret,configmap --namespace "$PANGOLIN_NAMESPACE"
|
||||
kubectl get events --namespace "$PANGOLIN_NAMESPACE" --sort-by=.lastTimestamp
|
||||
|
||||
# Logs
|
||||
kubectl logs --namespace "$PANGOLIN_NAMESPACE" \
|
||||
-l app.kubernetes.io/name=pangolin \
|
||||
--tail=200
|
||||
|
||||
kubectl logs --namespace "$PANGOLIN_NAMESPACE" \
|
||||
-l app.kubernetes.io/name=gerbil \
|
||||
--tail=200
|
||||
|
||||
# Dashboard local test
|
||||
kubectl port-forward --namespace "$PANGOLIN_NAMESPACE" svc/pangolin 8080:3002
|
||||
|
||||
# Traefik resources
|
||||
kubectl get ingressroute --namespace "$PANGOLIN_NAMESPACE"
|
||||
|
||||
# Resource usage
|
||||
kubectl top pod --namespace "$PANGOLIN_NAMESPACE"
|
||||
kubectl top node
|
||||
```
|
||||
|
||||
## Next steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Pangolin Configuration" href="/self-host/manual/kubernetes/pangolin/configuration" icon="sliders">
|
||||
Review Pangolin chart options.
|
||||
</Card>
|
||||
<Card title="Helm Quick-Start" href="/self-host/manual/kubernetes/pangolin/helm" icon="box">
|
||||
Install Pangolin with Helm.
|
||||
</Card>
|
||||
<Card title="Kustomize Quick-Start" href="/self-host/manual/kubernetes/pangolin/kustomize" icon="layer-group">
|
||||
Install Pangolin with rendered manifests and Kustomize overlays.
|
||||
</Card>
|
||||
<Card title="GitOps Overview" href="/self-host/manual/kubernetes/gitops/overview" icon="code-branch">
|
||||
Deploy Pangolin with Argo CD or Flux.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
426
self-host/manual/kubernetes/prerequisites.mdx
Normal file
426
self-host/manual/kubernetes/prerequisites.mdx
Normal file
@@ -0,0 +1,426 @@
|
||||
---
|
||||
title: "Prerequisites"
|
||||
description: "Cluster requirements, tools, and setup needed to deploy Pangolin and Newt on Kubernetes."
|
||||
---
|
||||
|
||||
import PangolinCloudTocCta from "/snippets/pangolin-cloud-toc-cta.mdx";
|
||||
|
||||
<PangolinCloudTocCta />
|
||||
|
||||
|
||||
Before installing Pangolin or Newt on Kubernetes, check that your cluster, local tools, networking, and storage setup are ready.
|
||||
|
||||
## Cluster requirements
|
||||
|
||||
### Kubernetes version
|
||||
|
||||
The Pangolin and Newt Helm charts currently require Kubernetes **1.30.14 or newer**.
|
||||
|
||||
Use a Kubernetes version that is both:
|
||||
|
||||
- supported by your Kubernetes provider or distribution
|
||||
- compatible with the chart requirement
|
||||
|
||||
Kubernetes 1.30 satisfies the chart minimum, but it is no longer a supported upstream Kubernetes release. For production, use a currently supported Kubernetes minor release whenever possible.
|
||||
|
||||
Check your cluster version:
|
||||
|
||||
```bash
|
||||
kubectl version
|
||||
```
|
||||
|
||||
<Info>
|
||||
For the exact version support, refer to the Pangolin and Newt Helm chart READMEs before installing or upgrading.
|
||||
</Info>
|
||||
|
||||
### Cluster access
|
||||
|
||||
You need `kubectl` access to the target cluster.
|
||||
|
||||
The user or service account used for installation must be able to create and manage the resources required by the selected install method.
|
||||
|
||||
For a standard Helm install, this usually includes:
|
||||
|
||||
* namespaces
|
||||
* deployments and statefulsets
|
||||
* services
|
||||
* configmaps
|
||||
* secrets
|
||||
* persistent volume claims
|
||||
* service accounts
|
||||
* roles and role bindings
|
||||
* network policies, if enabled
|
||||
|
||||
For Pangolin controller mode, additional permissions are required for the controller resources managed by the chart.
|
||||
|
||||
Check cluster access:
|
||||
|
||||
```bash
|
||||
kubectl cluster-info
|
||||
kubectl auth can-i create namespace
|
||||
kubectl auth can-i create deployments --namespace pangolin
|
||||
kubectl auth can-i create secrets --namespace pangolin
|
||||
```
|
||||
|
||||
<Note>
|
||||
The exact permissions depend on the selected chart options. If you install cluster-scoped components or CRDs, cluster-level permissions may be required.
|
||||
</Note>
|
||||
|
||||
## Required tools
|
||||
|
||||
### kubectl
|
||||
|
||||
`kubectl` is required for checking cluster access, inspecting resources, and troubleshooting.
|
||||
|
||||
Install a `kubectl` version that is compatible with your cluster version. As a general rule, keep `kubectl` close to the Kubernetes API server version used by your cluster.
|
||||
|
||||
Verify:
|
||||
|
||||
```bash
|
||||
kubectl version --client
|
||||
```
|
||||
|
||||
### Helm
|
||||
|
||||
Helm is required for Helm-based installs and for rendering Helm charts.
|
||||
- **Minimum version**: 3.10 or later
|
||||
- **Installation**: [Helm official install guide](https://helm.sh/docs/intro/install/)
|
||||
|
||||
Verify:
|
||||
|
||||
```bash
|
||||
helm version
|
||||
```
|
||||
|
||||
Install Helm from the official Helm installation guide if it is not already available.
|
||||
|
||||
### Kustomize
|
||||
|
||||
Kustomize is required for Kustomize-based installs.
|
||||
|
||||
You can use either:
|
||||
|
||||
* `kubectl apply -k`
|
||||
* `kubectl kustomize`
|
||||
* the standalone `kustomize` CLI
|
||||
|
||||
Verify:
|
||||
|
||||
```bash
|
||||
kubectl kustomize --help
|
||||
```
|
||||
|
||||
Or, when using the standalone CLI:
|
||||
|
||||
```bash
|
||||
kustomize version
|
||||
```
|
||||
|
||||
### Git
|
||||
|
||||
Git is required for GitOps workflows with Argo CD or Flux.
|
||||
|
||||
Verify:
|
||||
|
||||
```bash
|
||||
git --version
|
||||
```
|
||||
|
||||
## Storage requirements
|
||||
|
||||
### StorageClass
|
||||
|
||||
Pangolin requires persistent storage depending on the selected database mode and chart configuration.
|
||||
|
||||
Check available StorageClasses:
|
||||
|
||||
```bash
|
||||
kubectl get storageclasses
|
||||
```
|
||||
|
||||
If your cluster has a default StorageClass, Kubernetes can usually provision persistent volumes automatically.
|
||||
|
||||
If no default StorageClass exists, configure the StorageClass explicitly in your values file.
|
||||
|
||||
### Pangolin storage
|
||||
|
||||
Pangolin deployments use persistent storage for database-backed setups, CloudNativePG, embedded PostgreSQL, or other chart-managed persistent components.
|
||||
|
||||
For production, prefer one of these database modes:
|
||||
|
||||
* CloudNativePG
|
||||
* external PostgreSQL
|
||||
|
||||
Avoid SQLite for production deployments.
|
||||
|
||||
### Newt storage
|
||||
|
||||
Newt is lightweight, but persistent storage is still recommended for stable Kubernetes operation.
|
||||
The Newt chart supports writable configuration persistence through either `emptyDir` or an existing PVC. While `emptyDir` can be used for simple test deployments, it is ephemeral and is recreated when the Pod is replaced. In that case, Newt may lose its writable runtime configuration and has to re-establish its connection state after the Pod starts again. During this reconnect and handshake phase, existing tunnels or proxied connections can be interrupted temporarily.
|
||||
|
||||
<Warning>
|
||||
`emptyDir` is suitable for short-lived tests, but pod replacement can interrupt active Newt traffic while connection state is rebuilt.
|
||||
</Warning>
|
||||
|
||||
<Tip>
|
||||
For production Newt deployments, use a PersistentVolumeClaim so writable runtime configuration survives restarts, upgrades, and rescheduling.
|
||||
</Tip>
|
||||
|
||||
For production or any setup where short interruptions after Pod restarts should be avoided, use a PersistentVolumeClaim. This allows Newt to keep its writable configuration across Pod restarts, node drains, upgrades, and rescheduling events.
|
||||
|
||||
## Networking requirements
|
||||
|
||||
### Ingress or Traefik routing
|
||||
|
||||
Pangolin needs an external entrypoint for the dashboard, API, and site traffic.
|
||||
|
||||
The Pangolin chart supports different deployment modes:
|
||||
|
||||
* `controller` mode with a Traefik ingress controller and Traefik CRDs integration
|
||||
* `standalone` mode with chart-managed Traefik workload
|
||||
* optional bundled Traefik controller installation in controller mode
|
||||
|
||||
Controller mode is the recommended production mode.
|
||||
|
||||
<Note>
|
||||
In controller mode, Traefik CRDs must be available. And it may add additional version requirements based on the Pangolin/Controller version. Check the chart README for the exact requirements.
|
||||
</Note>
|
||||
|
||||
Check ingress-related resources:
|
||||
|
||||
```bash
|
||||
kubectl get ingress -A
|
||||
kubectl get ingressroute.traefik.io -A
|
||||
```
|
||||
|
||||
The `IngressRoute.traefik.io` command only works when Traefik CRDs are installed.
|
||||
|
||||
### DNS
|
||||
|
||||
Configure DNS records before exposing Pangolin publicly.
|
||||
|
||||
At minimum, the Pangolin dashboard domain should resolve to the ingress controller, load balancer, or public endpoint used by your deployment.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
nslookup pangolin.example.com
|
||||
```
|
||||
|
||||
For tunneled site deployments, also verify the DNS records used by the tunnel entrypoint and Newt connection settings.
|
||||
|
||||
### TLS
|
||||
|
||||
Use HTTPS for the Pangolin dashboard and API.
|
||||
|
||||
Common TLS options are:
|
||||
|
||||
* Traefik ACME / Let's Encrypt
|
||||
* cert-manager, Infisical or similar with an existing ingress or certificate workflow
|
||||
* a pre-created Kubernetes TLS secret
|
||||
* TLS termination at an external load balancer or ingress controller
|
||||
|
||||
The Pangolin chart supports cert-manager, Infisical, Traefik-related TLS configuration and custom Kubernetes TLS secrets. Make sure the configured entrypoints, certificate resolver names, or TLS secret names match your actual Traefik setup.
|
||||
|
||||
If you use cert-manager, verify that cert-manager is already installed:
|
||||
|
||||
<Info>
|
||||
cert-manager is useful for many Kubernetes TLS setups, but it is not required for every Pangolin deployment. Use the TLS method that matches your ingress controller and cluster.
|
||||
</Info>
|
||||
|
||||
### Network policies
|
||||
|
||||
The Pangolin and Newt charts include NetworkPolicy configuration for the required application traffic. When enabled, the chart-managed policies are designed to allow the necessary communication between Pangolin, Newt, Gerbil, Traefik, the database, DNS, and other required components.
|
||||
|
||||
<Note>
|
||||
Keep chart-managed NetworkPolicies enabled by default. Add custom policies mainly when your security model requires stricter controls.
|
||||
</Note>
|
||||
|
||||
You usually do not need to create additional NetworkPolicies for a standard installation. However, if you disable the chart-managed policies or replace them with your own policies because of custom security or other requirements, make sure your policies still allow the required traffic between:
|
||||
|
||||
* Traefik (IngressController or Standalone), Pangolin and Pangolin-Kube-Controller, if used
|
||||
* Pangolin and its database
|
||||
* Pangolin and Gerbil, when the tunnel stack is enabled
|
||||
* Newt and the Pangolin endpoint
|
||||
* workloads and DNS
|
||||
* workloads and external identity providers or APIs, if used
|
||||
|
||||
For most deployments, it is recommended to keep the chart-managed NetworkPolicies enabled and only customize them when your cluster has specific network security requirements.
|
||||
|
||||
## Namespace and RBAC
|
||||
|
||||
### Namespace
|
||||
|
||||
Choose a namespace for the installation.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
kubectl create namespace pangolin
|
||||
```
|
||||
|
||||
When installing with Helm, you can also let Helm create the namespace:
|
||||
|
||||
```bash
|
||||
helm upgrade --install pangolin fossorial/pangolin \
|
||||
--namespace pangolin \
|
||||
--create-namespace
|
||||
```
|
||||
|
||||
It's recommended to create the namespace explicitly before installation, so you can apply any required labels or annotations for Pod Security Admission or other cluster policies.
|
||||
|
||||
### Pod Security Admission
|
||||
|
||||
Some clusters enforce Pod Security Admission labels at the namespace level.
|
||||
|
||||
Pangolin deployments that include Gerbil may require permissions that are not compatible with a restricted namespace profile, because Gerbil manages WireGuard and requires capabilities such as `NET_ADMIN`.
|
||||
|
||||
If the chart creates the namespace, it can apply the labels required by its configuration. If you manage the namespace yourself, apply the required labels manually based on the chart values and your selected deployment mode.
|
||||
|
||||
### Service accounts and RBAC
|
||||
|
||||
The Helm charts can create the required service accounts and RBAC resources.
|
||||
|
||||
Controller mode requires Kubernetes API access for the Pangolin controller. The main Pangolin application and Gerbil do not need the same Kubernetes API permissions in the default multi-workload topology.
|
||||
|
||||
## Secrets and configuration
|
||||
|
||||
### Secret management
|
||||
|
||||
Pangolin and Newt require secrets for different parts of the deployment.
|
||||
|
||||
Common examples:
|
||||
|
||||
* Pangolin application secrets
|
||||
* database credentials or connection strings
|
||||
* Newt credentials or provisioning keys
|
||||
* TLS certificates, if not managed by the ingress layer
|
||||
* identity provider client secrets, if used
|
||||
|
||||
Do not commit plaintext secrets to Git.
|
||||
|
||||
<Warning>
|
||||
Do not commit plaintext secrets to Git. Use encrypted or external secret backends for GitOps workflows.
|
||||
</Warning>
|
||||
|
||||
If you deploy with GitOps tools such as Argo CD or Flux, use a secret management approach that allows secrets to be stored safely in Git or injected from an external secret backend. Common options include encrypted secrets with SOPS, Sealed Secrets, External Secrets Operator, HashiCorp Vault, Infisical, or cloud provider secret managers. These approaches allow you to keep the deployment declarative without storing plaintext credentials in the repository.
|
||||
|
||||
Use your existing secret management workflow, for example:
|
||||
|
||||
* SOPS-encrypted secrets for GitOps workflows
|
||||
* Sealed Secrets
|
||||
* External Secrets Operator
|
||||
* HashiCorp Vault
|
||||
* Infisical
|
||||
* cloud provider secret managers
|
||||
* manually created Kubernetes Secrets for small test environments
|
||||
|
||||
### ConfigMaps
|
||||
|
||||
Configuration that is not sensitive can be stored in ConfigMaps or provided through Helm values.
|
||||
|
||||
Do not put passwords, private keys, API tokens, provisioning secrets, or other sensitive values into ConfigMaps. ConfigMaps are not designed for secret data and should only be used for non-sensitive configuration.
|
||||
## Database requirements
|
||||
|
||||
### Pangolin
|
||||
|
||||
Pangolin supports several database modes through the Helm chart.
|
||||
|
||||
For production, use:
|
||||
|
||||
* CloudNativePG
|
||||
* external PostgreSQL
|
||||
|
||||
The default Pangolin chart database mode is `cloudnativepg`.
|
||||
|
||||
When using CloudNativePG, make sure either:
|
||||
|
||||
* the chart installs the required CloudNativePG components, or
|
||||
* an existing CloudNativePG operator and cluster are already available, depending on your selected values
|
||||
|
||||
When using an external PostgreSQL database, provide the connection details through a Kubernetes Secret or a chart-supported secret generation method.
|
||||
|
||||
## Resource planning
|
||||
|
||||
Set resource requests and limits according to your expected workload and cluster sizing.
|
||||
|
||||
At minimum, plan resources for:
|
||||
|
||||
* Pangolin
|
||||
* Gerbil, when the tunnel stack is enabled
|
||||
* pangolin-kube-controller, when controller mode is used
|
||||
* Traefik, if installed or managed as part of the deployment
|
||||
* PostgreSQL or CloudNativePG components, if used
|
||||
* Newt instances
|
||||
|
||||
Resource usage depends on traffic volume, number of sites, number of users, database mode, enabled metrics, and ingress/tunnel configuration.
|
||||
|
||||
Configure resources in your Helm values, for example:
|
||||
|
||||
```yaml
|
||||
resources:
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
limits:
|
||||
memory: 1Gi
|
||||
```
|
||||
|
||||
<Note>
|
||||
Use the chart defaults as the starting point, then adjust requests and limits based on actual usage in your cluster.
|
||||
</Note>
|
||||
|
||||
<Warning>
|
||||
Avoid setting CPU limits unless you have a specific reason to enforce them. CPU limits can cause throttling when a workload temporarily needs more CPU, even if spare CPU capacity is available on the node. This can negatively affect latency-sensitive components such as ingress, tunnel, proxy, or controller workloads.
|
||||
For most deployments, set CPU requests to reserve an appropriate baseline and set memory limits to protect the node from excessive memory usage. Add CPU limits only when your cluster policy requires them or when you intentionally want to cap a component's maximum CPU usage.
|
||||
</Warning>
|
||||
|
||||
## Optional tools
|
||||
|
||||
### Argo CD
|
||||
|
||||
Use Argo CD if you want GitOps reconciliation with a web UI, sync status, and drift detection.
|
||||
|
||||
### Flux
|
||||
|
||||
Use Flux if you want GitOps reconciliation through Kubernetes custom resources such as `HelmRelease` and `Kustomization`.
|
||||
|
||||
### Helmfile
|
||||
|
||||
Use Helmfile if you want to manage multiple Helm releases together, for example supporting components plus Pangolin and Newt.
|
||||
|
||||
## Verification checklist
|
||||
|
||||
Before proceeding with installation:
|
||||
|
||||
* [ ] The cluster runs a supported Kubernetes version that satisfies the chart requirement.
|
||||
* [ ] `kubectl` can access the cluster.
|
||||
* [ ] Helm is installed, if using the Helm workflow.
|
||||
* [ ] Kustomize is available, if using the Kustomize workflow.
|
||||
* [ ] A namespace is created or planned.
|
||||
* [ ] A StorageClass is available if persistent storage is required.
|
||||
* [ ] The ingress or Traefik routing strategy is defined.
|
||||
* [ ] DNS records are configured.
|
||||
* [ ] The TLS strategy is defined.
|
||||
* [ ] Database mode is selected for Pangolin.
|
||||
* [ ] Secret management is planned.
|
||||
* [ ] Pod Security Admission requirements are understood.
|
||||
* [ ] NetworkPolicy requirements are understood, if policies are enabled.
|
||||
* [ ] Resource requests and limits are reviewed.
|
||||
|
||||
## Next steps
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Helm Quick-Start" href="/self-host/manual/kubernetes/helm" icon="box">
|
||||
Install Pangolin or Newt with Helm.
|
||||
</Card>
|
||||
<Card title="Kustomize Quick-Start" href="/self-host/manual/kubernetes/kustomize" icon="layer-group">
|
||||
Use Kustomize overlays and patches.
|
||||
</Card>
|
||||
<Card title="GitOps Overview" href="/self-host/manual/kubernetes/gitops/overview" icon="code-branch">
|
||||
Deploy with Argo CD or Flux.
|
||||
</Card>
|
||||
<Card title="Pangolin Helm" href="/self-host/manual/kubernetes/pangolin/helm" icon="server">
|
||||
Start with the Pangolin Helm installation guide.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
Reference in New Issue
Block a user