Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions braintrust/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,44 @@ Pools use fixed replica counts by default (`api.replicas` and
`api.workloadIsolation.<pool>.replicas`). On GKE, enable `api.autoscaling` to
let each pool scale independently instead.

## Brainstore Cache Sizing

By default, each Brainstore pod sizes its object store cache when it starts,
as a percentage of its cache volume. Readers and fast readers use 90%. Writers
use 75% because they need more free disk. This matches how the AWS Terraform
module sizes the cache from the instance's local disk.

The cache volume size is the size of the filesystem mounted at `cacheDir`,
capped by the smallest of `volume.sizeLimit`, `volume.size`,
`ephemeralStorage.request` and `ephemeralStorage.limit` that is set. This works
the same way on every cloud:

| Platform | Cache volume | What sets the size |
| --- | --- | --- |
| GKE Autopilot | `emptyDir` on the node's local SSD | `volume.size` (also the ephemeral-storage request) or `ephemeralStorage.request` |
| GKE Standard | `emptyDir` on the node pool's disk | The node disk, capped by any size set above |
| EKS (managed nodes, Karpenter, Auto Mode) | `emptyDir` on the node's kubelet disk | `ephemeralStorage.request` (see [AWS EKS Local Storage](#aws-eks-local-storage)) |
| AKS with Azure Container Storage | Ephemeral volume of `volume.size` | `volume.size` |
| AKS without Azure Container Storage | `emptyDir` on the node's disk | The node disk, capped by any size set above |

An `emptyDir` lives on a node disk that container images, logs and other pods
also use. When no size is set, the percentage applies to that whole disk, so
either give Brainstore pods dedicated nodes (see the anti-affinity examples
above) or set one of the sizes above.

```yaml
brainstore:
writer:
# Change the percentage
objectStoreCacheFileSizePercent: 70
reader:
# Or set a fixed size, which disables the percentage
objectStoreCacheFileSize: "800Gi"
```

The pod logs the size it picked at startup. If the computed size is under
1Gi, the pod exits with an error asking you to set `objectStoreCacheFileSize`.

## Brainstore Rollout Controls

Brainstore readers, fast readers, and writers have independently configurable
Expand Down
3 changes: 0 additions & 3 deletions braintrust/examples/google-autopilot-cel/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,6 @@ brainstore:
memory: "32Gi"
cacheDir: "/mnt/tmp/brainstore"
objectStoreCacheMemoryLimit: "1Gi"
objectStoreCacheFileSize: "900Gi"
verbose: true
securityContext:
readOnlyRootFilesystem: true
Expand Down Expand Up @@ -121,7 +120,6 @@ brainstore:
memory: "32Gi"
cacheDir: "/mnt/tmp/brainstore"
objectStoreCacheMemoryLimit: "1Gi"
objectStoreCacheFileSize: "900Gi"
verbose: true
securityContext:
readOnlyRootFilesystem: true
Expand Down Expand Up @@ -154,7 +152,6 @@ brainstore:
memory: "64Gi"
cacheDir: "/mnt/tmp/brainstore"
objectStoreCacheMemoryLimit: "1Gi"
objectStoreCacheFileSize: "900Gi"
verbose: true
securityContext:
readOnlyRootFilesystem: true
Expand Down
3 changes: 0 additions & 3 deletions braintrust/examples/google-autopilot/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ brainstore:
memory: "32Gi"
cacheDir: "/mnt/tmp/brainstore"
objectStoreCacheMemoryLimit: "1Gi"
objectStoreCacheFileSize: "900Gi"
verbose: true
volume:
size: "1000Gi"
Expand All @@ -120,7 +119,6 @@ brainstore:
memory: "32Gi"
cacheDir: "/mnt/tmp/brainstore"
objectStoreCacheMemoryLimit: "1Gi"
objectStoreCacheFileSize: "900Gi"
verbose: true
volume:
size: "1000Gi"
Expand All @@ -144,7 +142,6 @@ brainstore:
memory: "64Gi"
cacheDir: "/mnt/tmp/brainstore"
objectStoreCacheMemoryLimit: "1Gi"
objectStoreCacheFileSize: "900Gi"
verbose: true
volume:
size: "1000Gi"
Expand Down
2 changes: 0 additions & 2 deletions braintrust/examples/google-standard/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ brainstore:
topologyKey: kubernetes.io/hostname
cacheDir: "/mnt/tmp/brainstore"
objectStoreCacheMemoryLimit: "1Gi"
objectStoreCacheFileSize: "1000Gi"
verbose: true
volume:
size: "200Gi"
Expand Down Expand Up @@ -136,7 +135,6 @@ brainstore:
topologyKey: kubernetes.io/hostname
cacheDir: "/mnt/tmp/brainstore"
objectStoreCacheMemoryLimit: "1Gi"
objectStoreCacheFileSize: "1000Gi"
verbose: true
volume:
size: "200Gi"
Expand Down
81 changes: 81 additions & 0 deletions braintrust/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,84 @@ and normal writable-layer/log overhead.
{{- end -}}
{{- toYaml $resources -}}
{{- end -}}

