From b8129902b4612a37241f66b977d4a607d8ee2687 Mon Sep 17 00:00:00 2001 From: Levi van Noort <73097785+levivannoort@users.noreply.github.com> Date: Wed, 14 Oct 2026 14:00:52 +0200 Subject: [PATCH 1/2] docs: GitOps and own-Secrets examples for 2.0.0's defaults With Functions and Sites and the built-in object storage on by default, the generate: false examples in gitops.md and security.md no longer rendered ("No value for executor-secret", then the S3 keys): with generation off, the built-in store's keys and the compute secrets have to come from Secrets too. Both examples now include them (and the Argo CD Application keeps one storage block); the credentials table says when they're needed by default, and how to leave Functions and Sites out instead. Also names storage.s3.external.endpoint and .region where storage.md's provider table and troubleshooting's S3 entry still said endpoint and region, and adds the built-in store to that entry. --- docs/gitops.md | 38 +++++++++++++++++++++++++++++++------- docs/security.md | 11 +++++++++++ docs/storage.md | 4 ++-- docs/troubleshooting.md | 10 ++++++---- 4 files changed, 50 insertions(+), 13 deletions(-) diff --git a/docs/gitops.md b/docs/gitops.md index 14dc768..7ba1081 100644 --- a/docs/gitops.md +++ b/docs/gitops.md @@ -36,12 +36,26 @@ credentials, and how upgrades run Appwrite's data migration. > clickhouse: > password: > secretName: appwrite-credentials +> storage: +> s3: # the built-in object storage's keys too +> accessKeyId: +> secretName: appwrite-credentials +> secretAccessKey: +> secretName: appwrite-credentials +> compute: +> secrets: +> existingSecret: appwrite-credentials +> executor: +> existingSecret: appwrite-executor # a copy in the executor namespace > migrations: > mode: job > ``` > -> With Functions and Sites, add the [compute Secrets](#what-goes-in-the-secrets) -> too. [Credentials](#credentials) has the details. +> Functions and Sites are on by default, so the executor needs +> [its own copy](#what-goes-in-the-secrets) of its secret and the S3 keys, in +> its namespace. Without Functions and Sites, set `compute.enabled: false` +> and leave out the `compute` block. [Credentials](#credentials) has the +> details. ## Credentials @@ -83,9 +97,9 @@ change it. | `database.password.secretName` | `db-password` (`database.password.secretKey`) | always: generated for the built-in PostgreSQL, required for an external database | | `redis.password.secretName` | `redis-password` (`redis.password.secretKey`) | built-in Redis with `redis.builtin.requirePassword` (the default), or an external Redis with a password | | `clickhouse.password.secretName` | `clickhouse-password` (`clickhouse.password.secretKey`) | built-in ClickHouse, or an external one with a password | -| `compute.secrets.existingSecret` | `executor-secret`, `orchestrator-secret` (`compute.secrets.executorSecretKey`, `orchestratorSecretKey`) | `compute.enabled` | -| `compute.executor.existingSecret`, **in the executor namespace** | `executor-secret`, `s3-access-key`, `s3-secret-key` ([executor.md](executor.md#existing-secrets)) | `compute.enabled`, with `compute.secrets.existingSecret` or an S3 `secretName` | -| `storage.s3.accessKeyId.secretName`, `storage.s3.secretAccessKey.secretName` | `s3-access-key`, `s3-secret-key` (their `secretKey`) | S3 storage | +| `compute.secrets.existingSecret` | `executor-secret`, `orchestrator-secret` (`compute.secrets.executorSecretKey`, `orchestratorSecretKey`) | `compute.enabled`, the default | +| `compute.executor.existingSecret`, **in the executor namespace** | `executor-secret`, `s3-access-key`, `s3-secret-key` ([executor.md](executor.md#existing-secrets)) | `compute.enabled`, the default, with `compute.secrets.existingSecret` or an S3 `secretName` | +| `storage.s3.accessKeyId.secretName`, `storage.s3.secretAccessKey.secretName` | `s3-access-key`, `s3-secret-key` (their `secretKey`) | `storage.device: s3`, the default: for the built-in object storage too, whose keys the chart would otherwise generate | | `documentsDb.password.secretName`, `vectorsDb.password.secretName` | `documentsdb-password`, `vectorsdb-password` (their `secretKey`) | DocumentsDB or VectorsDB with a password other than the main database's | | `smtp.password.secretName` | `smtp-password` (`smtp.password.secretKey`) | SMTP with a password | @@ -298,12 +312,22 @@ spec: clickhouse: password: secretName: appwrite-credentials - migrations: - mode: job storage: + s3: + accessKeyId: + secretName: appwrite-credentials + secretAccessKey: + secretName: appwrite-credentials volume: annotations: argocd.argoproj.io/sync-options: Prune=false,Delete=false + compute: + secrets: + existingSecret: appwrite-credentials + executor: + existingSecret: appwrite-executor + migrations: + mode: job # ... the rest of your values destination: server: https://kubernetes.default.svc diff --git a/docs/security.md b/docs/security.md index aae277e..e2b3236 100644 --- a/docs/security.md +++ b/docs/security.md @@ -166,6 +166,17 @@ redis: clickhouse: password: secretName: appwrite-clickhouse # key: clickhouse-password +storage: + s3: # the built-in object storage's keys too + accessKeyId: + secretName: appwrite-s3 # key: s3-access-key + secretAccessKey: + secretName: appwrite-s3 # key: s3-secret-key +compute: # Functions and Sites, on by default + secrets: + existingSecret: appwrite-compute # keys: executor-secret, orchestrator-secret + executor: + existingSecret: appwrite-executor # a copy in the executor namespace (executor.md#existing-secrets) ``` Key names are configurable (`appwrite.secrets.keys.*`, and `secretKey` next diff --git a/docs/storage.md b/docs/storage.md index c4acaea..ae90937 100644 --- a/docs/storage.md +++ b/docs/storage.md @@ -186,12 +186,12 @@ If you restricted egress with `networkPolicy.egress.enabled`, allow the endpoint in `networkPolicy.egress.extraRules` ([security.md](security.md#egress)). -With `endpoint` empty, Appwrite talks to AWS S3 with virtual-hosted URLs +With `storage.s3.external.endpoint` empty, Appwrite talks to AWS S3 with virtual-hosted URLs (`.s3..amazonaws.com`). With an endpoint, it uses path-style URLs (`//...`), which every S3-compatible store accepts. An endpoint without a scheme gets `https://`. -| Provider | `endpoint` | `region` | +| Provider | `external.endpoint` | `external.region` | | --- | --- | --- | | AWS S3 | *(empty)* | the bucket's region, e.g. `eu-central-1` | | Cloudflare R2 | `https://.r2.cloudflarestorage.com` | `auto` | diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 5ccf8f9..efa7400 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -219,10 +219,12 @@ the built-in ClickHouse with your own Secret too. ### S3: uploads fail with `SignatureDoesNotMatch`, `AccessDenied` or `NoSuchBucket` -Check `region` (R2 and GCS use `auto`), that the bucket exists, and that the -key may read, write, list and delete in it. With an `endpoint`, Appwrite uses -path-style URLs, which the store must accept -([storage.md](storage.md#s3)). +With your own store, check `storage.s3.external.region` (R2 and GCS use +`auto`), that the bucket exists, and that the key may read, write, list and +delete in it. With an `external.endpoint`, Appwrite uses path-style URLs, +which the store must accept ([storage.md](storage.md#your-own-s3-store)). With +the built-in object storage, check that the `seaweedfs` pod is ready: it +creates the bucket when it starts. ### Emails don't arrive From e1ee19b14e984713d51219e0c7e4a7ba03f16d06 Mon Sep 17 00:00:00 2001 From: Levi van Noort <73097785+levivannoort@users.noreply.github.com> Date: Wed, 14 Oct 2026 14:09:37 +0200 Subject: [PATCH 2/2] docs: Sysbox needs privileged: false with 2.0.0's defaults compute.executor.privileged defaults to true since 2.0.0, so setting only runtimeClassName still renders a privileged container. security.md, the troubleshooting FAQ and the values comments now say to set privileged: false with the Sysbox runtime class, as executor.md already did. --- charts/appwrite/README.md | 4 ++-- charts/appwrite/values.schema.json | 4 ++-- charts/appwrite/values.yaml | 9 +++++---- docs/security.md | 5 +++-- docs/troubleshooting.md | 3 ++- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/charts/appwrite/README.md b/charts/appwrite/README.md index 0604d96..e131ac7 100644 --- a/charts/appwrite/README.md +++ b/charts/appwrite/README.md @@ -908,10 +908,10 @@ The build orchestrator and the executor. | compute.executor.podAnnotations | object | `{}` | Pod annotations, merged over `defaults.podAnnotations`. | | compute.executor.podLabels | object | `{}` | Pod labels, merged over `defaults.podLabels`. | | compute.executor.priorityClassName | string | `""` | Priority class. Empty inherits `defaults.priorityClassName`. | -| compute.executor.privileged | bool | `true` | Run the Docker daemon as a privileged container, which makes it root on its node. Required unless `runtimeClassName` names a runtime that runs Docker without it, such as Sysbox. For production, give the executor nodes of its own (`nodeSelector`, `tolerations`). | +| compute.executor.privileged | bool | `true` | Run the Docker daemon as a privileged container, which makes it root on its node. Set to false, together with `runtimeClassName`, for a runtime that runs Docker without it, such as Sysbox. For production, give the executor nodes of its own (`nodeSelector`, `tolerations`). | | compute.executor.replicaCount | int | `1` | Executor replicas. Each has its own Docker daemon: a runtime starts on the replica an execution reaches and stays there until it's idle. | | compute.executor.resources | object | `{"limits":{"memory":"4Gi"},"requests":{"cpu":"500m","memory":"1Gi"}}` | Resources of the Docker daemon container, which runs the executor and every runtime: size it for the executions you expect. | -| compute.executor.runtimeClassName | string | `""` | RuntimeClass of executor pods, e.g. `sysbox-runc`. | +| compute.executor.runtimeClassName | string | `""` | RuntimeClass of executor pods, e.g. `sysbox-runc` (with `privileged: false`). | | compute.executor.terminationGracePeriodSeconds | int | `60` | Seconds to wait on shutdown. | | compute.executor.tolerations | list | `[]` | Tolerations. Empty inherits `defaults.tolerations`. | | compute.executor.topologySpreadConstraints | list | `[]` | Topology spread constraints. Empty inherits `defaults.topologySpreadConstraints`, or spreads replicas across nodes. | diff --git a/charts/appwrite/values.schema.json b/charts/appwrite/values.schema.json index 7b0f4d1..7b1ee3d 100644 --- a/charts/appwrite/values.schema.json +++ b/charts/appwrite/values.schema.json @@ -1379,7 +1379,7 @@ "type": "string" }, "privileged": { - "description": "Run the Docker daemon as a privileged container, which makes it root on its node. Required unless `runtimeClassName` names a runtime that runs Docker without it, such as Sysbox. For production, give the executor nodes of its own (`nodeSelector`, `tolerations`).", + "description": "Run the Docker daemon as a privileged container, which makes it root on its node. Set to false, together with `runtimeClassName`, for a runtime that runs Docker without it, such as Sysbox. For production, give the executor nodes of its own (`nodeSelector`, `tolerations`).", "type": "boolean" }, "replicaCount": { @@ -1419,7 +1419,7 @@ "description": "Resources of the Docker daemon container, which runs the executor and every runtime: size it for the executions you expect." }, "runtimeClassName": { - "description": "RuntimeClass of executor pods, e.g. `sysbox-runc`.", + "description": "RuntimeClass of executor pods, e.g. `sysbox-runc` (with `privileged: false`).", "type": "string" }, "terminationGracePeriodSeconds": { diff --git a/charts/appwrite/values.yaml b/charts/appwrite/values.yaml index ea2d9b1..bf74b95 100644 --- a/charts/appwrite/values.yaml +++ b/charts/appwrite/values.yaml @@ -828,11 +828,12 @@ compute: # on Docker-in-Docker, in a namespace of its own. executor: # -- Run the Docker daemon as a privileged container, which makes it root - # on its node. Required unless `runtimeClassName` names a runtime that runs - # Docker without it, such as Sysbox. For production, give the executor - # nodes of its own (`nodeSelector`, `tolerations`). + # on its node. Set to false, together with `runtimeClassName`, for a + # runtime that runs Docker without it, such as Sysbox. For production, + # give the executor nodes of its own (`nodeSelector`, `tolerations`). privileged: true - # -- RuntimeClass of executor pods, e.g. `sysbox-runc`. + # -- RuntimeClass of executor pods, e.g. `sysbox-runc` (with + # `privileged: false`). runtimeClassName: "" # -- Namespace of the executor. Defaults to `-executor`. # Use a different one per release when several releases share a namespace. diff --git a/docs/security.md b/docs/security.md index e2b3236..2e678c5 100644 --- a/docs/security.md +++ b/docs/security.md @@ -77,8 +77,9 @@ Executions need a Docker daemon: the container per runtime. In the cluster the chart gives each executor pod its own daemon (Docker-in-Docker), which runs as a **privileged container: root on its node**, and it runs your users' code. That is the one exception to the -standards above, and the chart only renders it when you accept it -(`compute.executor.privileged: true`, or `runtimeClassName` for Sysbox): +standards above. It's on by default (`compute.executor.privileged: true`); +turn it off with `compute.enabled: false`, or run the daemon through Sysbox +instead (`privileged: false` with `runtimeClassName`): - The executor gets a namespace of its own, the only one labelled for the `privileged` standard. The Appwrite namespace stays `restricted` and the diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index efa7400..ac2c5c5 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -394,7 +394,8 @@ ordinary Jobs. The alternative is [Sysbox](https://github.com/nestybox/sysbox), which runs the daemon without `privileged`: install it on the executor's nodes and set -`compute.executor.runtimeClassName: sysbox-runc` instead +`compute.executor.privileged: false` with +`compute.executor.runtimeClassName: sysbox-runc` ([executor.md](executor.md#without-a-privileged-container)). CI doesn't test it.