diff --git a/charts/donetick/Chart.yaml b/charts/donetick/Chart.yaml index 48c5bab..5e88ac7 100644 --- a/charts/donetick/Chart.yaml +++ b/charts/donetick/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 name: donetick description: Donetick helm chart for Kubernetes type: application -version: 1.0.1 -appVersion: "v0.1.38" +version: 1.0.2 +appVersion: "v0.1.60" maintainers: - name: Richard Tomik email: no@m.com diff --git a/charts/donetick/readme.md b/charts/donetick/readme.md index 2069f86..fb35cd1 100644 --- a/charts/donetick/readme.md +++ b/charts/donetick/readme.md @@ -27,12 +27,184 @@ $ helm install donetick donetick-chart/donetick > **Tip**: List all releases using `helm list` +## Configuration Examples + +### Basic Installation with SQLite (Default) + +```bash +helm install donetick donetick-chart/donetick +``` + +### Installation with External PostgreSQL + +Create a values file for PostgreSQL configuration: + +```yaml +# values-postgres.yaml +config: + database: + type: "postgres" + host: "postgresql.database.svc.cluster.local" + port: 5432 + user: "donetick" + password: "your-secure-password" + name: "donetick" + migration: true + + # Update JWT secret for production + jwt: + secret: "your-secure-jwt-secret-at-least-32-characters-long" + + # Configure server settings + server: + cors_allow_origins: + - "https://your-domain.com" + - "http://localhost:5173" + + # Enable features as needed + features: + notifications: true + realtime: true + oauth: false + +# Enable ingress for external access +ingress: + enabled: true + className: "nginx" + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + hosts: + - host: donetick.your-domain.com + paths: + - path: / + pathType: Prefix + tls: + - secretName: donetick-tls + hosts: + - donetick.your-domain.com + +# Configure persistence +persistence: + enabled: true + storageClass: "fast-ssd" + size: "5Gi" +``` + +Install with PostgreSQL configuration: + +```bash +helm install donetick donetick-chart/donetick -f values-postgres.yaml +``` + +### Production Installation with External Secrets + +For production deployments, use Kubernetes secrets for sensitive data: + +```yaml +# values-production.yaml +config: + database: + type: "postgres" + host: "postgresql.database.svc.cluster.local" + port: 5432 + user: "donetick" + name: "donetick" + # Use existing secret for database credentials + existingSecret: "donetick-db-secret" + passwordKey: "postgresql-password" + + # Use existing secret for JWT + jwt: + existingSecret: "donetick-jwt-secret" + secretKey: "jwt-secret" + session_time: "168h" + max_refresh: "168h" + + # OAuth2 configuration with secrets + oauth2: + existingSecret: "donetick-oauth-secret" + clientIdKey: "client-id" + clientSecretKey: "client-secret" + auth_url: "https://your-oauth-provider.com/auth" + token_url: "https://your-oauth-provider.com/token" + user_info_url: "https://your-oauth-provider.com/userinfo" + redirect_url: "https://donetick.your-domain.com/auth/callback" + + # Production server settings + server: + cors_allow_origins: + - "https://donetick.your-domain.com" + rate_limit: 100 + rate_period: "60s" + + # Enable production features + features: + notifications: true + realtime: true + oauth: true + +# Security context for production +podSecurityContext: + runAsNonRoot: true + runAsUser: 1000 + fsGroup: 1000 + +# Resource limits for production +resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 100m + memory: 128Mi + +# Ingress with TLS +ingress: + enabled: true + className: "nginx" + annotations: + nginx.ingress.kubernetes.io/ssl-redirect: "true" + cert-manager.io/cluster-issuer: "letsencrypt-prod" + hosts: + - host: donetick.your-domain.com + paths: + - path: / + pathType: Prefix + tls: + - secretName: donetick-tls + hosts: + - donetick.your-domain.com +``` + +Create the required secrets: + +```bash +# Database secret +kubectl create secret generic donetick-db-secret \ + --from-literal=postgresql-password='your-secure-db-password' + +# JWT secret +kubectl create secret generic donetick-jwt-secret \ + --from-literal=jwt-secret='your-very-secure-jwt-secret-at-least-32-characters-long' + +# OAuth secret (if using OAuth) +kubectl create secret generic donetick-oauth-secret \ + --from-literal=client-id='your-oauth-client-id' \ + --from-literal=client-secret='your-oauth-client-secret' +``` + +Install with production configuration: + +```bash +helm install donetick donetick-chart/donetick -f values-production.yaml +``` + ## Uninstalling the Chart To uninstall/delete the `donetick` deployment: ```bash -$ helm uninstall donetick +helm uninstall donetick ``` ## Parameters @@ -49,7 +221,7 @@ $ helm uninstall donetick | Name | Description | Value | |-------------------------|--------------------------------------------------------------------------------------|--------------------| | `image.repository` | Donetick image repository | `donetick/donetick` | -| `image.tag` | Donetick image tag | `latest` | +| `image.tag` | Donetick image tag | `v0.1.60` | | `image.pullPolicy` | Donetick image pull policy | `IfNotPresent` | | `imagePullSecrets` | Global Docker registry secret names as an array | `[]` | @@ -90,7 +262,12 @@ $ helm uninstall donetick | `service.type` | Kubernetes Service type | `ClusterIP` | | `service.port` | Service HTTP port | `2021` | | `service.annotations` | Additional annotations for Service | `{}` | -| `service.nodePort` | Service HTTP node port (when applicable) | `""` | + +### Pod Configuration + +| Name | Description | Value | +|----------------------------|------------------------------------------------------|-------------| +| `podAnnotations` | Additional annotations for pods | `{}` | ### Ingress parameters @@ -108,7 +285,174 @@ $ helm uninstall donetick | Name | Description | Value | |-------------------------------|------------------------------------------------------|---------------| -| `persistence.enabled` | Enable persistence using PVC | `true` | -| `persistence.storageClass` | PVC Storage Class | `"longhorn"` | +| `persistence.enabled` | Enable persistence using PVC | `false` | +| `persistence.storageClass` | PVC Storage Class | `""` | | `persistence.accessMode` | PVC Access Mode | `ReadWriteOnce` | -| `persistence.size` | +| `persistence.size` | PVC Size | `1Gi` | + +### Health Checks + +| Name | Description | Value | +|----------------------------------------|------------------------------------------------------|---------------| +| `probes.startup.enabled` | Enable startup probe | `true` | +| `probes.startup.initialDelaySeconds` | Initial delay for startup probe | `10` | +| `probes.startup.periodSeconds` | Period for startup probe | `10` | +| `probes.startup.failureThreshold` | Failure threshold for startup probe | `30` | +| `probes.liveness.enabled` | Enable liveness probe | `true` | +| `probes.liveness.initialDelaySeconds` | Initial delay for liveness probe | `30` | +| `probes.liveness.periodSeconds` | Period for liveness probe | `10` | +| `probes.readiness.enabled` | Enable readiness probe | `true` | +| `probes.readiness.initialDelaySeconds` | Initial delay for readiness probe | `5` | +| `probes.readiness.periodSeconds` | Period for readiness probe | `5` | + +### Application Configuration + +| Name | Description | Value | +|----------------------------------------|------------------------------------------------------|---------------| +| `config.name` | Application name | `selfhosted` | +| `config.is_done_tick_dot_com` | Enable donetick.com features | `false` | +| `config.is_user_creation_disabled` | Disable user registration | `false` | + +### Real-time Configuration + +| Name | Description | Value | +|----------------------------------------|------------------------------------------------------|---------------| +| `config.realtime.max_connections` | Maximum WebSocket connections | `100` | +| `config.realtime.ping_interval` | WebSocket ping interval | `30s` | +| `config.realtime.pong_wait` | WebSocket pong wait timeout | `60s` | +| `config.realtime.write_wait` | WebSocket write timeout | `10s` | +| `config.realtime.max_message_size` | Maximum WebSocket message size | `512` | + +### Database Configuration + +| Name | Description | Value | +|----------------------------------------|------------------------------------------------------|---------------| +| `config.database.type` | Database type (sqlite or postgres) | `sqlite` | +| `config.database.migration` | Enable database migrations | `true` | +| `config.database.host` | PostgreSQL host (when type=postgres) | `""` | +| `config.database.port` | PostgreSQL port (when type=postgres) | `5432` | +| `config.database.user` | PostgreSQL user (when type=postgres) | `""` | +| `config.database.password` | PostgreSQL password (when type=postgres) | `""` | +| `config.database.name` | PostgreSQL database name (when type=postgres) | `""` | + +### JWT Configuration + +| Name | Description | Value | +|----------------------------------------|------------------------------------------------------|---------------| +| `config.jwt.secret` | JWT signing secret | `changeme-this-secret-should-be-at-least-32-characters-long` | +| `config.jwt.session_time` | JWT session duration | `168h` | +| `config.jwt.max_refresh` | JWT maximum refresh duration | `168h` | + +### Server Configuration + +| Name | Description | Value | +|----------------------------------------|------------------------------------------------------|---------------| +| `config.server.port` | Server port | `2021` | +| `config.server.read_timeout` | Server read timeout | `10s` | +| `config.server.write_timeout` | Server write timeout | `10s` | +| `config.server.rate_period` | Rate limiting period | `60s` | +| `config.server.rate_limit` | Rate limiting requests per period | `300` | +| `config.server.serve_frontend` | Serve frontend files | `true` | + +### Feature Flags + +| Name | Description | Value | +|----------------------------------------|------------------------------------------------------|---------------| +| `config.features.notifications` | Enable notifications | `true` | +| `config.features.realtime` | Enable real-time features | `true` | +| `config.features.oauth` | Enable OAuth authentication | `false` | + +## Database Setup + +### PostgreSQL Requirements + +When using PostgreSQL, ensure you have: + +1. **Database Created**: Create a database for Donetick +```sql +CREATE DATABASE donetick; +CREATE USER donetick WITH PASSWORD 'your-secure-password'; +GRANT ALL PRIVILEGES ON DATABASE donetick TO donetick; +``` + +2. **Network Access**: Ensure Donetick can reach your PostgreSQL instance +3. **Proper Credentials**: Configure database credentials in values or secrets + +### Database Migration + +Donetick automatically runs database migrations on startup when `config.database.migration: true`. For production: + +1. **Review Migrations**: Check what migrations will be applied +2. **Backup Database**: Always backup before running migrations +3. **Monitor Startup**: Watch pod logs during initial deployment + +## Troubleshooting + +### Common Issues + +#### 1. Real-time Configuration Panic +**Error**: `Invalid real-time configuration: maxConnections must be positive, got 0` + +**Solution**: Ensure the real-time configuration is properly set: +```yaml +config: + realtime: + max_connections: 100 # Must be > 0 +``` + +#### 2. Database Connection Issues +**Error**: Database connection failures + +**Solutions**: +- Verify PostgreSQL is running and accessible +- Check database credentials in secrets +- Ensure database name exists +- Verify network policies allow connection + +#### 3. JWT Secret Issues +**Error**: JWT authentication failures + +**Solution**: Ensure JWT secret is at least 32 characters: +```yaml +config: + jwt: + secret: "your-very-secure-jwt-secret-at-least-32-characters-long" +``` + +#### 4. CORS Issues +**Error**: Cross-origin request blocked + +**Solution**: Configure CORS origins: +```yaml +config: + server: + cors_allow_origins: + - "https://your-domain.com" + - "http://localhost:5173" +``` + +### Debugging + +Check application logs: +```bash +kubectl logs deployment/donetick -f +``` + +Check configuration: +```bash +kubectl get configmap donetick-configmap -o yaml +``` + +Verify secrets: +```bash +kubectl get secret donetick-secrets -o yaml +``` + +## Contributing + +Please feel free to contribute by opening issues or pull requests at: +https://github.com/rtomik/helm-charts + +## License + +This Helm chart is licensed under the MIT License. diff --git a/charts/donetick/templates/configmap.yaml b/charts/donetick/templates/configmap.yaml index bf6257c..a90a5b1 100644 --- a/charts/donetick/templates/configmap.yaml +++ b/charts/donetick/templates/configmap.yaml @@ -74,4 +74,20 @@ data: token_url: {{ .Values.config.oauth2.token_url | default "" | quote }} user_info_url: {{ .Values.config.oauth2.user_info_url | default "" | quote }} redirect_url: {{ .Values.config.oauth2.redirect_url | default "" | quote }} - name: {{ .Values.config.oauth2.name | default "" | quote }} \ No newline at end of file + name: {{ .Values.config.oauth2.name | default "" | quote }} + realtime: + max_connections: {{ .Values.config.realtime.max_connections }} + ping_interval: {{ .Values.config.realtime.ping_interval | quote }} + pong_wait: {{ .Values.config.realtime.pong_wait | quote }} + write_wait: {{ .Values.config.realtime.write_wait | quote }} + max_message_size: {{ .Values.config.realtime.max_message_size }} + logging: + level: {{ .Values.config.logging.level | quote }} + format: {{ .Values.config.logging.format | quote }} + storage: + type: {{ .Values.config.storage.type | quote }} + path: {{ .Values.config.storage.path | quote }} + features: + notifications: {{ .Values.config.features.notifications }} + realtime: {{ .Values.config.features.realtime }} + oauth: {{ .Values.config.features.oauth }} \ No newline at end of file diff --git a/charts/donetick/templates/deployment.yaml b/charts/donetick/templates/deployment.yaml index 7268b92..84585d3 100644 --- a/charts/donetick/templates/deployment.yaml +++ b/charts/donetick/templates/deployment.yaml @@ -50,6 +50,17 @@ spec: - name: http containerPort: {{ .Values.config.server.port }} protocol: TCP + {{- if .Values.probes.startup.enabled }} + startupProbe: + httpGet: + path: {{ .Values.probes.startup.path }} + port: http + initialDelaySeconds: {{ .Values.probes.startup.initialDelaySeconds }} + periodSeconds: {{ .Values.probes.startup.periodSeconds }} + timeoutSeconds: {{ .Values.probes.startup.timeoutSeconds }} + failureThreshold: {{ .Values.probes.startup.failureThreshold }} + successThreshold: {{ .Values.probes.startup.successThreshold }} + {{- end }} {{- if .Values.probes.liveness.enabled }} livenessProbe: httpGet: @@ -148,9 +159,14 @@ spec: - name: config configMap: name: {{ include "donetick.fullname" . }}-configmap + {{- if .Values.persistence.enabled }} - name: data persistentVolumeClaim: claimName: {{ include "donetick.fullname" . }}-data + {{- else }} + - name: data + emptyDir: {} + {{- end }} {{- if not .Values.containerSecurityContext.readOnlyRootFilesystem }} - name: tmp emptyDir: {} diff --git a/charts/donetick/templates/service.yaml b/charts/donetick/templates/service.yaml index c04d7eb..b3ea134 100644 --- a/charts/donetick/templates/service.yaml +++ b/charts/donetick/templates/service.yaml @@ -4,6 +4,10 @@ metadata: name: {{ include "donetick.fullname" . }} labels: {{- include "donetick.labels" . | nindent 4 }} + {{- with .Values.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} spec: type: {{ .Values.service.type }} ports: diff --git a/charts/donetick/values.yaml b/charts/donetick/values.yaml index 88234d7..0888746 100644 --- a/charts/donetick/values.yaml +++ b/charts/donetick/values.yaml @@ -5,8 +5,10 @@ fullnameOverride: "" ## Image settings image: repository: donetick/donetick - tag: "v0.1.38" + tag: "v0.1.60" pullPolicy: IfNotPresent + +imagePullSecrets: [] ## Deployment settings replicaCount: 1 @@ -34,10 +36,14 @@ nodeSelector: {} tolerations: [] affinity: {} +## Pod annotations +podAnnotations: {} + ## Service settings service: type: ClusterIP port: 2021 + annotations: {} ## Ingress settings ingress: @@ -85,16 +91,28 @@ extraVolumeMounts: [] extraVolumes: [] ## Resource limits and requests -# resources: -# limits: -# cpu: 500m -# memory: 512Mi -# requests: -# cpu: 100m -# memory: 128Mi +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 500m + # memory: 512Mi + # requests: + # cpu: 100m + # memory: 128Mi ## Application health checks probes: + startup: + enabled: true + initialDelaySeconds: 10 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 30 + successThreshold: 1 + path: /health liveness: enabled: true initialDelaySeconds: 30 @@ -207,4 +225,28 @@ config: token_url: "" user_info_url: "" redirect_url: "" - name: "" \ No newline at end of file + name: "" + + # Real-time configuration + realtime: + max_connections: 100 + ping_interval: "30s" + pong_wait: "60s" + write_wait: "10s" + max_message_size: 512 + + # Logging configuration + logging: + level: "info" + format: "json" + + # Storage configuration + storage: + type: "local" + path: "/donetick-data/uploads" + + # Feature flags + features: + notifications: true + realtime: true + oauth: false \ No newline at end of file