Add Helm chart tooling, CI, and release packaging
This commit is contained in:
parent
d79b8e8883
commit
d15ad1d0b4
25 changed files with 1299 additions and 5 deletions
31
.github/workflows/README.md
vendored
31
.github/workflows/README.md
vendored
|
|
@ -49,3 +49,34 @@ ssh pulse-relay "curl -fsSL https://raw.githubusercontent.com/rcourtman/Pulse/ma
|
||||||
- ✅ Validates install script works on real server
|
- ✅ Validates install script works on real server
|
||||||
- ✅ Removes manual step from release process
|
- ✅ Removes manual step from release process
|
||||||
- ✅ Free to run (public repos get unlimited GitHub Actions minutes)
|
- ✅ Free to run (public repos get unlimited GitHub Actions minutes)
|
||||||
|
|
||||||
|
## Helm CI
|
||||||
|
|
||||||
|
**File**: `helm-ci.yml`
|
||||||
|
|
||||||
|
Runs `helm lint --strict` and renders the chart with common configuration combinations on every pull request that touches Helm content (and on pushes to `main`). This prevents regressions before they land.
|
||||||
|
|
||||||
|
- Triggered by PRs/pushes touching `deploy/helm/**`, docs, or the workflow itself
|
||||||
|
- Uses Helm v3.15.2
|
||||||
|
- Renders both the default deployment and an agent-enabled configuration to catch template issues
|
||||||
|
|
||||||
|
## Publish Helm Chart
|
||||||
|
|
||||||
|
**File**: `publish-helm-chart.yml`
|
||||||
|
|
||||||
|
Packages the Helm chart and pushes it to the GitHub Container Registry (OCI) whenever a GitHub Release is published. Also makes the packaged `.tgz` available as both an Actions artifact and a release asset. The same behaviour can be triggered locally via `./scripts/package-helm-chart.sh <version> [--push]`.
|
||||||
|
|
||||||
|
- Triggered automatically on `release: published`, or manually via workflow dispatch (requires `chart_version` input)
|
||||||
|
- Chart and app versions mirror the Pulse release tag (e.g., `v4.24.0` → `4.24.0`)
|
||||||
|
- Publishes to `oci://ghcr.io/<owner>/pulse-chart`
|
||||||
|
- Requires no additional secrets—uses the built-in `GITHUB_TOKEN` with `packages: write` permission
|
||||||
|
|
||||||
|
## Helm Integration (Kind)
|
||||||
|
|
||||||
|
**File**: `helm-integration.yml`
|
||||||
|
|
||||||
|
Creates a disposable Kind cluster, installs the chart, waits for the hub deployment to report ready, and performs a `/health` smoke check from inside the cluster.
|
||||||
|
|
||||||
|
- Triggered alongside the lint workflow for PRs/pushes touching Helm content
|
||||||
|
- Disables persistence to keep the Kind cluster lightweight
|
||||||
|
- Provides early detection of runtime issues (missing secrets, invalid probes, etc.)
|
||||||
|
|
|
||||||
48
.github/workflows/helm-ci.yml
vendored
Normal file
48
.github/workflows/helm-ci.yml
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
name: Helm CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- "deploy/helm/**"
|
||||||
|
- ".github/workflows/helm-ci.yml"
|
||||||
|
- "docs/KUBERNETES.md"
|
||||||
|
- "README.md"
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "deploy/helm/**"
|
||||||
|
- ".github/workflows/helm-ci.yml"
|
||||||
|
- "docs/KUBERNETES.md"
|
||||||
|
- "README.md"
|
||||||
|
workflow_dispatch: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
name: Lint and Render Chart
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Helm
|
||||||
|
uses: azure/setup-helm@v4
|
||||||
|
with:
|
||||||
|
version: v3.15.2
|
||||||
|
|
||||||
|
- name: Helm lint (strict)
|
||||||
|
run: helm lint deploy/helm/pulse --strict
|
||||||
|
|
||||||
|
- name: Render default manifests
|
||||||
|
run: helm template pulse deploy/helm/pulse > /tmp/pulse-rendered.yaml
|
||||||
|
|
||||||
|
- name: Render agent-enabled manifests
|
||||||
|
run: |
|
||||||
|
helm template pulse deploy/helm/pulse \
|
||||||
|
--set agent.enabled=true \
|
||||||
|
--set agent.kind=Deployment \
|
||||||
|
--set agent.secretEnv.create=true \
|
||||||
|
--set agent.secretEnv.data.PULSE_TOKEN=dummy-token \
|
||||||
|
--set server.secretEnv.create=true \
|
||||||
|
--set server.secretEnv.data.API_TOKENS=dummy-token \
|
||||||
|
--set persistence.enabled=false \
|
||||||
|
> /tmp/pulse-agent-rendered.yaml
|
||||||
58
.github/workflows/helm-integration.yml
vendored
Normal file
58
.github/workflows/helm-integration.yml
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
name: Helm Integration
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- "deploy/helm/**"
|
||||||
|
- ".github/workflows/helm-*.yml"
|
||||||
|
- "docs/KUBERNETES.md"
|
||||||
|
- "README.md"
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "deploy/helm/**"
|
||||||
|
- ".github/workflows/helm-*.yml"
|
||||||
|
- "docs/KUBERNETES.md"
|
||||||
|
- "README.md"
|
||||||
|
workflow_dispatch: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
kind-smoke-test:
|
||||||
|
name: Deploy to Kind and Smoke Test
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 15
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Helm
|
||||||
|
uses: azure/setup-helm@v4
|
||||||
|
with:
|
||||||
|
version: v3.15.2
|
||||||
|
|
||||||
|
- name: Create Kind cluster
|
||||||
|
uses: helm/kind-action@v1.8.0
|
||||||
|
with:
|
||||||
|
wait: 120s
|
||||||
|
|
||||||
|
- name: Install Pulse chart
|
||||||
|
run: |
|
||||||
|
helm upgrade --install pulse ./deploy/helm/pulse \
|
||||||
|
--namespace pulse \
|
||||||
|
--create-namespace \
|
||||||
|
--set persistence.enabled=false \
|
||||||
|
--set server.secretEnv.create=true \
|
||||||
|
--set server.secretEnv.data.API_TOKENS=dummy-token \
|
||||||
|
--wait \
|
||||||
|
--timeout 5m
|
||||||
|
|
||||||
|
- name: Verify deployment is available
|
||||||
|
run: kubectl -n pulse wait --for=condition=available deployment/pulse --timeout=120s
|
||||||
|
|
||||||
|
- name: Hit health endpoint from inside the cluster
|
||||||
|
run: |
|
||||||
|
kubectl -n pulse run smoke-test \
|
||||||
|
--rm \
|
||||||
|
--image=curlimages/curl:8.3.0 \
|
||||||
|
--restart=Never \
|
||||||
|
-- curl -fsS http://pulse:7655/health
|
||||||
92
.github/workflows/publish-helm-chart.yml
vendored
Normal file
92
.github/workflows/publish-helm-chart.yml
vendored
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
name: Publish Helm Chart
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
chart_version:
|
||||||
|
description: "Chart version (required when running manually, use format 4.24.0)"
|
||||||
|
required: true
|
||||||
|
app_version:
|
||||||
|
description: "Application version to embed (defaults to chart version)"
|
||||||
|
required: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
name: Package and Push Helm Chart
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Helm
|
||||||
|
uses: azure/setup-helm@v4
|
||||||
|
with:
|
||||||
|
version: v3.15.2
|
||||||
|
|
||||||
|
- name: Determine chart version
|
||||||
|
id: versions
|
||||||
|
run: |
|
||||||
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||||
|
CHART_VERSION="${{ inputs.chart_version }}"
|
||||||
|
if [ -z "$CHART_VERSION" ]; then
|
||||||
|
echo "::error::chart_version input is required when running manually"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
APP_VERSION="${{ inputs.app_version }}"
|
||||||
|
if [ -z "$APP_VERSION" ]; then
|
||||||
|
APP_VERSION="$CHART_VERSION"
|
||||||
|
fi
|
||||||
|
RELEASE_TAG="$CHART_VERSION"
|
||||||
|
else
|
||||||
|
RELEASE_TAG="${{ github.event.release.tag_name }}"
|
||||||
|
if [ -z "$RELEASE_TAG" ]; then
|
||||||
|
echo "::error::Release tag is empty"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
CHART_VERSION="${RELEASE_TAG#v}"
|
||||||
|
APP_VERSION="$CHART_VERSION"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "chart_version=$CHART_VERSION" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "app_version=$APP_VERSION" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "release_tag=$RELEASE_TAG" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Helm lint (strict)
|
||||||
|
run: helm lint deploy/helm/pulse --strict
|
||||||
|
|
||||||
|
- name: Package chart
|
||||||
|
run: |
|
||||||
|
mkdir -p dist
|
||||||
|
helm package deploy/helm/pulse \
|
||||||
|
--version "${{ steps.versions.outputs.chart_version }}" \
|
||||||
|
--app-version "${{ steps.versions.outputs.app_version }}" \
|
||||||
|
--destination dist
|
||||||
|
|
||||||
|
- name: Upload packaged chart artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: pulse-chart-${{ steps.versions.outputs.chart_version }}
|
||||||
|
path: dist/pulse-${{ steps.versions.outputs.chart_version }}.tgz
|
||||||
|
|
||||||
|
- name: Authenticate with GHCR
|
||||||
|
run: |
|
||||||
|
echo "${{ github.token }}" | helm registry login ghcr.io --username "${{ github.actor }}" --password-stdin
|
||||||
|
|
||||||
|
- name: Push chart to GHCR
|
||||||
|
run: |
|
||||||
|
helm push dist/pulse-${{ steps.versions.outputs.chart_version }}.tgz \
|
||||||
|
oci://ghcr.io/${{ github.repository_owner }}/pulse-chart
|
||||||
|
|
||||||
|
- name: Attach chart to release
|
||||||
|
if: github.event_name == 'release'
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
run: |
|
||||||
|
gh release upload "${{ steps.versions.outputs.release_tag }}" \
|
||||||
|
dist/pulse-${{ steps.versions.outputs.chart_version }}.tgz \
|
||||||
|
--clobber
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,6 +1,6 @@
|
||||||
# Binaries
|
# Binaries
|
||||||
/bin/
|
/bin/
|
||||||
pulse
|
/pulse
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
*.log
|
*.log
|
||||||
|
|
|
||||||
|
|
@ -84,6 +84,14 @@ docker run -d -p 7655:7655 -v pulse_data:/data rcourtman/pulse:latest
|
||||||
|
|
||||||
# Testing: Install from main branch source (for testing latest fixes)
|
# Testing: Install from main branch source (for testing latest fixes)
|
||||||
curl -fsSL https://raw.githubusercontent.com/rcourtman/Pulse/main/install.sh | bash -s -- --main
|
curl -fsSL https://raw.githubusercontent.com/rcourtman/Pulse/main/install.sh | bash -s -- --main
|
||||||
|
|
||||||
|
# Alternative: Kubernetes (Helm)
|
||||||
|
helm registry login ghcr.io
|
||||||
|
helm install pulse oci://ghcr.io/rcourtman/pulse-chart \
|
||||||
|
--version $(curl -fsSL https://raw.githubusercontent.com/rcourtman/Pulse/main/VERSION) \
|
||||||
|
--namespace pulse \
|
||||||
|
--create-namespace
|
||||||
|
# Replace the VERSION lookup with a specific release if you need to pin. For local development, see docs/KUBERNETES.md.
|
||||||
```
|
```
|
||||||
|
|
||||||
**Proxmox users**: The installer detects PVE hosts and automatically creates an optimized LXC container. Choose Quick mode for one-minute setup.
|
**Proxmox users**: The installer detects PVE hosts and automatically creates an optimized LXC container. Choose Quick mode for one-minute setup.
|
||||||
|
|
|
||||||
17
deploy/helm/pulse/Chart.yaml
Normal file
17
deploy/helm/pulse/Chart.yaml
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
apiVersion: v2
|
||||||
|
name: pulse
|
||||||
|
description: Helm chart for deploying the Pulse hub and optional Docker monitoring agent.
|
||||||
|
type: application
|
||||||
|
version: 0.1.0
|
||||||
|
appVersion: "4.24.0"
|
||||||
|
icon: https://raw.githubusercontent.com/rcourtman/Pulse/main/docs/images/pulse-logo.svg
|
||||||
|
keywords:
|
||||||
|
- monitoring
|
||||||
|
- proxmox
|
||||||
|
- observability
|
||||||
|
home: https://github.com/rcourtman/Pulse
|
||||||
|
sources:
|
||||||
|
- https://github.com/rcourtman/Pulse
|
||||||
|
maintainers:
|
||||||
|
- name: Pulse Maintainers
|
||||||
|
email: pulse@rcourtman.dev
|
||||||
41
deploy/helm/pulse/README.md
Normal file
41
deploy/helm/pulse/README.md
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Pulse Helm Chart
|
||||||
|
|
||||||
|
This chart deploys the Pulse hub (web UI + API) and, optionally, the Docker monitoring agent.
|
||||||
|
|
||||||
|
## Installing from GHCR
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm registry login ghcr.io
|
||||||
|
helm install pulse oci://ghcr.io/rcourtman/pulse-chart \
|
||||||
|
--version $(curl -fsSL https://raw.githubusercontent.com/rcourtman/Pulse/main/VERSION) \
|
||||||
|
--namespace pulse \
|
||||||
|
--create-namespace
|
||||||
|
```
|
||||||
|
|
||||||
|
Replace the inline `curl` command if you need to pin to a specific release. The chart version tracks the Pulse release version (e.g., Pulse `v4.24.0` → chart `4.24.0`).
|
||||||
|
|
||||||
|
## Common Values
|
||||||
|
|
||||||
|
| Key | Description | Default |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `persistence.enabled` | Persist /data using a PVC. Disable for ephemeral testing. | `true` |
|
||||||
|
| `ingress.enabled` | Create an Ingress resource. Configure hosts/TLS via `ingress.hosts` and `ingress.tls`. | `false` |
|
||||||
|
| `server.secretEnv` | Manage sensitive env vars (API tokens, auth secrets). Enable `create` or point at an existing secret. | `{}` |
|
||||||
|
| `agent.enabled` | Deploy the Docker agent as a DaemonSet or Deployment. Requires access to the Docker socket by default. | `false` |
|
||||||
|
|
||||||
|
See `values.yaml` for the full list of overridable settings.
|
||||||
|
|
||||||
|
## Local Development
|
||||||
|
|
||||||
|
Install from the working copy when testing chart changes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm upgrade --install pulse ./deploy/helm/pulse \
|
||||||
|
--namespace pulse \
|
||||||
|
--create-namespace \
|
||||||
|
--set persistence.enabled=false \
|
||||||
|
--set server.secretEnv.create=true \
|
||||||
|
--set server.secretEnv.data.API_TOKENS=dummy-token
|
||||||
|
```
|
||||||
|
|
||||||
|
For more deployment details (ingress, agent, persistence options), refer to `docs/KUBERNETES.md`.
|
||||||
4
deploy/helm/pulse/templates/NOTES.txt
Normal file
4
deploy/helm/pulse/templates/NOTES.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
1. Pulse hub URL: http://{{ include "pulse.fullname" . }}:{{ .Values.service.port }}
|
||||||
|
(Adjust if using ingress or LoadBalancer.)
|
||||||
|
2. Create an API token from the Pulse UI under Settings → Security for the Docker agent.
|
||||||
|
3. Deploy the optional agent by enabling `agent.enabled` and providing your server URL and token.
|
||||||
97
deploy/helm/pulse/templates/_helpers.tpl
Normal file
97
deploy/helm/pulse/templates/_helpers.tpl
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
{{/*
|
||||||
|
Expand the name of the chart.
|
||||||
|
*/}}
|
||||||
|
{{- define "pulse.name" -}}
|
||||||
|
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create a default fully qualified app name.
|
||||||
|
*/}}
|
||||||
|
{{- define "pulse.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 label.
|
||||||
|
*/}}
|
||||||
|
{{- define "pulse.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Common labels.
|
||||||
|
*/}}
|
||||||
|
{{- define "pulse.labels" -}}
|
||||||
|
helm.sh/chart: {{ include "pulse.chart" . }}
|
||||||
|
{{ include "pulse.selectorLabels" . }}
|
||||||
|
{{- if .Chart.AppVersion }}
|
||||||
|
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||||
|
{{- end }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Selector labels.
|
||||||
|
*/}}
|
||||||
|
{{- define "pulse.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ include "pulse.name" . }}
|
||||||
|
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Return the name of the service account to use.
|
||||||
|
*/}}
|
||||||
|
{{- define "pulse.serviceAccountName" -}}
|
||||||
|
{{- if .Values.serviceAccount.create -}}
|
||||||
|
{{- default (printf "%s-sa" (include "pulse.fullname" .)) .Values.serviceAccount.name -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- default "default" .Values.serviceAccount.name -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Return the server secret name (Pulse hub env vars).
|
||||||
|
*/}}
|
||||||
|
{{- define "pulse.serverSecretName" -}}
|
||||||
|
{{- $secret := .Values.server.secretEnv -}}
|
||||||
|
{{- if $secret.name -}}
|
||||||
|
{{- $secret.name -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- printf "%s-server-env" (include "pulse.fullname" .) -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Return the agent secret name.
|
||||||
|
*/}}
|
||||||
|
{{- define "pulse.agentSecretName" -}}
|
||||||
|
{{- $secret := .Values.agent.secretEnv -}}
|
||||||
|
{{- if $secret.name -}}
|
||||||
|
{{- $secret.name -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- printf "%s-agent-env" (include "pulse.fullname" .) -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Return the agent service account name.
|
||||||
|
*/}}
|
||||||
|
{{- define "pulse.agentServiceAccountName" -}}
|
||||||
|
{{- if .Values.agent.serviceAccount.create -}}
|
||||||
|
{{- default (printf "%s-agent" (include "pulse.fullname" .)) .Values.agent.serviceAccount.name -}}
|
||||||
|
{{- else if .Values.agent.serviceAccount.name -}}
|
||||||
|
{{- .Values.agent.serviceAccount.name -}}
|
||||||
|
{{- else -}}
|
||||||
|
{{- include "pulse.serviceAccountName" . -}}
|
||||||
|
{{- end -}}
|
||||||
|
{{- end -}}
|
||||||
14
deploy/helm/pulse/templates/agent-secret.yaml
Normal file
14
deploy/helm/pulse/templates/agent-secret.yaml
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
{{- $secret := .Values.agent.secretEnv }}
|
||||||
|
{{- if and .Values.agent.enabled $secret.create (gt (len $secret.data) 0) }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pulse.agentSecretName" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "pulse.labels" . | nindent 4 }}
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
{{- range $key, $value := $secret.data }}
|
||||||
|
{{ $key }}: {{ $value | toString | b64enc }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
12
deploy/helm/pulse/templates/agent-serviceaccount.yaml
Normal file
12
deploy/helm/pulse/templates/agent-serviceaccount.yaml
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
{{- if and .Values.agent.enabled .Values.agent.serviceAccount.create }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: {{ default (printf "%s-agent" (include "pulse.fullname" .)) .Values.agent.serviceAccount.name }}
|
||||||
|
labels:
|
||||||
|
{{- include "pulse.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.agent.serviceAccount.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
125
deploy/helm/pulse/templates/agent.yaml
Normal file
125
deploy/helm/pulse/templates/agent.yaml
Normal file
|
|
@ -0,0 +1,125 @@
|
||||||
|
{{- if .Values.agent.enabled }}
|
||||||
|
{{- $kind := default "DaemonSet" .Values.agent.kind | lower }}
|
||||||
|
{{- $isDaemon := eq $kind "daemonset" }}
|
||||||
|
{{- $workloadName := printf "%s-agent" (include "pulse.fullname" .) }}
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: {{ if $isDaemon }}DaemonSet{{ else }}Deployment{{ end }}
|
||||||
|
metadata:
|
||||||
|
name: {{ $workloadName }}
|
||||||
|
labels:
|
||||||
|
{{- include "pulse.labels" . | nindent 4 }}
|
||||||
|
app.kubernetes.io/component: agent
|
||||||
|
spec:
|
||||||
|
{{- if not $isDaemon }}
|
||||||
|
replicas: {{ .Values.agent.replicaCount }}
|
||||||
|
{{- end }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pulse.selectorLabels" . | nindent 6 }}
|
||||||
|
app.kubernetes.io/component: agent
|
||||||
|
{{- if $isDaemon }}
|
||||||
|
updateStrategy:
|
||||||
|
type: RollingUpdate
|
||||||
|
{{- end }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "pulse.selectorLabels" . | nindent 8 }}
|
||||||
|
app.kubernetes.io/component: agent
|
||||||
|
{{- with .Values.agent.podLabels }}
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.agent.podAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml .Values.agent.podAnnotations | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
serviceAccountName: {{ include "pulse.agentServiceAccountName" . }}
|
||||||
|
{{- $podSecurityContext := .Values.agent.podSecurityContext }}
|
||||||
|
{{- if $podSecurityContext }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml $podSecurityContext | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
containers:
|
||||||
|
- name: pulse-docker-agent
|
||||||
|
image: "{{ .Values.agent.image.repository }}:{{ default .Chart.AppVersion .Values.agent.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.agent.image.pullPolicy }}
|
||||||
|
{{- if .Values.agent.args }}
|
||||||
|
args:
|
||||||
|
{{- toYaml .Values.agent.args | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $csec := .Values.agent.securityContext }}
|
||||||
|
{{- if $csec }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml $csec | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $envList := list }}
|
||||||
|
{{- range .Values.agent.env }}
|
||||||
|
{{- $envList = append $envList . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- range .Values.agent.extraEnv }}
|
||||||
|
{{- $envList = append $envList . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $secret := .Values.agent.secretEnv }}
|
||||||
|
{{- $secretKeys := list }}
|
||||||
|
{{- if $secret.keys }}
|
||||||
|
{{- $secretKeys = $secret.keys }}
|
||||||
|
{{- else if $secret.data }}
|
||||||
|
{{- $secretKeys = keys $secret.data }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $root := . }}
|
||||||
|
{{- range $key := $secretKeys }}
|
||||||
|
{{- $envList = append $envList (dict "name" $key "valueFrom" (dict "secretKeyRef" (dict "name" (include "pulse.agentSecretName" $root) "key" $key))) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $envList }}
|
||||||
|
env:
|
||||||
|
{{- toYaml $envList | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $envFrom := concat .Values.agent.envFrom .Values.agent.extraEnvFrom }}
|
||||||
|
{{- if $envFrom }}
|
||||||
|
envFrom:
|
||||||
|
{{- range $envFrom }}
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if or .Values.agent.dockerSocket.enabled .Values.agent.extraVolumeMounts }}
|
||||||
|
volumeMounts:
|
||||||
|
{{- if .Values.agent.dockerSocket.enabled }}
|
||||||
|
- name: docker-socket
|
||||||
|
mountPath: {{ .Values.agent.dockerSocket.path }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.agent.extraVolumeMounts }}
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.agent.resources }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if or .Values.agent.dockerSocket.enabled .Values.agent.extraVolumes }}
|
||||||
|
volumes:
|
||||||
|
{{- if .Values.agent.dockerSocket.enabled }}
|
||||||
|
- name: docker-socket
|
||||||
|
hostPath:
|
||||||
|
path: {{ .Values.agent.dockerSocket.path }}
|
||||||
|
{{- with .Values.agent.dockerSocket.hostPathType }}
|
||||||
|
type: {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.agent.extraVolumes }}
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.agent.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.agent.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.agent.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
135
deploy/helm/pulse/templates/deployment.yaml
Normal file
135
deploy/helm/pulse/templates/deployment.yaml
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pulse.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "pulse.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ .Values.replicaCount }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "pulse.selectorLabels" . | nindent 6 }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "pulse.selectorLabels" . | nindent 8 }}
|
||||||
|
{{- with .Values.server.podLabels }}
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $podAnnotations := merge (dict) .Values.podAnnotations .Values.server.podAnnotations }}
|
||||||
|
{{- if $podAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml $podAnnotations | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
serviceAccountName: {{ include "pulse.serviceAccountName" . }}
|
||||||
|
{{- $podSecurityContext := merge (dict) .Values.podSecurityContext .Values.server.podSecurityContext }}
|
||||||
|
{{- if $podSecurityContext }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml $podSecurityContext | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.imagePullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
containers:
|
||||||
|
- name: pulse
|
||||||
|
image: "{{ .Values.image.repository }}:{{ default .Chart.AppVersion .Values.image.tag }}"
|
||||||
|
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 7655
|
||||||
|
{{- $containerSecurityContext := merge (dict) .Values.securityContext .Values.server.securityContext }}
|
||||||
|
{{- if $containerSecurityContext }}
|
||||||
|
securityContext:
|
||||||
|
{{- toYaml $containerSecurityContext | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $envList := list }}
|
||||||
|
{{- range .Values.server.env }}
|
||||||
|
{{- $envList = append $envList . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- range .Values.server.extraEnv }}
|
||||||
|
{{- $envList = append $envList . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $secret := .Values.server.secretEnv }}
|
||||||
|
{{- $secretKeys := list }}
|
||||||
|
{{- if $secret.keys }}
|
||||||
|
{{- $secretKeys = $secret.keys }}
|
||||||
|
{{- else if $secret.data }}
|
||||||
|
{{- $secretKeys = keys $secret.data }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $root := . }}
|
||||||
|
{{- range $key := $secretKeys }}
|
||||||
|
{{- $envList = append $envList (dict "name" $key "valueFrom" (dict "secretKeyRef" (dict "name" (include "pulse.serverSecretName" $root) "key" $key))) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $envList }}
|
||||||
|
env:
|
||||||
|
{{- toYaml $envList | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $envFrom := concat .Values.server.envFrom .Values.server.extraEnvFrom }}
|
||||||
|
{{- if $envFrom }}
|
||||||
|
envFrom:
|
||||||
|
{{- range $envFrom }}
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
{{- with .Values.server.extraVolumeMounts }}
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.server.livenessProbe }}
|
||||||
|
{{- if .enabled }}
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: {{ .path }}
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: {{ .initialDelaySeconds }}
|
||||||
|
periodSeconds: {{ .periodSeconds }}
|
||||||
|
timeoutSeconds: {{ .timeoutSeconds }}
|
||||||
|
failureThreshold: {{ .failureThreshold }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.server.readinessProbe }}
|
||||||
|
{{- if .enabled }}
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: {{ .path }}
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: {{ .initialDelaySeconds }}
|
||||||
|
periodSeconds: {{ .periodSeconds }}
|
||||||
|
timeoutSeconds: {{ .timeoutSeconds }}
|
||||||
|
failureThreshold: {{ .failureThreshold }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.server.resources }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }}
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: {{ include "pulse.fullname" . }}
|
||||||
|
{{- else if and .Values.persistence.enabled .Values.persistence.existingClaim }}
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: {{ .Values.persistence.existingClaim }}
|
||||||
|
{{- else }}
|
||||||
|
emptyDir: {}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.server.extraVolumes }}
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.server.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.server.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .Values.server.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
35
deploy/helm/pulse/templates/ingress.yaml
Normal file
35
deploy/helm/pulse/templates/ingress.yaml
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
{{- if .Values.ingress.enabled }}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pulse.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "pulse.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.ingress.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- if .Values.ingress.className }}
|
||||||
|
ingressClassName: {{ .Values.ingress.className }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
{{- range .Values.ingress.hosts }}
|
||||||
|
- host: {{ .host }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
{{- range .paths }}
|
||||||
|
- path: {{ .path }}
|
||||||
|
pathType: {{ .pathType }}
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ include "pulse.fullname" $ }}
|
||||||
|
port:
|
||||||
|
number: {{ $.Values.service.port }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .Values.ingress.tls }}
|
||||||
|
tls:
|
||||||
|
{{- toYaml .Values.ingress.tls | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
21
deploy/helm/pulse/templates/pvc.yaml
Normal file
21
deploy/helm/pulse/templates/pvc.yaml
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pulse.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "pulse.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.persistence.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
{{- toYaml .Values.persistence.accessModes | nindent 4 }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ .Values.persistence.size }}
|
||||||
|
{{- with .Values.persistence.storageClass }}
|
||||||
|
storageClassName: {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
14
deploy/helm/pulse/templates/server-secret.yaml
Normal file
14
deploy/helm/pulse/templates/server-secret.yaml
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
{{- $secret := .Values.server.secretEnv }}
|
||||||
|
{{- if and $secret.create (gt (len $secret.data) 0) }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pulse.serverSecretName" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "pulse.labels" . | nindent 4 }}
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
{{- range $key, $value := $secret.data }}
|
||||||
|
{{ $key }}: {{ $value | toString | b64enc }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
30
deploy/helm/pulse/templates/service.yaml
Normal file
30
deploy/helm/pulse/templates/service.yaml
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pulse.fullname" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "pulse.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.service.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
type: {{ .Values.service.type }}
|
||||||
|
{{- if and (eq .Values.service.type "LoadBalancer") .Values.service.loadBalancerIP }}
|
||||||
|
loadBalancerIP: {{ .Values.service.loadBalancerIP }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and (eq .Values.service.type "LoadBalancer") (ne .Values.service.externalTrafficPolicy "") }}
|
||||||
|
externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy }}
|
||||||
|
{{- end }}
|
||||||
|
selector:
|
||||||
|
{{- include "pulse.selectorLabels" . | nindent 4 }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: {{ .Values.service.port }}
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
{{- if eq .Values.service.type "NodePort" }}
|
||||||
|
{{- with .Values.service.nodePort }}
|
||||||
|
nodePort: {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
12
deploy/helm/pulse/templates/serviceaccount.yaml
Normal file
12
deploy/helm/pulse/templates/serviceaccount.yaml
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
{{- if .Values.serviceAccount.create }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ServiceAccount
|
||||||
|
metadata:
|
||||||
|
name: {{ include "pulse.serviceAccountName" . }}
|
||||||
|
labels:
|
||||||
|
{{- include "pulse.labels" . | nindent 4 }}
|
||||||
|
{{- with .Values.serviceAccount.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
137
deploy/helm/pulse/values.yaml
Normal file
137
deploy/helm/pulse/values.yaml
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
# Default values for the Pulse Helm chart.
|
||||||
|
# This file can be used as-is for a minimal installation or as a reference when
|
||||||
|
# overriding values (for example with `-f custom-values.yaml`).
|
||||||
|
|
||||||
|
replicaCount: 1
|
||||||
|
|
||||||
|
image:
|
||||||
|
repository: rcourtman/pulse
|
||||||
|
# Overrides the image tag whose default is the chart appVersion.
|
||||||
|
tag: ""
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
imagePullSecrets: []
|
||||||
|
nameOverride: ""
|
||||||
|
fullnameOverride: ""
|
||||||
|
|
||||||
|
serviceAccount:
|
||||||
|
create: true
|
||||||
|
annotations: {}
|
||||||
|
name: ""
|
||||||
|
|
||||||
|
podAnnotations: {}
|
||||||
|
podLabels: {}
|
||||||
|
|
||||||
|
podSecurityContext: {}
|
||||||
|
|
||||||
|
securityContext:
|
||||||
|
runAsNonRoot: true
|
||||||
|
runAsUser: 1000
|
||||||
|
runAsGroup: 1000
|
||||||
|
fsGroup: 1000
|
||||||
|
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
port: 7655
|
||||||
|
annotations: {}
|
||||||
|
loadBalancerIP: ""
|
||||||
|
externalTrafficPolicy: Cluster
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: false
|
||||||
|
className: ""
|
||||||
|
annotations: {}
|
||||||
|
hosts:
|
||||||
|
- host: pulse.local
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls: []
|
||||||
|
|
||||||
|
persistence:
|
||||||
|
enabled: true
|
||||||
|
existingClaim: ""
|
||||||
|
storageClass: ""
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
size: 8Gi
|
||||||
|
annotations: {}
|
||||||
|
|
||||||
|
server:
|
||||||
|
env:
|
||||||
|
- name: TZ
|
||||||
|
value: UTC
|
||||||
|
envFrom: []
|
||||||
|
extraEnv: []
|
||||||
|
extraEnvFrom: []
|
||||||
|
secretEnv:
|
||||||
|
create: false
|
||||||
|
name: ""
|
||||||
|
data: {}
|
||||||
|
keys: []
|
||||||
|
podAnnotations: {}
|
||||||
|
podLabels: {}
|
||||||
|
podSecurityContext: {}
|
||||||
|
securityContext: {}
|
||||||
|
extraVolumes: []
|
||||||
|
extraVolumeMounts: []
|
||||||
|
resources: {}
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
|
livenessProbe:
|
||||||
|
enabled: true
|
||||||
|
path: /
|
||||||
|
initialDelaySeconds: 20
|
||||||
|
periodSeconds: 30
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
readinessProbe:
|
||||||
|
enabled: true
|
||||||
|
path: /
|
||||||
|
initialDelaySeconds: 10
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
|
||||||
|
agent:
|
||||||
|
enabled: false
|
||||||
|
kind: DaemonSet # Supported: DaemonSet | Deployment
|
||||||
|
replicaCount: 1
|
||||||
|
serviceAccount:
|
||||||
|
create: false
|
||||||
|
name: ""
|
||||||
|
annotations: {}
|
||||||
|
image:
|
||||||
|
repository: ghcr.io/rcourtman/pulse-docker-agent
|
||||||
|
tag: ""
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
env:
|
||||||
|
- name: PULSE_URL
|
||||||
|
value: http://pulse:7655
|
||||||
|
envFrom: []
|
||||||
|
extraEnv: []
|
||||||
|
extraEnvFrom: []
|
||||||
|
secretEnv:
|
||||||
|
create: false
|
||||||
|
name: ""
|
||||||
|
data: {}
|
||||||
|
keys: []
|
||||||
|
args: []
|
||||||
|
resources: {}
|
||||||
|
podAnnotations: {}
|
||||||
|
podLabels: {}
|
||||||
|
podSecurityContext: {}
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 0
|
||||||
|
runAsGroup: 0
|
||||||
|
privileged: false
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
|
dockerSocket:
|
||||||
|
enabled: true
|
||||||
|
path: /var/run/docker.sock
|
||||||
|
hostPathType: Socket
|
||||||
|
extraVolumes: []
|
||||||
|
extraVolumeMounts: []
|
||||||
|
|
@ -52,6 +52,26 @@ docker run -d -p 7655:7655 -v pulse_data:/data rcourtman/pulse:latest
|
||||||
|
|
||||||
See [Docker Guide](DOCKER.md) for advanced options.
|
See [Docker Guide](DOCKER.md) for advanced options.
|
||||||
|
|
||||||
|
### Kubernetes (Helm)
|
||||||
|
|
||||||
|
Use the bundled Helm chart for Kubernetes clusters:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm registry login ghcr.io
|
||||||
|
helm install pulse oci://ghcr.io/rcourtman/pulse-chart \
|
||||||
|
--version $(curl -fsSL https://raw.githubusercontent.com/rcourtman/Pulse/main/VERSION) \
|
||||||
|
--namespace pulse \
|
||||||
|
--create-namespace
|
||||||
|
# Replace the VERSION lookup with a specific release tag (without "v") if you need to pin.
|
||||||
|
|
||||||
|
# Developing locally? Install from the checked-out chart directory instead:
|
||||||
|
# helm upgrade --install pulse ./deploy/helm/pulse \
|
||||||
|
# --namespace pulse \
|
||||||
|
# --create-namespace
|
||||||
|
```
|
||||||
|
|
||||||
|
Read the full [Kubernetes deployment guide](KUBERNETES.md) for ingress, persistence, and Docker agent configuration.
|
||||||
|
|
||||||
## Updating
|
## Updating
|
||||||
|
|
||||||
### Automatic Updates (Recommended)
|
### Automatic Updates (Recommended)
|
||||||
|
|
@ -177,4 +197,4 @@ sudo rm /etc/systemd/system/pulse.service
|
||||||
docker stop pulse
|
docker stop pulse
|
||||||
docker rm pulse
|
docker rm pulse
|
||||||
docker volume rm pulse_data # Warning: deletes all data
|
docker volume rm pulse_data # Warning: deletes all data
|
||||||
```
|
```
|
||||||
|
|
|
||||||
176
docs/KUBERNETES.md
Normal file
176
docs/KUBERNETES.md
Normal file
|
|
@ -0,0 +1,176 @@
|
||||||
|
# Kubernetes Deployment (Helm)
|
||||||
|
|
||||||
|
Deploy Pulse to Kubernetes with the bundled Helm chart under `deploy/helm/pulse`. The chart provisions the Pulse hub (web UI + API) and can optionally run the Docker monitoring agent alongside it. Stable builds are published automatically to the GitHub Container Registry (GHCR) whenever a Pulse release goes out.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Kubernetes 1.24 or newer with access to a default `StorageClass`
|
||||||
|
- Helm 3.9+
|
||||||
|
- An ingress controller (only if you plan to expose Pulse through an Ingress)
|
||||||
|
- (Optional) A Docker-compatible runtime on the nodes where you expect to run the Docker agent; the agent talks to `/var/run/docker.sock`
|
||||||
|
|
||||||
|
## Installing from GHCR (recommended)
|
||||||
|
|
||||||
|
1. Authenticate against GHCR (one-time step on each machine):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm registry login ghcr.io
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Install the chart published for the latest Pulse release (swap the inline `curl` command with a pinned version if you need to lock upgrades):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm install pulse oci://ghcr.io/rcourtman/pulse-chart \
|
||||||
|
--version $(curl -fsSL https://raw.githubusercontent.com/rcourtman/Pulse/main/VERSION) \
|
||||||
|
--namespace pulse \
|
||||||
|
--create-namespace
|
||||||
|
```
|
||||||
|
|
||||||
|
The chart version tracks the Pulse release version. Check [GitHub Releases](https://github.com/rcourtman/Pulse/releases) or run `gh release list --limit 1` to find the newest tag if you prefer to specify it manually.
|
||||||
|
|
||||||
|
3. Port-forward the service to finish the first-time security setup:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n pulse port-forward svc/pulse 7655:7655
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Browse to `http://localhost:7655`, complete the security bootstrap (admin user + MFA + TLS preferences), and create an API token under **Settings → Security** for any automation or agents you plan to run.
|
||||||
|
|
||||||
|
The chart mounts a PersistentVolumeClaim at `/data` so database files, credentials, and configuration survive pod restarts. By default it requests 8 GiB with `ReadWriteOnce` access—adjust via `persistence.*` in `values.yaml`.
|
||||||
|
|
||||||
|
## Working From Source (local packaging)
|
||||||
|
|
||||||
|
Need to test local modifications or work offline? Install directly from the checked-out repository:
|
||||||
|
|
||||||
|
1. Clone the repository and switch into it.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/rcourtman/Pulse.git
|
||||||
|
cd Pulse
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Render or install the chart from `deploy/helm/pulse`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm upgrade --install pulse ./deploy/helm/pulse \
|
||||||
|
--namespace pulse \
|
||||||
|
--create-namespace
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Continue with the port-forward and initial setup steps described above.
|
||||||
|
|
||||||
|
## Common Configuration
|
||||||
|
|
||||||
|
Most day-to-day overrides are done in a custom values file:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# file: helm-values.yaml
|
||||||
|
service:
|
||||||
|
type: ClusterIP
|
||||||
|
|
||||||
|
ingress:
|
||||||
|
enabled: true
|
||||||
|
className: nginx
|
||||||
|
hosts:
|
||||||
|
- host: pulse.example.com
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
tls:
|
||||||
|
- hosts: [pulse.example.com]
|
||||||
|
secretName: pulse-tls
|
||||||
|
|
||||||
|
server:
|
||||||
|
env:
|
||||||
|
- name: TZ
|
||||||
|
value: Europe/Berlin
|
||||||
|
secretEnv:
|
||||||
|
create: true
|
||||||
|
data:
|
||||||
|
API_TOKENS: docker-agent-token
|
||||||
|
```
|
||||||
|
|
||||||
|
Install or upgrade with the overrides:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm upgrade --install pulse ./deploy/helm/pulse \
|
||||||
|
--namespace pulse \
|
||||||
|
--create-namespace \
|
||||||
|
-f helm-values.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
The `server.secretEnv` block above pre-seeds one or more API tokens so the UI is immediately accessible and automation can authenticate. If you prefer to manage credentials separately, set `server.secretEnv.name` to reference an existing secret instead of letting the chart create one.
|
||||||
|
|
||||||
|
### Accessing Pulse
|
||||||
|
|
||||||
|
- **Port forward:** `kubectl -n pulse port-forward svc/pulse 7655:7655`
|
||||||
|
- **Ingress:** Enable via the snippet above, or supply your own annotations for external DNS, TLS, etc.
|
||||||
|
- **LoadBalancer:** Set `service.type: LoadBalancer` and, optionally, `service.loadBalancerIP`.
|
||||||
|
|
||||||
|
### Persistence Options
|
||||||
|
|
||||||
|
- `persistence.enabled`: Disable to use an ephemeral `emptyDir`
|
||||||
|
- `persistence.existingClaim`: Bind to a pre-provisioned PVC
|
||||||
|
- `persistence.storageClass`: Pin to a specific storage class
|
||||||
|
- `persistence.size`: Resize the default PVC request
|
||||||
|
|
||||||
|
## Enabling the Docker Agent
|
||||||
|
|
||||||
|
The optional agent reports Docker host metrics back to the Pulse hub. Enable it once you have a valid API token:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# agent-values.yaml
|
||||||
|
agent:
|
||||||
|
enabled: true
|
||||||
|
env:
|
||||||
|
- name: PULSE_URL
|
||||||
|
value: https://pulse.example.com
|
||||||
|
secretEnv:
|
||||||
|
create: true
|
||||||
|
data:
|
||||||
|
PULSE_TOKEN: docker-agent-token
|
||||||
|
dockerSocket:
|
||||||
|
enabled: true
|
||||||
|
path: /var/run/docker.sock
|
||||||
|
hostPathType: Socket
|
||||||
|
```
|
||||||
|
|
||||||
|
Apply with (choose one):
|
||||||
|
|
||||||
|
- **Published chart:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm upgrade pulse oci://ghcr.io/rcourtman/pulse-chart \
|
||||||
|
--install \
|
||||||
|
--version <pulse-version> \
|
||||||
|
--namespace pulse \
|
||||||
|
-f agent-values.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Local checkout:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm upgrade --install pulse ./deploy/helm/pulse \
|
||||||
|
--namespace pulse \
|
||||||
|
-f agent-values.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
- The agent expects a Docker-compatible runtime and access to the Docker socket. Set `agent.dockerSocket.enabled: false` if you run the agent elsewhere or publish the Docker API securely.
|
||||||
|
- Use separate API tokens per host; list multiple tokens with `;` or `,` separators in `PULSE_TARGETS` if needed.
|
||||||
|
- Run the agent as a `DaemonSet` (default) to cover every node, or switch to `agent.kind: Deployment` for a single pod.
|
||||||
|
|
||||||
|
## Upgrades and Removal
|
||||||
|
|
||||||
|
- **Upgrade (GHCR):** `helm upgrade pulse oci://ghcr.io/rcourtman/pulse-chart --version <new-version> -n pulse -f <values.yaml>`
|
||||||
|
- **Upgrade (source):** Re-run `helm upgrade --install pulse ./deploy/helm/pulse -f <values>` with updated overrides.
|
||||||
|
- **Rollback:** `helm rollback pulse <revision>`
|
||||||
|
- **Uninstall:** `helm uninstall pulse -n pulse` (PVCs remain unless you delete them manually)
|
||||||
|
|
||||||
|
## Reference
|
||||||
|
|
||||||
|
- Review every available option in `deploy/helm/pulse/values.yaml`
|
||||||
|
- Inspect published charts without installing: `helm show values oci://ghcr.io/rcourtman/pulse-chart --version <version>`
|
||||||
|
- Helm template rendering preview: `helm template pulse ./deploy/helm/pulse -f <values>`
|
||||||
|
- `NOTES.txt` emitted by Helm summarizes the service endpoint and agent prerequisites after each install or upgrade
|
||||||
72
docs/RELEASE.md
Normal file
72
docs/RELEASE.md
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
# Pulse Release Checklist
|
||||||
|
|
||||||
|
Use this checklist when preparing and publishing a new Pulse release.
|
||||||
|
|
||||||
|
## Pre-release
|
||||||
|
|
||||||
|
- [ ] Ensure `VERSION` is up to date and matches the tag you plan to cut (format `4.x.y`)
|
||||||
|
- [ ] Confirm the Helm chart renders and installs locally:
|
||||||
|
```bash
|
||||||
|
helm lint deploy/helm/pulse --strict
|
||||||
|
helm template pulse deploy/helm/pulse \
|
||||||
|
--set persistence.enabled=false \
|
||||||
|
--set server.secretEnv.create=true \
|
||||||
|
--set server.secretEnv.data.API_TOKENS=dummy-token
|
||||||
|
```
|
||||||
|
- [ ] (Optional) Run the Kind-based integration test locally:
|
||||||
|
```bash
|
||||||
|
kind create cluster
|
||||||
|
helm upgrade --install pulse ./deploy/helm/pulse \
|
||||||
|
--namespace pulse \
|
||||||
|
--create-namespace \
|
||||||
|
--set persistence.enabled=false \
|
||||||
|
--set server.secretEnv.create=true \
|
||||||
|
--set server.secretEnv.data.API_TOKENS=dummy-token \
|
||||||
|
--wait
|
||||||
|
kubectl -n pulse get pods
|
||||||
|
kind delete cluster
|
||||||
|
```
|
||||||
|
|
||||||
|
## Publishing
|
||||||
|
|
||||||
|
1. Tag the release (`git tag v4.x.y && git push origin v4.x.y`) or draft a GitHub release.
|
||||||
|
|
||||||
|
2. Package the Helm chart locally so you can preview the artifact (the GitHub workflow performs the same command, but local packaging provides an explicit hand-off):
|
||||||
|
```bash
|
||||||
|
./scripts/package-helm-chart.sh 4.x.y
|
||||||
|
# Optional: push to GHCR after authenticating
|
||||||
|
# helm registry login ghcr.io
|
||||||
|
# ./scripts/package-helm-chart.sh 4.x.y --push
|
||||||
|
```
|
||||||
|
The script emits `dist/pulse-4.x.y.tgz`, and `scripts/build-release.sh` copies the tarball into `release/` alongside the binary archives. Uploading can be handled manually with the `--push` flag or delegated to the automated workflow described below.
|
||||||
|
> `scripts/build-release.sh` automatically runs the same packaging step (unless you export `SKIP_HELM_PACKAGE=1`) so release archives and chart tarballs are produced together.
|
||||||
|
|
||||||
|
3. If you rely on automation, monitor the **Publish Helm Chart** workflow (triggered by the release) to ensure it finishes successfully. When running entirely locally, skip this step and verify the push command completed.
|
||||||
|
|
||||||
|
4. (Optional) Sign `release/checksums.txt` by exporting `SIGNING_KEY_ID=<gpg-key-id>` before running `scripts/build-release.sh`, or re-run the signing step manually:
|
||||||
|
```bash
|
||||||
|
SIGNING_KEY_ID=<gpg-key-id> ./scripts/build-release.sh
|
||||||
|
# or sign later
|
||||||
|
gpg --detach-sign --armor --local-user <gpg-key-id> release/checksums.txt
|
||||||
|
```
|
||||||
|
Publish both `checksums.txt` and `checksums.txt.asc` so users can verify artifacts:
|
||||||
|
```bash
|
||||||
|
gpg --verify checksums.txt.asc checksums.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Update the release notes to include an upgrade/install snippet pointing at GHCR, for example:
|
||||||
|
```bash
|
||||||
|
helm install pulse oci://ghcr.io/rcourtman/pulse-chart \
|
||||||
|
--version 4.x.y \
|
||||||
|
--namespace pulse \
|
||||||
|
--create-namespace
|
||||||
|
```
|
||||||
|
|
||||||
|
6. Mention any chart-breaking changes (new values, migrations) in the release notes.
|
||||||
|
|
||||||
|
## Post-release
|
||||||
|
|
||||||
|
- [ ] Verify `helm show chart oci://ghcr.io/rcourtman/pulse-chart --version 4.x.y` shows the expected metadata (version, appVersion, icon)
|
||||||
|
- [ ] Run `helm install` against a test cluster (Kind/k3s) using the published OCI artifact
|
||||||
|
- [ ] Announce the release with links to both the GitHub release and the Helm installation instructions (`docs/KUBERNETES.md`)
|
||||||
|
- [ ] Verify signatures: `gpg --verify checksums.txt.asc checksums.txt`
|
||||||
|
|
@ -203,9 +203,43 @@ for build_name in "${!builds[@]}"; do
|
||||||
cp "$BUILD_DIR/pulse-sensor-proxy-$build_name" "$RELEASE_DIR/"
|
cp "$BUILD_DIR/pulse-sensor-proxy-$build_name" "$RELEASE_DIR/"
|
||||||
done
|
done
|
||||||
|
|
||||||
# Generate checksums (include tarballs and standalone binaries)
|
# Optionally package Helm chart
|
||||||
cd $RELEASE_DIR
|
if [ "${SKIP_HELM_PACKAGE:-0}" != "1" ]; then
|
||||||
sha256sum *.tar.gz pulse-sensor-proxy-* > checksums.txt
|
if command -v helm >/dev/null 2>&1; then
|
||||||
|
echo "Packaging Helm chart..."
|
||||||
|
./scripts/package-helm-chart.sh "$VERSION"
|
||||||
|
if [ -f "dist/pulse-$VERSION.tgz" ]; then
|
||||||
|
cp "dist/pulse-$VERSION.tgz" "$RELEASE_DIR/"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "Helm not found on PATH; skipping Helm chart packaging. Install Helm 3.9+ or set SKIP_HELM_PACKAGE=1 to silence this message."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Generate checksums (include tarballs, helm chart, and standalone binaries)
|
||||||
|
cd "$RELEASE_DIR"
|
||||||
|
shopt -s nullglob
|
||||||
|
checksum_files=( *.tar.gz pulse-sensor-proxy-* )
|
||||||
|
if compgen -G "pulse-*.tgz" > /dev/null; then
|
||||||
|
checksum_files+=( pulse-*.tgz )
|
||||||
|
fi
|
||||||
|
if [ ${#checksum_files[@]} -eq 0 ]; then
|
||||||
|
echo "Warning: no release artifacts found to checksum."
|
||||||
|
else
|
||||||
|
sha256sum "${checksum_files[@]}" > checksums.txt
|
||||||
|
if [ -n "${SIGNING_KEY_ID:-}" ]; then
|
||||||
|
if command -v gpg >/dev/null 2>&1; then
|
||||||
|
echo "Signing checksums with GPG key ${SIGNING_KEY_ID}..."
|
||||||
|
gpg --batch --yes --detach-sign --armor \
|
||||||
|
--local-user "${SIGNING_KEY_ID}" \
|
||||||
|
--output checksums.txt.asc \
|
||||||
|
checksums.txt
|
||||||
|
else
|
||||||
|
echo "SIGNING_KEY_ID is set but gpg is not installed; skipping signature."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
shopt -u nullglob
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
echo
|
echo
|
||||||
|
|
|
||||||
61
scripts/package-helm-chart.sh
Executable file
61
scripts/package-helm-chart.sh
Executable file
|
|
@ -0,0 +1,61 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Package (and optionally push) the Pulse Helm chart.
|
||||||
|
# Usage:
|
||||||
|
# ./scripts/package-helm-chart.sh [version] [--push]
|
||||||
|
# Environment:
|
||||||
|
# OCI_REPO (default: ghcr.io/rcourtman/pulse-chart)
|
||||||
|
# HELM_BIN (default: helm)
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
CHART_DIR="$REPO_ROOT/deploy/helm/pulse"
|
||||||
|
DIST_DIR="$REPO_ROOT/dist"
|
||||||
|
HELM_BIN="${HELM_BIN:-helm}"
|
||||||
|
OCI_REPO="${OCI_REPO:-ghcr.io/rcourtman/pulse-chart}"
|
||||||
|
|
||||||
|
if ! command -v "$HELM_BIN" >/dev/null 2>&1; then
|
||||||
|
echo "Error: Helm not found (expected at \$HELM_BIN=$HELM_BIN). Install Helm 3.9+ first." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
VERSION_DEFAULT="$(cat "$REPO_ROOT/VERSION")"
|
||||||
|
VERSION="${1:-$VERSION_DEFAULT}"
|
||||||
|
VERSION="${VERSION#v}" # strip leading v if provided
|
||||||
|
|
||||||
|
PUSH=false
|
||||||
|
for arg in "$@"; do
|
||||||
|
if [ "$arg" = "--push" ]; then
|
||||||
|
PUSH=true
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "Packaging Pulse chart version $VERSION (appVersion=$VERSION)"
|
||||||
|
|
||||||
|
rm -rf "$DIST_DIR"
|
||||||
|
mkdir -p "$DIST_DIR"
|
||||||
|
|
||||||
|
"$HELM_BIN" lint "$CHART_DIR" --strict
|
||||||
|
"$HELM_BIN" package "$CHART_DIR" \
|
||||||
|
--version "$VERSION" \
|
||||||
|
--app-version "$VERSION" \
|
||||||
|
--destination "$DIST_DIR"
|
||||||
|
|
||||||
|
PACKAGE_PATH="$DIST_DIR/pulse-$VERSION.tgz"
|
||||||
|
if [ ! -f "$PACKAGE_PATH" ]; then
|
||||||
|
echo "Error: Expected package $PACKAGE_PATH not found" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$PUSH" = true ]; then
|
||||||
|
echo "Pushing chart to oci://$OCI_REPO"
|
||||||
|
"$HELM_BIN" push "$PACKAGE_PATH" "oci://$OCI_REPO"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Chart packaged at $PACKAGE_PATH"
|
||||||
|
if [ "$PUSH" = true ]; then
|
||||||
|
echo "Chart pushed to oci://$OCI_REPO"
|
||||||
|
else
|
||||||
|
echo "Run with --push (after logging into GHCR) to upload the artifact."
|
||||||
|
fi
|
||||||
Loading…
Reference in a new issue