Compare commits

...

6 Commits

18 changed files with 362 additions and 32 deletions

View File

@ -2,7 +2,7 @@ apiVersion: v2
name: donetick
description: Donetick helm chart for Kubernetes
type: application
version: 1.0.4
version: 1.0.6
appVersion: "v0.1.60"
maintainers:
- name: Richard Tomik

View File

@ -2,8 +2,8 @@ apiVersion: v2
name: norish
description: Norish helm chart for Kubernetes - A recipe management and meal planning application
type: application
version: 0.0.3
appVersion: "v0.13.6-beta"
version: 0.0.4
appVersion: "v0.14.1-beta"
maintainers:
- name: Richard Tomik
email: no@m.com

View File

@ -6,7 +6,7 @@ A Helm chart for deploying [Norish](https://github.com/norishapp/norish), a reci
This chart bootstraps a Norish deployment on a Kubernetes cluster using the Helm package manager.
**IMPORTANT: This chart requires a central PostgreSQL database.** You must have a PostgreSQL server available before deploying this chart. The chart does not include a PostgreSQL deployment.
**IMPORTANT: This chart requires a central PostgreSQL database and Redis server.** You must have both a PostgreSQL and Redis server available before deploying this chart. The chart does not include PostgreSQL or Redis deployments.
**Note:** This chart includes a Chrome headless sidecar container that is required for recipe parsing and scraping functionality. Chrome requires elevated security privileges (`SYS_ADMIN` capability) and additional resources (recommend 256Mi-512Mi memory).
@ -15,6 +15,7 @@ This chart bootstraps a Norish deployment on a Kubernetes cluster using the Helm
- Kubernetes 1.19+
- Helm 3.0+
- **PostgreSQL database server** (required)
- **Redis server** (required for v0.14.0+)
- PV provisioner support in the underlying infrastructure (if persistence is enabled)
## Installing the Chart
@ -49,13 +50,18 @@ Before deploying, you must configure:
- Ensure the database exists before deployment
- Set appropriate credentials
2. **Master Key**: A 32-byte base64-encoded encryption key
2. **Redis Server** (REQUIRED for v0.14.0+): A Redis server must be available
- Configure `redis.host` to point to your Redis server
- Configure authentication if required
- Used for background job processing and queues
3. **Master Key**: A 32-byte base64-encoded encryption key
```bash
# Generate a master key
openssl rand -base64 32
```
3. **Application URL**: Set `config.authUrl` to match your ingress hostname
4. **Application URL**: Set `config.authUrl` to match your ingress hostname
### Authentication Configuration
@ -88,6 +94,12 @@ database:
username: norish
password: "secure-password"
redis:
host: "redis.default.svc.cluster.local"
port: 6379
database: 0
# Leave password empty if Redis has no authentication
config:
authUrl: "https://norish.example.com"
masterKey:
@ -288,7 +300,7 @@ Or if using a centralized PostgreSQL Helm chart or service, ensure the database
| Name | Description | Default |
|------|-------------|---------|
| `image.repository` | Norish image repository | `norishapp/norish` |
| `image.tag` | Norish image tag | `v0.13.6-beta` |
| `image.tag` | Norish image tag | `v0.14.1-beta` |
| `image.pullPolicy` | Image pull policy | `IfNotPresent` |
| `imagePullSecrets` | Image pull secrets | `[]` |
@ -366,6 +378,19 @@ Or if using a centralized PostgreSQL Helm chart or service, ensure the database
| `database.databaseKey` | Key in secret for database name | `"database"` |
| `database.hostKey` | Key in secret for host | `"host"` |
### Redis Parameters (REQUIRED for v0.14.0+)
| Name | Description | Default |
|------|-------------|---------|
| `redis.host` | Redis server hostname (required) | `""` |
| `redis.port` | Redis server port | `6379` |
| `redis.database` | Redis database number | `0` |
| `redis.username` | Redis username (Redis 6.0+, optional) | `""` |
| `redis.password` | Redis password (leave empty if no auth) | `""` |
| `redis.existingSecret` | Use existing secret for Redis URL (recommended for production) | `""` |
| `redis.urlKey` | Key in existingSecret containing the full Redis URL | `"redis-url"` |
| `redis.passwordKey` | Key in existingSecret for password (for compatibility) | `"password"` |
### Chrome Headless Parameters (REQUIRED)
| Name | Description | Default |
@ -533,6 +558,100 @@ To upgrade the chart:
$ helm upgrade norish helm-charts/norish -f values.yaml
```
### Upgrading from v0.13.x to v0.14.x
**BREAKING CHANGE:** Norish v0.14.0+ requires Redis for background job processing.
Before upgrading, you **must** configure Redis:
**Option 1: Using an existing Redis cluster (Recommended for production)**
Update your `values.yaml`:
```yaml
redis:
host: "redis.default.svc.cluster.local" # Your Redis server
port: 6379
database: 0
# If Redis requires authentication:
existingSecret: "my-redis-secret" # Secret containing redis-url key
urlKey: "redis-url"
```
Create the Redis secret with the full URL:
```bash
# For Redis with authentication
kubectl create secret generic my-redis-secret \
--from-literal=redis-url="redis://username:password@redis.default.svc.cluster.local:6379/0"
# For Redis without authentication
kubectl create secret generic my-redis-secret \
--from-literal=redis-url="redis://redis.default.svc.cluster.local:6379/0"
```
**Option 2: Using plain password in values (Simple setup)**
```yaml
redis:
host: "redis.default.svc.cluster.local"
port: 6379
database: 0
username: "default" # Optional
password: "mypassword" # Chart will auto-generate redis-url
```
**Option 3: Redis without authentication**
```yaml
redis:
host: "redis.default.svc.cluster.local"
port: 6379
database: 0
# No password or existingSecret - chart will generate simple URL
```
After configuring Redis, upgrade the chart:
```bash
$ helm upgrade norish helm-charts/norish -f values.yaml
```
### What's New in v0.14.x
**Breaking Changes:**
- Redis is now required for the application to function
- See the [upgrade guide](#upgrading-from-v013x-to-v014x) above
**New Features:**
- Recipe improvements:
- Full redesign of the recipe desktop page
- Recipe linking and headings in description/instruction steps
- Attach images to steps as reference material
- Keep screen on during cooking
- Drag and drop ingredient and step reordering
- Manual or AI-powered macro nutrient estimation
- New creation options:
- Recipe creation by image (supports multiple images, requires AI)
- Recipe creation via plain recipe text
- "Always use AI to import" override in admin settings
- Allergy MVP:
- Users can set allergies in their settings page
- Warnings when planning recipes with matching allergies
- Rating and liking recipes (including filtering)
**Technical Improvements:**
- Redis + BullMQ for importing and other background tasks
- Removed puppeteer in favor of playwright
- All dependencies updated
- Improved reverse proxy support
- Rate limiting for brute force attacks
**Bug Fixes:**
- User menu not opening import modal
- User menu creation not linking
- Improved pre-fetching of recipes and virtualization
## Support
- Norish Repository: https://github.com/norishapp/norish

View File

@ -55,3 +55,43 @@ Database connection URL
{{- $database := .Values.database.name }}
{{- printf "postgres://%s:%s@%s:%d/%s" $username $password $host (int $port) $database }}
{{- end }}
{{/*
Redis URL (for non-authenticated Redis)
Constructs the Redis URL without authentication.
Format: redis://host:port/database
*/}}
{{- define "norish.redis.url.noauth" -}}
{{- $host := .Values.redis.host }}
{{- $port := .Values.redis.port }}
{{- $database := .Values.redis.database | toString }}
{{- printf "redis://%s:%d/%s" $host (int $port) $database }}
{{- end }}
{{/*
Check if Redis authentication is configured
Returns true if either existingSecret or password is set
*/}}
{{- define "norish.redis.hasAuth" -}}
{{- if or .Values.redis.existingSecret .Values.redis.password }}
{{- "true" }}
{{- end }}
{{- end }}
{{/*
Redis URL with authentication (for secret generation)
Constructs the Redis URL with password interpolation for use in secrets.
Format: redis://[username]:[password]@host:port/database
*/}}
{{- define "norish.redis.url.withPassword" -}}
{{- $host := .Values.redis.host }}
{{- $port := .Values.redis.port }}
{{- $database := .Values.redis.database | toString }}
{{- $username := .Values.redis.username | default "" }}
{{- $password := .Values.redis.password | default "" }}
{{- if $username }}
{{- printf "redis://%s:%s@%s:%d/%s" $username $password $host (int $port) $database }}
{{- else }}
{{- printf "redis://:%s@%s:%d/%s" $password $host (int $port) $database }}
{{- end }}
{{- end }}

View File

@ -145,6 +145,16 @@ spec:
name: {{ include "norish.fullname" . }}-secret
key: master-key
{{- end }}
- name: REDIS_URL
valueFrom:
secretKeyRef:
{{- if .Values.redis.existingSecret }}
name: {{ .Values.redis.existingSecret }}
key: {{ .Values.redis.urlKey | default "redis-url" }}
{{- else }}
name: {{ include "norish.fullname" . }}-secret
key: redis-url
{{- end }}
{{- if .Values.config.auth.oidc.enabled }}
- name: OIDC_NAME
value: {{ .Values.config.auth.oidc.name | quote }}

View File

@ -12,6 +12,13 @@ stringData:
{{- if not .Values.database.existingSecret }}
database-url: {{ include "norish.databaseUrl" . | quote }}
{{- end }}
{{- if not .Values.redis.existingSecret }}
{{- if .Values.redis.password }}
redis-url: {{ include "norish.redis.url.withPassword" . | quote }}
{{- else }}
redis-url: {{ include "norish.redis.url.noauth" . | quote }}
{{- end }}
{{- end }}
{{- if .Values.config.auth.oidc.enabled }}
{{- if not .Values.config.auth.oidc.existingSecret }}
oidc-client-id: {{ .Values.config.auth.oidc.clientId | quote }}

View File

@ -5,7 +5,7 @@ fullnameOverride: ""
## Image settings
image:
repository: norishapp/norish
tag: "v0.13.6-beta"
tag: "v0.14.1-beta"
pullPolicy: IfNotPresent
imagePullSecrets: []
@ -211,6 +211,24 @@ database:
databaseKey: "database" # Key in the secret for database name (optional)
hostKey: "" # Key in the secret for database host (optional)
## External Redis configuration (REQUIRED for v0.14.0+)
## Redis is required for job queues and background tasks starting from v0.14.0-beta
redis:
# Redis connection details
host: "" # Required: Redis server hostname
port: 6379
database: 0
# Authentication (leave empty if Redis has no auth)
username: "" # Optional: Redis username (Redis 6.0+)
password: "" # Redis password (leave empty if no auth)
# Use existing secret for Redis credentials (recommended for production)
# NOTE: When using existingSecret, the secret MUST contain a key with the full Redis URL
# Format: redis://[username]:[password]@host:port/database
existingSecret: "" # Name of existing Kubernetes secret
urlKey: "redis-url" # Key in existingSecret containing the full Redis URL
passwordKey: "password" # Key in existingSecret for password (for compatibility)
## Chrome Headless configuration (REQUIRED)
## Required for improved recipe parsing and scraping
chrome:

View File

@ -2,11 +2,11 @@ apiVersion: v2
name: paperless-ngx
description: Paperless-ngx helm chart for Kubernetes
type: application
version: 0.0.2
appVersion: "latest"
version: 0.0.5
appVersion: "2.20.3"
maintainers:
- name: Richard Tomik
email: no@m.com
email: richard.tomik@proton.me
keywords:
- productivity
- document-management

View File

@ -127,12 +127,16 @@ The following table lists the configurable parameters and their default values.
| Name | Description | Value |
|----------------------------------------|--------------------------------------------------------------------|---------------------|
| `persistence.data.enabled` | Enable persistence for data directory | `true` |
| `persistence.data.existingClaim` | Use an existing PVC for data directory | `""` |
| `persistence.data.size` | Size of data PVC | `1Gi` |
| `persistence.media.enabled` | Enable persistence for media directory | `true` |
| `persistence.media.existingClaim` | Use an existing PVC for media directory | `""` |
| `persistence.media.size` | Size of media PVC | `10Gi` |
| `persistence.consume.enabled` | Enable persistence for consume directory | `true` |
| `persistence.consume.existingClaim` | Use an existing PVC for consume directory | `""` |
| `persistence.consume.size` | Size of consume PVC | `5Gi` |
| `persistence.export.enabled` | Enable persistence for export directory | `true` |
| `persistence.export.existingClaim` | Use an existing PVC for export directory | `""` |
| `persistence.export.size` | Size of export PVC | `1Gi` |
### Service Parameters
@ -287,6 +291,37 @@ Paperless-ngx uses several directories:
All directories can be configured with separate PVCs and storage classes.
### Using Existing PVCs
The chart supports using existing PersistentVolumeClaims instead of creating new ones. This is useful for:
- Migrating from an existing Paperless-ngx deployment
- Using pre-provisioned storage with specific settings
- Sharing volumes across deployments
To use an existing PVC, specify the `existingClaim` parameter for the relevant volume:
```yaml
persistence:
data:
enabled: true
existingClaim: "my-existing-data-pvc"
media:
enabled: true
existingClaim: "my-existing-media-pvc"
export:
enabled: true
existingClaim: "" # Will create new PVC
consume:
enabled: true
existingClaim: "" # Will create new PVC
```
When `existingClaim` is specified:
- The chart will **NOT** create a new PVC
- The specified PVC must already exist in the same namespace
- `storageClass`, `size`, and `accessMode` parameters are ignored for that volume
- You can mix existing and new PVCs (some volumes with `existingClaim`, others without)
## Uninstalling the Chart
To uninstall/delete the `paperless-ngx` deployment:

View File

@ -89,21 +89,42 @@ Redis port
{{- end }}
{{/*
Redis URL
Constructs the Redis URL with optional authentication.
Redis URL (for non-authenticated Redis)
Constructs the Redis URL without authentication.
Format: redis://host:port/database
*/}}
{{- define "paperless-ngx.redis.url.noauth" -}}
{{- $host := include "paperless-ngx.redis.host" . }}
{{- $port := include "paperless-ngx.redis.port" . }}
{{- $database := .Values.redis.external.database | toString }}
{{- printf "redis://%s:%s/%s" $host $port $database }}
{{- end }}
{{/*
Check if Redis authentication is configured
Returns true if either existingSecret or password is set
*/}}
{{- define "paperless-ngx.redis.hasAuth" -}}
{{- if or .Values.redis.external.existingSecret .Values.redis.external.password }}
{{- "true" }}
{{- end }}
{{- end }}
{{/*
Redis URL with authentication (for secret generation)
Constructs the Redis URL with password interpolation for use in secrets.
This uses the actual password value when building the secret.
Format: redis://[username]:[password]@host:port/database
*/}}
{{- define "paperless-ngx.redis.url" -}}
{{- define "paperless-ngx.redis.url.withPassword" -}}
{{- $host := include "paperless-ngx.redis.host" . }}
{{- $port := include "paperless-ngx.redis.port" . }}
{{- $database := .Values.redis.external.database | toString }}
{{- $username := .Values.redis.external.username | default "" }}
{{- $password := .Values.redis.external.password | default "" }}
{{- if and $username $password }}
{{- if $username }}
{{- printf "redis://%s:%s@%s:%s/%s" $username $password $host $port $database }}
{{- else if $password }}
{{- printf "redis://:%s@%s:%s/%s" $password $host $port $database }}
{{- else }}
{{- printf "redis://%s:%s/%s" $host $port $database }}
{{- printf "redis://:%s@%s:%s/%s" $password $host $port $database }}
{{- end }}
{{- end }}

View File

@ -67,12 +67,23 @@ spec:
{{- end }}
env:
# Required services
{{- if include "paperless-ngx.redis.hasAuth" . }}
# When Redis has authentication, read the full URL from secret
- name: PAPERLESS_REDIS
value: {{ include "paperless-ngx.redis.url" . | quote }}
valueFrom:
secretKeyRef:
name: {{ .Values.redis.external.existingSecret | default (printf "%s-secrets" (include "paperless-ngx.fullname" .)) }}
key: {{ .Values.redis.external.urlKey | default "redis-url" }}
{{- else }}
# When Redis has no authentication, use the simple URL
- name: PAPERLESS_REDIS
value: {{ include "paperless-ngx.redis.url.noauth" . | quote }}
{{- end }}
{{- if .Values.redis.external.prefix }}
- name: PAPERLESS_REDIS_PREFIX
value: {{ .Values.redis.external.prefix | quote }}
{{- end }}
- name: PAPERLESS_DBHOST
value: {{ include "paperless-ngx.postgresql.host" . | quote }}
- name: PAPERLESS_DBPORT
@ -324,7 +335,7 @@ spec:
{{- if .Values.persistence.data.enabled }}
- name: data
persistentVolumeClaim:
claimName: {{ include "paperless-ngx.fullname" . }}-data
claimName: {{ if .Values.persistence.data.existingClaim }}{{ .Values.persistence.data.existingClaim }}{{ else }}{{ include "paperless-ngx.fullname" . }}-data{{ end }}
{{- else }}
- name: data
emptyDir: {}
@ -332,7 +343,7 @@ spec:
{{- if .Values.persistence.media.enabled }}
- name: media
persistentVolumeClaim:
claimName: {{ include "paperless-ngx.fullname" . }}-media
claimName: {{ if .Values.persistence.media.existingClaim }}{{ .Values.persistence.media.existingClaim }}{{ else }}{{ include "paperless-ngx.fullname" . }}-media{{ end }}
{{- else }}
- name: media
emptyDir: {}
@ -340,7 +351,7 @@ spec:
{{- if .Values.persistence.export.enabled }}
- name: export
persistentVolumeClaim:
claimName: {{ include "paperless-ngx.fullname" . }}-export
claimName: {{ if .Values.persistence.export.existingClaim }}{{ .Values.persistence.export.existingClaim }}{{ else }}{{ include "paperless-ngx.fullname" . }}-export{{ end }}
{{- else }}
- name: export
emptyDir: {}
@ -348,7 +359,7 @@ spec:
{{- if .Values.persistence.consume.enabled }}
- name: consume
persistentVolumeClaim:
claimName: {{ include "paperless-ngx.fullname" . }}-consume
claimName: {{ if .Values.persistence.consume.existingClaim }}{{ .Values.persistence.consume.existingClaim }}{{ else }}{{ include "paperless-ngx.fullname" . }}-consume{{ end }}
{{- else }}
- name: consume
emptyDir: {}

View File

@ -1,4 +1,4 @@
{{- if .Values.persistence.data.enabled }}
{{- if and .Values.persistence.data.enabled (not .Values.persistence.data.existingClaim) }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
@ -21,7 +21,7 @@ spec:
---
{{- end }}
{{- if .Values.persistence.media.enabled }}
{{- if and .Values.persistence.media.enabled (not .Values.persistence.media.existingClaim) }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
@ -44,7 +44,7 @@ spec:
---
{{- end }}
{{- if .Values.persistence.export.enabled }}
{{- if and .Values.persistence.export.enabled (not .Values.persistence.export.existingClaim) }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
@ -67,7 +67,7 @@ spec:
---
{{- end }}
{{- if .Values.persistence.consume.enabled }}
{{- if and .Values.persistence.consume.enabled (not .Values.persistence.consume.existingClaim) }}
apiVersion: v1
kind: PersistentVolumeClaim
metadata:

View File

@ -32,6 +32,7 @@ data:
{{- end }}
{{- if and .Values.redis.external.password (not .Values.redis.external.existingSecret) }}
{{ .Values.redis.external.passwordKey | default "redis-password" }}: {{ .Values.redis.external.password | b64enc }}
{{ .Values.redis.external.urlKey | default "redis-url" }}: {{ include "paperless-ngx.redis.url.withPassword" . | b64enc }}
{{- end }}
{{- if and .Values.config.admin.user (not .Values.config.admin.existingSecret) }}
{{ .Values.config.admin.userKey | default "admin-user" }}: {{ .Values.config.admin.user | b64enc }}

View File

@ -5,7 +5,7 @@ fullnameOverride: ""
## Image settings
image:
repository: ghcr.io/paperless-ngx/paperless-ngx
tag: "2.18.4"
tag: "2.20.3"
pullPolicy: IfNotPresent
## Deployment settings
@ -65,6 +65,7 @@ persistence:
# Paperless data directory (search index, classification model, etc.)
data:
enabled: true
existingClaim: ""
storageClass: ""
accessMode: ReadWriteOnce
size: 1Gi
@ -72,6 +73,7 @@ persistence:
# Paperless media directory (documents and thumbnails)
media:
enabled: true
existingClaim: ""
storageClass: ""
accessMode: ReadWriteOnce
size: 10Gi
@ -79,6 +81,7 @@ persistence:
# Export directory (for exporting documents)
export:
enabled: true
existingClaim: ""
storageClass: ""
accessMode: ReadWriteOnce
size: 1Gi
@ -86,6 +89,7 @@ persistence:
# Consume directory (for importing documents)
consume:
enabled: true
existingClaim: ""
storageClass: ""
accessMode: ReadWriteOnce
size: 5Gi
@ -161,9 +165,13 @@ redis:
# Authentication (leave empty if Redis has no auth)
username: "" # Optional: Redis username (Redis 6.0+)
# Use existingSecret for credentials if Redis has auth
# NOTE: When using existingSecret, the secret MUST contain a key with the full Redis URL
# Format: redis://[username]:[password]@host:port/database
existingSecret: ""
passwordKey: "redis-password"
urlKey: "redis-url" # Key in existingSecret containing the full Redis URL
passwordKey: "redis-password" # Key in existingSecret for password (for compatibility)
# Or set password directly (leave empty if no auth)
# When using plain password, the full Redis URL will be auto-generated in the secret
password: ""
# Optional: Prefix for Redis keys and channels
# Useful for sharing one Redis server among multiple Paperless instances

View File

@ -2,7 +2,7 @@ apiVersion: v2
name: qbittorrent-vpn
description: qBittorrent with Gluetun VPN sidecar for Kubernetes
type: application
version: 0.0.1
version: 0.0.2
appVersion: 5.1.0
maintainers:
- name: Richard Tomik

View File

@ -222,6 +222,45 @@ gluetun:
STATUS_FILE: "/tmp/gluetun-status.json"
```
### Custom Sidecar Containers
The chart supports adding custom sidecar containers to the pod. This is useful for adding additional functionality like port forwarding management (NATMap), monitoring, or other helper containers.
Sidecars are specified using the standard Kubernetes container specification:
```yaml
sidecars:
- name: natmap
image: ghcr.io/muink/natmap:latest
imagePullPolicy: IfNotPresent
env:
- name: GATEWAY
value: "10.2.0.1"
- name: INTERFACE
value: "tun0"
- name: INTERVAL
value: "30"
volumeMounts:
- name: config
mountPath: /config
subPath: natmap
```
**Common Use Cases:**
1. **NATMap**: Automatically update port forwarding configurations
2. **Monitoring**: Add monitoring agents or exporters
3. **Custom Scripts**: Run periodic maintenance or update tasks
**Sharing Volumes:**
Sidecars can access the same volumes as the main containers:
- `config`: qBittorrent configuration volume
- `downloads`: Downloads volume
- `gluetun-config`: Gluetun configuration volume (if enabled)
For the full Kubernetes container specification reference, see the [Kubernetes documentation](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.28/#container-v1-core).
## Troubleshooting
### VPN Connection Issues

View File

@ -255,7 +255,11 @@ spec:
resources:
{{- toYaml .Values.qbittorrent.resources | nindent 12 }}
{{- with .Values.sidecars }}
{{- toYaml . | nindent 8 }}
{{- end }}
volumes:
# Create /dev/net/tun as a device
- name: tun

View File

@ -225,4 +225,21 @@ extraVolumes: []
# Temporary options for development/debugging
hostNetwork: false
initContainers: []
initContainers: []
# Additional sidecar containers
# This allows you to add custom sidecar containers to the pod
# Each sidecar is specified using standard Kubernetes container spec
# Example: Add NATMap for port forwarding with VPN
# sidecars:
# - name: natmap
# image: ghcr.io/muink/natmap:latest
# env:
# - name: GATEWAY
# value: "10.2.0.1"
# - name: INTERFACE
# value: "tun0"
# volumeMounts:
# - name: config
# mountPath: /config
sidecars: []