diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 00000000..e4ad5c71 --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,124 @@ +on: + push: + branches: + - main + +permissions: + contents: write + issues: write + pull-requests: write + +env: + PUBLISHABLE_ITEMS: '["supplemental/helm/beszel-agent", "supplemental/helm/beszel-hub"]' + +name: helm-release + +jobs: + release: + name: Release + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v5 + with: + fetch-depth: 0 + + - uses: googleapis/release-please-action@v4 + name: Prepare release + id: release-please + with: + token: ${{ secrets.CR_TOKEN }} + + - name: Dump Release Please Output + env: + RELEASE_PLEASE_OUTPUT: ${{ toJson(steps.release-please.outputs) }} + run: | + echo "$RELEASE_PLEASE_OUTPUT" + + - name: Determine what should be published + uses: actions/github-script@v8 + id: items-to-publish + env: + CHANGED_ITEMS: "${{ steps.release-please.outputs.paths_released }}" + with: + script: | + const changedItems = JSON.parse(process.env.CHANGED_ITEMS || '[]'); + console.log("changed items", changedItems); + const eligibleItems = JSON.parse(process.env.PUBLISHABLE_ITEMS || '[]'); + console.log("eligible items", eligibleItems); + const itemsToPublish = changedItems.filter(i => eligibleItems.includes(i)); + console.log("items to publish", itemsToPublish); + return itemsToPublish; + outputs: + items_to_publish: ${{ steps.items-to-publish.outputs.result }} + releases: ${{ toJson(steps.release-please.outputs) }} + + release-charts: + name: Release Charts + needs: release + runs-on: ubuntu-latest + if: ${{ needs.release.outputs.items_to_publish != '' && toJson(fromJson(needs.release.outputs.items_to_publish)) != '[]' }} + strategy: + fail-fast: false + matrix: + path: ${{ fromJSON(needs.release.outputs.items_to_publish) }} + + env: + TAG: ${{ fromJson(needs.release.outputs.releases)[format('{0}--tag_name', matrix.path)] }} + VERSION: ${{ fromJson(needs.release.outputs.releases)[format('{0}--version', matrix.path)] }} + + steps: + - name: Debug + run: | + echo ${{ env.TAG }} + echo ${{ env.VERSION }} + echo ${{ matrix.path }} + + - name: ✨ Checkout repository + uses: actions/checkout@v5 + with: + fetch-depth: 0 + + - name: Configure Git + run: | + echo ${{ needs.release.outputs.items_to_publish }} + git config user.name "$GITHUB_ACTOR" + git config user.email "$GITHUB_ACTOR@users.noreply.github.com" + + - name: Install Chart Releaser + run: | + version=v1.6.0 + mkdir .tmp + install_dir=.tmp + echo "Installing chart-releaser on $install_dir..." + curl -sSLo cr.tar.gz "https://github.com/helm/chart-releaser/releases/download/$version/chart-releaser_${version#v}_linux_amd64.tar.gz" + tar -xzf cr.tar.gz -C "$install_dir" + rm -f cr.tar.gz + + - name: Package chart + run: | + .tmp/cr package ${{ matrix.path }} + ls -la .cr-release-packages/ + + - name: Upload binaries to release + uses: svenstaro/upload-release-action@v2 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + file: .cr-release-packages/*.tgz + file_glob: true + overwrite: true + tag: ${{ env.TAG }} + + - name: Update index + run: | + owner=$(cut -d '/' -f 1 <<< "$GITHUB_REPOSITORY") + repo=$(cut -d '/' -f 2 <<< "$GITHUB_REPOSITORY") + + # Create docs directory and copy chart + mkdir -p docs + cp .cr-release-packages/*.tgz docs/ || true + + # Generate index.yaml for GitHub Pages + args=(-o "$owner" -r "$repo" -c "https://henrygd.github.io/beszel" --push -t "${{ secrets.CR_TOKEN }}" --index-path docs/index.yaml) + .tmp/cr index "${args[@]}" diff --git a/.gitignore b/.gitignore index 98b0fb5d..432f7926 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ pb_data data temp .vscode -beszel-agent beszel_data beszel_data* dist @@ -21,3 +20,5 @@ __debug_* agent/lhm/obj agent/lhm/bin dockerfile_agent_dev +.cr-release-packages +.tmp diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 00000000..43c41384 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,4 @@ +{ + "supplemental/helm/beszel-agent": "0.1.0", + "supplemental/helm/beszel-hub": "0.1.0" +} diff --git a/docs/index.yaml b/docs/index.yaml new file mode 100644 index 00000000..f4143206 --- /dev/null +++ b/docs/index.yaml @@ -0,0 +1,3 @@ +apiVersion: v1 +entries: {} +generated: "2026-03-05T00:00:00Z" diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 00000000..c60bcbe1 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "release-type": "simple", + "packages": { + "supplemental/helm/beszel-agent": { + "package-name": "beszel-agent", + "release-type": "helm", + "changelog-path": "CHANGELOG.md", + "bump-minor-pre-major": true, + "bump-patch-for-minor-pre-major": true, + "draft": false, + "prerelease": false + }, + "supplemental/helm/beszel-hub": { + "package-name": "beszel-hub", + "release-type": "helm", + "changelog-path": "CHANGELOG.md", + "bump-minor-pre-major": true, + "bump-patch-for-minor-pre-major": true, + "draft": false, + "prerelease": false + } + } +} diff --git a/supplemental/kubernetes/beszel-hub/charts/.helmignore b/supplemental/helm/beszel-agent/.helmignore similarity index 100% rename from supplemental/kubernetes/beszel-hub/charts/.helmignore rename to supplemental/helm/beszel-agent/.helmignore diff --git a/supplemental/helm/beszel-agent/Chart.yaml b/supplemental/helm/beszel-agent/Chart.yaml new file mode 100644 index 00000000..1a25b423 --- /dev/null +++ b/supplemental/helm/beszel-agent/Chart.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +description: Installs beszel-agent in kubernetes +home: https://github.com/henrygd/beszel/tree/main/supplemental/helm/beszel-agent +name: beszel-agent +appVersion: "0.17.0" +# Do not touch will be updated during release +version: 0.1.0 +sources: + - https://github.com/henrygd/beszel/tree/main/supplemental/helm/beszel-agent + - https://www.beszel.dev/ + - https://github.com/henrygd/beszel +icon: https://repository-images.githubusercontent.com/825470378/2710c6db-f934-4a8b-a2c4-7a0abbcd2ad6 +maintainers: + - name: cloudwithdan + email: nikoloskid@pm.me diff --git a/supplemental/helm/beszel-agent/README.md b/supplemental/helm/beszel-agent/README.md new file mode 100644 index 00000000..aa709948 --- /dev/null +++ b/supplemental/helm/beszel-agent/README.md @@ -0,0 +1,538 @@ +# Beszel Agent Helm Chart + +A Kubernetes Helm chart for deploying [Beszel Agent](https://www.beszel.dev/) - a lightweight monitoring agent that collects system metrics and sends them to a central Beszel Hub. + +## Overview + +This Helm chart simplifies the deployment of Beszel Agent in Kubernetes environments. By default, it deploys as a DaemonSet to run one agent on each node in the cluster. The agent monitors node-level system resources (CPU, memory, disk, network, temperature, GPU, etc.) and provides detailed metrics to the Beszel Hub for centralized monitoring and alerting. + +## Features + +- ✅ DaemonSet deployment by default (one agent per node) +- ✅ GPU support via NVIDIA runtime (optional) +- ✅ Additional filesystem mounting for multi-disk monitoring +- ✅ Flexible deployment as DaemonSet or single Deployment +- ✅ Environment variable configuration for agent authentication +- ✅ Host network support for detailed network monitoring +- ✅ Automatic handling of tainted nodes via tolerations + +## Prerequisites + +- Kubernetes 1.19+ +- Helm 3.0+ +- Beszel Hub instance running and accessible +- SSH public key for agent authentication + +## What Gets Monitored + +In Kubernetes environments, the Beszel agent monitors **node-level metrics**: + +- **CPU usage** - Node CPU utilization and per-core stats +- **Memory usage** - Node memory, swap, and ZFS ARC +- **Disk usage** - Node filesystem usage and I/O statistics +- **Network usage** - Node network traffic (requires `hostNetwork: true`) +- **Load average** - System load averages +- **Temperature** - Node hardware sensors +- **GPU usage/power** - NVIDIA, AMD, and Intel GPUs (with appropriate image) +- **Battery** - Node battery status (if applicable) +- **S.M.A.T.** - Disk health monitoring + +**Note**: The agent does **not** monitor individual Kubernetes pods or containers. For pod/container metrics, use Kubernetes metrics-server or monitoring tools like Prometheus. + +## Quick Start + +### 1. Add the Helm Repository + +```bash +helm repo add beszel https://henrygd.github.io/beszel +helm repo update +``` + +### 2. Install the Chart + +```bash +helm install beszel-agent ./beszel-agent \ + --set env.KEY="ssh-ed25519 AAAA... your-public-key" \ + --set env.TOKEN="your-token-value" \ + --set env.HUB_URL="http://beszel-hub:8090" +``` + +Or with custom values: + +```bash +helm install beszel-agent ./beszel-agent -f custom-values.yaml +``` + +### 3. Verify the Agent is Running + +```bash +kubectl get pods -l app.kubernetes.io/name=beszel-agent +kubectl logs -l app.kubernetes.io/name=beszel-agent +``` + +## Configuration + +### Basic Configuration + +Essential parameters to configure: + +| Parameter | Default | Description | +|-----------|---------|-------------| +| `daemonset.enabled` | `true` | Deploy as DaemonSet (one pod per node) | +| `env.KEY` | Required* | SSH public key for Hub authentication (*unless using existingSecret) | +| `env.TOKEN` | Empty | Authentication token (optional) | +| `env.HUB_URL` | Empty | Hub URL (e.g., http://beszel-hub:8090) | +| `env.PORT` | `45876` | Port the agent listens on | +| `secret.existingSecret` | Empty | Name of an existing Kubernetes Secret to use | +| `secret.sshKey` | `ssh-key` | Key name in the secret for the SSH public key | +| `secret.tokenKey` | `token` | Key name in the secret for the authentication token | +| `image.repository` | `henrygd/beszel-agent` | Container image | +| `image.tag` | Chart AppVersion (0.17.0) | Image version | +| `hostNetwork` | `false` | Use host network for network monitoring | +| `tolerations` | Allows all taints | Tolerations for running on tainted nodes | + +### Minimal Configuration + +```bash +helm install beszel-agent ./beszel-agent \ + --set env.KEY="ssh-ed25519 AAAA... your-public-key" \ + --set env.TOKEN="your-token-value" \ + --set env.HUB_URL="http://beszel-hub:8090" +``` + +### Standard Configuration + +```yaml +# values.yaml +image: + repository: henrygd/beszel-agent + tag: "" # Uses chart appVersion + +env: + PORT: "45876" + KEY: "ssh-ed25519 AAAA... your-public-key" + TOKEN: "your-token-value" + HUB_URL: "http://beszel-hub:8090" + +# Use host network for accurate network monitoring +hostNetwork: false +``` + +### GPU Support (NVIDIA) + +For systems with NVIDIA GPUs, use the special GPU-enabled image: + +```yaml +image: + repository: henrygd/beszel-agent-nvidia + +# Enable NVIDIA runtime +gpuRuntime: nvidia + +env: + PORT: "45876" + KEY: "ssh-ed25519 AAAA... your-public-key" + TOKEN: "your-token-value" + HUB_URL: "http://beszel-hub:8090" + NVIDIA_VISIBLE_DEVICES: "all" + NVIDIA_DRIVER_CAPABILITIES: "compute,video,utility" +``` + +**Note**: The GPU image (`henrygd/beszel-agent-nvidia`) is specifically for monitoring NVIDIA GPUs on the node. It does not provide container-level GPU metrics. + +Or via CLI: + +```bash +helm install beszel-agent ./beszel-agent \ + --set image.repository=henrygd/beszel-agent-nvidia \ + --set gpuRuntime=nvidia \ + --set env.NVIDIA_VISIBLE_DEVICES=all \ + --set env.NVIDIA_DRIVER_CAPABILITIES="compute,video,utility" \ + --set env.KEY="ssh-ed25519 AAAA... your-public-key" \ + --set env.TOKEN="your-token-value" \ + --set env.HUB_URL="http://beszel-hub:8090" +``` + +### Monitor Additional Filesystems + +To monitor additional disks or partitions: + +```yaml +volumes: + - name: extra-filesystems + hostPath: + path: /mnt/disk/.beszel + type: DirectoryOrCreate + +volumeMounts: + - name: extra-filesystems + mountPath: /extra-filesystems + readOnly: true + +env: + PORT: "45876" + KEY: "ssh-ed25519 AAAA... your-public-key" + TOKEN: "your-token-value" + HUB_URL: "http://beszel-hub:8090" +``` + +### Advanced Configuration + +#### Resource Limits + +```yaml +resources: + limits: + cpu: 500m + memory: 256Mi + requests: + cpu: 100m + memory: 128Mi +``` + +#### Node Selection + +Run agents on specific nodes: + +```yaml +nodeSelector: + monitoring: "true" + +tolerations: + - key: monitoring + operator: Equal + value: "true" + effect: NoSchedule + +affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchExpressions: + - key: app.kubernetes.io/name + operator: In + values: + - beszel-agent + topologyKey: kubernetes.io/hostname +``` + +#### Host Network + +For detailed network statistics, enable host network mode: + +```yaml +hostNetwork: true + +env: + PORT: "45876" + KEY: "ssh-ed25519 AAAA... your-public-key" + TOKEN: "your-token-value" + HUB_URL: "http://beszel-hub:8090" +``` + +**Note**: When `hostNetwork: true`, the agent can monitor the node's actual network interfaces. When `false`, it only sees the pod's network namespace. + +#### DaemonSet Mode + +By default, the agent is deployed as a DaemonSet, running one pod on each cluster node: + +```yaml +daemonset: + enabled: true # Default - one agent per node + +# Or disable for single Deployment deployment +daemonset: + enabled: false +replicaCount: 1 +``` + +#### Tolerations + +By default, tolerations are set to allow agents to run on all nodes, including tainted ones: + +```yaml +tolerations: + - operator: Exists + effect: NoSchedule + - operator: Exists + effect: NoExecute +``` + +To restrict agents to specific nodes: + +```yaml +tolerations: [] +nodeSelector: + monitoring: "true" +``` + +### Using Existing Secrets + +The chart supports referencing an existing Kubernetes Secret instead of having the chart create one. This is useful when: + +- You want to manage secrets externally (e.g., with a secret operator, external secret manager, or GitOps) +- You want to share a single secret across multiple deployments +- You prefer not to store sensitive values in Helm values + +```yaml +# Create the secret manually +apiVersion: v1 +kind: Secret +metadata: + name: my-beszel-secret +type: Opaque +data: + ssh-key: c3NoLWVkMjU1IDEgQUFBQU... # base64 encoded SSH public key + token: dG9rZW4tdmFsdWU= # base64 encoded token (optional) +``` + +Then reference it in your values: + +```yaml +secret: + existingSecret: my-beszel-secret + sshKey: ssh-key # key name in the secret (default: ssh-key) + tokenKey: token # key name in the secret (default: token) + +env: + HUB_URL: "http://beszel-hub:8090" +``` + +**Note**: When using `existingSecret`, do not set `env.KEY` or `env.TOKEN` - the chart will use the values from the existing secret instead. + +You can also use different key names if your secret uses non-standard keys: + +```yaml +secret: + existingSecret: my-beszel-secret + sshKey: public-key # custom key name + tokenKey: auth-token # custom key name +``` + +## Deployment Examples + +### Full Cluster Monitoring (DaemonSet - Default) + +```bash +helm install beszel-agent ./beszel-agent \ + --set env.KEY="ssh-ed25519 AAAA... your-public-key" \ + --set env.TOKEN="your-token-value" \ + --set env.HUB_URL="http://beszel-hub:8090" +``` + +This deploys one agent on every node in the cluster automatically. + +### Single Agent Deployment (Non-DaemonSet) + +```yaml +# values.yaml +daemonset: + enabled: false + +replicaCount: 1 + +env: + PORT: "45876" + KEY: "ssh-ed25519 AAAA... your-public-key" + TOKEN: "your-token-value" + HUB_URL: "http://beszel-hub:8090" +``` + +Or via CLI: + +```bash +helm install beszel-agent ./beszel-agent \ + --set daemonset.enabled=false \ + --set replicaCount=1 \ + --set env.KEY="ssh-ed25519 AAAA... your-public-key" \ + --set env.TOKEN="your-token-value" \ + --set env.HUB_URL="http://beszel-hub:8090" +``` + +### Network Monitoring with Host Network + +```yaml +hostNetwork: true + +env: + PORT: "45876" + KEY: "ssh-ed25519 AAAA... your-public-key" + TOKEN: "your-token-value" + HUB_URL: "http://beszel-hub:8090" + +podSecurityContext: + hostNetwork: true +``` + +## Managing the Agent + +### Check Agent Status + +```bash +# List agent pods +kubectl get pods -l app.kubernetes.io/name=beszel-agent + +# View agent logs +kubectl logs -l app.kubernetes.io/name=beszel-agent -f + +# Describe a specific pod +kubectl describe pod +``` + +### Update Configuration + +```bash +# Update the SSH key +helm upgrade beszel-agent ./beszel-agent \ + --set env.KEY="ssh-ed25519 AAAA... your-public-key" \ + --set env.TOKEN="your-token-value" \ + --set env.HUB_URL="http://beszel-hub:8090" + +# Change image version +helm upgrade beszel-agent ./beszel-agent \ + --set image.tag="0.17.0" +``` + +### Restart All Agents + +```bash +# For DaemonSet (default) +kubectl rollout restart daemonset beszel-agent + +# For Deployment (if daemonset.enabled=false) +kubectl rollout restart deployment beszel-agent +``` + +### Uninstall + +```bash +helm uninstall beszel-agent +``` + +### View Helm Release History + +```bash +helm history beszel-agent +helm rollback beszel-agent 1 # Rollback to previous version +``` + +## Environment Variables + +| Variable | Default | Description | +|----------|---------|-------------| +| `PORT` | `45876` | Port the agent listens on | +| `KEY` | Required | SSH public key for Hub authentication | +| `TOKEN` | Empty | Authentication token (optional) | +| `HUB_URL` | Empty | Hub URL (e.g., http://beszel-hub:8090) | +| `NVIDIA_VISIBLE_DEVICES` | Not set | GPU visibility (GPU agents only) | +| `NVIDIA_DRIVER_CAPABILITIES` | Not set | GPU capabilities (GPU agents only) | + +## Troubleshooting + +### Agent Pod Won't Start + +```bash +# Check pod events and logs +kubectl describe pod +kubectl logs +``` + +### Cannot Connect to Hub + +- Verify Hub is accessible from the pod's network +- Check DNS resolution: `kubectl exec -- nslookup beszel-hub.default.svc.cluster.local` +- Verify SSH key is correctly configured +- Check firewall rules for port 8090 (Hub) and 45876 (Agent) + +### GPU Not Detected + +- Confirm image is `henrygd/beszel-agent-nvidia` +- Verify NVIDIA runtime is installed on nodes +- Check GPU visibility: `kubectl exec -- nvidia-smi` +- Verify runtimeClassName matches your GPU runtime + +### SSH Key Authentication Failed + +- Verify key format (should be valid SSH public key) +- Check key is correctly set in `env.KEY` +- Ensure Hub has the corresponding private key +- Verify Hub can authenticate agents with this key + +### High Memory Usage + +Adjust resource limits: + +```yaml +resources: + limits: + memory: 512Mi + requests: + memory: 256Mi +``` + +## Security Considerations + +- Store SSH keys securely (use Kubernetes Secrets) +- Restrict container to read-only root filesystem if possible +- Limit resource usage with resource limits +- Use network policies to restrict traffic +- Run with minimal privileges +- Regularly update agent image to latest version +- Use private container registries if applicable + +### Using Kubernetes Secrets for Configuration + +The chart automatically creates a Kubernetes Secret to store sensitive authentication data: + +```bash +# Install with all configuration options +helm install beszel-agent ./beszel-agent \ + --set env.KEY="ssh-ed25519 AAAA... your-public-key" \ + --set env.TOKEN="your-optional-token" \ + --set env.HUB_URL="http://beszel-hub:8090" +``` + +Or create the installation with a values file: + +```yaml +# values.yaml +env: + KEY: "ssh-ed25519 AAAA... your-public-key" + TOKEN: "your-optional-token" + HUB_URL: "http://beszel-hub:8090" +``` + +Configuration stored in Kubernetes Secrets (encrypted at rest): +- `KEY` - SSH public key for authentication (required) +- `TOKEN` - Authentication token (optional) + +Configuration as regular environment variables: +- `HUB_URL` - Hub address (e.g., http://beszel-hub:8090 or https://beszel.example.com) + +To verify the secret was created: + +```bash +kubectl get secret beszel-agent +kubectl get secret beszel-agent -o jsonpath='{.data.ssh-key}' | base64 -d +``` + +## Support and Documentation + +- **Project Homepage**: https://www.beszel.dev/ +- **GitHub Repository**: https://github.com/henrygd/beszel +- **Agent Documentation**: https://www.beszel.dev/ + +**Note**: The main Beszel documentation describes Docker/Podman container monitoring. In Kubernetes, the agent focuses on node-level metrics. For Kubernetes-specific container/pod monitoring, use tools like metrics-server, Prometheus, or the Kubernetes Metrics API. + +## Chart Information + +- **Chart Version**: 0.1.0 +- **App Version**: 0.17.0 +- **Kubernetes Version**: 1.19+ +- **Maintainer**: cloudwithdan (nikoloskid@pm.me) + +## License + +Please refer to the main Beszel project repository for license information. diff --git a/supplemental/helm/beszel-agent/templates/NOTES.txt b/supplemental/helm/beszel-agent/templates/NOTES.txt new file mode 100644 index 00000000..a47ef60f --- /dev/null +++ b/supplemental/helm/beszel-agent/templates/NOTES.txt @@ -0,0 +1,21 @@ +1. Get Beszel Agent Status + kubectl get daemonset -n {{ .Release.Namespace }} {{ include "beszel-agent.fullname" . }} + kubectl get pods -n {{ .Release.Namespace }} -l app.kubernetes.io/name={{ include "beszel-agent.name" . }} +2. View Agent Logs + kubectl logs -n {{ .Release.Namespace }} -l app.kubernetes.io/name={{ include "beszel-agent.name" . }} -f +3. Verify SSH Key Configuration + kubectl get secret -n {{ .Release.Namespace }} {{ include "beszel-agent.fullname" . }} -o jsonpath='{.data.ssh-key}' | base64 -d +4. Agent Configuration + - Port: {{ .Values.env.PORT }} + - Image: {{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }} + {{- if .Values.hostNetwork }} + - Host Network: Enabled + {{- end }} + {{- if .Values.gpuRuntime }} + - GPU Runtime: {{ .Values.gpuRuntime }} + {{- end }} +5. Next Steps + - Ensure the Beszel Hub is accessible from the cluster + - Check that the SSH key is registered with the Hub + - Verify agent connectivity: kubectl logs -n {{ .Release.Namespace }} -l app.kubernetes.io/name={{ include "beszel-agent.name" . }} +For more information, visit: https://www.beszel.dev/ diff --git a/supplemental/helm/beszel-agent/templates/_helpers.tpl b/supplemental/helm/beszel-agent/templates/_helpers.tpl new file mode 100644 index 00000000..1b73b115 --- /dev/null +++ b/supplemental/helm/beszel-agent/templates/_helpers.tpl @@ -0,0 +1,73 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "beszel-agent.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "beszel-agent.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "beszel-agent.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "beszel-agent.labels" -}} +helm.sh/chart: {{ include "beszel-agent.chart" . }} +{{ include "beszel-agent.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "beszel-agent.selectorLabels" -}} +app.kubernetes.io/name: {{ include "beszel-agent.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "beszel-agent.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "beszel-agent.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Create the name of the secret to use +*/}} +{{- define "beszel-agent.secretName" -}} +{{- if .Values.secret.existingSecret }} +{{- .Values.secret.existingSecret }} +{{- else }} +{{- include "beszel-agent.fullname" . }} +{{- end }} +{{- end }} diff --git a/supplemental/helm/beszel-agent/templates/daemonset.yaml b/supplemental/helm/beszel-agent/templates/daemonset.yaml new file mode 100644 index 00000000..69f157e2 --- /dev/null +++ b/supplemental/helm/beszel-agent/templates/daemonset.yaml @@ -0,0 +1,109 @@ +{{- if .Values.daemonset.enabled }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ include "beszel-agent.fullname" . }} + labels: + {{- include "beszel-agent.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "beszel-agent.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "beszel-agent.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "beszel-agent.serviceAccountName" . }} + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.hostNetwork }} + hostNetwork: {{ .Values.hostNetwork }} + {{- end }} + {{- if .Values.gpuRuntime }} + runtimeClassName: {{ .Values.gpuRuntime }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: agent + containerPort: {{ .Values.service.port }} + protocol: TCP + {{- if .Values.service.hostPort }} + hostPort: {{ .Values.service.hostPort }} + {{- end }} + env: + - name: SYSTEM_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: KEY + valueFrom: + secretKeyRef: + name: {{ include "beszel-agent.secretName" . }} + key: {{ .Values.secret.sshKey }} + {{- if or .Values.env.TOKEN .Values.secret.existingSecret }} + - name: TOKEN + valueFrom: + secretKeyRef: + name: {{ include "beszel-agent.secretName" . }} + key: {{ .Values.secret.tokenKey }} + {{- end }} + {{- range $key, $value := .Values.env }} + {{- if and (ne $key "KEY") (ne $key "TOKEN") (ne $key "SYSTEM_NAME") (ne $value "") }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- with .Values.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/supplemental/helm/beszel-agent/templates/deployment.yaml b/supplemental/helm/beszel-agent/templates/deployment.yaml new file mode 100644 index 00000000..1570f928 --- /dev/null +++ b/supplemental/helm/beszel-agent/templates/deployment.yaml @@ -0,0 +1,112 @@ +{{- if not .Values.daemonset.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "beszel-agent.fullname" . }} + labels: + {{- include "beszel-agent.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "beszel-agent.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "beszel-agent.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "beszel-agent.serviceAccountName" . }} + {{- with .Values.podSecurityContext }} + securityContext: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if .Values.hostNetwork }} + hostNetwork: {{ .Values.hostNetwork }} + {{- end }} + {{- if .Values.gpuRuntime }} + runtimeClassName: {{ .Values.gpuRuntime }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + {{- with .Values.securityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: agent + containerPort: {{ .Values.service.port }} + protocol: TCP + {{- if .Values.service.hostPort }} + hostPort: {{ .Values.service.hostPort }} + {{- end }} + env: + - name: SYSTEM_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: KEY + valueFrom: + secretKeyRef: + name: {{ include "beszel-agent.secretName" . }} + key: {{ .Values.secret.sshKey }} + {{- if or .Values.env.TOKEN .Values.secret.existingSecret }} + - name: TOKEN + valueFrom: + secretKeyRef: + name: {{ include "beszel-agent.secretName" . }} + key: {{ .Values.secret.tokenKey }} + {{- end }} + {{- range $key, $value := .Values.env }} + {{- if and (ne $key "KEY") (ne $key "TOKEN") (ne $key "SYSTEM_NAME") (ne $value "") }} + - name: {{ $key }} + value: {{ $value | quote }} + {{- end }} + {{- end }} + {{- with .Values.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/supplemental/helm/beszel-agent/templates/hpa.yaml b/supplemental/helm/beszel-agent/templates/hpa.yaml new file mode 100644 index 00000000..0bb0a1b7 --- /dev/null +++ b/supplemental/helm/beszel-agent/templates/hpa.yaml @@ -0,0 +1,32 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "beszel-agent.fullname" . }} + labels: + {{- include "beszel-agent.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "beszel-agent.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/supplemental/helm/beszel-agent/templates/httproute.yaml b/supplemental/helm/beszel-agent/templates/httproute.yaml new file mode 100644 index 00000000..e3eff35f --- /dev/null +++ b/supplemental/helm/beszel-agent/templates/httproute.yaml @@ -0,0 +1,38 @@ +{{- if .Values.httpRoute.enabled -}} +{{- $fullName := include "beszel-agent.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ $fullName }} + labels: + {{- include "beszel-agent.labels" . | nindent 4 }} + {{- with .Values.httpRoute.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + parentRefs: + {{- with .Values.httpRoute.parentRefs }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.httpRoute.hostnames }} + hostnames: + {{- toYaml . | nindent 4 }} + {{- end }} + rules: + {{- range .Values.httpRoute.rules }} + {{- with .matches }} + - matches: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .filters }} + filters: + {{- toYaml . | nindent 8 }} + {{- end }} + backendRefs: + - name: {{ $fullName }} + port: {{ $svcPort }} + weight: 1 + {{- end }} +{{- end }} diff --git a/supplemental/helm/beszel-agent/templates/ingress.yaml b/supplemental/helm/beszel-agent/templates/ingress.yaml new file mode 100644 index 00000000..bd049a15 --- /dev/null +++ b/supplemental/helm/beszel-agent/templates/ingress.yaml @@ -0,0 +1,43 @@ +{{- if .Values.ingress.enabled -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "beszel-agent.fullname" . }} + labels: + {{- include "beszel-agent.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- with .Values.ingress.className }} + ingressClassName: {{ . }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- with .pathType }} + pathType: {{ . }} + {{- end }} + backend: + service: + name: {{ include "beszel-agent.fullname" $ }} + port: + number: {{ $.Values.service.port }} + {{- end }} + {{- end }} +{{- end }} diff --git a/supplemental/helm/beszel-agent/templates/secret.yaml b/supplemental/helm/beszel-agent/templates/secret.yaml new file mode 100644 index 00000000..27b9e025 --- /dev/null +++ b/supplemental/helm/beszel-agent/templates/secret.yaml @@ -0,0 +1,20 @@ +{{- if and (not .Values.secret.existingSecret) (not .Values.env.KEY) }} +{{- fail "env.KEY is required when not using an existingSecret. Please provide an SSH public key for agent authentication." }} +{{- end }} +{{- if and .Values.secret.existingSecret .Values.env.KEY }} +{{- fail "Cannot use both existingSecret and env.KEY. Please choose one method for providing authentication credentials." }} +{{- end }} +{{- if not .Values.secret.existingSecret }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "beszel-agent.fullname" . }} + labels: + {{- include "beszel-agent.labels" . | nindent 4 }} +type: Opaque +data: + {{ .Values.secret.sshKey }}: {{ .Values.env.KEY | b64enc | quote }} + {{- if .Values.env.TOKEN }} + {{ .Values.secret.tokenKey }}: {{ .Values.env.TOKEN | b64enc | quote }} + {{- end }} +{{- end }} diff --git a/supplemental/helm/beszel-agent/templates/service.yaml b/supplemental/helm/beszel-agent/templates/service.yaml new file mode 100644 index 00000000..516a618e --- /dev/null +++ b/supplemental/helm/beszel-agent/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "beszel-agent.fullname" . }} + labels: + {{- include "beszel-agent.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: agent + protocol: TCP + name: agent + selector: + {{- include "beszel-agent.selectorLabels" . | nindent 4 }} diff --git a/supplemental/helm/beszel-agent/templates/serviceaccount.yaml b/supplemental/helm/beszel-agent/templates/serviceaccount.yaml new file mode 100644 index 00000000..f42ffcf3 --- /dev/null +++ b/supplemental/helm/beszel-agent/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "beszel-agent.serviceAccountName" . }} + labels: + {{- include "beszel-agent.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +{{- end }} diff --git a/supplemental/helm/beszel-agent/templates/tests/test-connection.yaml b/supplemental/helm/beszel-agent/templates/tests/test-connection.yaml new file mode 100644 index 00000000..d88596fd --- /dev/null +++ b/supplemental/helm/beszel-agent/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "beszel-agent.fullname" . }}-test-connection" + labels: + {{- include "beszel-agent.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "beszel-agent.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/supplemental/helm/beszel-agent/values.yaml b/supplemental/helm/beszel-agent/values.yaml new file mode 100644 index 00000000..a1d040ac --- /dev/null +++ b/supplemental/helm/beszel-agent/values.yaml @@ -0,0 +1,205 @@ +# Default values for beszel-agent. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# To add the Helm repository: +# helm repo add beszel https://henrygd.github.io/beszel +# helm repo update + +# This will set the replicaset count more information can be found here: https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/ +replicaCount: 1 + +# This sets the container image more information can be found here: https://kubernetes.io/docs/concepts/containers/images/ +image: + # Use 'henrygd/beszel-agent' for standard, 'henrygd/beszel-agent-nvidia' for GPU support + repository: henrygd/beszel-agent + # This sets the pull policy for images. + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +# This is for the secrets for pulling an image from a private repository more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ +imagePullSecrets: [] +# This is to override the chart name. +nameOverride: "" +fullnameOverride: "" + +# This section builds out the service account more information can be found here: https://kubernetes.io/docs/concepts/security/service-accounts/ +serviceAccount: + # Specifies whether a service account should be created + create: true + # Automatically mount a ServiceAccount's API credentials? + automount: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +# This is for setting Kubernetes Annotations to a Pod. +# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ +podAnnotations: {} +# This is for setting Kubernetes Labels to a Pod. +# For more information checkout: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/ +podLabels: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +# This is for setting up a service more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/ +service: + # This sets the service type more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types + type: ClusterIP + # This sets the ports more information can be found here: https://kubernetes.io/docs/concepts/services-networking/service/#field-spec-ports + port: 45876 + # -- Expose agent port to host network + hostPort: null + +# This block is for setting up the ingress for more information can be found here: https://kubernetes.io/docs/concepts/services-networking/ingress/ +ingress: + enabled: false + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: + - path: / + pathType: ImplementationSpecific + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +# -- Expose the service via gateway-api HTTPRoute +# Requires Gateway API resources and suitable controller installed within the cluster +# (see: https://gateway-api.sigs.k8s.io/guides/) +httpRoute: + # HTTPRoute enabled. + enabled: false + # HTTPRoute annotations. + annotations: {} + # Which Gateways this Route is attached to. + parentRefs: + - name: gateway + sectionName: http + # namespace: default + # Hostnames matching HTTP header. + hostnames: + - chart-example.local + # List of rules and filters applied. + rules: + - matches: + - path: + type: PathPrefix + value: /headers + # filters: + # - type: RequestHeaderModifier + # requestHeaderModifier: + # set: + # - name: My-Overwrite-Header + # value: this-is-the-only-value + # remove: + # - User-Agent + # - matches: + # - path: + # type: PathPrefix + # value: /echo + # headers: + # - name: version + # value: v2 + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +# This is to setup the liveness and readiness probes more information can be found here: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ +livenessProbe: {} +readinessProbe: {} + +# This section is for setting up autoscaling more information can be found here: https://kubernetes.io/docs/concepts/workloads/autoscaling/ +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +# Additional volumes on the output Deployment definition. +volumes: [] + # Uncomment to monitor additional filesystems + # - name: extra-filesystems + # hostPath: + # path: /mnt/disk/.beszel + # type: DirectoryOrCreate + +# Additional volumeMounts on the output Deployment definition. +volumeMounts: [] + # Uncomment to monitor additional filesystems + # - name: extra-filesystems + # mountPath: /extra-filesystems + # readOnly: true + +# -- Environment variables for the agent +env: + PORT: "45876" + # Hub URL - OPTIONAL (e.g., http://beszel-hub:8090) + HUB_URL: "" + # SSH public key for agent authentication - REQUIRED (unless using existingSecret) + KEY: "" + # Authentication token - OPTIONAL (unless using existingSecret) + TOKEN: "" + # Agent name in the Hub - OPTIONAL (defaults to node name) + SYSTEM_NAME: "" + # For GPU support (henrygd/beszel-agent-nvidia only) + # NVIDIA_VISIBLE_DEVICES: "all" + # NVIDIA_DRIVER_CAPABILITIES: "compute,video,utility" + +# -- Secret configuration for sensitive data +secret: + # Name of an existing Kubernetes Secret to use + # When set, the chart will not create a Secret and will use this existing one instead + # The secret should contain keys specified by sshKey and tokenKey below + existingSecret: "" + # Key name in the secret for the SSH public key + sshKey: "ssh-key" + # Key name in the secret for the authentication token + tokenKey: "token" + +# -- Use host network to allow network monitoring +hostNetwork: false + +# -- GPU runtime configuration (for NVIDIA GPU support) +# Set to 'nvidia' when using henrygd/beszel-agent-nvidia +gpuRuntime: null + +nodeSelector: {} + +tolerations: + - operator: Exists + effect: NoSchedule + - operator: Exists + effect: NoExecute + +affinity: {} + +# -- DaemonSet mode - deploy one agent per node +daemonset: + enabled: true diff --git a/supplemental/helm/beszel-hub/.helmignore b/supplemental/helm/beszel-hub/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/supplemental/helm/beszel-hub/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/supplemental/kubernetes/beszel-hub/charts/Chart.yaml b/supplemental/helm/beszel-hub/Chart.yaml similarity index 63% rename from supplemental/kubernetes/beszel-hub/charts/Chart.yaml rename to supplemental/helm/beszel-hub/Chart.yaml index 2295b48a..3ba0fe8c 100644 --- a/supplemental/kubernetes/beszel-hub/charts/Chart.yaml +++ b/supplemental/helm/beszel-hub/Chart.yaml @@ -1,15 +1,15 @@ apiVersion: v1 description: Installs beszel-hub in kubernetes -home: https://github.com/dnikoloski/beszel-kubernetes/tree/main/charts/beszel-hub +home: https://github.com/henrygd/beszel/tree/main/supplemental/helm/beszel-hub name: beszel-hub -appVersion: "0.9" +appVersion: "0.17.0" # Do not touch will be updated during release version: 0.1.0 sources: - - https://github.com/dnikoloski/beszel-kubernetes/tree/main/charts/beszel-hub + - https://github.com/henrygd/beszel/tree/main/supplemental/helm/beszel-hub - https://www.beszel.dev/ - https://github.com/henrygd/beszel icon: https://repository-images.githubusercontent.com/825470378/2710c6db-f934-4a8b-a2c4-7a0abbcd2ad6 maintainers: - - name: dnikoloski + - name: cloudwithdan email: nikoloskid@pm.me diff --git a/supplemental/helm/beszel-hub/README.md b/supplemental/helm/beszel-hub/README.md new file mode 100644 index 00000000..97ae7ea7 --- /dev/null +++ b/supplemental/helm/beszel-hub/README.md @@ -0,0 +1,346 @@ +# Beszel Hub Helm Chart + +A Kubernetes Helm chart for deploying [Beszel Hub](https://www.beszel.dev/) - a monitoring and alerting solution for systems, containers, and services. + +## Overview + +This Helm chart simplifies the deployment of Beszel Hub in Kubernetes environments. Beszel Hub is a centralized monitoring hub that collects and aggregates system metrics from multiple agents deployed across your infrastructure. + +## Prerequisites + +- Kubernetes 1.19+ +- Helm 3.0+ +- At least 500Mi of persistent storage (configurable) + +## Quick Start + +### 1. Add the Repository + +```bash +helm repo add beszel https://henrygd.github.io/beszel +helm repo update +``` + +### 2. Install the Chart + +```bash +helm install beszel-hub ./beszel-hub +``` + +Or with a custom values file: + +```bash +helm install beszel-hub ./beszel-hub -f custom-values.yaml +``` + +### 3. Access Beszel Hub + +By default, Beszel Hub is accessible at `http://beszel-hub:8090` within the cluster. + +```bash +# Port forward to access locally +kubectl port-forward svc/beszel-hub 8090:8090 +``` + +Then visit: `http://localhost:8090` + +## Configuration + +### Basic Configuration + +Key configuration options in `values.yaml`: + +| Parameter | Default | Description | +|-----------|---------|-------------| +| `replicaCount` | `1` | Number of Beszel Hub replicas | +| `image.repository` | `henrygd/beszel` | Container image repository | +| `image.tag` | Chart AppVersion (0.17.0) | Container image tag | +| `image.pullPolicy` | `IfNotPresent` | Image pull policy | +| `service.port` | `8090` | Service port | +| `persistentVolumeClaim.enabled` | `true` | Enable persistent volume | +| `persistentVolumeClaim.size` | `500Mi` | PVC size | + +### Installation with Custom Values + +```bash +helm install beszel-hub ./beszel-hub \ + --set replicaCount=2 \ + --set persistentVolumeClaim.size=1Gi \ + --set service.type=LoadBalancer +``` + +Or create a custom values file: + +```yaml +# custom-values.yaml +replicaCount: 2 +service: + type: LoadBalancer +persistentVolumeClaim: + size: 1Gi +``` + +Then install: + +```bash +helm install beszel-hub ./beszel-hub -f custom-values.yaml +``` + +## Advanced Configuration + +### Ingress Configuration + +Enable and configure Ingress for external access: + +```yaml +ingress: + enabled: true + className: nginx # or your ingress class + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + hosts: + - host: beszel.example.com + paths: + - path: / + pathType: Prefix + tls: + - secretName: beszel-tls + hosts: + - beszel.example.com +``` + +### Persistent Volume Configuration + +To use an existing PersistentVolumeClaim: + +```yaml +persistentVolumeClaim: + enabled: true + existingClaim: "my-existing-pvc" +``` + +Or to use a specific storage class: + +```yaml +persistentVolumeClaim: + enabled: true + storageClass: "fast-ssd" + size: 1Gi +``` + +### Resource Limits + +Set CPU and memory limits: + +```yaml +resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 250m + memory: 256Mi +``` + +### Autoscaling + +Enable Horizontal Pod Autoscaler: + +```yaml +autoscaling: + enabled: true + minReplicas: 2 + maxReplicas: 10 + targetCPUUtilizationPercentage: 80 +``` + +### Node Selection + +Schedule pods on specific nodes: + +```yaml +nodeSelector: + node-type: monitoring + +tolerations: + - key: "monitoring" + operator: "Equal" + value: "true" + effect: "NoSchedule" +``` + +## Deployment Examples + +### Production Setup + +```yaml +replicaCount: 3 +image: + tag: "0.17.0" +service: + type: LoadBalancer +ingress: + enabled: true + className: nginx + hosts: + - host: beszel.example.com + paths: + - path: / + pathType: Prefix + tls: + - secretName: beszel-tls + hosts: + - beszel.example.com +persistentVolumeClaim: + enabled: true + storageClass: "fast-ssd" + size: 2Gi +resources: + limits: + cpu: 1000m + memory: 1Gi + requests: + cpu: 500m + memory: 512Mi +autoscaling: + enabled: true + minReplicas: 3 + maxReplicas: 10 + targetCPUUtilizationPercentage: 75 +``` + +### Development/Test Setup + +```yaml +replicaCount: 1 +service: + type: ClusterIP +persistentVolumeClaim: + enabled: true + size: 500Mi +resources: + limits: + cpu: 200m + memory: 256Mi + requests: + cpu: 100m + memory: 128Mi +``` + +## Managing Beszel Hub + +### Upgrade + +```bash +helm upgrade beszel-hub ./beszel-hub +``` + +### Check Status + +```bash +# Get deployment status +kubectl get deployment beszel-hub +kubectl get pods -l app.kubernetes.io/name=beszel + +# Get service info +kubectl get svc beszel-hub +``` + +### View Logs + +```bash +kubectl logs -l app.kubernetes.io/name=beszel -f +``` + +### Access Pod Shell + +```bash +kubectl exec -it -- sh +``` + +### Uninstall + +```bash +helm uninstall beszel-hub +``` + +## Connecting Beszel Agents + +After deploying Beszel Hub, you can connect Beszel agents running on: +- Kubernetes nodes +- VM instances +- Bare metal servers +- Docker containers + +Agents communicate with the Hub on port `8090`. Configure the agent with the Hub's address: + +``` +HUB_URL=http://beszel-hub.default.svc.cluster.local:8090 +``` + +Or for external access, use the LoadBalancer IP/DNS or Ingress hostname. + +## Troubleshooting + +### Pod won't start + +```bash +# Check pod status and events +kubectl describe pod +kubectl logs +``` + +### Persistent volume issues + +```bash +# Check PVC status +kubectl get pvc +kubectl describe pvc beszel-hub +``` + +### Connection issues with agents + +- Verify the service is accessible: `kubectl get svc beszel-hub` +- Check network policies aren't blocking traffic +- Ensure agents can resolve the Hub's DNS name +- Verify port `8090` is open on the service + +### Storage full + +Increase PVC size: + +```bash +# Update the PVC size in values +helm upgrade beszel-hub ./charts/beszel-hub \ + --set persistentVolumeClaim.size=2Gi +``` + +## Security Considerations + +- Use network policies to restrict traffic to Beszel Hub +- Enable RBAC and pod security policies +- Use TLS/HTTPS via Ingress with cert-manager +- Regularly update the image to the latest version +- Consider running with read-only filesystem +- Use private container registries if applicable + +## Persistence + +By default, Beszel Hub uses a PersistentVolumeClaim for data storage. Ensure your Kubernetes cluster has enough storage capacity and a default storage class configured. + +## Support and Documentation + +- **Project Homepage**: https://www.beszel.dev/ +- **GitHub Repository**: https://github.com/henrygd/beszel +- **Chart Repository**: https://github.com/henrygd/beszel-kubernetes + +## Chart Information + +- **Chart Version**: 0.1.0 +- **App Version**: 0.17.0 +- **Kubernetes Version**: 1.19+ +- **Maintainer**: cloudwithdan (nikoloskid@pm.me) + +## License + +Please refer to the main Beszel project repository for license information. diff --git a/supplemental/kubernetes/beszel-hub/charts/templates/NOTES.txt b/supplemental/helm/beszel-hub/templates/NOTES.txt similarity index 100% rename from supplemental/kubernetes/beszel-hub/charts/templates/NOTES.txt rename to supplemental/helm/beszel-hub/templates/NOTES.txt diff --git a/supplemental/kubernetes/beszel-hub/charts/templates/_helpers.tpl b/supplemental/helm/beszel-hub/templates/_helpers.tpl similarity index 100% rename from supplemental/kubernetes/beszel-hub/charts/templates/_helpers.tpl rename to supplemental/helm/beszel-hub/templates/_helpers.tpl diff --git a/supplemental/kubernetes/beszel-hub/charts/templates/deployment.yaml b/supplemental/helm/beszel-hub/templates/deployment.yaml similarity index 100% rename from supplemental/kubernetes/beszel-hub/charts/templates/deployment.yaml rename to supplemental/helm/beszel-hub/templates/deployment.yaml diff --git a/supplemental/helm/beszel-hub/templates/httproute.yaml b/supplemental/helm/beszel-hub/templates/httproute.yaml new file mode 100644 index 00000000..4f4c14f3 --- /dev/null +++ b/supplemental/helm/beszel-hub/templates/httproute.yaml @@ -0,0 +1,38 @@ +{{- if .Values.httpRoute.enabled -}} +{{- $fullName := include "beszel.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: {{ $fullName }} + labels: + {{- include "beszel.labels" . | nindent 4 }} + {{- with .Values.httpRoute.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + parentRefs: + {{- with .Values.httpRoute.parentRefs }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.httpRoute.hostnames }} + hostnames: + {{- toYaml . | nindent 4 }} + {{- end }} + rules: + {{- range .Values.httpRoute.rules }} + {{- with .matches }} + - matches: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .filters }} + filters: + {{- toYaml . | nindent 8 }} + {{- end }} + backendRefs: + - name: {{ $fullName }} + port: {{ $svcPort }} + weight: 1 + {{- end }} +{{- end }} diff --git a/supplemental/kubernetes/beszel-hub/charts/templates/ingress.yaml b/supplemental/helm/beszel-hub/templates/ingress.yaml similarity index 100% rename from supplemental/kubernetes/beszel-hub/charts/templates/ingress.yaml rename to supplemental/helm/beszel-hub/templates/ingress.yaml diff --git a/supplemental/kubernetes/beszel-hub/charts/templates/service.yaml b/supplemental/helm/beszel-hub/templates/service.yaml similarity index 100% rename from supplemental/kubernetes/beszel-hub/charts/templates/service.yaml rename to supplemental/helm/beszel-hub/templates/service.yaml diff --git a/supplemental/kubernetes/beszel-hub/charts/templates/tests/test-beszel-hub-endpoint.yaml b/supplemental/helm/beszel-hub/templates/tests/test-beszel-hub-endpoint.yaml similarity index 100% rename from supplemental/kubernetes/beszel-hub/charts/templates/tests/test-beszel-hub-endpoint.yaml rename to supplemental/helm/beszel-hub/templates/tests/test-beszel-hub-endpoint.yaml diff --git a/supplemental/kubernetes/beszel-hub/charts/templates/volume-claim.yaml b/supplemental/helm/beszel-hub/templates/volume-claim.yaml similarity index 100% rename from supplemental/kubernetes/beszel-hub/charts/templates/volume-claim.yaml rename to supplemental/helm/beszel-hub/templates/volume-claim.yaml diff --git a/supplemental/kubernetes/beszel-hub/charts/values.yaml b/supplemental/helm/beszel-hub/values.yaml similarity index 62% rename from supplemental/kubernetes/beszel-hub/charts/values.yaml rename to supplemental/helm/beszel-hub/values.yaml index dabae712..ceff6c35 100644 --- a/supplemental/kubernetes/beszel-hub/charts/values.yaml +++ b/supplemental/helm/beszel-hub/values.yaml @@ -2,6 +2,10 @@ # This is a YAML-formatted file. # Declare variables to be passed into your templates. +# To add the Helm repository: +# helm repo add beszel https://henrygd.github.io/beszel +# helm repo update + # -- The number of replicas replicaCount: 1 @@ -51,6 +55,44 @@ ingress: # hosts: # - chart-example.local +# -- Expose the service via gateway-api HTTPRoute +# Requires Gateway API resources and suitable controller installed within the cluster +# (see: https://gateway-api.sigs.k8s.io/guides/) +httpRoute: + # HTTPRoute enabled. + enabled: false + # HTTPRoute annotations. + annotations: {} + # Which Gateways this Route is attached to. + parentRefs: + - name: gateway + sectionName: http + # namespace: default + # Hostnames matching HTTP header. + hostnames: + - chart-example.local + # List of rules and filters applied. + rules: + - matches: + - path: + type: PathPrefix + value: /headers + # filters: + # - type: RequestHeaderModifier + # requestHeaderModifier: + # set: + # - name: My-Overwrite-Header + # value: this-is-the-only-value + # remove: + # - User-Agent + # - matches: + # - path: + # type: PathPrefix + # value: /echo + # headers: + # - name: version + # value: v2 + resources: {} # limits: # cpu: 100m