# Kubernetes

Diagrama platformei Helm implementează aplicația platformei și Chrome fără cap. Pentru producție, conectați graficul la o bază de date externă PostgreSQL și la un spațiu de stocare a obiectelor compatibil cu S3, pe care echipa dvs. îl operează deja și îl face backup.

Utilizați Kubernetes atunci când echipa dvs. a stabilit deja practici pentru intrări, certificate, secrete, monitorizare și operațiuni de bază de date.

## Requirements

- Kubernetes 1.23 or newer
- Helm 3.8 or newer
- `kubectl` access to the target cluster
- A PostgreSQL database reachable from the cluster
- An S3 or tested S3-compatible bucket
- An ingress controller and TLS certificate
- An SMTP relay if you want the platform to send email

The database role must be able to create or use the `citext`, `pgcrypto`, `unaccent`, and `pg_stat_statements` extensions. On PostgreSQL 15 and newer, make the the platform role the owner of the `public` schema before first startup:

```sql
ALTER SCHEMA public OWNER TO probod;
GRANT ALL ON SCHEMA public TO probod;
```

## Prepare the deployment

1. **Choose and pin a chart version**

   The chart is published at `oci://artifact.probo.inc/probo/probo`. Set the version you have tested:

   ```bash
   export PROBO_CHART_VERSION="0.0.0"

   helm show chart oci://artifact.probo.inc/probo/probo \
     --version "$PROBO_CHART_VERSION"
   ```

   Replace `0.0.0` with an available chart version. Do not rely on an unpinned chart in production.

2. **Generate application secrets**

   ```bash
   umask 077
   openssl rand -base64 32
   openssl rand -base64 32
   openssl rand -base64 32
   openssl rand -base64 32

   openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 \
     -out oauth2-signing-key.pem
   ```

   Înregistrați cele patru valori generate separat ca cheia de criptare, secretul cookie-ului, pepperul de parolă și secretul tokenului de încredere.

3. **Create non-secret values**

   Save the following as `values.yaml` and replace the example hostnames and service details:

   ```yaml
   replicaCount: 2

   haproxy-ingress:
     enabled: false

   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:
     baseUrl: probo.example.com
     cors:
       allowedOrigins:
         - https://probo.example.com
     auth:
       disableSignup: true
       cookieDomain: probo.example.com
     trustAuth:
       cookieDomain: probo.example.com
     mailer:
       senderName: Probo
       senderEmail: no-reply@example.com
       smtp:
         addr: smtp.example.com:587
         tlsRequired: true

   postgresql:
     enabled: false
     host: postgres.example.internal
     port: 5432
     database: probod
     username: probod

   seaweedfs:
     enabled: false

   s3:
     region: eu-west-1
     bucket: probo-production
     endpoint: ""
     usePathStyle: false

   chrome:
     enabled: true

   resources:
     requests:
       cpu: 500m
       memory: 1Gi
     limits:
       cpu: 2
       memory: 4Gi
   ```

   This example assumes an existing ingress controller. If you intentionally want the chart to install HAProxy Ingress, enable `haproxy-ingress` and set `ingress.className` to `haproxy`.

4. **Create secret values**

   Save the following as `values-secrets.yaml`, fill every placeholder, and keep the file outside version control:

   ```yaml
   probo:
     encryptionKey: "<base64 encryption key>"
     auth:
       cookieSecret: "<base64 cookie secret>"
       passwordPepper: "<base64 password pepper>"
     trustAuth:
       tokenSecret: "<base64 trust-token secret>"
     mailer:
       smtp:
         user: ""
         password: ""

   postgresql:
     password: "<database password>"

   s3:
     accessKeyId: ""
     secretAccessKey: ""
   ```

   ```bash
   chmod 600 values-secrets.yaml oauth2-signing-key.pem
   ```

   
     The current chart renders its own Kubernetes Secret from Helm values.
     Secret values are therefore present in the Helm release metadata as well as
     the generated Secret. Restrict access to Helm release Secrets and the
     namespace. If your policy requires an external secret manager, review and
     adapt the chart before deployment; adding an `ExternalSecret` alone does
     not make the chart consume it.
   

5. **Renunță și inspectează manifestele**

   ```bash
   helm template probo oci://artifact.probo.inc/probo/probo \
     --version "$PROBO_CHART_VERSION" \
     --namespace probo \
     --values values.yaml \
     --values values-secrets.yaml \
     --set-file probo.oauth2.signingKey=oauth2-signing-key.pem \
     > rendered.yaml
   ```

   Inspect the resource names, ingress class, storage, security context, and scheduling behavior. `rendered.yaml` contains secrets; delete it securely after review and do not commit it.

6. **Install the platform**

   ```bash
   kubectl create namespace probo

   helm install probo oci://artifact.probo.inc/probo/probo \
     --version "$PROBO_CHART_VERSION" \
     --namespace probo \
     --values values.yaml \
     --values values-secrets.yaml \
     --set-file probo.oauth2.signingKey=oauth2-signing-key.pem \
     --wait \
     --timeout 10m
   ```