{{/*
Convert a Kubernetes quantity such as "900Gi" or "1T" to bytes.
*/}}
{{- define "braintrust.quantityToBytes" -}}
{{- $quantity := toString .quantity -}}
{{- $match := regexFindAll "^([0-9]+)(Ki|Mi|Gi|Ti|Pi|k|K|M|G|T|P)?$" $quantity -1 -}}
{{- if not $match -}}
{{- fail (printf "%s must be a whole-number Kubernetes quantity such as 900Gi (got %q)" .path $quantity) -}}
{{- end -}}
{{- $number := regexFind "^[0-9]+" $quantity | int64 -}}
{{- $suffix := trimPrefix (toString $number) $quantity -}}
{{- $multipliers := dict
"" 1
"Ki" 1024 "Mi" 1048576 "Gi" 1073741824 "Ti" 1099511627776 "Pi" 1125899906842624
"k" 1000 "K" 1000 "M" 1000000 "G" 1000000000 "T" 1000000000000 "P" 1000000000000000
-}}
{{- mul $number (index $multipliers $suffix) -}}
{{- end -}}

{{/*
Render the Brainstore container command.

When objectStoreCacheFileSize is set, Brainstore starts directly and reads the
size from its ConfigMap. Otherwise the container sets
BRAINSTORE_OBJECT_STORE_CACHE_FILE_SIZE at startup to
objectStoreCacheFileSizePercent of the cache volume, the same way the AWS
Terraform module sizes the cache from the instance's local disk. The cache
volume size is the size of the filesystem mounted at cacheDir, capped by the
smallest of volume.sizeLimit, volume.size, ephemeralStorage.request and
ephemeralStorage.limit that is set. The cap matters when the cache is an
emptyDir on a node disk shared with images, logs and other pods.

Template-level percent defaults keep `helm upgrade --reuse-values` working
from chart versions that predate objectStoreCacheFileSizePercent.
*/}}
{{- define "braintrust.brainstoreCommand" -}}
{{- $config := .config -}}
{{- if $config.objectStoreCacheFileSize -}}
command: ["brainstore"]
args: ["web"]
{{- else -}}
{{- $percent := $config.objectStoreCacheFileSizePercent | default .defaultPercent -}}
{{- if not (regexMatch "^[0-9]+$" (toString $percent)) -}}
{{- fail (printf "%s.objectStoreCacheFileSizePercent must be a whole number between 1 and 100" .path) -}}
{{- end -}}
{{- if or (lt (int $percent) 1) (gt (int $percent) 100) -}}
{{- fail (printf "%s.objectStoreCacheFileSizePercent must be a whole number between 1 and 100" .path) -}}
{{- end -}}
{{- $limitBytes := 0 -}}
{{- range $field := list "volume.sizeLimit" "volume.size" "ephemeralStorage.request" "ephemeralStorage.limit" -}}
{{- $parts := splitList "." $field -}}
{{- $quantity := index ((index $config (first $parts)) | default dict) (last $parts) -}}
{{- if $quantity -}}
{{- $bytes := include "braintrust.quantityToBytes" (dict "quantity" $quantity "path" (printf "%s.%s" $.path $field)) | int64 -}}
{{- if or (eq $limitBytes 0) (lt $bytes $limitBytes) -}}
{{- $limitBytes = $bytes -}}
{{- end -}}
{{- end -}}
{{- end -}}
command: ["/bin/sh", "-c"]
args:
- |
set -eu
percent={{ $percent }}
limit_bytes={{ $limitBytes }}
set -- $(stat -f -c '%b %S' "$BRAINSTORE_CACHE_DIR")
volume_bytes=$(( $1 * $2 ))
if [ "$limit_bytes" -gt 0 ] && [ "$limit_bytes" -lt "$volume_bytes" ]; then
volume_bytes=$limit_bytes
fi
size_gib=$(( volume_bytes / 100 * percent / 1073741824 ))
if [ "$size_gib" -lt 1 ]; then
echo "Brainstore cache volume at $BRAINSTORE_CACHE_DIR is too small ($volume_bytes bytes); set objectStoreCacheFileSize" >&2
exit 1
fi
export BRAINSTORE_OBJECT_STORE_CACHE_FILE_SIZE="${size_gib}Gi"
echo "Using ${size_gib}Gi object store cache (${percent}% of $volume_bytes bytes at $BRAINSTORE_CACHE_DIR)"
exec brainstore web
{{- end -}}
{{- end -}}
2 changes: 2 additions & 0 deletions braintrust/templates/brainstore-fastreader-configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ data:
BRAINSTORE_PORT: {{ .Values.brainstore.fastreader.service.port | quote }}
BRAINSTORE_CACHE_DIR: {{ .Values.brainstore.fastreader.cacheDir | quote }}
BRAINSTORE_OBJECT_STORE_CACHE_MEMORY_LIMIT: {{ .Values.brainstore.fastreader.objectStoreCacheMemoryLimit | quote }}
{{- if .Values.brainstore.fastreader.objectStoreCacheFileSize }}
BRAINSTORE_OBJECT_STORE_CACHE_FILE_SIZE: {{ .Values.brainstore.fastreader.objectStoreCacheFileSize | quote }}
{{- end }}
{{- if eq .Values.cloud "azure" }}
# See here for reference:
# https://docs.rs/object_store/latest/object_store/azure/struct.MicrosoftAzureBuilder.html
Expand Down
7 changes: 5 additions & 2 deletions braintrust/templates/brainstore-fastreader-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,11 @@ spec:
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
command: ["brainstore"]
args: ["web"]
{{- include "braintrust.brainstoreCommand" (dict
"path" "brainstore.fastreader"
"config" .Values.brainstore.fastreader
"defaultPercent" 90
) | nindent 10 }}
ports:
- containerPort: {{ .Values.brainstore.fastreader.service.port }}
resources:
Expand Down
2 changes: 2 additions & 0 deletions braintrust/templates/brainstore-reader-configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ data:
BRAINSTORE_PORT: {{ .Values.brainstore.reader.service.port | quote }}
BRAINSTORE_CACHE_DIR: {{ .Values.brainstore.reader.cacheDir | quote }}
BRAINSTORE_OBJECT_STORE_CACHE_MEMORY_LIMIT: {{ .Values.brainstore.reader.objectStoreCacheMemoryLimit | quote }}
{{- if .Values.brainstore.reader.objectStoreCacheFileSize }}
BRAINSTORE_OBJECT_STORE_CACHE_FILE_SIZE: {{ .Values.brainstore.reader.objectStoreCacheFileSize | quote }}
{{- end }}
{{- if eq .Values.cloud "azure" }}
# See here for reference:
# https://docs.rs/object_store/latest/object_store/azure/struct.MicrosoftAzureBuilder.html
Expand Down
7 changes: 5 additions & 2 deletions braintrust/templates/brainstore-reader-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,11 @@ spec:
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
command: ["brainstore"]
args: ["web"]
{{- include "braintrust.brainstoreCommand" (dict
"path" "brainstore.reader"
"config" .Values.brainstore.reader
"defaultPercent" 90
) | nindent 10 }}
ports:
- containerPort: {{ .Values.brainstore.reader.service.port }}
resources:
Expand Down
2 changes: 2 additions & 0 deletions braintrust/templates/brainstore-writer-configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ data:
BRAINSTORE_PORT: {{ .Values.brainstore.writer.service.port | quote }}
BRAINSTORE_CACHE_DIR: {{ .Values.brainstore.writer.cacheDir | quote }}
BRAINSTORE_OBJECT_STORE_CACHE_MEMORY_LIMIT: {{ .Values.brainstore.writer.objectStoreCacheMemoryLimit | quote }}
{{- if .Values.brainstore.writer.objectStoreCacheFileSize }}
BRAINSTORE_OBJECT_STORE_CACHE_FILE_SIZE: {{ .Values.brainstore.writer.objectStoreCacheFileSize | quote }}
{{- end }}
{{- if eq .Values.cloud "azure" }}
# See here for reference:
# https://docs.rs/object_store/latest/object_store/azure/struct.MicrosoftAzureBuilder.html
Expand Down
7 changes: 5 additions & 2 deletions braintrust/templates/brainstore-writer-deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,11 @@ spec:
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
command: ["brainstore"]
args: ["web"]
{{- include "braintrust.brainstoreCommand" (dict
"path" "brainstore.writer"
"config" .Values.brainstore.writer
"defaultPercent" 75
) | nindent 10 }}
ports:
- containerPort: {{ .Values.brainstore.writer.service.port }}
resources:
Expand Down
Loading
Loading