Configure the persistent volume Thoras uses to retain historical usage metrics, and optionally point Thoras at an external TimescaleDB.
To produce production-grade predictions, Thoras needs durable storage for
historical usage metrics. The chart supports two independent pieces of state:
A Kubernetes
persistent volume
(PV) attached to the metrics collector.
A TimescaleDB instance for time-series storage. The chart deploys one
in-cluster by default; you can point it at an external database instead.
You’ll want to ensure Thoras has the disk space it needs now and in the future.
This may or may not require configuration based on your backend storage
provider.
These are PV storage backends that don’t enforce a fixed size, they dynamically
grow as-needed and require no Thoras configuration to specify volume size.
Examples include:
AWS Elastic File System (EFS)
Google Cloud Filestore (enterprise tier)
Azure Files
CephFS
Action: If you use one of these backends, you don’t need to allocate disk
space in the Thoras configuration, the disk will automatically grow to meet your
needs.
These are PV storage backends that require explicit provisioning of a fixed
capacity and enforce the size specified in the PersistentVolumeClaim. These
backends require you to specify the desired size of the disk, which you should
configure as a Helm chart value (read on for details on how to do that).
Examples include:
AWS Elastic Block Store (EBS)
Google Persistent Disk (GCP PD)
Azure Disk Storage
VMware vSphere Volumes
Action: If you use a fixed-size storage backend, you’ll need to specify the
volume size as a Helm value:
Determine how much total size will be needed using
guidance above
Configure the storage size by setting the following helm value:
metricsCollector: persistence: # Or whatever size needed based on your math from step #1 pvcStorageRequestSize: "100Gi"
You may have an established workflow for provisioning Kubernetes Persistent
Volumes (PV). That’s great! Here’s how to get up and running depending on your
preferred approach:
If you have a Kubernetes StorageClass that you’d like to use to dynamically
provision your PV (such as an
EFS StorageClass).
In that case, simply reference the storage class name in your Thoras helm chart
values.yaml:
metricsCollector.persistence.enabled defaults to null, which auto-enables
persistence as soon as you set any of storageClassName,
pvcStorageRequestSize, or createEFSStorageClass.fileSystemId. Setting
enabled: true is only necessary if you want to force persistence on without
configuring any of the above.
If you have a workflow for provisioning a PV and would like to simply reference
the PV directly by name, add the following config block to your Helm
values.yaml:
The chart deploys an in-cluster TimescaleDB by default. If you’d rather manage
TimescaleDB yourself, for backups, HA, or shared infrastructure, point Thoras at
an external database instead:
externalTimescale: # Full postgres DSN, including the database name. dsn: "postgres://user:password@host:5432/tsdb?sslmode=require"
Or reference an existing Secret containing the DSN:
When either is set, the chart skips deploying its bundled TimescaleDB and wires
all components to the external database. The TimescaleDB extension must be
pre-installed on the external database.See Credentials for how the DSN interacts with the
other credentials Thoras manages.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Thoras Documentation","description":"Documentation for Thoras, the autonomous control plane for compute efficiency. Predictive Kubernetes autoscaling, self-hosted.","colors":{"primary":"#6b998f","light":"#9bc1b9","dark":"#3e8055"},"logo":{"light":"https://mintcdn.com/thoras/d2dju-xNTLxLCVzd/logo/light.png?fit=max\u0026auto=format\u0026n=d2dju-xNTLxLCVzd\u0026q=85\u0026s=657db4d808549261842fe7ed7fd4332c","dark":"https://mintcdn.com/thoras/d2dju-xNTLxLCVzd/logo/dark.png?fit=max\u0026auto=format\u0026n=d2dju-xNTLxLCVzd\u0026q=85\u0026s=da741af6fba7fc23f3bd17420f7109ef","href":"https://docs.thoras.ai"},"favicon":"https://mintcdn.com/thoras/SlaX_dne9nsRxoWC/favicon.png?fit=max\u0026auto=format\u0026n=SlaX_dne9nsRxoWC\u0026q=85\u0026s=f2e4225c1bfcda4dc6ad64e7f51ebdde","navbar":{"links":[{"href":"https://thoras.ai","label":"Website"},{"href":"https://github.com/thoras-ai/helm-charts","label":"GitHub"}],"primary":{"type":"button","label":"Book a demo","href":"https://thoras.ai/book-a-demo"}},"footer":{"socials":{"linkedin":"https://www.linkedin.com/company/thoras","x":"https://x.com/thorasai","github":"https://github.com/thoras-ai","youtube":"https://www.youtube.com/@Thorasai"},"links":[{"header":"Product","items":[{"label":"Book a demo","href":"https://thoras.ai/book-a-demo"},{"label":"Cloud savings calculator","href":"https://thoras.ai/cloud-savings-calculator"},{"label":"Website","href":"https://thoras.ai"}]},{"header":"Company","items":[{"label":"About","href":"https://thoras.ai/about-us"},{"label":"Case studies","href":"https://thoras.ai/case-studies"},{"label":"Blog","href":"https://thoras.ai/blog"},{"label":"Newsroom","href":"https://thoras.ai/newsroom"},{"label":"Partners","href":"https://thoras.ai/partners"}]},{"header":"Resources","items":[{"label":"Quickstart","href":"https://docs.thoras.ai/getting-started/quickstart"},{"label":"GitHub","href":"https://github.com/thoras-ai/helm-charts"}]}]},"seo":{"metatags":{"og:title":"Thoras Documentation","og:description":"The autonomous control plane for compute efficiency. Predictive Kubernetes autoscaling, self-hosted.","og:image":"/og-image.png","og:url":"https://docs.thoras.ai","og:site_name":"Thoras Documentation","twitter:card":"summary_large_image","twitter:site":"@thorasai"},"indexing":"navigable"},"styling":{"latex":false},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"thoras","hasAudioNarration":false,"actualSubdomain":"thoras","customDomains":["docs.thoras.ai"],"gitSource":{"type":"github","owner":"thoras-ai","repo":"docs-mintlify","deployBranch":"main","contentDirectory":"","isPrivate":true,"mountPath":"","label":""},"chroma":{"liveDeploymentHistoryId":"6adbbad25370aeb5d3fb84d5","collectionId":"da86ee12-1413-4831-9812-8a2a60415e27","schemaVersion":"v3","latestBuiltDeploymentHistoryId":"6adbbad25370aeb5d3fb84d5"},"entitlements":{},"buildId":"6adbbad25370aeb5d3fb84d5","clientVersion":"0.0.3966","searchFilterCounts":[{"language":"default","tag":"Documentation","count":28},{"language":"default","tag":"Guides","count":20},{"language":"default","tag":"Reference","count":8},{"language":"default","tag":"Operating Thoras","count":7},{"language":"default","tag":"Scaling workloads","count":7},{"language":"default","tag":"FAQ","count":6},{"language":"default","tag":"Installation","count":6},{"language":"default","tag":"Policies","count":4},{"language":"default","tag":"Dashboard authentication","count":3},{"language":"default","tag":"Getting Started","count":2}]},"assistantConfig":{},"hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-v7-file-tree","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"pause-universal-search-reconcile","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"per-site-search-delta","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-private-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-nav-generations","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"byok-sep-25","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-agent-model-picker","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"isAtlas":false,"googleFontsInlined":false},"customCss":[],"page":{"pagePath":"installation/persistent-storage","slug":"/installation/persistent-storage","pageMetadata":{"title":"Persistent Storage","description":"Configure the persistent volume Thoras uses to retain historical usage metrics, and optionally point Thoras at an external TimescaleDB.","href":"/installation/persistent-storage"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"Configure the persistent volume Thoras uses to retain historical usage metrics, and optionally point Thoras at an external TimescaleDB.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,code:`code`,li:`li`,ol:`ol`,p:`p`,pre:`pre`,span:`span`,strong:`strong`,ul:`ul`,..._provideComponents(),...props.components},{CodeBlock,Heading,Note}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Note)_missingMdxReference(`Note`,true);return _jsxs(_Fragment,{children:[_jsx(_components.p,{children:`To produce production-grade predictions, Thoras needs durable storage for\nhistorical usage metrics. The chart supports two independent pieces of state:`}),`\n`,_jsxs(_components.ol,{children:[`\n`,_jsxs(_components.li,{children:[`A Kubernetes\n`,_jsx(_components.a,{href:`https://kubernetes.io/docs/concepts/storage/persistent-volumes/`,children:`persistent volume`}),`\n(PV) attached to the metrics collector.`]}),`\n`,_jsx(_components.li,{children:`A TimescaleDB instance for time-series storage. The chart deploys one\nin-cluster by default; you can point it at an external database instead.`}),`\n`]}),`\n`,_jsx(Heading,{level:`2`,id:`understanding-storage-requirements`,children:`Understanding Storage Requirements`}),`\n`,_jsx(_components.p,{children:`You’ll want to ensure Thoras has the disk space it needs now and in the future.\nThis may or may not require configuration based on your backend storage\nprovider.`}),`\n`,_jsx(Heading,{level:`3`,id:`understanding-usage`,children:`Understanding Usage`}),`\n`,_jsxs(_components.p,{children:[`The storage requirement for a managed workload is `,_jsx(_components.code,{children:`1GB`}),`. So for a cluster with\ntwenty managed workloads, Thoras requires `,_jsx(_components.code,{children:`20GB`}),` of disk space.`]}),`\n`,_jsx(Heading,{level:`3`,id:`understanding-kubernetes-storage-backend`,children:`Understanding Kubernetes Storage Backend`}),`\n`,_jsx(_components.p,{children:`In general there are two patterns for Kubernetes storage backends with regard to\ndisk space configuration:`}),`\n`,_jsx(Heading,{level:`4`,id:`growable-storage-backends`,children:`Growable Storage Backends`}),`\n`,_jsx(_components.p,{children:`These are PV storage backends that don’t enforce a fixed size, they dynamically\ngrow as-needed and require no Thoras configuration to specify volume size.\nExamples include:`}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:_jsx(_components.code,{children:`AWS Elastic File System (EFS)`})}),`\n`,_jsx(_components.li,{children:_jsx(_components.code,{children:`Google Cloud Filestore (enterprise tier)`})}),`\n`,_jsx(_components.li,{children:_jsx(_components.code,{children:`Azure Files`})}),`\n`,_jsx(_components.li,{children:_jsx(_components.code,{children:`CephFS`})}),`\n`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Action:`}),` If you use one of these backends, you don’t need to allocate disk\nspace in the Thoras configuration, the disk will automatically grow to meet your\nneeds.`]}),`\n`,_jsx(Heading,{level:`4`,id:`fixed-size-storage-backends`,children:`Fixed-Size Storage Backends`}),`\n`,_jsxs(_components.p,{children:[`These are PV storage backends that require explicit provisioning of a fixed\ncapacity and enforce the size specified in the `,_jsx(_components.code,{children:`PersistentVolumeClaim`}),`. These\nbackends require you to specify the desired size of the disk, which you should\nconfigure as a Helm chart value (read on for details on how to do that).\nExamples include:`]}),`\n`,_jsxs(_components.ul,{children:[`\n`,_jsx(_components.li,{children:_jsx(_components.code,{children:`AWS Elastic Block Store (EBS)`})}),`\n`,_jsx(_components.li,{children:_jsx(_components.code,{children:`Google Persistent Disk (GCP PD)`})}),`\n`,_jsx(_components.li,{children:_jsx(_components.code,{children:`Azure Disk Storage`})}),`\n`,_jsx(_components.li,{children:_jsx(_components.code,{children:`VMware vSphere Volumes`})}),`\n`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`Action:`}),` If you use a fixed-size storage backend, you’ll need to specify the\nvolume size as a Helm value:`]}),`\n`,_jsxs(_components.ol,{children:[`\n`,_jsxs(_components.li,{children:[`Determine how much total size will be needed using\n`,_jsx(_components.a,{href:`#understanding-usage`,children:`guidance above`})]}),`\n`,_jsx(_components.li,{children:`Configure the storage size by setting the following helm value:`}),`\n`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`4`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`4`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`metricsCollector`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` persistence`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # Or whatever size needed based on your math from step #1`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` pvcStorageRequestSize`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"100Gi\"`})]}),`\n`]})})}),`\n`,_jsx(Heading,{level:`2`,id:`managing-persistent-volumes`,children:`Managing Persistent Volumes`}),`\n`,_jsx(_components.p,{children:`You may have an established workflow for provisioning Kubernetes Persistent\nVolumes (PV). That’s great! Here’s how to get up and running depending on your\npreferred approach:`}),`\n`,_jsxs(Heading,{level:`3`,id:`referencing-an-existing-storageclass-provisioner`,children:[`Referencing an existing `,_jsx(_components.code,{children:`StorageClass`}),` provisioner`]}),`\n`,_jsxs(_components.p,{children:[`If you have a Kubernetes `,_jsx(_components.code,{children:`StorageClass`}),` that you’d like to use to dynamically\nprovision your PV (such as an\n`,_jsx(_components.a,{href:`https://github.com/kubernetes-sigs/aws-efs-csi-driver/blob/master/examples/kubernetes/dynamic_provisioning/specs/storageclass.yaml`,children:`EFS StorageClass`}),`).\nIn that case, simply reference the storage class name in your Thoras helm chart\n`,_jsx(_components.code,{children:`values.yaml`}),`:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`3`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`3`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`metricsCollector`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` persistence`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` storageClassName`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"{{ YOUR_STORAGE_CLASS_NAME }}\"`})]}),`\n`]})})}),`\n`,_jsx(Note,{children:_jsxs(_components.p,{children:[_jsx(_components.code,{children:`metricsCollector.persistence.enabled`}),` defaults to `,_jsx(_components.code,{children:`null`}),`, which auto-enables\npersistence as soon as you set any of `,_jsx(_components.code,{children:`storageClassName`}),`,\n`,_jsx(_components.code,{children:`pvcStorageRequestSize`}),`, or `,_jsx(_components.code,{children:`createEFSStorageClass.fileSystemId`}),`. Setting\n`,_jsx(_components.code,{children:`enabled: true`}),` is only necessary if you want to force persistence on without\nconfiguring any of the above.`]})}),`\n`,_jsx(Heading,{level:`3`,id:`referencing-an-existing-pv`,children:`Referencing an existing PV`}),`\n`,_jsxs(_components.p,{children:[`If you have a workflow for provisioning a PV and would like to simply reference\nthe PV directly by name, add the following config block to your Helm\n`,_jsx(_components.code,{children:`values.yaml`}),`:`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`4`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`4`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`metricsCollector`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` persistence`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` enabled`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0550AE`,\"--shiki-dark\":`#569CD6`},children:`true`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` volumeName`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"{{ YOUR_VOLUME_NAME_HERE }}\"`})]}),`\n`]})})}),`\n`,_jsx(Heading,{level:`2`,id:`external-timescaledb-byodb`,children:`External TimescaleDB (BYODB)`}),`\n`,_jsx(_components.p,{children:`The chart deploys an in-cluster TimescaleDB by default. If you’d rather manage\nTimescaleDB yourself, for backups, HA, or shared infrastructure, point Thoras at\nan external database instead:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`3`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`3`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`externalTimescale`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#6E7781`,\"--shiki-dark\":`#6A9955`},children:` # Full postgres DSN, including the database name.`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` dsn`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`\"postgres://user:password@host:5432/tsdb?sslmode=require\"`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`Or reference an existing Secret containing the DSN:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`3`,language:`yaml`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-default dark-plus`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0B0C0E`,color:`#1f2328`,\"--shiki-dark\":`#D4D4D4`},language:`yaml`,children:_jsxs(_components.code,{language:`yaml`,numberOfLines:`3`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:`externalTimescale`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`:`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` secretRefName`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`my-timescale-dsn`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#116329`,\"--shiki-dark\":`#569CD6`},children:` secretRefKey`}),_jsx(_components.span,{style:{color:`#1F2328`,\"--shiki-dark\":`#D4D4D4`},children:`: `}),_jsx(_components.span,{style:{color:`#0A3069`,\"--shiki-dark\":`#CE9178`},children:`dsn`})]}),`\n`]})})}),`\n`,_jsx(_components.p,{children:`When either is set, the chart skips deploying its bundled TimescaleDB and wires\nall components to the external database. The TimescaleDB extension must be\npre-installed on the external database.`}),`\n`,_jsxs(_components.p,{children:[`See `,_jsx(_components.a,{href:`/installation/credentials`,children:`Credentials`}),` for how the DSN interacts with the\nother credentials Thoras manages.`]}),`\n`,_jsx(Heading,{level:`2`,id:`questions`,children:`Questions?`}),`\n`,_jsxs(_components.p,{children:[`For help, email `,_jsx(_components.a,{href:`mailto:support@thoras.ai`,children:`support@thoras.ai`}),`.`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Persistent Storage","description":"Configure the persistent volume Thoras uses to retain historical usage metrics, and optionally point Thoras at an external TimescaleDB.","href":"/installation/persistent-storage"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Understanding Storage Requirements","slug":"understanding-storage-requirements","depth":2,"children":[{"title":"Understanding Usage","slug":"understanding-usage","depth":3,"children":[]},{"title":"Understanding Kubernetes Storage Backend","slug":"understanding-kubernetes-storage-backend","depth":3,"children":[]},{"title":"Growable Storage Backends","slug":"growable-storage-backends","depth":4,"children":[]},{"title":"Fixed-Size Storage Backends","slug":"fixed-size-storage-backends","depth":4,"children":[]}]},{"title":"Managing Persistent Volumes","slug":"managing-persistent-volumes","depth":2,"children":[{"title":"Referencing an existing StorageClass provisioner","slug":"referencing-an-existing-storageclass-provisioner","depth":3,"children":[]},{"title":"Referencing an existing PV","slug":"referencing-an-existing-pv","depth":3,"children":[]}]},{"title":"External TimescaleDB (BYODB)","slug":"external-timescaledb-byodb","depth":2,"children":[]},{"title":"Questions?","slug":"questions","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":[],"subdomain":"thoras","siteName":"Thoras Documentation","title":"Thoras Documentation","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-09-10T22:23:57.479Z","originalFileLocation":"installation/persistent-storage.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Configure the persistent volume Thoras uses to retain historical usage metrics, and optionally point Thoras at an external TimescaleDB.\">\u003cmeta data-mint-head name=\"application-name\" content=\"Thoras Documentation\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/thoras/ZwCsC7wnwzlNbvBX/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/thoras/ZwCsC7wnwzlNbvBX/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/thoras/ZwCsC7wnwzlNbvBX/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/thoras/ZwCsC7wnwzlNbvBX/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/thoras/ZwCsC7wnwzlNbvBX/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/thoras/ZwCsC7wnwzlNbvBX/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/thoras/ZwCsC7wnwzlNbvBX/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/thoras/ZwCsC7wnwzlNbvBX/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/thoras/ZwCsC7wnwzlNbvBX/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Thoras Documentation\">\u003cmeta data-mint-head property=\"og:description\" content=\"The autonomous control plane for compute efficiency. Predictive Kubernetes autoscaling, self-hosted.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Thoras Documentation\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.thoras.ai/installation/persistent-storage\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://thoras.mintlify.app/og-image.png\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Thoras Documentation\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"The autonomous control plane for compute efficiency. Predictive Kubernetes autoscaling, self-hosted.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://thoras.mintlify.app/og-image.png\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/thoras/ZwCsC7wnwzlNbvBX/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Thoras Documentation\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#6b998f\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.thoras.ai/installation/persistent-storage\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/installation/persistent-storage.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.thoras.ai/#organization\",\"name\":\"Thoras Documentation\",\"url\":\"https://docs.thoras.ai\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/thoras/d2dju-xNTLxLCVzd/logo/light.png?fit=max\u0026auto=format\u0026n=d2dju-xNTLxLCVzd\u0026q=85\u0026s=657db4d808549261842fe7ed7fd4332c\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.thoras.ai#website\",\"name\":\"Thoras Documentation\",\"url\":\"https://docs.thoras.ai\",\"publisher\":{\"@id\":\"https://docs.thoras.ai/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.thoras.ai/installation/persistent-storage#webpage\",\"url\":\"https://docs.thoras.ai/installation/persistent-storage\",\"name\":\"Persistent Storage\",\"description\":\"Configure the persistent volume Thoras uses to retain historical usage metrics, and optionally point Thoras at an external TimescaleDB.\",\"dateModified\":\"2026-09-10T22:23:57.479Z\",\"isPartOf\":{\"@id\":\"https://docs.thoras.ai#website\"},\"breadcrumb\":{\"@id\":\"https://docs.thoras.ai/installation/persistent-storage#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.thoras.ai/installation/persistent-storage#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Installation\",\"item\":\"https://docs.thoras.ai/installation/system-requirements\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Persistent Storage\",\"item\":\"https://docs.thoras.ai/installation/persistent-storage\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://docs.thoras.ai/installation/persistent-storage#article\",\"headline\":\"Persistent Storage\",\"name\":\"Persistent Storage\",\"description\":\"Configure the persistent volume Thoras uses to retain historical usage metrics, and optionally point Thoras at an external TimescaleDB.\",\"url\":\"https://docs.thoras.ai/installation/persistent-storage\",\"mainEntityOfPage\":{\"@id\":\"https://docs.thoras.ai/installation/persistent-storage#webpage\"},\"image\":\"https://docs.thoras.ai/og-image.png\",\"dateModified\":\"2026-09-10T22:23:57.479Z\",\"publisher\":{\"@id\":\"https://docs.thoras.ai/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.thoras.ai#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Thoras Documentation\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Thoras Documentation","nav":{"global":null,"tabs":[{"tab":"Documentation","groups":[{"group":"Getting Started","pages":[{"title":"What is Thoras?","href":"/getting-started/what-is-thoras"},{"title":"Quickstart","href":"/getting-started/quickstart"}]},{"group":"Installation","pages":[{"title":"System Requirements","href":"/installation/system-requirements"},{"title":"Advanced Setup","description":null,"href":"/installation/advanced-setup"},{"title":"Persistent Storage","href":"/installation/persistent-storage"},{"title":"Credentials","description":"How Thoras handles the credentials it needs, and how to supply your own.","href":"/installation/credentials"},{"title":"Private Container Registry","href":"/installation/private-registry"},{"title":"Upgrading","href":"/installation/upgrading"}]},{"group":"Guides","pages":[{"group":"Scaling workloads","pages":[{"title":"Configuring AIScaleTargets","href":"/guides/configuring-asts"},{"title":"Predictive Vertical Pod Rightsizing","href":"/guides/vertical-pod-rightsizing"},{"title":"In-Place Resize Behavior","href":"/guides/in-place-resize"},{"title":"Predictive Horizontal Pod Autoscaling","href":"/guides/hpa"},{"title":"Choosing a Forecast Optimization Strategy","href":"/guides/forecast-optimization-strategies"},{"title":"OOM Remediation","href":"/guides/oom-remediation"},{"title":"JVM Workload Scaling","href":"/guides/jvm-scaling"}]},{"group":"Operating Thoras","pages":[{"title":"Enabling Autonomous Mode","href":"/guides/enabling-autonomous-mode"},{"title":"Pausing Autonomous Scaling","href":"/guides/pause-scaling"},{"title":"Audit Trail","href":"/guides/audit-trail"},{"title":"Stopping Autonomous Scaling","href":"/guides/stopping-autoscaling"},{"title":"ArgoCD","href":"/guides/argo-cd"},{"title":"Tuning for Large Clusters","href":"/guides/large-clusters"},{"title":"Diagnostics Export","href":"/guides/diagnostics"}]},{"title":"Monitoring Thoras","href":"/guides/metrics"},{"title":"Cost Estimates","href":"/guides/cost-estimates"},{"title":"AWS Cost Explorer","href":"/guides/aws-cost-explorer"},{"group":"Dashboard authentication","root":{"title":"Dashboard authentication","href":"/guides/dashboard-auth"},"pages":[{"title":"Default (htpasswd) dashboard auth","href":"/guides/dashboard-auth/htpasswd"},{"title":"Okta OIDC dashboard auth","href":"/guides/dashboard-auth/okta"},{"title":"Azure Entra OIDC dashboard auth","href":"/guides/dashboard-auth/entra"}]}]}]},{"tab":"Reference","pages":[{"title":"Reference","href":"/reference/ast-definition"}]},{"tab":"FAQ","pages":[{"title":"FAQ","href":"/faq/introduction"}]},{"tab":"Policies","pages":[{"title":"Policies","href":"/policies/support-policy"}]}]},"title":"Thoras Documentation","buildId":"dpl_cadrRc5H9XQiJQbDFN5mcYRs2PAj","deploymentId":"dpl_cadrRc5H9XQiJQbDFN5mcYRs2PAj","dynamics":[],"chunks":[]}