feat: add helm charts
Signed-off-by: Thomas Stocker <thomas.stocker.pro@gmail.com>
This commit is contained in:
committed by
Bryan Frimin
parent
6d1760ce9b
commit
4a96bd796a
22
contrib/helm/.gitignore
vendored
Normal file
22
contrib/helm/.gitignore
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
# General files for the project
|
||||
pkg/*
|
||||
*.pyc
|
||||
bin/*
|
||||
.project
|
||||
/.bin
|
||||
/_test/secrets/*.json
|
||||
|
||||
# OSX leaves these everywhere on SMB shares
|
||||
._*
|
||||
|
||||
# OSX trash
|
||||
.DS_Store
|
||||
|
||||
# Files generated by JetBrains IDEs, e.g. IntelliJ IDEA
|
||||
.idea/
|
||||
*.iml
|
||||
|
||||
# Vscode files
|
||||
.vscode
|
||||
|
||||
charts/probo/charts
|
||||
474
contrib/helm/README.md
Normal file
474
contrib/helm/README.md
Normal file
@@ -0,0 +1,474 @@
|
||||
# Probo Kubernetes Deployment
|
||||
|
||||
This directory contains the Helm chart for deploying Probo on Kubernetes with external managed services.
|
||||
|
||||
## Quick Links
|
||||
|
||||
- [Helm Chart Documentation](charts/probo/README.md)
|
||||
- [Values Reference](charts/probo/values.yaml)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before deploying Probo, ensure you have:
|
||||
|
||||
1. **Kubernetes Cluster** - Version 1.23+
|
||||
2. **Helm** - Version 3.8+
|
||||
3. **PostgreSQL Database** - Managed service (AWS RDS, GCP Cloud SQL, Azure Database, etc.)
|
||||
4. **S3 Storage** - AWS S3 or S3-compatible storage (GCS, DigitalOcean Spaces, MinIO, etc.)
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Generate Secrets
|
||||
|
||||
```bash
|
||||
export ENCRYPTION_KEY=$(openssl rand -base64 32)
|
||||
export COOKIE_SECRET=$(openssl rand -base64 32)
|
||||
export PASSWORD_PEPPER=$(openssl rand -base64 32)
|
||||
export TRUST_TOKEN_SECRET=$(openssl rand -base64 32)
|
||||
|
||||
echo "Save these secrets securely!"
|
||||
```
|
||||
|
||||
### 2. Install
|
||||
|
||||
## Install
|
||||
|
||||
#### Using Official Chart Repository
|
||||
> Have Helm 3 [installed](https://helm.sh/docs/intro/install).
|
||||
|
||||
```sh
|
||||
helm repo add probo https://getprobo.github.io/probo-helm-charts/
|
||||
helm install probo probo/probo -n probo --create-namespace --values values.yaml
|
||||
```
|
||||
|
||||
To update versions:
|
||||
|
||||
```
|
||||
helm repo update probo
|
||||
helm upgrade probo probo/probo -n probo --values values.yaml
|
||||
```
|
||||
|
||||
#### Using Local Chart
|
||||
|
||||
##### Generate Secrets
|
||||
|
||||
```bash
|
||||
export ENCRYPTION_KEY=$(openssl rand -base64 32)
|
||||
export COOKIE_SECRET=$(openssl rand -base64 32)
|
||||
export PASSWORD_PEPPER=$(openssl rand -base64 32)
|
||||
export TRUST_TOKEN_SECRET=$(openssl rand -base64 32)
|
||||
|
||||
# Save these somewhere secure!
|
||||
echo "ENCRYPTION_KEY=$ENCRYPTION_KEY"
|
||||
echo "COOKIE_SECRET=$COOKIE_SECRET"
|
||||
echo "PASSWORD_PEPPER=$PASSWORD_PEPPER"
|
||||
echo "TRUST_TOKEN_SECRET=$TRUST_TOKEN_SECRET"
|
||||
```
|
||||
|
||||
##### Install using Chart and set values
|
||||
|
||||
```bash
|
||||
helm install my-probo ./charts/probo \
|
||||
--set probo.hostname="probo.example.com" \
|
||||
--set probo.encryptionKey="$ENCRYPTION_KEY" \
|
||||
--set probo.auth.cookieSecret="$COOKIE_SECRET" \
|
||||
--set probo.auth.passwordPepper="$PASSWORD_PEPPER" \
|
||||
--set probo.trustAuth.tokenSecret="$TRUST_TOKEN_SECRET" \
|
||||
--set postgresql.enabled=true \
|
||||
--set postgres.auth.postgresUser="probod" \
|
||||
--set postgres.auth.postgresPassword="your-db-password" \
|
||||
--set postgres.auth.database="probod" \
|
||||
--set minio.enabled=true \
|
||||
--set s3.bucket="your-bucket-name" \
|
||||
--set s3.accessKeyId="your-access-key" \
|
||||
--set s3.secretAccessKey="your-secret-key"
|
||||
```
|
||||
|
||||
##### Install using Chart and values file
|
||||
|
||||
|
||||
```bash
|
||||
helm install my-probo ./charts/probo \
|
||||
--set probo.encryptionKey="$ENCRYPTION_KEY" \
|
||||
--set probo.auth.cookieSecret="$COOKIE_SECRET" \
|
||||
--set probo.auth.passwordPepper="$PASSWORD_PEPPER" \
|
||||
--set probo.trustAuth.tokenSecret="$TRUST_TOKEN_SECRET" \
|
||||
-f ./charts/probo/values.yaml
|
||||
```
|
||||
|
||||
### 3. Access
|
||||
|
||||
```bash
|
||||
kubectl port-forward svc/probo 8080:8080
|
||||
# Visit http://localhost:8080
|
||||
```
|
||||
|
||||
## Production Deployment
|
||||
|
||||
For production deployments, we recommend:
|
||||
|
||||
1. **Copy the production template:**
|
||||
```bash
|
||||
cp charts/probo/values.yaml charts/probo/values-k8s-production.yaml
|
||||
```
|
||||
|
||||
2. **Edit the configuration:**
|
||||
- Set your domain name
|
||||
- Configure external PostgreSQL connection
|
||||
- Configure S3 storage credentials
|
||||
- Add SMTP settings for email
|
||||
- Enable ingress with TLS
|
||||
- Configure autoscaling
|
||||
|
||||
3. **Install:**
|
||||
```bash
|
||||
helm install probo ./charts/probo -f ./charts/probo/values-k8s-production.yaml
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
### What Gets Deployed
|
||||
|
||||
- **Probo Application** - Main Go binary serving GraphQL APIs and React frontends
|
||||
- **Chrome Headless** - For PDF generation (optional, can use external service)
|
||||
- **LoadBalancer Service** - For external access via TCP on ports 80, 443, and 8080
|
||||
- **Ingress** - Alternative to LoadBalancer for HTTP routing (optional)
|
||||
|
||||
### External Dependencies (Required)
|
||||
|
||||
- **PostgreSQL** - Managed database for compliance data
|
||||
- **S3 Storage** - Object storage for files and documents
|
||||
|
||||
The chart is designed to work with managed cloud services, ensuring reliability and scalability.
|
||||
|
||||
### Deployment Mode: HAProxy Ingress (Default)
|
||||
|
||||
The default configuration uses HAProxy Ingress controller which provides both Layer 4 (TCP passthrough) and Layer 7 (HTTP routing) capabilities.
|
||||
|
||||
**Architecture:**
|
||||
|
||||
```
|
||||
Client
|
||||
↓
|
||||
HAProxy Ingress LoadBalancer
|
||||
├─ Port 80 (TCP Layer 4 passthrough) → probo:80
|
||||
├─ Port 443 (TCP Layer 4 passthrough) → probo:443
|
||||
└─ HTTP probo.example.com (Layer 7 routing) → probo:8080
|
||||
```
|
||||
|
||||
**How it works:**
|
||||
|
||||
1. **HAProxy Ingress Controller** runs in the release namespace with a LoadBalancer service
|
||||
2. **TCP ConfigMap** defines Layer 4 TCP passthrough rules:
|
||||
- Port 80 → Probo service port 80
|
||||
- Port 443 → Probo service port 443
|
||||
3. **HTTP Ingress** defines Layer 7 HTTP routing:
|
||||
- Host `probo.example.com` → Probo service port 8080
|
||||
|
||||
**Benefits:**
|
||||
- Single LoadBalancer for both TCP and HTTP traffic
|
||||
- TCP passthrough for ports 80/443 (Probo handles TLS directly)
|
||||
- HTTP routing for backoffice on port 8080
|
||||
- Supports ACME/Let's Encrypt integration
|
||||
|
||||
**Port Configuration:**
|
||||
- **Port 80** - TCP passthrough to Probo:80 (HTTP service, ACME challenges)
|
||||
- **Port 443** - TCP passthrough to Probo:443 (HTTPS service with TLS)
|
||||
- **Port 8080** - HTTP routing to Probo:8080 (Backoffice, via host-based routing)
|
||||
|
||||
## Configuration
|
||||
|
||||
### Required Configuration
|
||||
|
||||
All deployments require:
|
||||
|
||||
- `probo.encryptionKey` - For data encryption at rest
|
||||
- `probo.auth.cookieSecret` - For session management
|
||||
- `probo.auth.passwordPepper` - For password hashing
|
||||
- `probo.trustAuth.tokenSecret` - For trust center tokens
|
||||
- `postgresql.host` - PostgreSQL server hostname
|
||||
- `postgresql.password` - Database password
|
||||
- `s3.accessKeyId` - S3 access credentials
|
||||
- `s3.secretAccessKey` - S3 secret key
|
||||
|
||||
See [values.yaml](charts/probo/values.yaml) for all available options.
|
||||
|
||||
|
||||
## Cloud Provider Examples
|
||||
|
||||
### AWS
|
||||
- PostgreSQL: Amazon RDS for PostgreSQL
|
||||
- Storage: Amazon S3
|
||||
- Kubernetes: Amazon EKS
|
||||
|
||||
#### Exemple
|
||||
```bash
|
||||
# Prerequisites:
|
||||
# - Amazon RDS PostgreSQL instance
|
||||
# - S3 bucket created
|
||||
|
||||
helm install my-probo ././charts/probo \
|
||||
--set probo.encryptionKey="$ENCRYPTION_KEY" \
|
||||
--set probo.auth.cookieSecret="$COOKIE_SECRET" \
|
||||
--set probo.auth.passwordPepper="$PASSWORD_PEPPER" \
|
||||
--set probo.trustAuth.tokenSecret="$TRUST_TOKEN_SECRET" \
|
||||
--set postgresql.host="mydb.abc123.us-east-1.rds.amazonaws.com" \
|
||||
--set postgresql.password="<rds-password>" \
|
||||
--set s3.region="us-east-1" \
|
||||
--set s3.bucket="my-probo-bucket" \
|
||||
--set s3.accessKeyId="<aws-access-key>" \
|
||||
--set s3.secretAccessKey="<aws-secret-key>"
|
||||
```
|
||||
|
||||
### GCP
|
||||
- PostgreSQL: Cloud SQL for PostgreSQL
|
||||
- Storage: Cloud Storage with S3 compatibility
|
||||
- Kubernetes: Google Kubernetes Engine (GKE)
|
||||
|
||||
#### Exemple
|
||||
|
||||
```bash
|
||||
# Prerequisites:
|
||||
# - Cloud SQL PostgreSQL instance
|
||||
# - Cloud Storage bucket with HMAC keys
|
||||
|
||||
helm install my-probo ././charts/probo \
|
||||
--set probo.encryptionKey="$ENCRYPTION_KEY" \
|
||||
--set probo.auth.cookieSecret="$COOKIE_SECRET" \
|
||||
--set probo.auth.passwordPepper="$PASSWORD_PEPPER" \
|
||||
--set probo.trustAuth.tokenSecret="$TRUST_TOKEN_SECRET" \
|
||||
--set postgresql.host="10.0.0.5" \
|
||||
--set postgresql.password="<cloudsql-password>" \
|
||||
--set s3.endpoint="https://storage.googleapis.com" \
|
||||
--set s3.bucket="my-probo-bucket" \
|
||||
--set s3.accessKeyId="<hmac-access-key>" \
|
||||
--set s3.secretAccessKey="<hmac-secret>"
|
||||
```
|
||||
|
||||
### Azure
|
||||
- PostgreSQL: Azure Database for PostgreSQL
|
||||
- Storage: Azure Blob Storage (with S3 compatibility)
|
||||
- Kubernetes: Azure Kubernetes Service (AKS)
|
||||
|
||||
#### Exemple
|
||||
|
||||
|
||||
```bash
|
||||
# Prerequisites:
|
||||
# - Azure Database for PostgreSQL instance
|
||||
# - Azure Blob Storage container with S3 compatibility
|
||||
helm install my-probo ././charts/probo \
|
||||
--set probo.encryptionKey="$ENCRYPTION_KEY" \
|
||||
--set probo.auth.cookieSecret="$COOKIE_SECRET" \
|
||||
--set probo.auth.passwordPepper="$PASSWORD_PEPPER" \
|
||||
--set probo.trustAuth.tokenSecret="$TRUST_TOKEN_SECRET" \
|
||||
--set postgresql.host="mydb.postgres.database.azure.com" \
|
||||
--set postgresql.password="<azure-db-password>" \
|
||||
--set s3.endpoint="https://<your-storage-account>.blob.core.windows.net" \
|
||||
--set s3.bucket="my-probo-bucket" \
|
||||
--set s3.accessKeyId="<azure-access-key>" \
|
||||
--set s3.secretAccessKey="<azure-secret-key>"
|
||||
```
|
||||
|
||||
### DigitalOcean
|
||||
- PostgreSQL: Managed PostgreSQL Database
|
||||
- Storage: DigitalOcean Spaces
|
||||
- Kubernetes: DigitalOcean Kubernetes (DOKS)
|
||||
|
||||
#### Exemple
|
||||
```bash
|
||||
# Prerequisites:
|
||||
# - Managed PostgreSQL Database
|
||||
# - Spaces bucket
|
||||
|
||||
helm install my-probo ././charts/probo \
|
||||
--set probo.encryptionKey="$ENCRYPTION_KEY" \
|
||||
--set probo.auth.cookieSecret="$COOKIE_SECRET" \
|
||||
--set probo.auth.passwordPepper="$PASSWORD_PEPPER" \
|
||||
--set probo.trustAuth.tokenSecret="$TRUST_TOKEN_SECRET" \
|
||||
--set postgresql.host="db-postgresql-nyc1-12345.ondigitalocean.com" \
|
||||
--set postgresql.password="<db-password>" \
|
||||
--set s3.region="nyc3" \
|
||||
--set s3.endpoint="https://nyc3.digitaloceanspaces.com" \
|
||||
--set s3.bucket="my-probo-bucket" \
|
||||
--set s3.accessKeyId="<spaces-key>" \
|
||||
--set s3.secretAccessKey="<spaces-secret>"
|
||||
```
|
||||
|
||||
### Using External Secrets Operator
|
||||
|
||||
Example with AWS Secrets Manager:
|
||||
|
||||
```yaml
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: probo-secrets
|
||||
spec:
|
||||
secretStoreRef:
|
||||
name: aws-secrets-manager
|
||||
kind: SecretStore
|
||||
target:
|
||||
name: probo
|
||||
data:
|
||||
- secretKey: encryption-key
|
||||
remoteRef:
|
||||
key: probo/encryption-key
|
||||
- secretKey: db-password
|
||||
remoteRef:
|
||||
key: probo/db-password
|
||||
```
|
||||
|
||||
## Full Values
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
|-----------------------------------------------| ------- |----------------------------------------------------|-----------------------------------------------------------------------------------------------------|
|
||||
| replicaCount | int | `1` | Number of Probo application replicas |
|
||||
| image.repository | string | `"ghcr.io/getprobo/probo"` | Container image repository |
|
||||
| image.pullPolicy | string | `"IfNotPresent"` | Image pull policy |
|
||||
| image.tag | string | `"latest"` | Overrides the image tag whose default is the chart appVersion |
|
||||
| imagePullSecrets | list | `[]` | Image pull secrets for private registries |
|
||||
| nameOverride | string | `""` | Override the name of the chart |
|
||||
| fullnameOverride | string | `""` | Override the fullname of the chart |
|
||||
| serviceAccount.create | bool | `true` | Specifies whether a service account should be created |
|
||||
| serviceAccount.automount | bool | `true` | Automatically mount a ServiceAccount's API credentials |
|
||||
| serviceAccount.annotations | object | `{}` | Annotations to add to the service account |
|
||||
| serviceAccount.name | string | `""` | The name of the service account to use |
|
||||
| podAnnotations | object | `{}` | Annotations to add to pods |
|
||||
| podLabels | object | `{}` | Labels to add to pods |
|
||||
| podSecurityContext.runAsUser | int | `0` | User ID to run the container as (0 = root, change to 1000 for production) |
|
||||
| podSecurityContext.runAsGroup | int | `0` | Group ID to run the container as (0 = root, change to 1000 for production) |
|
||||
| securityContext.runAsUser | int | `0` | User ID for the security context |
|
||||
| securityContext.runAsGroup | int | `0` | Group ID for the security context |
|
||||
| securityContext.privileged | bool | `true` | Enable privileged mode for the container (set to false for production) |
|
||||
| securityContext.capabilities.drop | list | `["ALL"]` | Linux capabilities to drop from the container |
|
||||
| securityContext.readOnlyRootFilesystem | bool | `false` | Mount root filesystem as read-only (/data directory requires write access) |
|
||||
| service.type | string | `"ClusterIP"` | Kubernetes service type |
|
||||
| service.port | int | `8080` | Service port |
|
||||
| service.httpPort | int | `80` | HTTP port for TCP passthrough |
|
||||
| service.httpsPort | int | `443` | HTTPS port for TCP passthrough |
|
||||
| service.annotations | object | `{}` | Annotations for the service |
|
||||
| haproxy-ingress.enabled | bool | `true` | Enable included HAProxy Ingress controller |
|
||||
| haproxy-ingress.controller.ingressClass | string | `"haproxy"` | Ingress class name for the controller |
|
||||
| haproxy-ingress.controller.ingressClassResource.enabled | bool | `true` | Enable IngressClass resource creation |
|
||||
| haproxy-ingress.controller.ingressClassResource.name | string | `"haproxy"` | Name of the IngressClass resource |
|
||||
| haproxy-ingress.controller.ingressClassResource.default | bool | `false` | Set as default IngressClass |
|
||||
| haproxy-ingress.controller.service.type | string | `"LoadBalancer"` | HAProxy Ingress controller service type |
|
||||
| haproxy-ingress.controller.extraArgs | list | `["--tcp-services-configmap=$(POD_NAMESPACE)/haproxy-tcp-services"]` | Extra arguments for HAProxy controller |
|
||||
| haproxy-ingress.controller.config.ssl-redirect | string | `"false"` | Disable automatic SSL redirect |
|
||||
| ingress.enabled | bool | `true` | Enable ingress resource |
|
||||
| ingress.className | string | `"haproxy"` | Ingress class name |
|
||||
| ingress.annotations | object | `{"kubernetes.io/ingress.class": "haproxy"}` | Annotations for the ingress resource |
|
||||
| ingress.hosts[0].host | string | `"probo.example.com"` | Ingress hostname |
|
||||
| ingress.hosts[0].paths[0].path | string | `"/"` | Path to match |
|
||||
| ingress.hosts[0].paths[0].pathType | string | `"Prefix"` | Path matching type |
|
||||
| ingress.tls | list | `[]` | TLS configuration for ingress |
|
||||
| resources.limits.cpu | string | `"2000m"` | CPU limit for the container |
|
||||
| resources.limits.memory | string | `"2Gi"` | Memory limit for the container |
|
||||
| resources.requests.cpu | string | `"500m"` | CPU request for the container |
|
||||
| resources.requests.memory | string | `"512Mi"` | Memory request for the container |
|
||||
| livenessProbe.httpGet.path | string | `"/"` | Path for the liveness probe |
|
||||
| livenessProbe.httpGet.port | string | `"http"` | Port for the liveness probe |
|
||||
| livenessProbe.initialDelaySeconds | int | `30` | Initial delay for liveness probe |
|
||||
| livenessProbe.periodSeconds | int | `10` | Period for liveness probe |
|
||||
| livenessProbe.timeoutSeconds | int | `5` | Timeout for liveness probe |
|
||||
| livenessProbe.failureThreshold | int | `6` | Failure threshold for liveness probe |
|
||||
| readinessProbe.httpGet.path | string | `"/"` | Path for the readiness probe |
|
||||
| readinessProbe.httpGet.port | string | `"http"` | Port for the readiness probe |
|
||||
| readinessProbe.initialDelaySeconds | int | `10` | Initial delay for readiness probe |
|
||||
| readinessProbe.periodSeconds | int | `5` | Period for readiness probe |
|
||||
| readinessProbe.timeoutSeconds | int | `3` | Timeout for readiness probe |
|
||||
| readinessProbe.failureThreshold | int | `3` | Failure threshold for readiness probe |
|
||||
| autoscaling.enabled | bool | `false` | Enable horizontal pod autoscaling |
|
||||
| autoscaling.minReplicas | int | `1` | Minimum number of replicas |
|
||||
| autoscaling.maxReplicas | int | `10` | Maximum number of replicas |
|
||||
| autoscaling.targetCPUUtilizationPercentage | int | `80` | Target CPU utilization percentage |
|
||||
| volumes | list | `[]` | Additional volumes on the output Deployment definition |
|
||||
| volumeMounts | list | `[]` | Additional volumeMounts on the output Deployment definition |
|
||||
| nodeSelector | object | `{}` | Node selector for pod assignment |
|
||||
| tolerations | list | `[]` | Tolerations for pod assignment |
|
||||
| affinity | object | `{}` | Affinity rules for pod assignment |
|
||||
| persistence.enabled | bool | `false` | Enable persistent volume for data storage |
|
||||
| persistence.storageClass | string | `""` | Storage class for the persistent volume |
|
||||
| persistence.accessMode | string | `"ReadWriteOnce"` | Access mode for the persistent volume |
|
||||
| persistence.size | string | `"10Gi"` | Size of the persistent volume |
|
||||
| persistence.annotations | object | `{}` | Annotations for the persistent volume claim |
|
||||
| metrics.serviceMonitor.enabled | bool | `false` | Enable Prometheus Operator ServiceMonitor |
|
||||
| metrics.serviceMonitor.interval | string | `"30s"` | Scrape interval for metrics |
|
||||
| metrics.serviceMonitor.scrapeTimeout | string | `"10s"` | Scrape timeout for metrics |
|
||||
| metrics.serviceMonitor.labels | object | `{}` | Labels for the ServiceMonitor |
|
||||
| metrics.serviceMonitor.relabelings | list | `[]` | Relabeling configs for the ServiceMonitor |
|
||||
| probo.hostname | string | `"probo.example.com"` | Public hostname where Probo will be accessible |
|
||||
| probo.encryptionKey | string | `""` | **REQUIRED** Base64-encoded encryption key (generate with: openssl rand -base64 32) |
|
||||
| probo.service.port | int | `8080` | Probo application service port |
|
||||
| probo.metrics.port | int | `8081` | Probo metrics service port |
|
||||
| probo.tracing.enabled | bool | `false` | Enable OpenTelemetry tracing |
|
||||
| probo.tracing.addr | string | `""` | OTLP gRPC endpoint (e.g., tempo:4317) |
|
||||
| probo.tracing.maxBatchSize | int | `512` | Maximum batch size for trace exports |
|
||||
| probo.tracing.batchTimeout | int | `5` | Batch timeout in seconds |
|
||||
| probo.tracing.exportTimeout | int | `30` | Export timeout in seconds |
|
||||
| probo.tracing.maxQueueSize | int | `2048` | Maximum queue size for traces |
|
||||
| probo.cors.allowedOrigins | list | `["https://probo.example.com", "http://..."]` | CORS allowed origins |
|
||||
| probo.extraHeaderFields | object | `{}` | Extra HTTP headers to add to responses |
|
||||
| probo.auth.disableSignup | bool | `false` | Disable user signup |
|
||||
| probo.auth.invitationTokenValidity | int | `3600` | Invitation token validity in seconds |
|
||||
| probo.auth.cookieName | string | `"SSID"` | Authentication cookie name |
|
||||
| probo.auth.cookieDomain | string | `"probo.example.com"` | Authentication cookie domain |
|
||||
| probo.auth.cookieSecret | string | `""` | **REQUIRED** Cookie signing secret (at least 32 bytes, generate with: openssl rand -base64 32) |
|
||||
| probo.auth.cookieDuration | int | `24` | Cookie duration in hours |
|
||||
| probo.auth.passwordPepper | string | `""` | **REQUIRED** Password hashing pepper (at least 32 bytes, generate with: openssl rand -base64 32) |
|
||||
| probo.auth.passwordIterations | int | `1000000` | Password hashing iterations |
|
||||
| probo.trustAuth.cookieName | string | `"TCT"` | Trust center cookie name |
|
||||
| probo.trustAuth.cookieDomain | string | `"probo.example.com"` | Trust center cookie domain |
|
||||
| probo.trustAuth.cookieDuration | int | `24` | Trust center cookie duration in hours |
|
||||
| probo.trustAuth.tokenDuration | int | `168` | Trust token duration in hours |
|
||||
| probo.trustAuth.reportUrlDuration | int | `15` | Report URL duration in minutes |
|
||||
| probo.trustAuth.tokenSecret | string | `""` | **REQUIRED** Trust token signing secret (at least 32 bytes, generate with: openssl rand -base64 32) |
|
||||
| probo.trustAuth.scope | string | `"trust_center_readonly"` | Trust token scope |
|
||||
| probo.trustAuth.tokenType | string | `"trust_center_access"` | Trust token type |
|
||||
| probo.mailer.senderName | string | `"Probo"` | Email sender name |
|
||||
| probo.mailer.senderEmail | string | `"no-reply@notification.getprobo.com"` | Email sender address |
|
||||
| probo.mailer.smtp.addr | string | `"sandbox.smtp.mailtrap.io:2525"` | SMTP server address |
|
||||
| probo.mailer.smtp.user | string | `"2d1b1d0e8b3d0b"` | SMTP username |
|
||||
| probo.mailer.smtp.password | string | `"25a8eb11e75e8d"` | SMTP password |
|
||||
| probo.mailer.smtp.tlsRequired | bool | `true` | Require TLS for SMTP connection |
|
||||
| probo.openai.apiKey | string | `""` | OpenAI API key for AI features (optional) |
|
||||
| probo.openai.temperature | float | `0.1` | OpenAI temperature setting |
|
||||
| probo.openai.modelName | string | `"gpt-4o"` | OpenAI model name |
|
||||
| probo.customDomains.enabled | bool | `false` | Enable custom domains feature |
|
||||
| probo.customDomains.renewalInterval | int | `3600` | Certificate renewal interval in seconds |
|
||||
| probo.customDomains.provisionInterval | int | `30` | Domain provision interval in seconds |
|
||||
| probo.customDomains.cnameTarget | string | `"probo.example.com"` | CNAME target for custom domains |
|
||||
| probo.customDomains.acme.directory | string | `"https://acme-v02.api.letsencrypt.org/directory"` | ACME directory URL |
|
||||
| probo.customDomains.acme.email | string | `"admin@example.com"` | ACME registration email |
|
||||
| probo.customDomains.acme.keyType | string | `"EC256"` | ACME key type |
|
||||
| probo.customDomains.acme.insecureTls | bool | `false` | Allow insecure TLS for ACME |
|
||||
| probo.connectors | list | `[]` | External OAuth2 connectors configuration |
|
||||
| postgresql.enabled | bool | `true` | Enable included PostgreSQL container for demo purposes using CloudNativePG |
|
||||
| postgresql.resources.limits.memory | string | `"2Gi"` | PostgreSQL memory limit |
|
||||
| postgresql.resources.limits.ephemeral-storage | string | `"5Gi"` | PostgreSQL ephemeral storage limit |
|
||||
| postgresql.auth.postgresUser | string | `"probod"` | PostgreSQL username |
|
||||
| postgresql.auth.postgresPassword | string | `"probod"` | PostgreSQL password |
|
||||
| postgresql.auth.database | string | `"probod"` | PostgreSQL database name |
|
||||
| s3.region | string | `"us-east-1"` | S3 region |
|
||||
| s3.bucket | string | `"probod"` | S3 bucket name |
|
||||
| s3.endpoint | string | `""` | S3 endpoint (leave empty for AWS S3, set for S3-compatible storage) |
|
||||
| s3.accessKeyId | string | `""` | **REQUIRED** (when minio.enabled=false) S3 access key |
|
||||
| s3.secretAccessKey | string | `""` | **REQUIRED** (when minio.enabled=false) S3 secret key |
|
||||
| minio.enabled | bool | `true` | Enable included MinIO for demo purposes (NOT for production) |
|
||||
| minio.mode | string | `"standalone"` | MinIO mode |
|
||||
| minio.persistence.enabled | bool | `false` | Enable MinIO persistence |
|
||||
| minio.resources.requests.memory | string | `"128Mi"` | MinIO memory request |
|
||||
| minio.primary.enabled | bool | `true` | Enable MinIO primary node |
|
||||
| minio.auth.rootUser | string | `"probod"` | MinIO root username |
|
||||
| minio.auth.rootPassword | string | `"probod"` | MinIO root password |
|
||||
| chrome.enabled | bool | `true` | Deploy Chrome headless in the cluster for PDF generation |
|
||||
| chrome.replicaCount | int | `1` | Number of Chrome replicas |
|
||||
| chrome.image.repository | string | `"chromedp/headless-shell"` | Chrome container image repository |
|
||||
| chrome.image.tag | string | `"140.0.7259.2"` | Chrome image tag |
|
||||
| chrome.image.pullPolicy | string | `"IfNotPresent"` | Chrome image pull policy |
|
||||
| chrome.resources.limits.cpu | string | `"1000m"` | Chrome CPU limit |
|
||||
| chrome.resources.limits.memory | string | `"1Gi"` | Chrome memory limit |
|
||||
| chrome.resources.requests.cpu | string | `"100m"` | Chrome CPU request |
|
||||
| chrome.resources.requests.memory | string | `"256Mi"` | Chrome memory request |
|
||||
| chrome.external.addr | string | `""` | External Chrome address (used when chrome.enabled=false) |
|
||||
23
contrib/helm/charts/probo/.helmignore
Normal file
23
contrib/helm/charts/probo/.helmignore
Normal file
@@ -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/
|
||||
87
contrib/helm/charts/probo/CONFIG_NOTE.md
Normal file
87
contrib/helm/charts/probo/CONFIG_NOTE.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# Configuration Note
|
||||
|
||||
## Environment Variable Substitution
|
||||
|
||||
The Helm chart templates use a `-from-env` suffix pattern in the configuration file (e.g., `encryption-key-from-env: "ENCRYPTION_KEY"`). This pattern assumes the Probo application supports reading secrets from environment variables instead of directly from the config file.
|
||||
|
||||
### Current Implementation
|
||||
|
||||
The chart currently:
|
||||
1. Stores sensitive values in a Kubernetes Secret
|
||||
2. Mounts them as environment variables in the pod
|
||||
3. References them in the config with `-from-env` suffix
|
||||
|
||||
### If Probo Doesn't Support `-from-env` Pattern
|
||||
|
||||
If the current Probo application doesn't support the `-from-env` pattern, you have three options:
|
||||
|
||||
#### Option 1: Implement in Probo (Recommended)
|
||||
|
||||
Update the Probo configuration parser to recognize `-from-env` suffixes and read from environment variables. This is the most secure approach.
|
||||
|
||||
Example in Go:
|
||||
```go
|
||||
// In config loading code
|
||||
if strings.HasSuffix(key, "-from-env") {
|
||||
envVar := value.(string)
|
||||
actualValue := os.Getenv(envVar)
|
||||
// Use actualValue instead of value
|
||||
}
|
||||
```
|
||||
|
||||
#### Option 2: Use initContainer with envsubst
|
||||
|
||||
Modify the deployment to use an init container that substitutes environment variables:
|
||||
|
||||
```yaml
|
||||
initContainers:
|
||||
- name: config-init
|
||||
image: alpine:3.19
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
apk add --no-cache gettext
|
||||
envsubst < /config-template/config.yaml > /config/config.yaml
|
||||
env:
|
||||
# All environment variables from secrets
|
||||
- name: ENCRYPTION_KEY
|
||||
valueFrom: ...
|
||||
volumeMounts:
|
||||
- name: config-template
|
||||
mountPath: /config-template
|
||||
- name: config
|
||||
mountPath: /config
|
||||
```
|
||||
|
||||
Then update the ConfigMap to use `${ENCRYPTION_KEY}` instead of the `-from-env` pattern.
|
||||
|
||||
#### Option 3: Mount Everything as Secret
|
||||
|
||||
Create a complete config.yaml as a Secret (not ConfigMap) with actual values:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: probo-config
|
||||
stringData:
|
||||
config.yaml: |
|
||||
probod:
|
||||
encryption-key: {{ .Values.probo.encryptionKey }}
|
||||
# ... all config with actual values
|
||||
```
|
||||
|
||||
This is simpler but less secure as the entire config is stored as a Secret.
|
||||
|
||||
## Recommendation
|
||||
|
||||
We recommend implementing Option 1 in the Probo codebase as it:
|
||||
- Follows Kubernetes best practices
|
||||
- Keeps secrets separate from configuration
|
||||
- Works well with secret management tools (Vault, External Secrets, etc.)
|
||||
- Supports secret rotation without config changes
|
||||
|
||||
## Current Status
|
||||
|
||||
The Helm chart is built with Option 1 in mind. If the Probo application doesn't yet support `-from-env`, please implement it or use one of the alternative approaches above.
|
||||
9
contrib/helm/charts/probo/Chart.lock
Normal file
9
contrib/helm/charts/probo/Chart.lock
Normal file
@@ -0,0 +1,9 @@
|
||||
dependencies:
|
||||
- name: minio
|
||||
repository: https://charts.min.io/
|
||||
version: 5.4.0
|
||||
- name: kubernetes-ingress
|
||||
repository: https://haproxytech.github.io/helm-charts
|
||||
version: 1.45.1
|
||||
digest: sha256:86861ee988df3673c6306ff42719f09d12ce22e2d48a0db757ad4365d204bd85
|
||||
generated: "2025-10-31T10:17:36.108938+01:00"
|
||||
29
contrib/helm/charts/probo/Chart.yaml
Normal file
29
contrib/helm/charts/probo/Chart.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
apiVersion: v2
|
||||
name: probo
|
||||
description: A Helm chart for deploying Probo - Open Source Compliance Platform
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "0.74.7"
|
||||
keywords:
|
||||
- compliance
|
||||
- soc2
|
||||
- security
|
||||
- governance
|
||||
home: https://getprobo.com
|
||||
sources:
|
||||
- https://github.com/getprobo/probo
|
||||
maintainers:
|
||||
- name: Probo Team
|
||||
email: hello@getprobo.com
|
||||
icon: https://github.com/getprobo/probo/blob/main/.github/cover_v3.png
|
||||
|
||||
dependencies:
|
||||
- name: minio
|
||||
condition: minio.enabled
|
||||
repository: https://charts.min.io/
|
||||
version: 5.4.0 # Latest stable version
|
||||
- name: kubernetes-ingress
|
||||
alias: haproxy-ingress
|
||||
condition: haproxy-ingress.enabled
|
||||
version: 1.45.1
|
||||
repository: https://haproxytech.github.io/helm-charts
|
||||
267
contrib/helm/charts/probo/README.md
Normal file
267
contrib/helm/charts/probo/README.md
Normal file
@@ -0,0 +1,267 @@
|
||||
# Probo Helm Chart
|
||||
|
||||
This Helm chart deploys Probo - an open-source SOC-2 compliance platform - on Kubernetes.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Kubernetes 1.23+
|
||||
- Helm 3.8+
|
||||
- External PostgreSQL database (AWS RDS, GCP Cloud SQL, Azure Database, etc.)
|
||||
- S3 or S3-compatible object storage (AWS S3, GCS, DigitalOcean Spaces, MinIO, etc.)
|
||||
|
||||
## Installing the Chart
|
||||
|
||||
### Generate Required Secrets
|
||||
|
||||
```bash
|
||||
# Generate required secrets
|
||||
export ENCRYPTION_KEY=$(openssl rand -base64 32)
|
||||
export COOKIE_SECRET=$(openssl rand -base64 32)
|
||||
export PASSWORD_PEPPER=$(openssl rand -base64 32)
|
||||
export TRUST_TOKEN_SECRET=$(openssl rand -base64 32)
|
||||
|
||||
echo "Save these secrets securely!"
|
||||
```
|
||||
|
||||
### Install
|
||||
|
||||
```bash
|
||||
helm install probo . \
|
||||
--set probo.hostname="probo.example.com" \
|
||||
--set probo.encryptionKey="$ENCRYPTION_KEY" \
|
||||
--set probo.auth.cookieSecret="$COOKIE_SECRET" \
|
||||
--set probo.auth.passwordPepper="$PASSWORD_PEPPER" \
|
||||
--set probo.trustAuth.tokenSecret="$TRUST_TOKEN_SECRET" \
|
||||
--set postgresql.host="postgres.example.com" \
|
||||
--set postgresql.password="<db-password>" \
|
||||
--set s3.bucket="probo-production" \
|
||||
--set s3.accessKeyId="<aws-access-key-id>" \
|
||||
--set s3.secretAccessKey="<aws-secret-access-key>"
|
||||
```
|
||||
|
||||
### Production Deployment
|
||||
|
||||
For production, create a `values-production.yaml` file:
|
||||
|
||||
```yaml
|
||||
# values-production.yaml
|
||||
image:
|
||||
repository: ghcr.io/getprobo/probo
|
||||
tag: "0.74.7"
|
||||
|
||||
replicaCount: 3
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: "nginx"
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
hosts:
|
||||
- host: probo.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: probo-tls
|
||||
hosts:
|
||||
- probo.example.com
|
||||
|
||||
probo:
|
||||
hostname: "probo.example.com"
|
||||
encryptionKey: "<secret>"
|
||||
cors:
|
||||
allowedOrigins:
|
||||
- "https://probo.example.com"
|
||||
auth:
|
||||
cookieDomain: "example.com"
|
||||
cookieSecret: "<secret>"
|
||||
passwordPepper: "<secret>"
|
||||
trustAuth:
|
||||
cookieDomain: "example.com"
|
||||
tokenSecret: "<secret>"
|
||||
mailer:
|
||||
senderEmail: "noreply@example.com"
|
||||
smtp:
|
||||
addr: "smtp.sendgrid.net:587"
|
||||
user: "apikey"
|
||||
password: "<smtp-password>"
|
||||
tlsRequired: true
|
||||
|
||||
postgresql:
|
||||
host: "postgres.example.com"
|
||||
password: "<db-password>"
|
||||
|
||||
s3:
|
||||
region: "us-east-1"
|
||||
bucket: "probo-production"
|
||||
accessKeyId: "<aws-access-key-id>"
|
||||
secretAccessKey: "<aws-secret-access-key>"
|
||||
|
||||
autoscaling:
|
||||
enabled: true
|
||||
minReplicas: 3
|
||||
maxReplicas: 10
|
||||
```
|
||||
|
||||
Install with:
|
||||
|
||||
```bash
|
||||
helm install probo . -f values-production.yaml
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Required Configuration
|
||||
|
||||
The following parameters **must** be configured:
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------|-------------|
|
||||
| `probo.encryptionKey` | Base64-encoded encryption key (32+ bytes) |
|
||||
| `probo.auth.cookieSecret` | Cookie signing secret (32+ bytes) |
|
||||
| `probo.auth.passwordPepper` | Password hashing pepper (32+ bytes) |
|
||||
| `probo.trustAuth.tokenSecret` | Trust token secret (32+ bytes) |
|
||||
| `postgresql.host` | PostgreSQL hostname |
|
||||
| `postgresql.password` | PostgreSQL password |
|
||||
| `s3.accessKeyId` | S3 access key ID |
|
||||
| `s3.secretAccessKey` | S3 secret access key |
|
||||
|
||||
### Key Configuration Parameters
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `image.repository` | Probo image repository | `ghcr.io/getprobo/probo` |
|
||||
| `image.tag` | Probo image tag | Chart appVersion |
|
||||
| `replicaCount` | Number of Probo replicas | `1` |
|
||||
| `probo.hostname` | Public hostname | `probo.example.com` |
|
||||
| `postgresql.host` | PostgreSQL host | `""` (required) |
|
||||
| `postgresql.port` | PostgreSQL port | `5432` |
|
||||
| `postgresql.database` | Database name | `probod` |
|
||||
| `postgresql.username` | Database user | `probod` |
|
||||
| `s3.bucket` | S3 bucket name | `probod` |
|
||||
| `s3.region` | AWS region | `us-east-1` |
|
||||
| `s3.endpoint` | S3 endpoint (for S3-compatible) | `""` |
|
||||
| `chrome.enabled` | Deploy Chrome | `true` |
|
||||
| `chrome.external.addr` | External Chrome (if disabled) | `""` |
|
||||
| `ingress.enabled` | Enable ingress | `false` |
|
||||
|
||||
See [values.yaml](values.yaml) for all available options.
|
||||
|
||||
## Components
|
||||
|
||||
The chart deploys the following:
|
||||
|
||||
- **Probo Application**: Main Go binary serving GraphQL APIs and SPAs
|
||||
- **Chrome Headless**: For PDF generation (optional, can use external)
|
||||
- **Ingress**: For external access with TLS (optional)
|
||||
|
||||
### External Dependencies (Required)
|
||||
|
||||
- **PostgreSQL**: Managed database service
|
||||
- **S3 Storage**: Object storage for files and documents
|
||||
|
||||
## Database Management
|
||||
|
||||
### Migrations
|
||||
|
||||
Database migrations run automatically when Probo starts. No manual intervention is required.
|
||||
|
||||
### Backup
|
||||
|
||||
Use your PostgreSQL provider's backup solution (e.g., AWS RDS automated backups, GCP Cloud SQL backups).
|
||||
|
||||
## Upgrading
|
||||
|
||||
```bash
|
||||
helm upgrade probo . -f values-production.yaml
|
||||
```
|
||||
|
||||
## Uninstalling
|
||||
|
||||
```bash
|
||||
helm uninstall probo
|
||||
```
|
||||
|
||||
**Note:** This does not delete your external PostgreSQL database or S3 bucket.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### View Logs
|
||||
|
||||
```bash
|
||||
kubectl logs -f deployment/probo
|
||||
```
|
||||
|
||||
### Check Configuration
|
||||
|
||||
```bash
|
||||
kubectl describe configmap probo
|
||||
kubectl get secret probo -o yaml
|
||||
```
|
||||
|
||||
### Test Database Connection
|
||||
|
||||
Check the Probo logs for database connection errors. The application will fail to start if it cannot connect to PostgreSQL.
|
||||
|
||||
### Test S3 Connection
|
||||
|
||||
Check the Probo logs for S3 connection errors when uploading files.
|
||||
|
||||
## Examples
|
||||
|
||||
### AWS Deployment
|
||||
|
||||
```yaml
|
||||
postgresql:
|
||||
host: "mydb.abc123.us-east-1.rds.amazonaws.com"
|
||||
password: "<rds-password>"
|
||||
|
||||
s3:
|
||||
region: "us-east-1"
|
||||
bucket: "my-probo-bucket"
|
||||
accessKeyId: "<aws-key>"
|
||||
secretAccessKey: "<aws-secret>"
|
||||
# Leave endpoint empty for AWS S3
|
||||
```
|
||||
|
||||
### GCP Deployment
|
||||
|
||||
```yaml
|
||||
postgresql:
|
||||
host: "10.0.0.5" # Cloud SQL private IP
|
||||
password: "<cloudsql-password>"
|
||||
|
||||
s3:
|
||||
region: "us-east1"
|
||||
bucket: "my-probo-bucket"
|
||||
endpoint: "https://storage.googleapis.com"
|
||||
accessKeyId: "<hmac-access-key>"
|
||||
secretAccessKey: "<hmac-secret>"
|
||||
```
|
||||
|
||||
### DigitalOcean Deployment
|
||||
|
||||
```yaml
|
||||
postgresql:
|
||||
host: "db-postgresql-nyc1-12345.ondigitalocean.com"
|
||||
password: "<db-password>"
|
||||
|
||||
s3:
|
||||
region: "nyc3"
|
||||
bucket: "my-probo-bucket"
|
||||
endpoint: "https://nyc3.digitaloceanspaces.com"
|
||||
accessKeyId: "<spaces-access-key>"
|
||||
secretAccessKey: "<spaces-secret>"
|
||||
|
||||
```
|
||||
|
||||
### Using External Chrome Service
|
||||
|
||||
By default, Chrome is deployed in the cluster. To use an external Chrome service:
|
||||
|
||||
```yaml
|
||||
chrome:
|
||||
enabled: false
|
||||
external:
|
||||
addr: "chrome.browserless.io:3000"
|
||||
```
|
||||
84
contrib/helm/charts/probo/templates/NOTES.txt
Normal file
84
contrib/helm/charts/probo/templates/NOTES.txt
Normal file
@@ -0,0 +1,84 @@
|
||||
🎉 Probo has been successfully deployed!
|
||||
|
||||
📋 Release Information:
|
||||
Name: {{ .Release.Name }}
|
||||
Namespace: {{ .Release.Namespace }}
|
||||
Version: {{ .Chart.AppVersion }}
|
||||
|
||||
🌐 Accessing Probo:
|
||||
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range $host := .Values.ingress.hosts }}
|
||||
Application: {{ if $.Values.ingress.tls }}https{{ else }}http{{ end }}://{{ $host.host }}
|
||||
{{- end }}
|
||||
{{- else if contains "NodePort" .Values.service.type }}
|
||||
Get the application URL by running:
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "probo.fullname" . }})
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo "Application: http://$NODE_IP:$NODE_PORT"
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch the status by running:
|
||||
kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "probo.fullname" . }}
|
||||
|
||||
Once available, get the application URL by running:
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "probo.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
|
||||
echo "Application: http://$SERVICE_IP:{{ .Values.service.port }}"
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
Application is available only within the cluster.
|
||||
|
||||
To access it from your local machine, run:
|
||||
kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ include "probo.fullname" . }} 8080:{{ .Values.service.port }}
|
||||
|
||||
Then visit: http://localhost:8080
|
||||
{{- end }}
|
||||
|
||||
📊 Monitoring:
|
||||
Metrics endpoint: http://{{ include "probo.fullname" . }}:{{ .Values.probo.metrics.port }}/metrics
|
||||
|
||||
To access metrics from your local machine, run:
|
||||
kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ include "probo.fullname" . }} 8081:{{ .Values.probo.metrics.port }}
|
||||
|
||||
🔍 View Logs:
|
||||
kubectl --namespace {{ .Release.Namespace }} logs -f deployment/{{ include "probo.fullname" . }}
|
||||
|
||||
🗄️ Database:
|
||||
Using external PostgreSQL at: {{ .Values.postgresql.host }}:{{ .Values.postgresql.port }}
|
||||
Database: {{ .Values.postgresql.database }}
|
||||
|
||||
💾 Object Storage:
|
||||
Using S3 storage
|
||||
Bucket: {{ .Values.s3.bucket }}
|
||||
Region: {{ .Values.s3.region }}
|
||||
{{- if .Values.s3.endpoint }}
|
||||
Endpoint: {{ .Values.s3.endpoint }}
|
||||
{{- end }}
|
||||
|
||||
⚠️ Important Security Notes:
|
||||
|
||||
{{- if not .Values.ingress.tls }}
|
||||
⚠️ TLS is not enabled! Enable it for production by configuring ingress.tls
|
||||
{{- end }}
|
||||
|
||||
📚 Next Steps:
|
||||
|
||||
1. Update the hostname in values.yaml to match your domain:
|
||||
probo.hostname: "{{ .Values.probo.hostname }}"
|
||||
|
||||
2. Configure email delivery:
|
||||
Update probo.mailer.smtp settings with your SMTP server details.
|
||||
|
||||
{{- if not .Values.probo.openai.apiKey }}
|
||||
3. (Optional) Configure OpenAI integration for AI-powered features:
|
||||
Set probo.openai.apiKey in values.yaml
|
||||
{{- end }}
|
||||
|
||||
4. Review and update CORS allowed origins:
|
||||
probo.cors.allowedOrigins
|
||||
|
||||
📖 Documentation:
|
||||
- GitHub: https://github.com/getprobo/probo
|
||||
- Discord: https://discord.gg/8qfdJYfvpY
|
||||
- Website: https://getprobo.com
|
||||
|
||||
✨ Thank you for using Probo!
|
||||
159
contrib/helm/charts/probo/templates/_helpers.tpl
Normal file
159
contrib/helm/charts/probo/templates/_helpers.tpl
Normal file
@@ -0,0 +1,159 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "probo.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
*/}}
|
||||
{{- define "probo.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 "probo.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "probo.labels" -}}
|
||||
helm.sh/chart: {{ include "probo.chart" . }}
|
||||
{{ include "probo.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "probo.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "probo.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "probo.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "probo.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
PostgreSQL hostname
|
||||
*/}}
|
||||
{{- define "probo.postgresql.host" -}}
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
{{- printf "%s-postgresql-demo" .Release.Name }}
|
||||
{{- else }}
|
||||
{{- .Values.postgresql.host | required "postgresql.host is required when postgresql.enabled=false" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
PostgreSQL port
|
||||
*/}}
|
||||
{{- define "probo.postgresql.port" -}}
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
{{- 5432 }}
|
||||
{{- else }}
|
||||
{{- .Values.postgresql.port | default 5432 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
PostgreSQL database name
|
||||
*/}}
|
||||
{{- define "probo.postgresql.database" -}}
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
{{- .Values.postgresql.auth.database | default "probod" }}
|
||||
{{- else }}
|
||||
{{- .Values.postgresql.database | default "probod" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
PostgreSQL username
|
||||
*/}}
|
||||
{{- define "probo.postgresql.username" -}}
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
{{- .Values.postgresql.auth.postgresUser | default "probod" }}
|
||||
{{- else }}
|
||||
{{- .Values.postgresql.username | default "probod" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
PostgreSQL password (from subchart or external config)
|
||||
*/}}
|
||||
{{- define "probo.postgresql.password" -}}
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
{{- .Values.postgresql.auth.postgresPassword | required "postgresql.auth.postgresPassword is required when postgresql.enabled=true" }}
|
||||
{{- else }}
|
||||
{{- .Values.postgresql.password | required "postgresql.password is required when postgresql.enabled=false" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
S3 endpoint
|
||||
*/}}
|
||||
{{- define "probo.s3.endpoint" -}}
|
||||
{{- if .Values.minio.enabled }}
|
||||
{{- printf "http://%s-minio:9000" .Release.Name }}
|
||||
{{- else }}
|
||||
{{- .Values.s3.endpoint }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
S3 access key
|
||||
*/}}
|
||||
{{- define "probo.s3.accessKeyId" -}}
|
||||
{{- if .Values.minio.enabled }}
|
||||
{{- .Values.minio.auth.rootUser | required "minio.auth.rootUser is required when minio.enabled=true" }}
|
||||
{{- else }}
|
||||
{{- .Values.s3.accessKeyId | required "s3.accessKeyId is required when minio.enabled=false" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
S3 secret key
|
||||
*/}}
|
||||
{{- define "probo.s3.secretAccessKey" -}}
|
||||
{{- if .Values.minio.enabled }}
|
||||
{{- .Values.minio.auth.rootPassword | required "minio.auth.rootPassword is required when minio.enabled=true" }}
|
||||
{{- else }}
|
||||
{{- .Values.s3.secretAccessKey | required "s3.secretAccessKey is required when minio.enabled=false" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Chrome DevTools Protocol address
|
||||
*/}}
|
||||
{{- define "probo.chrome.addr" -}}
|
||||
{{- if .Values.chrome.enabled }}
|
||||
{{- printf "%s-chrome:9222" (include "probo.fullname" .) }}
|
||||
{{- else }}
|
||||
{{- .Values.chrome.external.addr | required "chrome.external.addr is required when chrome.enabled=false" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
77
contrib/helm/charts/probo/templates/chrome.yaml
Normal file
77
contrib/helm/charts/probo/templates/chrome.yaml
Normal file
@@ -0,0 +1,77 @@
|
||||
{{- if .Values.chrome.enabled }}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "probo.fullname" . }}-chrome
|
||||
labels:
|
||||
{{- include "probo.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: chrome
|
||||
spec:
|
||||
replicas: {{ .Values.chrome.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "probo.selectorLabels" . | nindent 6 }}
|
||||
app.kubernetes.io/component: chrome
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "probo.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: chrome
|
||||
spec:
|
||||
containers:
|
||||
- name: chrome
|
||||
image: "{{ .Values.chrome.image.repository }}:{{ .Values.chrome.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.chrome.image.pullPolicy }}
|
||||
args:
|
||||
- --headless
|
||||
- --disable-gpu
|
||||
- --disable-dev-shm-usage
|
||||
- --hide-scrollbars
|
||||
- --mute-audio
|
||||
- --no-default-browser-check
|
||||
- --no-first-run
|
||||
- --disable-background-networking
|
||||
- --disable-background-timer-throttling
|
||||
- --disable-extensions
|
||||
ports:
|
||||
- name: devtools
|
||||
containerPort: 9222
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /json/version
|
||||
port: devtools
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /json/version
|
||||
port: devtools
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 5
|
||||
resources:
|
||||
{{- toYaml .Values.chrome.resources | nindent 12 }}
|
||||
securityContext:
|
||||
capabilities:
|
||||
add:
|
||||
- SYS_ADMIN
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "probo.fullname" . }}-chrome
|
||||
labels:
|
||||
{{- include "probo.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: chrome
|
||||
spec:
|
||||
type: ClusterIP
|
||||
ports:
|
||||
- port: 9222
|
||||
targetPort: devtools
|
||||
protocol: TCP
|
||||
name: devtools
|
||||
selector:
|
||||
{{- include "probo.selectorLabels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: chrome
|
||||
{{- end }}
|
||||
119
contrib/helm/charts/probo/templates/configmap.yaml
Normal file
119
contrib/helm/charts/probo/templates/configmap.yaml
Normal file
@@ -0,0 +1,119 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ include "probo.fullname" . }}
|
||||
labels:
|
||||
{{- include "probo.labels" . | nindent 4 }}
|
||||
data:
|
||||
config.yml: |
|
||||
unit:
|
||||
metrics:
|
||||
addr: "0.0.0.0:{{ .Values.probo.metrics.port }}"
|
||||
{{- if .Values.probo.tracing.enabled }}
|
||||
tracing:
|
||||
addr: {{ .Values.probo.tracing.addr | quote }}
|
||||
max-batch-size: {{ .Values.probo.tracing.maxBatchSize }}
|
||||
batch-timeout: {{ .Values.probo.tracing.batchTimeout }}
|
||||
export-timeout: {{ .Values.probo.tracing.exportTimeout }}
|
||||
max-queue-size: {{ .Values.probo.tracing.maxQueueSize }}
|
||||
{{- end }}
|
||||
|
||||
probod:
|
||||
hostname: {{ .Values.probo.hostname | quote }}
|
||||
encryption-key: {{ .Values.probo.encryptionKey | quote }}
|
||||
chrome-dp-addr: {{ include "probo.chrome.addr" . | quote }}
|
||||
|
||||
api:
|
||||
addr: "0.0.0.0:{{ .Values.service.port }}"
|
||||
cors:
|
||||
allowed-origins:
|
||||
{{- toYaml .Values.probo.cors.allowedOrigins | nindent 12 }}
|
||||
{{- if .Values.probo.extraHeaderFields }}
|
||||
extra-header-fields:
|
||||
{{- toYaml .Values.probo.extraHeaderFields | nindent 10 }}
|
||||
{{- end }}
|
||||
|
||||
pg:
|
||||
addr: "{{ include "probo.postgresql.host" . }}:{{ include "probo.postgresql.port" . }}"
|
||||
username: {{ include "probo.postgresql.username" . | quote }}
|
||||
password: {{ include "probo.postgresql.password" . | quote }}
|
||||
database: {{ include "probo.postgresql.database" . | quote }}
|
||||
pool-size: {{ .Values.postgresql.poolSize }}
|
||||
{{- if .Values.postgresql.caCertBundle }}
|
||||
ca-cert-bundle: |
|
||||
{{- .Values.postgresql.caCertBundle | nindent 10 }}
|
||||
{{- end }}
|
||||
|
||||
auth:
|
||||
disable-signup: {{ .Values.probo.auth.disableSignup }}
|
||||
invitation-confirmation-token-validity: {{ .Values.probo.auth.invitationTokenValidity }}
|
||||
cookie:
|
||||
name: {{ .Values.probo.auth.cookieName | quote }}
|
||||
domain: {{ .Values.probo.auth.cookieDomain | quote }}
|
||||
secret: {{ .Values.probo.auth.cookieSecret | quote }}
|
||||
duration: {{ .Values.probo.auth.cookieDuration }}
|
||||
password:
|
||||
pepper: {{ .Values.probo.auth.passwordPepper | quote }}
|
||||
iterations: {{ .Values.probo.auth.passwordIterations }}
|
||||
|
||||
trust-auth:
|
||||
cookie-name: {{ .Values.probo.trustAuth.cookieName | quote }}
|
||||
cookie-domain: {{ .Values.probo.trustAuth.cookieDomain | quote }}
|
||||
cookie-duration: {{ .Values.probo.trustAuth.cookieDuration }}
|
||||
token-duration: {{ .Values.probo.trustAuth.tokenDuration }}
|
||||
report-url-duration: {{ .Values.probo.trustAuth.reportUrlDuration }}
|
||||
{{- if .Values.probo.trustAuth.ports }}
|
||||
ports:
|
||||
http-challenge: {{ .Values.probo.trustAuth.ports.httpChallenge }}
|
||||
tls-http-server: {{ .Values.probo.trustAuth.ports.tlsHttpServer }}
|
||||
{{- end }}
|
||||
token-secret: {{ .Values.probo.trustAuth.tokenSecret | quote }}
|
||||
scope: {{ .Values.probo.trustAuth.scope | quote }}
|
||||
token-type: {{ .Values.probo.trustAuth.tokenType | quote }}
|
||||
|
||||
aws:
|
||||
region: {{ .Values.s3.region | quote }}
|
||||
bucket: {{ .Values.s3.bucket | quote }}
|
||||
access-key-id: {{ .Values.s3.accessKey | quote }}
|
||||
secret-access-key: {{ .Values.s3.secretKey | quote }}
|
||||
{{- $s3Endpoint := include "probo.s3.endpoint" . }}
|
||||
{{- if $s3Endpoint }}
|
||||
endpoint: {{ $s3Endpoint | quote }}
|
||||
{{- end }}
|
||||
|
||||
mailer:
|
||||
sender-name: {{ .Values.probo.mailer.senderName | quote }}
|
||||
sender-email: {{ .Values.probo.mailer.senderEmail | quote }}
|
||||
smtp:
|
||||
addr: {{ .Values.probo.mailer.smtp.addr | quote }}
|
||||
{{- if .Values.probo.mailer.smtp.user }}
|
||||
user: {{ .Values.probo.mailer.smtp.user | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.probo.mailer.smtp.password }}
|
||||
password: {{ .Values.probo.mailer.smtp.password | quote }}
|
||||
{{- end }}
|
||||
tls-required: {{ .Values.probo.mailer.smtp.tlsRequired }}
|
||||
|
||||
{{- if .Values.probo.openai.apiKey }}
|
||||
openai:
|
||||
api-key-from-env: "OPENAI_API_KEY"
|
||||
temperature: {{ .Values.probo.openai.temperature }}
|
||||
model-name: {{ .Values.probo.openai.modelName | quote }}
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.probo.customDomains.enabled }}
|
||||
custom-domains:
|
||||
renewal-interval: {{ .Values.probo.customDomains.renewalInterval }}
|
||||
provision-interval: {{ .Values.probo.customDomains.provisionInterval }}
|
||||
cname-target: {{ .Values.probo.customDomains.cnameTarget | quote }}
|
||||
acme:
|
||||
directory: {{ .Values.probo.customDomains.acme.directory | quote }}
|
||||
email: {{ .Values.probo.customDomains.acme.email | quote }}
|
||||
key-type: {{ .Values.probo.customDomains.acme.keyType | quote }}
|
||||
insecure-tls: {{ .Values.probo.customDomains.acme.insecureTls }}
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.probo.connectors }}
|
||||
connectors:
|
||||
{{- toYaml .Values.probo.connectors | nindent 8 }}
|
||||
{{- end }}
|
||||
162
contrib/helm/charts/probo/templates/deployment.yaml
Normal file
162
contrib/helm/charts/probo/templates/deployment.yaml
Normal file
@@ -0,0 +1,162 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "probo.fullname" . }}
|
||||
labels:
|
||||
{{- include "probo.labels" . | nindent 4 }}
|
||||
spec:
|
||||
{{- if not .Values.autoscaling.enabled }}
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "probo.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
|
||||
checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
|
||||
{{- with .Values.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "probo.labels" . | nindent 8 }}
|
||||
{{- with .Values.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "probo.serviceAccountName" . }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
command: ["/bin/sh", "-c"] # replaces ENTRYPOINT
|
||||
args: ["echo $DB_PASSWORD && cat /etc/probod/config.yml && exec /usr/local/bin/probod -cfg-file /etc/probod/config.yml"]
|
||||
|
||||
# args:
|
||||
# - "-cfg-file"
|
||||
# - "/etc/probod/config.yml"
|
||||
env:
|
||||
# Database credentials
|
||||
- name: DB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "probo.fullname" . }}
|
||||
key: db-password
|
||||
# S3 credentials
|
||||
- name: S3_ACCESS_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "probo.fullname" . }}
|
||||
key: s3-access-key
|
||||
- name: S3_SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "probo.fullname" . }}
|
||||
key: s3-secret-key
|
||||
# Application secrets
|
||||
- name: ENCRYPTION_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "probo.fullname" . }}
|
||||
key: encryption-key
|
||||
- name: COOKIE_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "probo.fullname" . }}
|
||||
key: cookie-secret
|
||||
- name: PASSWORD_PEPPER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "probo.fullname" . }}
|
||||
key: password-pepper
|
||||
- name: TRUST_TOKEN_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "probo.fullname" . }}
|
||||
key: trust-token-secret
|
||||
# Optional SMTP credentials
|
||||
{{- if .Values.probo.mailer.smtp.user }}
|
||||
- name: SMTP_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "probo.fullname" . }}
|
||||
key: smtp-user
|
||||
{{- end }}
|
||||
{{- if .Values.probo.mailer.smtp.password }}
|
||||
- name: SMTP_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "probo.fullname" . }}
|
||||
key: smtp-password
|
||||
{{- end }}
|
||||
# Optional OpenAI API key
|
||||
{{- if .Values.probo.openai.apiKey }}
|
||||
- name: OPENAI_API_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "probo.fullname" . }}
|
||||
key: openai-api-key
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.service.httpPort }}
|
||||
protocol: TCP
|
||||
- name: https
|
||||
containerPort: {{ .Values.service.httpsPort }}
|
||||
protocol: TCP
|
||||
- name: backoffice
|
||||
containerPort: {{ .Values.service.port }}
|
||||
protocol: TCP
|
||||
- name: metrics
|
||||
containerPort: {{ .Values.probo.metrics.port }}
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.livenessProbe | nindent 12 }}
|
||||
readinessProbe:
|
||||
{{- toYaml .Values.readinessProbe | nindent 12 }}
|
||||
resources:
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /etc/probod
|
||||
readOnly: false
|
||||
- name: data
|
||||
mountPath: /data
|
||||
{{- with .Values.volumeMounts }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: {{ include "probo.fullname" . }}
|
||||
- name: data
|
||||
{{- if .Values.persistence.enabled }}
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ .Values.persistence.existingClaim | default (include "probo.fullname" .) }}
|
||||
{{- else }}
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
{{- with .Values.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 }}
|
||||
@@ -0,0 +1,16 @@
|
||||
{{- if index .Values "haproxy-ingress" "enabled" -}}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: haproxy-tcp-services
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "probo.labels" . | nindent 4 }}
|
||||
data:
|
||||
# TCP passthrough for port 80 (HTTP)
|
||||
# Format: "<port>": "<namespace>/<service>:<port>"
|
||||
"80": "{{ .Release.Namespace }}/{{ include "probo.fullname" . }}:{{ .Values.service.httpPort }}"
|
||||
|
||||
# TCP passthrough for port 443 (HTTPS)
|
||||
"443": "{{ .Release.Namespace }}/{{ include "probo.fullname" . }}:{{ .Values.service.httpsPort }}"
|
||||
{{- end }}
|
||||
32
contrib/helm/charts/probo/templates/hpa.yaml
Normal file
32
contrib/helm/charts/probo/templates/hpa.yaml
Normal file
@@ -0,0 +1,32 @@
|
||||
{{- if .Values.autoscaling.enabled }}
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ include "probo.fullname" . }}
|
||||
labels:
|
||||
{{- include "probo.labels" . | nindent 4 }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{ include "probo.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 }}
|
||||
41
contrib/helm/charts/probo/templates/ingress.yaml
Normal file
41
contrib/helm/charts/probo/templates/ingress.yaml
Normal file
@@ -0,0 +1,41 @@
|
||||
{{- if .Values.ingress.enabled -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ include "probo.fullname" . }}-http
|
||||
labels:
|
||||
{{- include "probo.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
{{- with .Values.ingress.annotations }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.className }}
|
||||
ingressClassName: {{ .Values.ingress.className }}
|
||||
{{- 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 }}
|
||||
pathType: {{ .pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "probo.fullname" $ }}
|
||||
port:
|
||||
number: {{ $.Values.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
81
contrib/helm/charts/probo/templates/postgresql-demo-app.yml
Normal file
81
contrib/helm/charts/probo/templates/postgresql-demo-app.yml
Normal file
@@ -0,0 +1,81 @@
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "probo.fullname" . }}-postgresql-demo
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: {{ include "probo.fullname" . }}-postgresql-demo
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ include "probo.fullname" . }}-postgresql-demo
|
||||
spec:
|
||||
containers:
|
||||
- name: postgres
|
||||
image: postgres:18
|
||||
env:
|
||||
- name: POSTGRES_USER
|
||||
value: {{ .Values.postgresql.auth.postgresUser }}
|
||||
- name: POSTGRES_PASSWORD
|
||||
value: {{ .Values.postgresql.auth.postgresPassword }}
|
||||
- name: POSTGRES_DB
|
||||
value: {{ .Values.postgresql.auth.database }}
|
||||
ports:
|
||||
- containerPort: 5432
|
||||
volumeMounts:
|
||||
- name: postgres-init
|
||||
mountPath: /docker-entrypoint-initdb.d
|
||||
readOnly: true
|
||||
resources:
|
||||
{{- toYaml .Values.postgresql.resources | nindent 12 }}
|
||||
volumes:
|
||||
- name: postgres-init
|
||||
configMap:
|
||||
name: {{ include "probo.fullname" . }}-postgres-init
|
||||
defaultMode: 0755
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-postgresql-demo
|
||||
spec:
|
||||
selector:
|
||||
app: {{ include "probo.fullname" . }}-postgresql-demo
|
||||
ports:
|
||||
- port: 5432
|
||||
targetPort: 5432
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ include "probo.fullname" . }}-postgres-init
|
||||
labels:
|
||||
{{- include "probo.labels" . | nindent 4 }}
|
||||
data:
|
||||
01_probod.sh: |
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
psql -v ON_ERROR_STOP=1 -U $POSTGRES_USER <<-EOF
|
||||
ALTER USER probod WITH SUPERUSER;
|
||||
ALTER USER probod PASSWORD 'probod';
|
||||
GRANT ALL PRIVILEGES ON DATABASE probod TO probod;
|
||||
CREATE DATABASE probod_test;
|
||||
GRANT ALL PRIVILEGES ON DATABASE probod_test TO probod;
|
||||
EOF
|
||||
|
||||
psql -v ON_ERROR_STOP=1 -U $POSTGRES_USER -d probod <<-EOF
|
||||
ALTER SCHEMA public OWNER TO probod;
|
||||
GRANT ALL ON SCHEMA public TO probod;
|
||||
EOF
|
||||
|
||||
psql -v ON_ERROR_STOP=1 -U $POSTGRES_USER -d probod_test <<-EOF
|
||||
ALTER SCHEMA public OWNER TO probod;
|
||||
GRANT ALL ON SCHEMA public TO probod;
|
||||
EOF
|
||||
---
|
||||
{{- end -}}
|
||||
25
contrib/helm/charts/probo/templates/pvc.yaml
Normal file
25
contrib/helm/charts/probo/templates/pvc.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ include "probo.fullname" . }}
|
||||
labels:
|
||||
{{- include "probo.labels" . | nindent 4 }}
|
||||
{{- with .Values.persistence.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
accessModes:
|
||||
- {{ .Values.persistence.accessMode | quote }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.persistence.size | quote }}
|
||||
{{- if .Values.persistence.storageClass }}
|
||||
{{- if (eq "-" .Values.persistence.storageClass) }}
|
||||
storageClassName: ""
|
||||
{{- else }}
|
||||
storageClassName: {{ .Values.persistence.storageClass | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
33
contrib/helm/charts/probo/templates/secret.yaml
Normal file
33
contrib/helm/charts/probo/templates/secret.yaml
Normal file
@@ -0,0 +1,33 @@
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "probo.fullname" . }}
|
||||
labels:
|
||||
{{- include "probo.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
# Database credentials
|
||||
db-password: {{ include "probo.postgresql.password" . | quote }}
|
||||
|
||||
# S3 credentials
|
||||
s3-access-key: {{ include "probo.s3.accessKeyId" . | quote }}
|
||||
s3-secret-key: {{ include "probo.s3.secretAccessKey" . | quote }}
|
||||
|
||||
# Application secrets
|
||||
encryption-key: {{ .Values.probo.encryptionKey | required "probo.encryptionKey is required" | quote }}
|
||||
cookie-secret: {{ .Values.probo.auth.cookieSecret | required "probo.auth.cookieSecret is required" | quote }}
|
||||
password-pepper: {{ .Values.probo.auth.passwordPepper | required "probo.auth.passwordPepper is required" | quote }}
|
||||
trust-token-secret: {{ .Values.probo.trustAuth.tokenSecret | required "probo.trustAuth.tokenSecret is required" | quote }}
|
||||
|
||||
# Optional SMTP credentials
|
||||
{{- if .Values.probo.mailer.smtp.user }}
|
||||
smtp-user: {{ .Values.probo.mailer.smtp.user | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.probo.mailer.smtp.password }}
|
||||
smtp-password: {{ .Values.probo.mailer.smtp.password | quote }}
|
||||
{{- end }}
|
||||
|
||||
# Optional OpenAI API key
|
||||
{{- if .Values.probo.openai.apiKey }}
|
||||
openai-api-key: {{ .Values.probo.openai.apiKey | quote }}
|
||||
{{- end }}
|
||||
44
contrib/helm/charts/probo/templates/service.yaml
Normal file
44
contrib/helm/charts/probo/templates/service.yaml
Normal file
@@ -0,0 +1,44 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "probo.fullname" . }}
|
||||
labels:
|
||||
{{- include "probo.labels" . | nindent 4 }}
|
||||
{{- with .Values.service.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
{{- if and .Values.service.clusterIP (eq .Values.service.type "ClusterIP") }}
|
||||
clusterIP: {{ .Values.service.clusterIP }}
|
||||
{{- end }}
|
||||
{{- if .Values.service.loadBalancerIP }}
|
||||
loadBalancerIP: {{ .Values.service.loadBalancerIP }}
|
||||
{{- end }}
|
||||
{{- if .Values.service.loadBalancerSourceRanges }}
|
||||
loadBalancerSourceRanges:
|
||||
{{- toYaml .Values.service.loadBalancerSourceRanges | nindent 4 }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- port: {{ .Values.service.httpPort }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
- port: {{ .Values.service.httpsPort }}
|
||||
targetPort: https
|
||||
protocol: TCP
|
||||
name: https
|
||||
- port: {{ .Values.service.port }}
|
||||
targetPort: backoffice
|
||||
protocol: TCP
|
||||
name: backoffice
|
||||
{{- if and (eq .Values.service.type "NodePort") .Values.service.nodePort }}
|
||||
nodePort: {{ .Values.service.nodePort }}
|
||||
{{- end }}
|
||||
- port: {{ .Values.probo.metrics.port }}
|
||||
targetPort: metrics
|
||||
protocol: TCP
|
||||
name: metrics
|
||||
selector:
|
||||
{{- include "probo.selectorLabels" . | nindent 4 }}
|
||||
13
contrib/helm/charts/probo/templates/serviceaccount.yaml
Normal file
13
contrib/helm/charts/probo/templates/serviceaccount.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "probo.serviceAccountName" . }}
|
||||
labels:
|
||||
{{- include "probo.labels" . | nindent 4 }}
|
||||
{{- with .Values.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
automountServiceAccountToken: {{ .Values.serviceAccount.automount }}
|
||||
{{- end }}
|
||||
24
contrib/helm/charts/probo/templates/servicemonitor.yaml
Normal file
24
contrib/helm/charts/probo/templates/servicemonitor.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
{{- if .Values.metrics.serviceMonitor.enabled }}
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: {{ include "probo.fullname" . }}
|
||||
labels:
|
||||
{{- include "probo.labels" . | nindent 4 }}
|
||||
{{- with .Values.metrics.serviceMonitor.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "probo.selectorLabels" . | nindent 6 }}
|
||||
endpoints:
|
||||
- port: metrics
|
||||
path: /metrics
|
||||
interval: {{ .Values.metrics.serviceMonitor.interval }}
|
||||
scrapeTimeout: {{ .Values.metrics.serviceMonitor.scrapeTimeout }}
|
||||
{{- with .Values.metrics.serviceMonitor.relabelings }}
|
||||
relabelings:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
311
contrib/helm/charts/probo/values-production.yaml.example
Normal file
311
contrib/helm/charts/probo/values-production.yaml.example
Normal file
@@ -0,0 +1,311 @@
|
||||
# Production values for probo.
|
||||
# This file provides a template for production deployment.
|
||||
# Copy this file to values-production.yaml and customize it for your environment.
|
||||
|
||||
# Use specific version tag
|
||||
image:
|
||||
repository: ghcr.io/getprobo/probo
|
||||
tag: "0.74.7"
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
# Scale for high availability
|
||||
replicaCount: 3
|
||||
|
||||
# Production security context (non-root user)
|
||||
podSecurityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000 # probo user (UID defined in Dockerfile)
|
||||
runAsGroup: 1000
|
||||
fsGroup: 1000
|
||||
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
readOnlyRootFilesystem: false # /data directory requires write access
|
||||
runAsUser: 1000
|
||||
runAsGroup: 1000
|
||||
|
||||
# Service configuration
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 8080
|
||||
httpPort: 80
|
||||
httpsPort: 443
|
||||
annotations: {}
|
||||
|
||||
# Production resource limits
|
||||
resources:
|
||||
limits:
|
||||
cpu: 2000m
|
||||
memory: 4Gi
|
||||
requests:
|
||||
cpu: 1000m
|
||||
memory: 2Gi
|
||||
|
||||
# Enable horizontal pod autoscaling
|
||||
autoscaling:
|
||||
enabled: true
|
||||
minReplicas: 3
|
||||
maxReplicas: 10
|
||||
targetCPUUtilizationPercentage: 70
|
||||
targetMemoryUtilizationPercentage: 80
|
||||
|
||||
# HAProxy Ingress Controller configuration
|
||||
haproxy-ingress:
|
||||
enabled: true
|
||||
controller:
|
||||
ingressClass: haproxy
|
||||
ingressClassResource:
|
||||
enabled: true
|
||||
name: haproxy
|
||||
default: false
|
||||
name: controller
|
||||
service:
|
||||
type: LoadBalancer
|
||||
annotations:
|
||||
# Cloud provider annotations for LoadBalancer
|
||||
# AWS example:
|
||||
# service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
|
||||
# GCP example:
|
||||
# cloud.google.com/load-balancer-type: "External"
|
||||
extraArgs:
|
||||
- --tcp-services-configmap=$(POD_NAMESPACE)/haproxy-tcp-services
|
||||
config:
|
||||
ssl-redirect: "false" # Probo handles SSL internally
|
||||
|
||||
# Configure ingress with TLS
|
||||
ingress:
|
||||
enabled: true
|
||||
className: "haproxy"
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: haproxy
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
hosts:
|
||||
- host: probo.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
- secretName: probo-tls
|
||||
hosts:
|
||||
- probo.example.com
|
||||
|
||||
# Probo application configuration
|
||||
probo:
|
||||
# Must match your ingress hostname
|
||||
hostname: "probo.example.com"
|
||||
|
||||
# REQUIRED: Generate with: openssl rand -base64 32
|
||||
encryptionKey: "CHANGE_ME_ENCRYPTION_KEY"
|
||||
|
||||
service:
|
||||
port: 8080
|
||||
|
||||
metrics:
|
||||
port: 8081
|
||||
|
||||
# CORS configuration - add all domains that will access the API
|
||||
cors:
|
||||
allowedOrigins:
|
||||
- "https://probo.example.com"
|
||||
|
||||
# Extra HTTP headers to add to responses
|
||||
extraHeaderFields: {}
|
||||
# X-Custom-Header: "custom-value"
|
||||
|
||||
# Authentication
|
||||
auth:
|
||||
# Set to true to disable public signup
|
||||
disableSignup: false
|
||||
# Cookie domain should be your root domain
|
||||
cookieDomain: "example.com"
|
||||
# REQUIRED: Generate with: openssl rand -base64 32
|
||||
cookieSecret: "CHANGE_ME_COOKIE_SECRET"
|
||||
# REQUIRED: Generate with: openssl rand -base64 32
|
||||
passwordPepper: "CHANGE_ME_PASSWORD_PEPPER"
|
||||
|
||||
# Trust center authentication
|
||||
trustAuth:
|
||||
cookieName: "TCT"
|
||||
cookieDomain: "example.com"
|
||||
cookieDuration: 24
|
||||
tokenDuration: 168
|
||||
reportUrlDuration: 15
|
||||
ports:
|
||||
httpChallenge: 80
|
||||
tlsHttpServer: 443
|
||||
# REQUIRED: Generate with: openssl rand -base64 32
|
||||
tokenSecret: "CHANGE_ME_TRUST_TOKEN_SECRET"
|
||||
scope: "trust_center_readonly"
|
||||
tokenType: "trust_center_access"
|
||||
|
||||
# Email configuration
|
||||
mailer:
|
||||
senderName: "Probo"
|
||||
senderEmail: "noreply@example.com"
|
||||
smtp:
|
||||
# Use your SMTP provider (e.g., SendGrid, Mailgun, AWS SES)
|
||||
addr: "smtp.sendgrid.net:587"
|
||||
user: "apikey"
|
||||
password: "CHANGE_ME_SMTP_PASSWORD"
|
||||
tlsRequired: true
|
||||
|
||||
# OpenAI integration for AI features (optional)
|
||||
openai:
|
||||
apiKey: "CHANGE_ME_OPENAI_API_KEY"
|
||||
temperature: 0.1
|
||||
modelName: "gpt-4o"
|
||||
|
||||
# OpenTelemetry tracing (optional)
|
||||
tracing:
|
||||
enabled: true
|
||||
addr: "tempo.monitoring:4317"
|
||||
maxBatchSize: 1000
|
||||
batchTimeout: 10
|
||||
exportTimeout: 30
|
||||
maxQueueSize: 10000
|
||||
|
||||
# Custom domains with Let's Encrypt (optional)
|
||||
customDomains:
|
||||
enabled: true
|
||||
renewalInterval: 86400 # 24 hours
|
||||
provisionInterval: 300 # 5 minutes
|
||||
cnameTarget: "custom.example.com"
|
||||
acme:
|
||||
directory: "https://acme-v02.api.letsencrypt.org/directory"
|
||||
email: "admin@example.com"
|
||||
keyType: "EC256"
|
||||
insecureTls: false
|
||||
|
||||
# External OAuth2 connectors (optional)
|
||||
connectors:
|
||||
- name: "github"
|
||||
type: "oauth2"
|
||||
config:
|
||||
client-id: "CHANGE_ME_GITHUB_CLIENT_ID"
|
||||
client-secret: "CHANGE_ME_GITHUB_CLIENT_SECRET"
|
||||
redirect-uri: "https://probo.example.com/api/console/v1/connectors/complete"
|
||||
auth-url: "https://github.com/login/oauth/authorize"
|
||||
token-url: "https://github.com/login/oauth/access_token"
|
||||
|
||||
# PostgreSQL configuration (REQUIRED)
|
||||
# For production: Use external managed PostgreSQL (AWS RDS, GCP Cloud SQL, etc.)
|
||||
# Disable the included PostgreSQL chart
|
||||
postgresql:
|
||||
# Disable the included PostgreSQL for production
|
||||
enabled: false
|
||||
|
||||
# External PostgreSQL connection (configure these when enabled=false)
|
||||
# Examples:
|
||||
# - AWS RDS: mydb.abc123.us-east-1.rds.amazonaws.com
|
||||
# - GCP Cloud SQL: 10.0.0.5 (private IP)
|
||||
# - Azure Database: myserver.postgres.database.azure.com
|
||||
# - DigitalOcean: db-postgresql-nyc1-12345.ondigitalocean.com
|
||||
host: "CHANGE_ME_POSTGRES_HOST"
|
||||
port: 5432
|
||||
database: "probod"
|
||||
username: "probod"
|
||||
password: "CHANGE_ME_DB_PASSWORD"
|
||||
poolSize: 200
|
||||
# Uncomment if using TLS with custom CA
|
||||
# caCertBundle: |
|
||||
# -----BEGIN CERTIFICATE-----
|
||||
# ...
|
||||
# -----END CERTIFICATE-----
|
||||
|
||||
# MinIO configuration
|
||||
# Disable included MinIO for production - use external S3 instead
|
||||
minio:
|
||||
enabled: false
|
||||
|
||||
# S3 storage configuration (REQUIRED)
|
||||
s3:
|
||||
# AWS S3 example:
|
||||
region: "us-east-1"
|
||||
bucket: "probo-production"
|
||||
# Leave endpoint empty for AWS S3
|
||||
endpoint: ""
|
||||
accessKeyId: "CHANGE_ME_AWS_ACCESS_KEY_ID"
|
||||
secretAccessKey: "CHANGE_ME_AWS_SECRET_ACCESS_KEY"
|
||||
|
||||
# GCP Cloud Storage example (uncomment and adjust):
|
||||
# region: "us-east1"
|
||||
# bucket: "probo-production"
|
||||
# endpoint: "https://storage.googleapis.com"
|
||||
# accessKeyId: "GOOG1E..." # HMAC access key
|
||||
# secretAccessKey: "..." # HMAC secret
|
||||
|
||||
# DigitalOcean Spaces example (uncomment and adjust):
|
||||
# region: "nyc3"
|
||||
# bucket: "probo-production"
|
||||
# endpoint: "https://nyc3.digitaloceanspaces.com"
|
||||
# accessKeyId: "..." # Spaces access key
|
||||
# secretAccessKey: "..." # Spaces secret
|
||||
|
||||
# Chrome for PDF generation
|
||||
chrome:
|
||||
enabled: true
|
||||
# Scale for concurrent PDF generation
|
||||
replicaCount: 3
|
||||
resources:
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 2Gi
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 1Gi
|
||||
|
||||
# To use external Chrome service instead, set enabled=false and configure:
|
||||
# external:
|
||||
# addr: "chrome.browserless.io:3000"
|
||||
|
||||
# Persistent data volume (optional)
|
||||
persistence:
|
||||
enabled: true
|
||||
# Use existing PVC or let Helm create one
|
||||
# existingClaim: "probo-data-pvc"
|
||||
storageClass: "" # Use default storage class or specify one
|
||||
accessMode: ReadWriteOnce
|
||||
size: 50Gi
|
||||
annotations: {}
|
||||
|
||||
# Enable Prometheus monitoring
|
||||
metrics:
|
||||
serviceMonitor:
|
||||
enabled: true
|
||||
interval: 30s
|
||||
scrapeTimeout: 10s
|
||||
labels:
|
||||
prometheus: kube-prometheus
|
||||
|
||||
# Pod placement (optional)
|
||||
nodeSelector: {}
|
||||
# node-role.kubernetes.io/worker: "true"
|
||||
|
||||
tolerations: []
|
||||
|
||||
# Anti-affinity for high availability
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchExpressions:
|
||||
- key: app.kubernetes.io/name
|
||||
operator: In
|
||||
values:
|
||||
- probo
|
||||
topologyKey: kubernetes.io/hostname
|
||||
|
||||
# Service account annotations (for workload identity, IRSA, etc.)
|
||||
serviceAccount:
|
||||
create: true
|
||||
annotations: {}
|
||||
# AWS EKS example (uncomment and adjust):
|
||||
# eks.amazonaws.com/role-arn: arn:aws:iam::ACCOUNT_ID:role/probo-role
|
||||
|
||||
# GCP GKE example (uncomment and adjust):
|
||||
# iam.gke.io/gcp-service-account: probo@PROJECT_ID.iam.gserviceaccount.com
|
||||
352
contrib/helm/charts/probo/values.yaml
Normal file
352
contrib/helm/charts/probo/values.yaml
Normal file
@@ -0,0 +1,352 @@
|
||||
# Default values for probo.
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
|
||||
replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: ghcr.io/getprobo/probo
|
||||
pullPolicy: IfNotPresent
|
||||
# Overrides the image tag whose default is the chart appVersion.
|
||||
tag: "latest"
|
||||
|
||||
imagePullSecrets: []
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
|
||||
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: ""
|
||||
|
||||
podAnnotations: {}
|
||||
podLabels: {}
|
||||
|
||||
podSecurityContext:
|
||||
runAsUser: 0
|
||||
runAsGroup: 0
|
||||
# runAsNonRoot: false
|
||||
# runAsUser: 1000 # probo user (UID defined in Dockerfile)
|
||||
# fsGroup: 1000 # probo group
|
||||
|
||||
securityContext:
|
||||
runAsUser: 0
|
||||
runAsGroup: 0
|
||||
privileged: true
|
||||
# allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
readOnlyRootFilesystem: false # /data directory requires write access for file uploads
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 8080
|
||||
httpPort: 80
|
||||
httpsPort: 443
|
||||
# nodePort: 30080
|
||||
# clusterIP: ""
|
||||
# loadBalancerIP: ""
|
||||
# loadBalancerSourceRanges: []
|
||||
annotations: {}
|
||||
|
||||
haproxy-ingress:
|
||||
enabled: true
|
||||
controller:
|
||||
ingressClass: haproxy # This tells the controller to create an IngressClass
|
||||
ingressClassResource:
|
||||
enabled: true # Enable IngressClass resource creation
|
||||
name: haproxy
|
||||
default: false
|
||||
name: controller
|
||||
service:
|
||||
type: LoadBalancer
|
||||
annotations: {}
|
||||
extraArgs:
|
||||
- --tcp-services-configmap=$(POD_NAMESPACE)/haproxy-tcp-services
|
||||
config:
|
||||
# HAProxy Ingress global config
|
||||
ssl-redirect: "false"
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
className: "haproxy"
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: haproxy
|
||||
# cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
hosts:
|
||||
- host: probo.example.com
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: probo
|
||||
port:
|
||||
number: 8080
|
||||
tls: []
|
||||
# - secretName: probo-tls
|
||||
# hosts:
|
||||
# - probo.example.com
|
||||
|
||||
resources:
|
||||
limits:
|
||||
cpu: 2000m
|
||||
memory: 2Gi
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: backoffice
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 6
|
||||
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: backoffice
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 10
|
||||
targetCPUUtilizationPercentage: 80
|
||||
# targetMemoryUtilizationPercentage: 80
|
||||
|
||||
# Additional volumes on the output Deployment definition.
|
||||
volumes: []
|
||||
# - name: foo
|
||||
# secret:
|
||||
# secretName: mysecret
|
||||
# optional: false
|
||||
|
||||
# Additional volumeMounts on the output Deployment definition.
|
||||
volumeMounts: []
|
||||
# - name: foo
|
||||
# mountPath: "/etc/foo"
|
||||
# readOnly: true
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
||||
|
||||
# Persistent data volume
|
||||
persistence:
|
||||
enabled: false
|
||||
# existingClaim: ""
|
||||
storageClass: ""
|
||||
accessMode: ReadWriteOnce
|
||||
size: 10Gi
|
||||
annotations: {}
|
||||
|
||||
# Prometheus Operator ServiceMonitor
|
||||
metrics:
|
||||
serviceMonitor:
|
||||
enabled: false
|
||||
interval: 30s
|
||||
scrapeTimeout: 10s
|
||||
labels: {}
|
||||
relabelings: []
|
||||
|
||||
# Probo application configuration
|
||||
probo:
|
||||
# Public hostname where Probo will be accessible
|
||||
# This should match your ingress host
|
||||
hostname: probo.example.com
|
||||
|
||||
# Base64-encoded encryption key (REQUIRED)
|
||||
# Generate with: openssl rand -base64 32
|
||||
encryptionKey: ""
|
||||
|
||||
service:
|
||||
port: 8080
|
||||
|
||||
metrics:
|
||||
port: 8081
|
||||
|
||||
# OpenTelemetry tracing configuration
|
||||
tracing:
|
||||
enabled: false
|
||||
# OTLP gRPC endpoint (e.g., tempo:4317)
|
||||
addr: ""
|
||||
maxBatchSize: 512
|
||||
batchTimeout: 5
|
||||
exportTimeout: 30
|
||||
maxQueueSize: 2048
|
||||
# pg:
|
||||
# addr: "probo-postgresql-demo-app:5432"
|
||||
# username: "postgres"
|
||||
# password: "probod"
|
||||
# database: "probod"
|
||||
# pool-size: 100
|
||||
|
||||
# CORS configuration
|
||||
cors:
|
||||
allowedOrigins:
|
||||
- "https://probo.example.com"
|
||||
- "http://probo.example.com"
|
||||
|
||||
# Extra HTTP headers to add to responses
|
||||
extraHeaderFields: {}
|
||||
|
||||
# Authentication configuration
|
||||
auth:
|
||||
disableSignup: false
|
||||
invitationTokenValidity: 3600
|
||||
cookieName: "SSID"
|
||||
cookieDomain: "probo.example.com"
|
||||
# Cookie signing secret (REQUIRED, at least 32 bytes)
|
||||
# Generate with: openssl rand -base64 32
|
||||
cookieSecret: ""
|
||||
cookieDuration: 24
|
||||
# Password hashing pepper (REQUIRED, at least 32 bytes)
|
||||
# Generate with: openssl rand -base64 32
|
||||
passwordPepper: ""
|
||||
passwordIterations: 1000000
|
||||
|
||||
# Trust center authentication
|
||||
trustAuth:
|
||||
cookieName: "TCT"
|
||||
cookieDomain: "probo.example.com"
|
||||
cookieDuration: 24
|
||||
tokenDuration: 168
|
||||
reportUrlDuration: 15
|
||||
ports:
|
||||
httpChallenge: 80
|
||||
tlsHttpServer: 443
|
||||
# Trust token signing secret (REQUIRED, at least 32 bytes)
|
||||
# Generate with: openssl rand -base64 32
|
||||
tokenSecret: ""
|
||||
scope: "trust_center_readonly"
|
||||
tokenType: "trust_center_access"
|
||||
|
||||
# Email configuration
|
||||
mailer:
|
||||
senderName: "Probo"
|
||||
senderEmail: "no-reply@notification.getprobo.com"
|
||||
smtp:
|
||||
addr: "sandbox.smtp.mailtrap.io:2525"
|
||||
user: "2d1b1d0e8b3d0b"
|
||||
password: "25a8eb11e75e8d"
|
||||
tlsRequired: true
|
||||
# smtp:
|
||||
# addr: "localhost:1025"
|
||||
# user: ""
|
||||
# password: ""
|
||||
# tlsRequired: false
|
||||
|
||||
# OpenAI integration (optional)
|
||||
openai:
|
||||
apiKey: ""
|
||||
temperature: 0.1
|
||||
modelName: "gpt-4o"
|
||||
|
||||
# Custom domains configuration (optional)
|
||||
customDomains:
|
||||
enabled: false
|
||||
renewalInterval: 3600
|
||||
provisionInterval: 30
|
||||
cnameTarget: "probo.example.com"
|
||||
acme:
|
||||
directory: "https://acme-v02.api.letsencrypt.org/directory"
|
||||
email: "admin@example.com"
|
||||
keyType: "EC256"
|
||||
insecureTls: false
|
||||
|
||||
# External OAuth2 connectors (optional)
|
||||
connectors: []
|
||||
# - name: "github"
|
||||
# type: "oauth2"
|
||||
# config:
|
||||
# client-id: "github-client-id"
|
||||
# client-secret: "github-client-secret"
|
||||
# redirect-uri: "https://probo.example.com/api/console/v1/connectors/complete"
|
||||
# auth-url: "https://github.com/login/oauth/authorize"
|
||||
# token-url: "https://github.com/login/oauth/access_token"
|
||||
|
||||
# PostgreSQL configuration
|
||||
# For production: Use external managed PostgreSQL (AWS RDS, GCP Cloud SQL, etc.)
|
||||
# For testing: Enable the included PostgreSQL chart
|
||||
postgresql:
|
||||
# -- enabled included Postgres container for demo purposes only using cloudnative-pg
|
||||
enabled: true
|
||||
resources:
|
||||
limits:
|
||||
memory: "2Gi"
|
||||
ephemeral-storage: "5Gi"
|
||||
auth:
|
||||
postgresUser: probod
|
||||
postgresPassword: probod
|
||||
database: probod
|
||||
|
||||
# S3 storage configuration
|
||||
# For production: Use external S3 (AWS S3, GCS, etc.)
|
||||
# For testing: Enable the included MinIO chart
|
||||
s3:
|
||||
# External S3 configuration (used when minio.enabled=false)
|
||||
region: "us-east-1"
|
||||
bucket: "probod"
|
||||
# For AWS S3, leave endpoint empty
|
||||
# For S3-compatible storage (MinIO, DigitalOcean Spaces, etc.), set the endpoint
|
||||
endpoint: ""
|
||||
accessKeyId: "" # REQUIRED when minio.enabled=false: S3 access key
|
||||
secretAccessKey: "" # REQUIRED when minio.enabled=false: S3 secret key
|
||||
|
||||
# MinIO configuration
|
||||
# Enable included MinIO for testing/development (NOT for production)
|
||||
minio:
|
||||
# -- enabled included Minio operator for s3 resource demo purposes
|
||||
enabled: true
|
||||
mode: standalone
|
||||
persistence:
|
||||
enabled: false
|
||||
resources:
|
||||
requests:
|
||||
memory: 128Mi
|
||||
primary:
|
||||
enabled: true
|
||||
auth:
|
||||
rootUser: probod
|
||||
rootPassword: probod
|
||||
|
||||
# Headless Chrome for PDF generation
|
||||
chrome:
|
||||
# Deploy Chrome in the cluster
|
||||
enabled: true
|
||||
|
||||
replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: chromedp/headless-shell
|
||||
tag: "140.0.7259.2"
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
resources:
|
||||
limits:
|
||||
cpu: 1000m
|
||||
memory: 1Gi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 256Mi
|
||||
|
||||
# External Chrome configuration
|
||||
# Used when chrome.enabled=false
|
||||
external:
|
||||
addr: ""
|
||||
Reference in New Issue
Block a user