7. **Verify the deployment**

   ```bash
   helm status probo --namespace probo

   kubectl get pods,service,ingress \
     --namespace probo \
     --selector app.kubernetes.io/instance=probo

   kubectl rollout status deployment/probo \
     --namespace probo \
     --timeout=10m

   kubectl logs deployment/probo \
     --namespace probo \
     --tail=100
   ```

   După ce DNS șiTLSsunt gata, verificați punctul public:

   ```bash
   curl --fail https://probo.example.com/
   ```

   De asemenea, testați autentificarea, încărcarea fișierelor, generarea PDF și livrarea prin e-mail înainte de a invita utilizatorii.

## Production decisions

### Ingress and TLS

Diagrama activează dependența HAProxy Ingress în mod implicit. dezactivați-o atunci când clusterul are deja un controler de intrare; în caz contrar, instalația poate crea un echilibrator de sarcină public neașteptat.

Diagrama direcționează intrarea către portul de back-office al platformei. ConfigurareaTLSdepinde de controlerul dvs. de intrare și de sistemul de certificate.

- only intended public services receive external addresses;
- HTTP redirects to HTTPS;
- the configured hostname matches `probo.baseUrl`;
- `probo.cors.allowedOrigins` contains the complete HTTPS origin;
- cookies are scoped to the intended domain.

### Replicas and local storage

Do not claim high availability solely by increasing `replicaCount`.

The chart mounts `/data` from `emptyDir` by default. Enabling `persistence` creates or mounts one PVC, and the production example uses `ReadWriteOnce`. Multiple pods scheduled on different nodes may not be able to mount that claim. Test the chart with your storage class and failure model before running multiple replicas.

PostgreSQL și S3 rămân sistemele durabile de înregistrare. Backup ambele servicii la un punct de recuperare consecvent și de restaurare de testare în mod regulat.

### Database connections

Dimensiunea bazinului implicită este de 100 de conexiuni pe platformă pod. Contul pentru replică și actualizări de rulare atunci când setați limite de conexiune PostgreSQL. De exemplu, trei pods curente plus un pod de creștere pot solicita substanțial mai mult de 300 de conexiuni.

If your provider requires a custom CA, set `postgresql.caBundle` or mount a certificate and set `postgresql.caBundlePath`. Do not disable database certificate verification to work around a CA error.

### S3 compatibility

For AWS S3, leave `s3.endpoint` empty and `s3.usePathStyle` false. Other providers may require a custom endpoint and path-style addressing.

Testarea încărcării, descărcării, metadatelor obiectului și ștergerii împotriva furnizorului exact înainte de utilizarea în producție. Azure Blob din spatele unui proxy de compatibilitate S3 are limitări cunoscute privind compatibilitatea metadatelor și nu ar trebui tratată ca echivalent acceptat fără testare.

## Monitoring

the platform exposes metrics on port `8081`. If Prometheus Operator is installed, enable the chart's `ServiceMonitor`:

```yaml
metrics:
  serviceMonitor:
    enabled: true
    interval: 30s
```

Cel puțin, avertizați despre pods-uri indisponibile, cicluri de redeschidere, implementări nereușite, erori de stocare a bazelor de date și a obiectelor, expirarea certificatelor și conexiunile de bază de date epuizate.

## Upgrade and rollback

Examinați notele de lansare a platformei și a diagramei, faceți backup PostgreSQL și S3 și testați versiunea țintă într-un mediu non-producție.

```bash
export PROBO_CHART_VERSION="0.0.0"

helm upgrade probo oci://artifact.probo.inc/probo/probo \
  --version "$PROBO_CHART_VERSION" \
  --namespace probo \
  --values values.yaml \
  --values values-secrets.yaml \
  --set-file probo.oauth2.signingKey=oauth2-signing-key.pem \
  --wait \
  --timeout 10m
```

Migrările bazei de date se execută automat atunci când se pornește platforma. Urmăriți atât jurnalele de implementare, cât și cele ale aplicațiilor:

```bash
kubectl rollout status deployment/probo --namespace probo --timeout=10m
kubectl logs deployment/probo --namespace probo --tail=200
```

Dacă este necesar să reveniți la versiunea de aplicație, determinați mai întâi dacă migrarea bazei de date este compatibilă înapoi.

```bash
helm history probo --namespace probo
helm rollback probo REVISION --namespace probo --wait --timeout 10m
```

## Troubleshooting

### Pods do not start

```bash
kubectl get pods --namespace probo
kubectl describe pod POD_NAME --namespace probo
kubectl logs POD_NAME --namespace probo --previous
kubectl get events --namespace probo --sort-by=.metadata.creationTimestamp
```

Cauzele comune sunt formate secrete nevalide, o cheie de semnătură OAuth lipsă, extensii de baze de date indisponibile, politici de rețea de baze de date și un punct final S3 inaccesibil.

### The ingress has no address

```bash
kubectl describe ingress probo-http --namespace probo
kubectl get ingressclass
```

Confirm that `ingress.className` names an installed controller and inspect that controller's logs. If the chart unexpectedly installed HAProxy, review the `haproxy-ingress.enabled` value.

### A rollout cannot mount `/data`

```bash
kubectl get pvc --namespace probo
kubectl describe pvc probo --namespace probo
```

Check the volume's access mode, storage class, availability zone, and pod scheduling events. A single `ReadWriteOnce` volume is not a portable shared-storage design for replicas on multiple nodes.

See the chart's [`values.yaml`](/docs) and the [environment variable reference](/docs/deployment/configuration/environment-reference) for additional configuration.
