├── .github └── workflows │ └── lint-test.yaml ├── LICENSE ├── README.md ├── build.sh ├── build ├── supabase-0.0.1.tgz └── supabase-0.0.2.tgz ├── charts ├── .helmignore └── supabase │ ├── .DS_Store │ ├── Chart.yaml │ ├── README.md │ ├── ci │ └── example-values.yaml │ ├── docker │ └── Database.Dockerfile │ ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── analytics │ │ ├── _helpers.tpl │ │ ├── deployment.yaml │ │ ├── gcloud.secret.yaml │ │ ├── service.yaml │ │ └── serviceaccount.yaml │ ├── auth │ │ ├── _helpers.tpl │ │ ├── deployment.yaml │ │ ├── service.yaml │ │ └── serviceaccount.yaml │ ├── db │ │ ├── _helpers.tpl │ │ ├── deployment.yaml │ │ ├── initdb.config.yaml │ │ ├── migration.config.yaml │ │ ├── service.yaml │ │ ├── serviceaccount.yaml │ │ └── volume.yaml │ ├── functions │ │ ├── _helpers.tpl │ │ ├── deployment.yaml │ │ ├── functions.config.yaml │ │ ├── service.yaml │ │ └── serviceaccount.yaml │ ├── imgproxy │ │ ├── _helpers.tpl │ │ ├── deployment.yaml │ │ ├── service.yaml │ │ ├── serviceaccount.yaml │ │ └── volume.yaml │ ├── kong │ │ ├── _helpers.tpl │ │ ├── config.yaml │ │ ├── deployment.yaml │ │ ├── ingress.yaml │ │ ├── service.yaml │ │ └── serviceaccount.yaml │ ├── meta │ │ ├── _helpers.tpl │ │ ├── deployment.yaml │ │ ├── service.yaml │ │ └── serviceaccount.yaml │ ├── minio │ │ ├── _helpers.tpl │ │ ├── deployment.yaml │ │ ├── service.yaml │ │ ├── serviceaccount.yaml │ │ └── volume.yaml │ ├── realtime │ │ ├── _helpers.tpl │ │ ├── deployment.yaml │ │ ├── service.yaml │ │ └── serviceaccount.yaml │ ├── rest │ │ ├── _helpers.tpl │ │ ├── deployment.yaml │ │ ├── service.yaml │ │ └── serviceaccount.yaml │ ├── secrets │ │ ├── _helpers.tpl │ │ ├── analytics.yaml │ │ ├── dashboard.yaml │ │ ├── db.yaml │ │ ├── jwt.yaml │ │ ├── s3.yaml │ │ └── smtp.yaml │ ├── storage │ │ ├── _helpers.tpl │ │ ├── deployment.yaml │ │ ├── service.yaml │ │ ├── serviceaccount.yaml │ │ └── volume.yaml │ ├── studio │ │ ├── _helpers.tpl │ │ ├── deployment.yaml │ │ ├── service.yaml │ │ └── serviceaccount.yaml │ ├── test │ │ ├── analytics.yaml │ │ ├── auth.yaml │ │ ├── db.yaml │ │ ├── imgproxy.yaml │ │ ├── kong.yaml │ │ ├── meta.yaml │ │ ├── minio.yaml │ │ ├── realtime.yaml │ │ ├── rest.yaml │ │ ├── secretrefs.yaml │ │ ├── storage.yaml │ │ └── studio.yaml │ └── vector │ │ ├── _helpers.tpl │ │ ├── config.yaml │ │ ├── deployment.yaml │ │ ├── service.yaml │ │ └── serviceaccount.yaml │ ├── values.example.yaml │ └── values.yaml └── index.yaml /.github/workflows/lint-test.yaml: -------------------------------------------------------------------------------- 1 | name: Lint and Test Charts 2 | 3 | on: pull_request 4 | 5 | jobs: 6 | lint-test: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout 10 | uses: actions/checkout@v3 11 | with: 12 | fetch-depth: 0 13 | 14 | - name: Set up Helm 15 | uses: azure/setup-helm@v3 16 | with: 17 | version: v3.12.1 18 | 19 | - uses: actions/setup-python@v4 20 | with: 21 | python-version: "3.10" 22 | check-latest: true 23 | 24 | - name: Set up chart-testing 25 | uses: helm/chart-testing-action@v2.6.0 26 | 27 | - name: Run chart-testing (list-changed) 28 | id: list-changed 29 | run: | 30 | changed=$(ct list-changed --target-branch ${{ github.event.repository.default_branch }}) 31 | if [[ -n "$changed" ]]; then 32 | echo "changed=true" >> "$GITHUB_OUTPUT" 33 | fi 34 | 35 | - name: Run chart-testing (lint) 36 | if: steps.list-changed.outputs.changed == 'true' 37 | run: ct lint --validate-maintainers=false --target-branch ${{ github.event.repository.default_branch }} 38 | 39 | - name: Create kind cluster 40 | if: steps.list-changed.outputs.changed == 'true' 41 | uses: helm/kind-action@v1.8.0 42 | 43 | - name: Run chart-testing (install) 44 | if: steps.list-changed.outputs.changed == 'true' 45 | run: ct install --target-branch ${{ github.event.repository.default_branch }} 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Supabase Kubernetes 2 | 3 | This repository contains the charts to deploy a [Supabase](https://github.com/supabase/supabase) instance inside a Kubernetes cluster using Helm 3. 4 | 5 | For any information regarding Supabase itself you can refer to the [official documentation](https://supabase.io/docs). 6 | 7 | ## What's Supabase ? 8 | 9 | Supabase is an open source Firebase alternative. We're building the features of Firebase using enterprise-grade open source tools. 10 | 11 | ## How to use ? 12 | 13 | You can find the documentation inside the [chart directory](./charts/supabase/README.md) 14 | 15 | # Roadmap 16 | 17 | - [ ] Multi-node Support 18 | 19 | ## Support 20 | 21 | This project is supported by the community and not officially supported by Supabase. Please do not create any issues on the official Supabase repositories if you face any problems using this project, but rather open an issue on this repository. 22 | 23 | ## Contributing 24 | 25 | You can contribute to this project by forking this repository and opening a pull request. 26 | 27 | When you're ready to publish your chart on the `main` branch, you'll have to execute `sh build.sh` to package the charts and generate the Helm manifest. 28 | 29 | ## License 30 | 31 | [Apache 2.0 License.](./LICENSE) 32 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | helm package ./charts/supabase -d build/ 4 | helm repo index ./ 5 | # sed 's+build+head+g' ./index.yaml > ./index.yaml 6 | 7 | # Crossplatform sed workaround from: https://unix.stackexchange.com/questions/92895/how-can-i-achieve-portability-with-sed-i-in-place-editing 8 | case $(sed --help 2>&1) in 9 | *GNU*) set sed -i;; 10 | *) set sed -i '';; 11 | esac 12 | 13 | "$@" -e 's+build+https://supabase-community.github.io/supabase-kubernetes/build+g' ./index.yaml 14 | -------------------------------------------------------------------------------- /build/supabase-0.0.1.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/supabase-kubernetes/17e14e812fd60a7b5eedb56bf3b359f42ebf91a4/build/supabase-0.0.1.tgz -------------------------------------------------------------------------------- /build/supabase-0.0.2.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/supabase-kubernetes/17e14e812fd60a7b5eedb56bf3b359f42ebf91a4/build/supabase-0.0.2.tgz -------------------------------------------------------------------------------- /charts/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /charts/supabase/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/supabase-community/supabase-kubernetes/17e14e812fd60a7b5eedb56bf3b359f42ebf91a4/charts/supabase/.DS_Store -------------------------------------------------------------------------------- /charts/supabase/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: supabase 3 | description: The open source Firebase alternative. 4 | 5 | # A chart can be either an 'application' or a 'library' chart. 6 | # 7 | # Application charts are a collection of templates that can be packaged into versioned archives 8 | # to be deployed. 9 | # 10 | # Library charts provide useful utilities or functions for the chart developer. They're included as 11 | # a dependency of application charts to inject those utilities and functions into the rendering 12 | # pipeline. Library charts do not define any templates and therefore cannot be deployed. 13 | type: application 14 | 15 | # This is the chart version. This version number should be incremented each time you make changes 16 | # to the chart and its templates, including the app version. 17 | # Versions are expected to follow Semantic Versioning (https://semver.org/) 18 | version: 0.1.3 19 | 20 | # This is the version number of the application being deployed. This version number should be 21 | # incremented each time you make changes to the application. Versions are not expected to 22 | # follow Semantic Versioning. They should reflect the version the application is using. 23 | # It is recommended to use it with quotes. 24 | # Not used because too difficult to follow correctly 25 | # appVersion: "1.16.0" 26 | 27 | # A URL to an SVG or PNG image to be used as an icon 28 | icon: https://avatars.githubusercontent.com/u/54469796?s=280&v=4 29 | -------------------------------------------------------------------------------- /charts/supabase/README.md: -------------------------------------------------------------------------------- 1 | # Supabase for Kubernetes with Helm 3 2 | 3 | This directory contains the configurations and scripts required to run Supabase inside a Kubernetes cluster. 4 | 5 | ## Disclamer 6 | 7 | We use [supabase/postgres](https://hub.docker.com/r/supabase/postgres) to create and manage the Postgres database. This permit you to use replication if needed but you'll have to use the Postgres image provided Supabase or build your own on top of it. You can also choose to use other databases provider like [StackGres](https://stackgres.io/) or [Postgres Operator](https://github.com/zalando/postgres-operator). 8 | 9 | For the moment we are using a root container to permit the installation of the missing `pgjwt` and `wal2json` extension inside the `initdbScripts`. This is considered a security issue, but you can use your own Postgres image instead with the extension already installed to prevent this. We provide an example of `Dockerfile`for this purpose, you can use [ours](https://hub.docker.com/r/tdeoliv/supabase-bitnami-postgres) or build and host it on your own. 10 | 11 | The database configuration we provide is an example using only one master. If you want to go to production, we highly recommend you to use a replicated database. 12 | 13 | ## Quickstart 14 | 15 | > For this section we're using Minikube and Docker to create a Kubernetes cluster 16 | 17 | ```bash 18 | # Clone Repository 19 | git clone https://github.com/supabase-community/supabase-kubernetes 20 | 21 | # Switch to charts directory 22 | cd supabase-kubernetes/charts/supabase/ 23 | 24 | # Install the chart 25 | helm install demo -f values.example.yaml . 26 | ``` 27 | 28 | The first deployment can take some time to complete (especially auth service). You can view the status of the pods using: 29 | 30 | ```bash 31 | kubectl get pod -l app.kubernetes.io/instance=demo 32 | 33 | NAME READY STATUS RESTARTS AGE 34 | demo-supabase-analytics-xxxxxxxxxx-xxxxx 1/1 Running 0 47s 35 | demo-supabase-auth-xxxxxxxxxx-xxxxx 1/1 Running 0 47s 36 | demo-supabase-db-xxxxxxxxxx-xxxxx 1/1 Running 0 47s 37 | demo-supabase-functions-xxxxxxxxxx-xxxxx 1/1 Running 0 47s 38 | demo-supabase-imgproxy-xxxxxxxxxx-xxxxx 1/1 Running 0 47s 39 | demo-supabase-kong-xxxxxxxxxx-xxxxx 1/1 Running 0 47s 40 | demo-supabase-meta-xxxxxxxxxx-xxxxx 1/1 Running 0 47s 41 | demo-supabase-realtime-xxxxxxxxxx-xxxxx 1/1 Running 0 47s 42 | demo-supabase-rest-xxxxxxxxxx-xxxxx 1/1 Running 0 47s 43 | demo-supabase-storage-xxxxxxxxxx-xxxxx 1/1 Running 0 47s 44 | ``` 45 | 46 | ### Access with Minikube 47 | 48 | Assuming that you have enabled Minikube ingress addon, note down the Minikube IP address: 49 | ```shell 50 | minikube ip 51 | ``` 52 | Then, add the IP into your `/etc/hosts` file: 53 | ```bash 54 | # This will redirect request for example.com to the minikube IP 55 | example.com 56 | ``` 57 | Open http://example.com in your browser. 58 | 59 | ### Uninstall 60 | 61 | ```Bash 62 | # Uninstall Helm chart 63 | helm uninstall demo 64 | 65 | # Backup and/or remove any Persistent Volume Claims that have keep annotation 66 | kubectl delete pvc demo-supabase-storage-pvc 67 | ``` 68 | 69 | ## Customize 70 | 71 | You should consider to adjust the following values in `values.yaml`: 72 | 73 | - `RELEASE_NAME`: Name used for helm release 74 | - `STUDIO.EXAMPLE.COM` URL to Studio 75 | 76 | If you want to use mail, consider to adjust the following values in `values.yaml`: 77 | 78 | - `SMTP_ADMIN_MAIL` 79 | - `SMTP_HOST` 80 | - `SMTP_PORT` 81 | - `SMTP_SENDER_NAME` 82 | 83 | ### JWT Secret 84 | 85 | We encourage you to use your own JWT keys by generating a new Kubernetes secret and reference it in `values.yaml`: 86 | 87 | ```yaml 88 | secret: 89 | jwt: 90 | anonKey: 91 | serviceKey: 92 | secret: 93 | ``` 94 | 95 | > 32 characters long secret can be generated with `openssl rand 64 | base64` 96 | > You can use the [JWT Tool](https://supabase.com/docs/guides/hosting/overview#api-keys) to generate anon and service keys. 97 | 98 | ### SMTP Secret 99 | 100 | Connection credentials for the SMTP mail server will also be provided via Kubernetes secret referenced in `values.yaml`: 101 | 102 | ```yaml 103 | secret: 104 | smtp: 105 | username: 106 | password: 107 | ``` 108 | 109 | ### DB Secret 110 | 111 | DB credentials will also be stored in a Kubernetes secret and referenced in `values.yaml`: 112 | 113 | ```yaml 114 | secret: 115 | db: 116 | username: 117 | password: 118 | database: 119 | ``` 120 | 121 | The secret can be created with kubectl via command-line: 122 | 123 | > If you depend on database providers like [StackGres](https://stackgres.io/), [Postgres Operator](https://github.com/zalando/postgres-operator) or self-hosted Postgres instance, fill in the secret above and modify any relevant Postgres attributes such as port or hostname (e.g. `PGPORT`, `DB_HOST`) for any relevant deployments. Refer to [values.yaml](values.yaml) for more details. 124 | 125 | ### Dashboard secret 126 | 127 | By default, a username and password is required to access the Supabase Studio dashboard. Simply change them at: 128 | 129 | ```yaml 130 | secret: 131 | dashboard: 132 | username: supabase 133 | password: this_password_is_insecure_and_should_be_updated 134 | ``` 135 | 136 | ### Analytics secret 137 | 138 | A new logflare secret API key is required for securing communication between all of the Supabase services. To set the secret, generate a new 32 characters long secret similar to the step [above](#jwt-secret). 139 | 140 | ```yaml 141 | secret: 142 | analytics: 143 | apiKey: your-super-secret-with-at-least-32-characters-long-logflare-key 144 | ``` 145 | 146 | ### S3 secret 147 | 148 | Supabase storage supports the use of S3 object-storage. To enable S3 for Supabase storage: 149 | 150 | 1. Set S3 key ID and access key: 151 | ```yaml 152 | secret: 153 | s3: 154 | keyId: your-s3-key-id 155 | accessKey: your-s3-access-key 156 | ``` 157 | 2. Set storage S3 environment variables: 158 | ```yaml 159 | storage: 160 | environment: 161 | # Set S3 endpoint if using external object-storage 162 | # GLOBAL_S3_ENDPOINT: http://minio:9000 163 | STORAGE_BACKEND: s3 164 | GLOBAL_S3_PROTOCOL: http 165 | GLOBAL_S3_FORCE_PATH_STYLE: true 166 | AWS_DEFAULT_REGION: stub 167 | ``` 168 | 3. (Optional) Enable internal minio deployment 169 | ```yaml 170 | minio: 171 | enabled: true 172 | ``` 173 | 174 | ## How to use in Production 175 | 176 | We didn't provide a complete configuration to go production because of the multiple possibility. 177 | 178 | But here are the important points you have to think about: 179 | 180 | - Use a replicated version of the Postgres database. 181 | - Add SSL to the Postgres database. 182 | - Add SSL configuration to the ingresses endpoints using either the `cert-manager` or a LoadBalancer provider. 183 | - Change the domain used in the ingresses endpoints. 184 | - Generate a new secure JWT Secret. 185 | 186 | ### Migration 187 | 188 | Migration from local development is made easy by adding migration scripts at `db.config` field. This will apply all of the migration scripts during the database initialization. For example: 189 | 190 | ```yaml 191 | db: 192 | config: 193 | 20230101000000_profiles.sql: | 194 | create table profiles ( 195 | id uuid references auth.users not null, 196 | updated_at timestamp with time zone, 197 | username text unique, 198 | avatar_url text, 199 | website text, 200 | 201 | primary key (id), 202 | unique(username), 203 | constraint username_length check (char_length(username) >= 3) 204 | ); 205 | ``` 206 | 207 | To make copying scripts easier, use this handy bash script: 208 | 209 | ```bash 210 | #!/bin/bash 211 | 212 | for file in $1/*; do 213 | clipboard+=" $(basename $file): |\n" 214 | clipboard+=$(cat $file | awk '{print " "$0}') 215 | clipboard+="\n" 216 | done 217 | 218 | echo -e "$clipboard" 219 | ``` 220 | 221 | and pipe it to your system clipboard handler: 222 | 223 | ```shell 224 | # Using xclip as an example 225 | ./script.sh supabase/migrations | xclip -sel clipboard 226 | ``` 227 | 228 | ## Troubleshooting 229 | 230 | ### Ingress Controller and Ingress Class 231 | 232 | Depending on your Kubernetes version you might want to fill the `className` property instead of the `kubernetes.io/ingress.class` annotations. For example: 233 | 234 | ```yml 235 | kong: 236 | ingress: 237 | enabled: 'true' 238 | className: "nginx" 239 | annotations: 240 | nginx.ingress.kubernetes.io/rewrite-target: / 241 | ``` 242 | 243 | ### Testing suite 244 | 245 | Before creating a merge request, you can test the charts locally by using [helm/chart-testing](https://github.com/helm/chart-testing). If you have Docker and a Kubernetes environment to test with, simply run: 246 | 247 | ```shell 248 | # Run chart-testing (lint) 249 | docker run -it \ 250 | --workdir=/data \ 251 | --volume $(pwd)/charts/supabase:/data \ 252 | quay.io/helmpack/chart-testing:v3.7.1 \ 253 | ct lint --validate-maintainers=false --chart-dirs . --charts . 254 | # Run chart-testing (install) 255 | docker run -it \ 256 | --network host \ 257 | --workdir=/data \ 258 | --volume ~/.kube/config:/root/.kube/config:ro \ 259 | --volume $(pwd)/charts/supabase:/data \ 260 | quay.io/helmpack/chart-testing:v3.7.1 \ 261 | ct install --chart-dirs . --charts . 262 | ``` 263 | 264 | ### Version compatibility 265 | 266 | #### `0.0.x` to `0.1.x` 267 | 268 | * `supabase/postgres` is updated from `14.1` to `15.1`, which warrants backing up all your data before proceeding to update to the next major version. 269 | * Intialization scripts for `supabase/postgres` has been reworked and matched closely to the [Docker Compose](https://github.com/supabase/supabase/blob/master/docker/docker-compose.yml) version. Further tweaks to the scripts are needed to ensure backward-compatibility. 270 | * Migration scripts are now exposed at `db.config`, which will be mounted at `/docker-entrypoint-initdb.d/migrations/`. Simply copy your migration files from your local project's `supabase/migration` and populate the `db.config`. 271 | * Ingress are now limited to `kong` & `db` services. This is by design to limit entry to the stack through secure `kong` service. 272 | * `kong.yaml` has been modified to follow [Docker kong.yaml](https://github.com/supabase/supabase/blob/master/docker/volumes/api/kong.yml) template. 273 | * `supabase/storage` does not comes with pre-populated `/var/lib/storage`, therefore an `emptyDir` will be created if persistence is disabled. This might be incompatible with previous version if the persistent storage location is set to location other than specified above. 274 | * `supabase/vector` requires read access to the `/var/log/pods` directory. When run in a Kubernetes cluster this can be provided with a [hostPath](https://kubernetes.io/docs/concepts/storage/volumes/#hostpath) volume. 275 | -------------------------------------------------------------------------------- /charts/supabase/ci/example-values.yaml: -------------------------------------------------------------------------------- 1 | ../values.example.yaml -------------------------------------------------------------------------------- /charts/supabase/docker/Database.Dockerfile: -------------------------------------------------------------------------------- 1 | FROM bitnami/postgresql:12.9.0-debian-10-r40 2 | 3 | USER root 4 | 5 | RUN install_packages make git gcc libc6-dev 6 | RUN git clone https://github.com/michelp/pgjwt.git 7 | RUN cd pgjwt && make install 8 | RUN git clone https://github.com/eulerto/wal2json.git 9 | RUN cd wal2json && make && make install 10 | 11 | USER 1001 -------------------------------------------------------------------------------- /charts/supabase/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | --- 2 | Thank you for installing {{ .Chart.Name }}! 3 | {{ if .Values.kong.ingress.enabled }} 4 | Visit the Studio dashboard at http://{{ (index .Values.kong.ingress.hosts 0).host }} 5 | {{- end }} 6 | -------------------------------------------------------------------------------- /charts/supabase/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "supabase.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "supabase.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "supabase.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "supabase.labels" -}} 37 | helm.sh/chart: {{ include "supabase.chart" . }} 38 | {{ include "supabase.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "supabase.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "supabase.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | {{/* 54 | Create the name of the service account to use 55 | */}} 56 | {{- define "supabase.serviceAccountName" -}} 57 | {{- if .Values.serviceAccount.create }} 58 | {{- default (include "supabase.fullname" .) .Values.serviceAccount.name }} 59 | {{- else }} 60 | {{- default "default" .Values.serviceAccount.name }} 61 | {{- end }} 62 | {{- end }} 63 | -------------------------------------------------------------------------------- /charts/supabase/templates/analytics/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "supabase.analytics.name" -}} 5 | {{- default (print .Chart.Name "-analytics") .Values.analytics.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "supabase.analytics.fullname" -}} 14 | {{- if .Values.analytics.fullnameOverride }} 15 | {{- .Values.analytics.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default (print .Chart.Name "-analytics") .Values.analytics.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Selector labels 28 | */}} 29 | {{- define "supabase.analytics.selectorLabels" -}} 30 | app.kubernetes.io/name: {{ include "supabase.analytics.name" . }} 31 | app.kubernetes.io/instance: {{ .Release.Name }} 32 | {{- end }} 33 | 34 | {{/* 35 | Create the name of the service account to use 36 | */}} 37 | {{- define "supabase.analytics.serviceAccountName" -}} 38 | {{- if .Values.analytics.serviceAccount.create }} 39 | {{- default (include "supabase.analytics.fullname" .) .Values.analytics.serviceAccount.name }} 40 | {{- else }} 41 | {{- default "default" .Values.analytics.serviceAccount.name }} 42 | {{- end }} 43 | {{- end }} 44 | -------------------------------------------------------------------------------- /charts/supabase/templates/analytics/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.analytics.enabled -}} 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: {{ include "supabase.analytics.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | {{- if not .Values.analytics.autoscaling.enabled }} 10 | replicas: {{ .Values.analytics.replicaCount }} 11 | {{- end }} 12 | selector: 13 | matchLabels: 14 | {{- include "supabase.analytics.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | {{- with .Values.analytics.podAnnotations }} 18 | annotations: 19 | {{- toYaml . | nindent 8 }} 20 | {{- end }} 21 | labels: 22 | {{- include "supabase.analytics.selectorLabels" . | nindent 8 }} 23 | spec: 24 | {{- with .Values.analytics.imagePullSecrets }} 25 | imagePullSecrets: 26 | {{- toYaml . | nindent 8 }} 27 | {{- end }} 28 | serviceAccountName: {{ include "supabase.analytics.serviceAccountName" . }} 29 | securityContext: 30 | {{- toYaml .Values.analytics.podSecurityContext | nindent 8 }} 31 | initContainers: 32 | - name: init-db 33 | image: postgres:15-alpine 34 | imagePullPolicy: IfNotPresent 35 | env: 36 | - name: DB_HOST 37 | {{- if .Values.db.enabled }} 38 | value: {{ include "supabase.db.fullname" . | quote }} 39 | {{- else }} 40 | value: {{ .Values.analytics.environment.DB_HOST | quote }} 41 | {{- end }} 42 | - name: DB_USER 43 | valueFrom: 44 | secretKeyRef: 45 | {{- if .Values.secret.db.secretRef }} 46 | name: {{ .Values.secret.db.secretRef }} 47 | key: {{ .Values.secret.db.secretRefKey.username | default "username" }} 48 | {{- else }} 49 | name: {{ include "supabase.secret.db" . }} 50 | key: username 51 | {{- end }} 52 | - name: DB_PORT 53 | value: {{ .Values.analytics.environment.DB_PORT | quote }} 54 | command: ["/bin/sh", "-c"] 55 | args: 56 | - | 57 | until pg_isready -h $(DB_HOST) -p $(DB_PORT) -U $(DB_USER); do 58 | echo "Waiting for database to start..." 59 | sleep 2 60 | done 61 | - echo "Database is ready" 62 | containers: 63 | - name: {{ include "supabase.analytics.name" $ }} 64 | securityContext: 65 | {{- toYaml .Values.analytics.securityContext | nindent 12 }} 66 | image: "{{ .Values.analytics.image.repository }}:{{ .Values.analytics.image.tag | default .Chart.AppVersion }}" 67 | imagePullPolicy: {{ .Values.analytics.image.pullPolicy }} 68 | env: 69 | {{- range $key, $value := .Values.analytics.environment }} 70 | - name: {{ $key }} 71 | value: {{ $value | quote }} 72 | {{- end }} 73 | {{- if .Values.db.enabled }} 74 | - name: DB_HOSTNAME 75 | value: {{ include "supabase.db.fullname" . }} 76 | {{- end }} 77 | - name: DB_PASSWORD 78 | valueFrom: 79 | secretKeyRef: 80 | {{- if .Values.secret.db.secretRef }} 81 | name: {{ .Values.secret.db.secretRef }} 82 | key: {{ .Values.secret.db.secretRefKey.password | default "password" }} 83 | {{- else }} 84 | name: {{ include "supabase.secret.db" . }} 85 | key: password 86 | {{- end }} 87 | - name: DB_PASSWORD_ENC 88 | valueFrom: 89 | secretKeyRef: 90 | {{- if .Values.secret.db.secretRef }} 91 | name: {{ .Values.secret.db.secretRef }} 92 | key: {{ .Values.secret.db.secretRefKey.password | default "password" }} 93 | {{- else }} 94 | name: {{ include "supabase.secret.db" . }} 95 | key: password_encoded 96 | {{- end }} 97 | - name: DB_DATABASE 98 | valueFrom: 99 | secretKeyRef: 100 | {{- if .Values.secret.db.secretRef }} 101 | name: {{ .Values.secret.db.secretRef }} 102 | key: {{ .Values.secret.db.secretRefKey.database | default "database" }} 103 | {{- else }} 104 | name: {{ include "supabase.secret.db" . }} 105 | key: database 106 | {{- end }} 107 | - name: LOGFLARE_API_KEY 108 | valueFrom: 109 | secretKeyRef: 110 | {{- if .Values.secret.analytics.secretRef }} 111 | name: {{ .Values.secret.analytics.secretRef }} 112 | key: {{ .Values.secret.analytics.secretRefKey.apiKey | default "apiKey" }} 113 | {{- else }} 114 | name: {{ include "supabase.secret.analytics" . }} 115 | key: apiKey 116 | {{- end }} 117 | {{- if .Values.analytics.bigQuery.enabled }} 118 | - name: GOOGLE_PROJECT_ID 119 | value: {{ .Values.analytics.bigQuery.projectId | quote }} 120 | - name: GOOGLE_PROJECT_NUMBER 121 | value: {{ .Values.analytics.bigQuery.projectNumber | quote }} 122 | {{- else }} 123 | - name: POSTGRES_BACKEND_URL 124 | value: $(DB_DRIVER)://$(DB_USERNAME):$(DB_PASSWORD_ENC)@$(DB_HOSTNAME):$(DB_PORT)/$(DB_DATABASE) 125 | - name: POSTGRES_BACKEND_SCHEMA 126 | value: $(DB_SCHEMA) 127 | - name: LOGFLARE_FEATURE_FLAG_OVERRIDE 128 | value: $(FEATURE_FLAG_OVERRIDE) 129 | {{- end }} 130 | {{- with .Values.analytics.livenessProbe }} 131 | livenessProbe: 132 | {{- toYaml . | nindent 12 }} 133 | {{- end }} 134 | {{- with .Values.analytics.readinessProbe }} 135 | readinessProbe: 136 | {{- toYaml . | nindent 12 }} 137 | {{- end }} 138 | ports: 139 | - containerPort: {{ .Values.analytics.service.port }} 140 | protocol: TCP 141 | {{- if or (.Values.analytics.bigQuery.enabled) (.Values.analytics.volumes) }} 142 | volumeMounts: 143 | {{- with .Values.analytics.volumeMounts }} 144 | {{- toYaml . | nindent 12 }} 145 | {{- end }} 146 | {{- if .Values.analytics.bigQuery.enabled }} 147 | - mountPath: /opt/app/rel/logflare/bin/gcloud.json 148 | name: gcloud-credentials 149 | subPath: gcloud.json 150 | {{- end }} 151 | {{- end }} 152 | {{- with .Values.analytics.resources }} 153 | resources: 154 | {{- toYaml . | nindent 12 }} 155 | {{- end }} 156 | {{- if or (.Values.analytics.bigQuery.enabled) (.Values.analytics.volumes) }} 157 | volumes: 158 | {{- with .Values.analytics.volumes }} 159 | {{- toYaml . | nindent 8 }} 160 | {{- end }} 161 | {{- if .Values.analytics.bigQuery.enabled }} 162 | - name: gcloud-credentials 163 | secret: 164 | secretName: {{ include "supabase.analytics.fullname" . }}-gcloud 165 | {{- end }} 166 | {{- end }} 167 | {{- with .Values.analytics.nodeSelector }} 168 | nodeSelector: 169 | {{- toYaml . | nindent 8 }} 170 | {{- end }} 171 | {{- with .Values.analytics.affinity }} 172 | affinity: 173 | {{- toYaml . | nindent 8 }} 174 | {{- end }} 175 | {{- with .Values.analytics.tolerations }} 176 | tolerations: 177 | {{- toYaml . | nindent 8 }} 178 | {{- end }} 179 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/analytics/gcloud.secret.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.analytics.bigQuery.enabled }} 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: {{ include "supabase.analytics.fullname" . }}-gcloud 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | type: Opaque 9 | data: 10 | gcloud.json: {{ .Values.analytics.bigQuery.gcloudJson | b64enc }} 11 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/analytics/service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.analytics.enabled -}} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ include "supabase.analytics.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | type: {{ .Values.analytics.service.type }} 10 | ports: 11 | - port: {{ .Values.analytics.service.port }} 12 | targetPort: 4000 13 | protocol: TCP 14 | name: http 15 | selector: 16 | {{- include "supabase.analytics.selectorLabels" . | nindent 4 }} 17 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/analytics/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.analytics.enabled -}} 2 | {{- if .Values.analytics.serviceAccount.create -}} 3 | apiVersion: v1 4 | kind: ServiceAccount 5 | metadata: 6 | name: {{ include "supabase.analytics.serviceAccountName" . }} 7 | labels: 8 | {{- include "supabase.labels" . | nindent 4 }} 9 | {{- with .Values.analytics.serviceAccount.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | {{- end }} 14 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/auth/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "supabase.auth.name" -}} 5 | {{- default (print .Chart.Name "-auth") .Values.auth.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "supabase.auth.fullname" -}} 14 | {{- if .Values.auth.fullnameOverride }} 15 | {{- .Values.auth.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default (print .Chart.Name "-auth") .Values.auth.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Selector labels 28 | */}} 29 | {{- define "supabase.auth.selectorLabels" -}} 30 | app.kubernetes.io/name: {{ include "supabase.auth.name" . }} 31 | app.kubernetes.io/instance: {{ .Release.Name }} 32 | {{- end }} 33 | 34 | {{/* 35 | Create the name of the service account to use 36 | */}} 37 | {{- define "supabase.auth.serviceAccountName" -}} 38 | {{- if .Values.auth.serviceAccount.create }} 39 | {{- default (include "supabase.auth.fullname" .) .Values.auth.serviceAccount.name }} 40 | {{- else }} 41 | {{- default "default" .Values.auth.serviceAccount.name }} 42 | {{- end }} 43 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/auth/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.auth.enabled -}} 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: {{ include "supabase.auth.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | {{- if not .Values.auth.autoscaling.enabled }} 10 | replicas: {{ .Values.auth.replicaCount }} 11 | {{- end }} 12 | selector: 13 | matchLabels: 14 | {{- include "supabase.auth.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | {{- with .Values.auth.podAnnotations }} 18 | annotations: 19 | {{- toYaml . | nindent 8 }} 20 | {{- end }} 21 | labels: 22 | {{- include "supabase.auth.selectorLabels" . | nindent 8 }} 23 | spec: 24 | {{- with .Values.auth.imagePullSecrets }} 25 | imagePullSecrets: 26 | {{- toYaml . | nindent 8 }} 27 | {{- end }} 28 | serviceAccountName: {{ include "supabase.auth.serviceAccountName" . }} 29 | securityContext: 30 | {{- toYaml .Values.auth.podSecurityContext | nindent 8 }} 31 | initContainers: 32 | - name: init-db 33 | image: postgres:15-alpine 34 | imagePullPolicy: IfNotPresent 35 | env: 36 | - name: DB_HOST 37 | {{- if .Values.db.enabled }} 38 | value: {{ include "supabase.db.fullname" . | quote }} 39 | {{- else }} 40 | value: {{ .Values.auth.environment.DB_HOST | quote }} 41 | {{- end }} 42 | - name: DB_USER 43 | valueFrom: 44 | secretKeyRef: 45 | {{- if .Values.secret.db.secretRef }} 46 | name: {{ .Values.secret.db.secretRef }} 47 | key: {{ .Values.secret.db.secretRefKey.username | default "username" }} 48 | {{- else }} 49 | name: {{ include "supabase.secret.db" . }} 50 | key: username 51 | {{- end }} 52 | - name: DB_PORT 53 | value: {{ .Values.auth.environment.DB_PORT | quote }} 54 | command: ["/bin/sh", "-c"] 55 | args: 56 | - | 57 | until pg_isready -h $(DB_HOST) -p $(DB_PORT) -U $(DB_USER); do 58 | echo "Waiting for database to start..." 59 | sleep 2 60 | done 61 | - echo "Database is ready" 62 | containers: 63 | - name: {{ include "supabase.auth.name" $ }} 64 | securityContext: 65 | {{- toYaml .Values.auth.securityContext | nindent 12 }} 66 | image: "{{ .Values.auth.image.repository }}:{{ .Values.auth.image.tag | default .Chart.AppVersion }}" 67 | imagePullPolicy: {{ .Values.auth.image.pullPolicy }} 68 | env: 69 | {{- range $key, $value := .Values.auth.environment }} 70 | - name: {{ $key }} 71 | value: {{ $value | quote }} 72 | {{- end }} 73 | {{- if .Values.db.enabled }} 74 | - name: DB_HOST 75 | value: {{ include "supabase.db.fullname" . }} 76 | {{- end }} 77 | - name: DB_PASSWORD 78 | valueFrom: 79 | secretKeyRef: 80 | {{- if .Values.secret.db.secretRef }} 81 | name: {{ .Values.secret.db.secretRef }} 82 | key: {{ .Values.secret.db.secretRefKey.password | default "password" }} 83 | {{- else }} 84 | name: {{ include "supabase.secret.db" . }} 85 | key: password 86 | {{- end }} 87 | - name: DB_PASSWORD_ENC 88 | valueFrom: 89 | secretKeyRef: 90 | {{- if .Values.secret.db.secretRef }} 91 | name: {{ .Values.secret.db.secretRef }} 92 | key: {{ .Values.secret.db.secretRefKey.password | default "password" }} 93 | {{- else }} 94 | name: {{ include "supabase.secret.db" . }} 95 | key: password_encoded 96 | {{- end }} 97 | - name: DB_NAME 98 | valueFrom: 99 | secretKeyRef: 100 | {{- if .Values.secret.db.secretRef }} 101 | name: {{ .Values.secret.db.secretRef }} 102 | key: {{ .Values.secret.db.secretRefKey.database | default "database" }} 103 | {{- else }} 104 | name: {{ include "supabase.secret.db" . }} 105 | key: database 106 | {{- end }} 107 | - name: GOTRUE_DB_DATABASE_URL 108 | value: $(DB_DRIVER)://$(DB_USER):$(DB_PASSWORD_ENC)@$(DB_HOST):$(DB_PORT)/$(DB_NAME)?search_path=auth&sslmode=$(DB_SSL) 109 | - name: GOTRUE_DB_DRIVER 110 | value: $(DB_DRIVER) 111 | - name: GOTRUE_JWT_SECRET 112 | valueFrom: 113 | secretKeyRef: 114 | {{- if .Values.secret.jwt.secretRef }} 115 | name: {{ .Values.secret.jwt.secretRef }} 116 | key: {{ .Values.secret.jwt.secretRefKey.secret | default "secret" }} 117 | {{- else }} 118 | name: {{ include "supabase.secret.jwt" . }} 119 | key: secret 120 | {{- end }} 121 | - name: GOTRUE_SMTP_USER 122 | valueFrom: 123 | secretKeyRef: 124 | {{- if .Values.secret.smtp.secretRef }} 125 | name: {{ .Values.secret.smtp.secretRef }} 126 | key: {{ .Values.secret.smtp.secretRefKey.username | default "username" }} 127 | {{- else }} 128 | name: {{ include "supabase.secret.smtp" . }} 129 | key: username 130 | {{- end }} 131 | - name: GOTRUE_SMTP_PASS 132 | valueFrom: 133 | secretKeyRef: 134 | {{- if .Values.secret.smtp.secretRef }} 135 | name: {{ .Values.secret.smtp.secretRef }} 136 | key: {{ .Values.secret.smtp.secretRefKey.password | default "password" }} 137 | {{- else }} 138 | name: {{ include "supabase.secret.smtp" . }} 139 | key: password 140 | {{- end }} 141 | {{- with .Values.auth.envFrom }} 142 | envFrom: 143 | {{- toYaml . | nindent 12 }} 144 | {{- end }} 145 | {{- with .Values.auth.livenessProbe }} 146 | livenessProbe: 147 | {{- toYaml . | nindent 12 }} 148 | {{- end }} 149 | {{- with .Values.auth.readinessProbe }} 150 | readinessProbe: 151 | {{- toYaml . | nindent 12 }} 152 | {{- end }} 153 | ports: 154 | - name: http 155 | containerPort: 9999 156 | protocol: TCP 157 | {{- with .Values.auth.resources }} 158 | resources: 159 | {{- toYaml . | nindent 12 }} 160 | {{- end }} 161 | {{- with .Values.auth.volumeMounts }} 162 | volumeMounts: 163 | {{- toYaml . | nindent 12 }} 164 | {{- end }} 165 | {{- with .Values.auth.volumes }} 166 | volumes: 167 | {{- toYaml . | nindent 8 }} 168 | {{- end }} 169 | {{- with .Values.auth.nodeSelector }} 170 | nodeSelector: 171 | {{- toYaml . | nindent 8 }} 172 | {{- end }} 173 | {{- with .Values.auth.affinity }} 174 | affinity: 175 | {{- toYaml . | nindent 8 }} 176 | {{- end }} 177 | {{- with .Values.auth.tolerations }} 178 | tolerations: 179 | {{- toYaml . | nindent 8 }} 180 | {{- end }} 181 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/auth/service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.auth.enabled -}} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ include "supabase.auth.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | type: {{ .Values.auth.service.type }} 10 | ports: 11 | - port: {{ .Values.auth.service.port }} 12 | targetPort: 9999 13 | protocol: TCP 14 | name: http 15 | selector: 16 | {{- include "supabase.auth.selectorLabels" . | nindent 4 }} 17 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/auth/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.auth.enabled -}} 2 | {{- if .Values.auth.serviceAccount.create -}} 3 | apiVersion: v1 4 | kind: ServiceAccount 5 | metadata: 6 | name: {{ include "supabase.auth.serviceAccountName" . }} 7 | labels: 8 | {{- include "supabase.labels" . | nindent 4 }} 9 | {{- with .Values.auth.serviceAccount.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | {{- end }} 14 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/db/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "supabase.db.name" -}} 5 | {{- default (print .Chart.Name "-db") .Values.db.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "supabase.db.fullname" -}} 14 | {{- if .Values.db.fullnameOverride }} 15 | {{- .Values.db.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default (print .Chart.Name "-db") .Values.db.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Selector labels 28 | */}} 29 | {{- define "supabase.db.selectorLabels" -}} 30 | app.kubernetes.io/name: {{ include "supabase.db.name" . }} 31 | app.kubernetes.io/instance: {{ .Release.Name }} 32 | {{- end }} 33 | 34 | {{/* 35 | Create the name of the service account to use 36 | */}} 37 | {{- define "supabase.db.serviceAccountName" -}} 38 | {{- if .Values.db.serviceAccount.create }} 39 | {{- default (include "supabase.db.fullname" .) .Values.db.serviceAccount.name }} 40 | {{- else }} 41 | {{- default "default" .Values.db.serviceAccount.name }} 42 | {{- end }} 43 | {{- end }} 44 | -------------------------------------------------------------------------------- /charts/supabase/templates/db/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.db.enabled -}} 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: {{ include "supabase.db.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | {{- if not .Values.db.autoscaling.enabled }} 10 | replicas: {{ .Values.db.replicaCount }} 11 | {{- end }} 12 | selector: 13 | matchLabels: 14 | {{- include "supabase.db.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | {{- with .Values.db.podAnnotations }} 18 | annotations: 19 | {{- toYaml . | nindent 8 }} 20 | {{- end }} 21 | labels: 22 | {{- include "supabase.db.selectorLabels" . | nindent 8 }} 23 | spec: 24 | {{- with .Values.db.imagePullSecrets }} 25 | imagePullSecrets: 26 | {{- toYaml . | nindent 8 }} 27 | {{- end }} 28 | serviceAccountName: {{ include "supabase.db.serviceAccountName" . }} 29 | securityContext: 30 | {{- toYaml .Values.db.podSecurityContext | nindent 8 }} 31 | initContainers: 32 | - name: init-db 33 | image: "{{ .Values.db.image.repository }}:{{ .Values.db.image.tag | default .Chart.AppVersion }}" 34 | imagePullPolicy: IfNotPresent 35 | command: ["/bin/sh", "-c"] 36 | args: 37 | - | 38 | echo "Copying init scripts into existing image script directory..." 39 | cp -r /docker-entrypoint-initdb.d/* /initdb.d/ 40 | cp /custom-init-scripts/98-webhooks.sql /initdb.d/init-scripts/ 41 | cp /custom-init-scripts/99-roles.sql /initdb.d/init-scripts/ 42 | cp /custom-init-scripts/99-logs.sql /initdb.d/migrations/ 43 | cp /custom-init-scripts/99-realtime.sql /initdb.d/migrations/ 44 | 45 | echo "Copying user-defined migration scripts..." 46 | cp /custom-migrations/* /initdb.d/migrations/ || echo "Skip migrations" 47 | echo "Initialization scripts are ready" 48 | volumeMounts: 49 | - mountPath: /custom-init-scripts 50 | name: custom-init-scripts 51 | - mountPath: /custom-migrations 52 | name: custom-migrations 53 | - mountPath: /initdb.d 54 | name: initdb-scripts-data 55 | containers: 56 | - name: {{ include "supabase.db.name" $ }} 57 | securityContext: 58 | {{- toYaml .Values.db.securityContext | nindent 12 }} 59 | image: "{{ .Values.db.image.repository }}:{{ .Values.db.image.tag | default .Chart.AppVersion }}" 60 | imagePullPolicy: {{ .Values.db.image.pullPolicy }} 61 | env: 62 | {{- range $key, $value := .Values.db.environment }} 63 | - name: {{ $key }} 64 | value: {{ $value | quote }} 65 | {{- end }} 66 | - name: POSTGRES_USER 67 | valueFrom: 68 | secretKeyRef: 69 | {{- if .Values.secret.db.secretRef }} 70 | name: {{ .Values.secret.db.secretRef }} 71 | key: {{ .Values.secret.db.secretRefKey.username | default "username" }} 72 | {{- else }} 73 | name: {{ include "supabase.secret.db" . }} 74 | key: username 75 | {{- end }} 76 | - name: PGPASSWORD 77 | valueFrom: 78 | secretKeyRef: 79 | {{- if .Values.secret.db.secretRef }} 80 | name: {{ .Values.secret.db.secretRef }} 81 | key: {{ .Values.secret.db.secretRefKey.password | default "password" }} 82 | {{- else }} 83 | name: {{ include "supabase.secret.db" . }} 84 | key: password 85 | {{- end }} 86 | - name: POSTGRES_PASSWORD 87 | valueFrom: 88 | secretKeyRef: 89 | {{- if .Values.secret.db.secretRef }} 90 | name: {{ .Values.secret.db.secretRef }} 91 | key: {{ .Values.secret.db.secretRefKey.password | default "password" }} 92 | {{- else }} 93 | name: {{ include "supabase.secret.db" . }} 94 | key: password 95 | {{- end }} 96 | - name: PGDATABASE 97 | valueFrom: 98 | secretKeyRef: 99 | {{- if .Values.secret.db.secretRef }} 100 | name: {{ .Values.secret.db.secretRef }} 101 | key: {{ .Values.secret.db.secretRefKey.database | default "database" }} 102 | {{- else }} 103 | name: {{ include "supabase.secret.db" . }} 104 | key: database 105 | {{- end }} 106 | - name: POSTGRES_DB 107 | valueFrom: 108 | secretKeyRef: 109 | {{- if .Values.secret.db.secretRef }} 110 | name: {{ .Values.secret.db.secretRef }} 111 | key: {{ .Values.secret.db.secretRefKey.database | default "database" }} 112 | {{- else }} 113 | name: {{ include "supabase.secret.db" . }} 114 | key: database 115 | {{- end }} 116 | {{- with .Values.db.livenessProbe }} 117 | livenessProbe: 118 | {{- toYaml . | nindent 12 }} 119 | {{- end }} 120 | {{- with .Values.db.readinessProbe }} 121 | readinessProbe: 122 | {{- toYaml . | nindent 12 }} 123 | {{- end }} 124 | ports: 125 | - name: http 126 | containerPort: 9999 127 | protocol: TCP 128 | volumeMounts: 129 | - mountPath: /docker-entrypoint-initdb.d 130 | name: initdb-scripts-data 131 | {{- with .Values.db.volumeMounts }} 132 | {{- toYaml . | nindent 12 }} 133 | {{- end }} 134 | {{- if .Values.db.persistence.enabled }} 135 | - mountPath: /var/lib/postgresql/data 136 | name: postgres-volume 137 | subPath: postgres-data 138 | {{- end }} 139 | {{- with .Values.db.resources }} 140 | resources: 141 | {{- toYaml . | nindent 12 }} 142 | {{- end }} 143 | volumes: 144 | - name: initdb-scripts-data 145 | emptyDir: 146 | medium: "" 147 | - name: custom-init-scripts 148 | configMap: 149 | name: {{ include "supabase.db.fullname" . }}-initdb 150 | - name: custom-migrations 151 | configMap: 152 | name: {{ include "supabase.db.fullname" . }}-migrations 153 | {{- with .Values.db.volumes }} 154 | {{- toYaml . | nindent 8 }} 155 | {{- end }} 156 | {{- if .Values.db.persistence.enabled }} 157 | - name: postgres-volume 158 | persistentVolumeClaim: 159 | claimName: {{ include "supabase.db.fullname" . }}-pvc 160 | {{- end }} 161 | {{- with .Values.db.nodeSelector }} 162 | nodeSelector: 163 | {{- toYaml . | nindent 8 }} 164 | {{- end }} 165 | {{- with .Values.db.affinity }} 166 | affinity: 167 | {{- toYaml . | nindent 8 }} 168 | {{- end }} 169 | {{- with .Values.db.tolerations }} 170 | tolerations: 171 | {{- toYaml . | nindent 8 }} 172 | {{- end }} 173 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/db/initdb.config.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.db.enabled -}} 2 | kind: ConfigMap 3 | apiVersion: v1 4 | metadata: 5 | name: {{ include "supabase.db.fullname" . }}-initdb 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | data: 9 | 99-jwt.sql: | 10 | \set jwt_secret `echo "$JWT_SECRET"` 11 | \set jwt_exp `echo "$JWT_EXP"` 12 | 13 | ALTER DATABASE postgres SET "app.settings.jwt_secret" TO :jwt_secret; 14 | ALTER DATABASE postgres SET "app.settings.jwt_exp" TO :jwt_exp; 15 | 99-logs.sql: | 16 | \set pguser `echo "$POSTGRES_USER"` 17 | 18 | create schema if not exists _analytics; 19 | alter schema _analytics owner to :pguser; 20 | 99-realtime.sql: | 21 | \set pguser `echo "$POSTGRES_USER"` 22 | 23 | create schema if not exists _realtime; 24 | alter schema _realtime owner to :pguser; 25 | 99-roles.sql: | 26 | -- NOTE: change to your own passwords for production environments 27 | \set pgpass `echo "$POSTGRES_PASSWORD"` 28 | 29 | ALTER USER authenticator WITH PASSWORD :'pgpass'; 30 | ALTER USER pgbouncer WITH PASSWORD :'pgpass'; 31 | ALTER USER supabase_auth_admin WITH PASSWORD :'pgpass'; 32 | ALTER USER supabase_functions_admin WITH PASSWORD :'pgpass'; 33 | ALTER USER supabase_storage_admin WITH PASSWORD :'pgpass'; 34 | 98-webhooks.sql: | 35 | BEGIN; 36 | -- Create pg_net extension 37 | CREATE EXTENSION IF NOT EXISTS pg_net SCHEMA extensions; 38 | -- Create supabase_functions schema 39 | CREATE SCHEMA supabase_functions AUTHORIZATION supabase_admin; 40 | GRANT USAGE ON SCHEMA supabase_functions TO postgres, anon, authenticated, service_role; 41 | ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON TABLES TO postgres, anon, authenticated, service_role; 42 | ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON FUNCTIONS TO postgres, anon, authenticated, service_role; 43 | ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON SEQUENCES TO postgres, anon, authenticated, service_role; 44 | -- supabase_functions.migrations definition 45 | CREATE TABLE supabase_functions.migrations ( 46 | version text PRIMARY KEY, 47 | inserted_at timestamptz NOT NULL DEFAULT NOW() 48 | ); 49 | -- Initial supabase_functions migration 50 | INSERT INTO supabase_functions.migrations (version) VALUES ('initial'); 51 | -- supabase_functions.hooks definition 52 | CREATE TABLE supabase_functions.hooks ( 53 | id bigserial PRIMARY KEY, 54 | hook_table_id integer NOT NULL, 55 | hook_name text NOT NULL, 56 | created_at timestamptz NOT NULL DEFAULT NOW(), 57 | request_id bigint 58 | ); 59 | CREATE INDEX supabase_functions_hooks_request_id_idx ON supabase_functions.hooks USING btree (request_id); 60 | CREATE INDEX supabase_functions_hooks_h_table_id_h_name_idx ON supabase_functions.hooks USING btree (hook_table_id, hook_name); 61 | COMMENT ON TABLE supabase_functions.hooks IS 'Supabase Functions Hooks: Audit trail for triggered hooks.'; 62 | CREATE FUNCTION supabase_functions.http_request() 63 | RETURNS trigger 64 | LANGUAGE plpgsql 65 | AS $function$ 66 | DECLARE 67 | request_id bigint; 68 | payload jsonb; 69 | url text := TG_ARGV[0]::text; 70 | method text := TG_ARGV[1]::text; 71 | headers jsonb DEFAULT '{}'::jsonb; 72 | params jsonb DEFAULT '{}'::jsonb; 73 | timeout_ms integer DEFAULT 1000; 74 | BEGIN 75 | IF url IS NULL OR url = 'null' THEN 76 | RAISE EXCEPTION 'url argument is missing'; 77 | END IF; 78 | 79 | IF method IS NULL OR method = 'null' THEN 80 | RAISE EXCEPTION 'method argument is missing'; 81 | END IF; 82 | 83 | IF TG_ARGV[2] IS NULL OR TG_ARGV[2] = 'null' THEN 84 | headers = '{"Content-Type": "application/json"}'::jsonb; 85 | ELSE 86 | headers = TG_ARGV[2]::jsonb; 87 | END IF; 88 | 89 | IF TG_ARGV[3] IS NULL OR TG_ARGV[3] = 'null' THEN 90 | params = '{}'::jsonb; 91 | ELSE 92 | params = TG_ARGV[3]::jsonb; 93 | END IF; 94 | 95 | IF TG_ARGV[4] IS NULL OR TG_ARGV[4] = 'null' THEN 96 | timeout_ms = 1000; 97 | ELSE 98 | timeout_ms = TG_ARGV[4]::integer; 99 | END IF; 100 | 101 | CASE 102 | WHEN method = 'GET' THEN 103 | SELECT http_get INTO request_id FROM net.http_get( 104 | url, 105 | params, 106 | headers, 107 | timeout_ms 108 | ); 109 | WHEN method = 'POST' THEN 110 | payload = jsonb_build_object( 111 | 'old_record', OLD, 112 | 'record', NEW, 113 | 'type', TG_OP, 114 | 'table', TG_TABLE_NAME, 115 | 'schema', TG_TABLE_SCHEMA 116 | ); 117 | 118 | SELECT http_post INTO request_id FROM net.http_post( 119 | url, 120 | payload, 121 | params, 122 | headers, 123 | timeout_ms 124 | ); 125 | ELSE 126 | RAISE EXCEPTION 'method argument % is invalid', method; 127 | END CASE; 128 | 129 | INSERT INTO supabase_functions.hooks 130 | (hook_table_id, hook_name, request_id) 131 | VALUES 132 | (TG_RELID, TG_NAME, request_id); 133 | 134 | RETURN NEW; 135 | END 136 | $function$; 137 | -- Supabase super admin 138 | DO 139 | $$ 140 | BEGIN 141 | IF NOT EXISTS ( 142 | SELECT 1 143 | FROM pg_roles 144 | WHERE rolname = 'supabase_functions_admin' 145 | ) 146 | THEN 147 | CREATE USER supabase_functions_admin NOINHERIT CREATEROLE LOGIN NOREPLICATION; 148 | END IF; 149 | END 150 | $$; 151 | GRANT ALL PRIVILEGES ON SCHEMA supabase_functions TO supabase_functions_admin; 152 | GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA supabase_functions TO supabase_functions_admin; 153 | GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA supabase_functions TO supabase_functions_admin; 154 | ALTER USER supabase_functions_admin SET search_path = "supabase_functions"; 155 | ALTER table "supabase_functions".migrations OWNER TO supabase_functions_admin; 156 | ALTER table "supabase_functions".hooks OWNER TO supabase_functions_admin; 157 | ALTER function "supabase_functions".http_request() OWNER TO supabase_functions_admin; 158 | GRANT supabase_functions_admin TO postgres; 159 | -- Remove unused supabase_pg_net_admin role 160 | DO 161 | $$ 162 | BEGIN 163 | IF EXISTS ( 164 | SELECT 1 165 | FROM pg_roles 166 | WHERE rolname = 'supabase_pg_net_admin' 167 | ) 168 | THEN 169 | REASSIGN OWNED BY supabase_pg_net_admin TO supabase_admin; 170 | DROP OWNED BY supabase_pg_net_admin; 171 | DROP ROLE supabase_pg_net_admin; 172 | END IF; 173 | END 174 | $$; 175 | -- pg_net grants when extension is already enabled 176 | DO 177 | $$ 178 | BEGIN 179 | IF EXISTS ( 180 | SELECT 1 181 | FROM pg_extension 182 | WHERE extname = 'pg_net' 183 | ) 184 | THEN 185 | GRANT USAGE ON SCHEMA net TO supabase_functions_admin, postgres, anon, authenticated, service_role; 186 | ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER; 187 | ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER; 188 | ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net; 189 | ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net; 190 | REVOKE ALL ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC; 191 | REVOKE ALL ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC; 192 | GRANT EXECUTE ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role; 193 | GRANT EXECUTE ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role; 194 | END IF; 195 | END 196 | $$; 197 | -- Event trigger for pg_net 198 | CREATE OR REPLACE FUNCTION extensions.grant_pg_net_access() 199 | RETURNS event_trigger 200 | LANGUAGE plpgsql 201 | AS $$ 202 | BEGIN 203 | IF EXISTS ( 204 | SELECT 1 205 | FROM pg_event_trigger_ddl_commands() AS ev 206 | JOIN pg_extension AS ext 207 | ON ev.objid = ext.oid 208 | WHERE ext.extname = 'pg_net' 209 | ) 210 | THEN 211 | GRANT USAGE ON SCHEMA net TO supabase_functions_admin, postgres, anon, authenticated, service_role; 212 | ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER; 213 | ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER; 214 | ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net; 215 | ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net; 216 | REVOKE ALL ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC; 217 | REVOKE ALL ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC; 218 | GRANT EXECUTE ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role; 219 | GRANT EXECUTE ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role; 220 | END IF; 221 | END; 222 | $$; 223 | COMMENT ON FUNCTION extensions.grant_pg_net_access IS 'Grants access to pg_net'; 224 | DO 225 | $$ 226 | BEGIN 227 | IF NOT EXISTS ( 228 | SELECT 1 229 | FROM pg_event_trigger 230 | WHERE evtname = 'issue_pg_net_access' 231 | ) THEN 232 | CREATE EVENT TRIGGER issue_pg_net_access ON ddl_command_end WHEN TAG IN ('CREATE EXTENSION') 233 | EXECUTE PROCEDURE extensions.grant_pg_net_access(); 234 | END IF; 235 | END 236 | $$; 237 | INSERT INTO supabase_functions.migrations (version) VALUES ('20210809183423_update_grants'); 238 | ALTER function supabase_functions.http_request() SECURITY DEFINER; 239 | ALTER function supabase_functions.http_request() SET search_path = supabase_functions; 240 | REVOKE ALL ON FUNCTION supabase_functions.http_request() FROM PUBLIC; 241 | GRANT EXECUTE ON FUNCTION supabase_functions.http_request() TO postgres, anon, authenticated, service_role; 242 | COMMIT; 243 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/db/migration.config.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.db.enabled -}} 2 | kind: ConfigMap 3 | apiVersion: v1 4 | metadata: 5 | name: {{ include "supabase.db.fullname" . }}-migrations 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | data: 9 | {{- toYaml .Values.db.config | nindent 2 }} 10 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/db/service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.db.enabled -}} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ include "supabase.db.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | type: {{ .Values.db.service.type }} 10 | ports: 11 | - port: {{ .Values.db.service.port }} 12 | targetPort: 5432 13 | protocol: TCP 14 | name: http 15 | selector: 16 | {{- include "supabase.db.selectorLabels" . | nindent 4 }} 17 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/db/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.db.enabled -}} 2 | {{- if .Values.db.serviceAccount.create -}} 3 | apiVersion: v1 4 | kind: ServiceAccount 5 | metadata: 6 | name: {{ include "supabase.db.serviceAccountName" . }} 7 | labels: 8 | {{- include "supabase.labels" . | nindent 4 }} 9 | {{- with .Values.db.serviceAccount.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | {{- end }} 14 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/db/volume.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.db.enabled -}} 2 | {{- if .Values.db.persistence.enabled -}} 3 | apiVersion: v1 4 | kind: PersistentVolumeClaim 5 | metadata: 6 | name: {{ include "supabase.db.fullname" . }}-pvc 7 | labels: 8 | {{- include "supabase.labels" . | nindent 4 }} 9 | {{- with .Values.db.persistence.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | spec: 14 | {{- if .Values.db.persistence.storageClassName }} 15 | storageClassName: {{ .Values.db.persistence.storageClassName }} 16 | {{- end }} 17 | accessModes: 18 | {{- range .Values.db.persistence.accessModes }} 19 | - {{ . | quote }} 20 | {{- end }} 21 | resources: 22 | requests: 23 | storage: {{ .Values.db.persistence.size | quote }} 24 | {{- end }} 25 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/functions/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "supabase.functions.name" -}} 5 | {{- default (print .Chart.Name "-functions") .Values.functions.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "supabase.functions.fullname" -}} 14 | {{- if .Values.functions.fullnameOverride }} 15 | {{- .Values.functions.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default (print .Chart.Name "-functions") .Values.functions.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Selector labels 28 | */}} 29 | {{- define "supabase.functions.selectorLabels" -}} 30 | app.kubernetes.io/name: {{ include "supabase.functions.name" . }} 31 | app.kubernetes.io/instance: {{ .Release.Name }} 32 | {{- end }} 33 | 34 | {{/* 35 | Create the name of the service account to use 36 | */}} 37 | {{- define "supabase.functions.serviceAccountName" -}} 38 | {{- if .Values.functions.serviceAccount.create }} 39 | {{- default (include "supabase.functions.fullname" .) .Values.functions.serviceAccount.name }} 40 | {{- else }} 41 | {{- default "default" .Values.functions.serviceAccount.name }} 42 | {{- end }} 43 | {{- end }} 44 | -------------------------------------------------------------------------------- /charts/supabase/templates/functions/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.functions.enabled -}} 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: {{ include "supabase.functions.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | {{- if not .Values.functions.autoscaling.enabled }} 10 | replicas: {{ .Values.functions.replicaCount }} 11 | {{- end }} 12 | selector: 13 | matchLabels: 14 | {{- include "supabase.functions.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | {{- with .Values.functions.podAnnotations }} 18 | annotations: 19 | {{- toYaml . | nindent 8 }} 20 | {{- end }} 21 | labels: 22 | {{- include "supabase.functions.selectorLabels" . | nindent 8 }} 23 | spec: 24 | {{- with .Values.functions.imagePullSecrets }} 25 | imagePullSecrets: 26 | {{- toYaml . | nindent 8 }} 27 | {{- end }} 28 | serviceAccountName: {{ include "supabase.functions.serviceAccountName" . }} 29 | securityContext: 30 | {{- toYaml .Values.functions.podSecurityContext | nindent 8 }} 31 | containers: 32 | - args: 33 | - start 34 | - --main-service 35 | - /home/deno/functions/main 36 | name: {{ include "supabase.functions.name" $ }} 37 | securityContext: 38 | {{- toYaml .Values.functions.securityContext | nindent 12 }} 39 | image: "{{ .Values.functions.image.repository }}:{{ .Values.functions.image.tag | default .Chart.AppVersion }}" 40 | imagePullPolicy: {{ .Values.functions.image.pullPolicy }} 41 | env: 42 | {{- range $key, $value := .Values.functions.environment }} 43 | - name: {{ $key }} 44 | value: {{ $value | quote }} 45 | {{- end }} 46 | - name: DB_HOSTNAME 47 | {{- if .Values.db.enabled }} 48 | value: {{ include "supabase.db.fullname" . }} 49 | {{- else }} 50 | value: $(DB_HOST) 51 | {{- end }} 52 | - name: DB_PASSWORD 53 | valueFrom: 54 | secretKeyRef: 55 | {{- if .Values.secret.db.secretRef }} 56 | name: {{ .Values.secret.db.secretRef }} 57 | key: {{ .Values.secret.db.secretRefKey.password | default "password" }} 58 | {{- else }} 59 | name: {{ include "supabase.secret.db" . }} 60 | key: password 61 | {{- end }} 62 | - name: DB_PASSWORD_ENC 63 | valueFrom: 64 | secretKeyRef: 65 | {{- if .Values.secret.db.secretRef }} 66 | name: {{ .Values.secret.db.secretRef }} 67 | key: {{ .Values.secret.db.secretRefKey.password | default "password" }} 68 | {{- else }} 69 | name: {{ include "supabase.secret.db" . }} 70 | key: password_encoded 71 | {{- end }} 72 | - name: DB_DATABASE 73 | valueFrom: 74 | secretKeyRef: 75 | {{- if .Values.secret.db.secretRef }} 76 | name: {{ .Values.secret.db.secretRef }} 77 | key: {{ .Values.secret.db.secretRefKey.database | default "database" }} 78 | {{- else }} 79 | name: {{ include "supabase.secret.db" . }} 80 | key: database 81 | {{- end }} 82 | - name: JWT_SECRET 83 | valueFrom: 84 | secretKeyRef: 85 | {{- if .Values.secret.jwt.secretRef }} 86 | name: {{ .Values.secret.jwt.secretRef }} 87 | key: {{ .Values.secret.jwt.secretRefKey.secret | default "secret" }} 88 | {{- else }} 89 | name: {{ include "supabase.secret.jwt" . }} 90 | key: secret 91 | {{- end }} 92 | - name: SUPABASE_ANON_KEY 93 | valueFrom: 94 | secretKeyRef: 95 | {{- if .Values.secret.jwt.secretRef }} 96 | name: {{ .Values.secret.jwt.secretRef }} 97 | key: {{ .Values.secret.jwt.secretRefKey.anonKey | default "anonKey" }} 98 | {{- else }} 99 | name: {{ include "supabase.secret.jwt" . }} 100 | key: anonKey 101 | {{- end }} 102 | - name: SUPABASE_SERVICE_ROLE_KEY 103 | valueFrom: 104 | secretKeyRef: 105 | {{- if .Values.secret.jwt.secretRef }} 106 | name: {{ .Values.secret.jwt.secretRef }} 107 | key: {{ .Values.secret.jwt.secretRefKey.serviceKey | default "serviceKey" }} 108 | {{- else }} 109 | name: {{ include "supabase.secret.jwt" . }} 110 | key: serviceKey 111 | {{- end }} 112 | - name: POSTGRES_BACKEND_URL 113 | value: $(DB_DRIVER)://$(DB_USERNAME):$(DB_PASSWORD_ENC)@$(DB_HOSTNAME):$(DB_PORT)/$(DB_DATABASE)?search_path=auth&sslmode=$(DB_SSL) 114 | {{- with .Values.functions.livenessProbe }} 115 | livenessProbe: 116 | {{- toYaml . | nindent 12 }} 117 | {{- end }} 118 | {{- with .Values.functions.readinessProbe }} 119 | readinessProbe: 120 | {{- toYaml . | nindent 12 }} 121 | {{- end }} 122 | volumeMounts: 123 | {{- with .Values.functions.volumeMounts }} 124 | {{- toYaml . | nindent 12 }} 125 | {{- end }} 126 | - mountPath: /home/deno/functions/main 127 | name: functions-main 128 | {{- with .Values.functions.resources }} 129 | resources: 130 | {{- toYaml . | nindent 12 }} 131 | {{- end }} 132 | volumes: 133 | {{- with .Values.functions.volumes }} 134 | {{- toYaml . | nindent 8 }} 135 | {{- end }} 136 | - name: functions-main 137 | configMap: 138 | name: {{ include "supabase.functions.fullname" . }}-main 139 | {{- with .Values.functions.nodeSelector }} 140 | nodeSelector: 141 | {{- toYaml . | nindent 8 }} 142 | {{- end }} 143 | {{- with .Values.functions.affinity }} 144 | affinity: 145 | {{- toYaml . | nindent 8 }} 146 | {{- end }} 147 | {{- with .Values.functions.tolerations }} 148 | tolerations: 149 | {{- toYaml . | nindent 8 }} 150 | {{- end }} 151 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/functions/functions.config.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.functions.enabled -}} 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: {{ include "supabase.functions.fullname" . }}-main 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | data: 9 | index.ts: | 10 | import { serve } from 'https://deno.land/std@0.131.0/http/server.ts' 11 | import * as jose from 'https://deno.land/x/jose@v4.14.4/index.ts' 12 | 13 | console.log('main function started') 14 | 15 | const JWT_SECRET = Deno.env.get('JWT_SECRET') 16 | const VERIFY_JWT = Deno.env.get('VERIFY_JWT') === 'true' 17 | 18 | function getAuthToken(req: Request) { 19 | const authHeader = req.headers.get('authorization') 20 | if (!authHeader) { 21 | throw new Error('Missing authorization header') 22 | } 23 | const [bearer, token] = authHeader.split(' ') 24 | if (bearer !== 'Bearer') { 25 | throw new Error(`Auth header is not 'Bearer {token}'`) 26 | } 27 | return token 28 | } 29 | 30 | async function verifyJWT(jwt: string): Promise { 31 | const encoder = new TextEncoder() 32 | const secretKey = encoder.encode(JWT_SECRET) 33 | try { 34 | await jose.jwtVerify(jwt, secretKey) 35 | } catch (err) { 36 | console.error(err) 37 | return false 38 | } 39 | return true 40 | } 41 | 42 | serve(async (req: Request) => { 43 | if (req.method !== 'OPTIONS' && VERIFY_JWT) { 44 | try { 45 | const token = getAuthToken(req) 46 | const isValidJWT = await verifyJWT(token) 47 | 48 | if (!isValidJWT) { 49 | return new Response(JSON.stringify({ msg: 'Invalid JWT' }), { 50 | status: 401, 51 | headers: { 'Content-Type': 'application/json' }, 52 | }) 53 | } 54 | } catch (e) { 55 | console.error(e) 56 | return new Response(JSON.stringify({ msg: e.toString() }), { 57 | status: 401, 58 | headers: { 'Content-Type': 'application/json' }, 59 | }) 60 | } 61 | } 62 | 63 | const url = new URL(req.url) 64 | const { pathname } = url 65 | const path_parts = pathname.split('/') 66 | const service_name = path_parts[1] 67 | 68 | if (!service_name || service_name === '') { 69 | const error = { msg: 'missing function name in request' } 70 | return new Response(JSON.stringify(error), { 71 | status: 400, 72 | headers: { 'Content-Type': 'application/json' }, 73 | }) 74 | } 75 | 76 | const servicePath = `/home/deno/functions/${service_name}` 77 | console.error(`serving the request with ${servicePath}`) 78 | 79 | const memoryLimitMb = 150 80 | const workerTimeoutMs = 1 * 60 * 1000 81 | const noModuleCache = false 82 | const importMapPath = null 83 | const envVarsObj = Deno.env.toObject() 84 | const envVars = Object.keys(envVarsObj).map((k) => [k, envVarsObj[k]]) 85 | 86 | try { 87 | const worker = await EdgeRuntime.userWorkers.create({ 88 | servicePath, 89 | memoryLimitMb, 90 | workerTimeoutMs, 91 | noModuleCache, 92 | importMapPath, 93 | envVars, 94 | }) 95 | return await worker.fetch(req) 96 | } catch (e) { 97 | const error = { msg: e.toString() } 98 | return new Response(JSON.stringify(error), { 99 | status: 500, 100 | headers: { 'Content-Type': 'application/json' }, 101 | }) 102 | } 103 | }) 104 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/functions/service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.functions.enabled -}} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ include "supabase.functions.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | type: {{ .Values.functions.service.type }} 10 | ports: 11 | - port: {{ .Values.functions.service.port }} 12 | targetPort: 9000 13 | protocol: TCP 14 | name: http 15 | selector: 16 | {{- include "supabase.functions.selectorLabels" . | nindent 4 }} 17 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/functions/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.functions.enabled -}} 2 | {{- if .Values.functions.serviceAccount.create -}} 3 | apiVersion: v1 4 | kind: ServiceAccount 5 | metadata: 6 | name: {{ include "supabase.functions.serviceAccountName" . }} 7 | labels: 8 | {{- include "supabase.labels" . | nindent 4 }} 9 | {{- with .Values.functions.serviceAccount.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | {{- end }} 14 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/imgproxy/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "supabase.imgproxy.name" -}} 5 | {{- default (print .Chart.Name "-imgproxy") .Values.imgproxy.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "supabase.imgproxy.fullname" -}} 14 | {{- if .Values.imgproxy.fullnameOverride }} 15 | {{- .Values.imgproxy.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default (print .Chart.Name "-imgproxy") .Values.imgproxy.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Selector labels 28 | */}} 29 | {{- define "supabase.imgproxy.selectorLabels" -}} 30 | app.kubernetes.io/name: {{ include "supabase.imgproxy.name" . }} 31 | app.kubernetes.io/instance: {{ .Release.Name }} 32 | {{- end }} 33 | 34 | {{/* 35 | Create the name of the service account to use 36 | */}} 37 | {{- define "supabase.imgproxy.serviceAccountName" -}} 38 | {{- if .Values.imgproxy.serviceAccount.create }} 39 | {{- default (include "supabase.imgproxy.fullname" .) .Values.imgproxy.serviceAccount.name }} 40 | {{- else }} 41 | {{- default "default" .Values.imgproxy.serviceAccount.name }} 42 | {{- end }} 43 | {{- end }} 44 | -------------------------------------------------------------------------------- /charts/supabase/templates/imgproxy/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.imgproxy.enabled -}} 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: {{ include "supabase.imgproxy.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | {{- if not .Values.imgproxy.autoscaling.enabled }} 10 | replicas: {{ .Values.imgproxy.replicaCount }} 11 | {{- end }} 12 | selector: 13 | matchLabels: 14 | {{- include "supabase.imgproxy.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | {{- with .Values.imgproxy.podAnnotations }} 18 | annotations: 19 | {{- toYaml . | nindent 8 }} 20 | {{- end }} 21 | labels: 22 | {{- include "supabase.imgproxy.selectorLabels" . | nindent 8 }} 23 | spec: 24 | {{- with .Values.imgproxy.imagePullSecrets }} 25 | imagePullSecrets: 26 | {{- toYaml . | nindent 8 }} 27 | {{- end }} 28 | serviceAccountName: {{ include "supabase.imgproxy.serviceAccountName" . }} 29 | securityContext: 30 | {{- toYaml .Values.imgproxy.podSecurityContext | nindent 8 }} 31 | containers: 32 | - name: {{ include "supabase.imgproxy.name" $ }} 33 | securityContext: 34 | {{- toYaml .Values.imgproxy.securityContext | nindent 12 }} 35 | image: "{{ .Values.imgproxy.image.repository }}:{{ .Values.imgproxy.image.tag | default .Chart.AppVersion }}" 36 | imagePullPolicy: {{ .Values.imgproxy.image.pullPolicy }} 37 | env: 38 | {{- range $key, $value := .Values.imgproxy.environment }} 39 | - name: {{ $key }} 40 | value: {{ $value | quote }} 41 | {{- end }} 42 | {{- with .Values.imgproxy.livenessProbe }} 43 | livenessProbe: 44 | {{- toYaml . | nindent 12 }} 45 | {{- end }} 46 | {{- with .Values.imgproxy.readinessProbe }} 47 | readinessProbe: 48 | {{- toYaml . | nindent 12 }} 49 | {{- end }} 50 | ports: 51 | - name: http 52 | containerPort: 8080 53 | protocol: TCP 54 | {{- if or (.Values.imgproxy.persistence.enabled) (.Values.imgproxy.volumes) }} 55 | volumeMounts: 56 | {{- with .Values.imgproxy.volumeMounts }} 57 | {{- toYaml . | nindent 12 }} 58 | {{- end }} 59 | {{- if .Values.imgproxy.persistence.enabled }} 60 | - mountPath: /var/lib/storage 61 | name: imgproxy-volume 62 | {{- end }} 63 | {{- end }} 64 | {{- with .Values.imgproxy.resources }} 65 | resources: 66 | {{- toYaml . | nindent 12 }} 67 | {{- end }} 68 | {{- if or (.Values.imgproxy.persistence.enabled) (.Values.imgproxy.volumes) }} 69 | volumes: 70 | {{- with .Values.imgproxy.volumes }} 71 | {{- toYaml . | nindent 8 }} 72 | {{- end }} 73 | {{- if .Values.imgproxy.persistence.enabled }} 74 | - name: imgproxy-volume 75 | persistentVolumeClaim: 76 | claimName: {{ include "supabase.imgproxy.fullname" . }}-pvc 77 | {{- end }} 78 | {{- end }} 79 | {{- with .Values.imgproxy.nodeSelector }} 80 | nodeSelector: 81 | {{- toYaml . | nindent 8 }} 82 | {{- end }} 83 | {{- with .Values.imgproxy.affinity }} 84 | affinity: 85 | {{- toYaml . | nindent 8 }} 86 | {{- end }} 87 | {{- with .Values.imgproxy.tolerations }} 88 | tolerations: 89 | {{- toYaml . | nindent 8 }} 90 | {{- end }} 91 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/imgproxy/service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.imgproxy.enabled -}} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ include "supabase.imgproxy.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | type: {{ .Values.imgproxy.service.type }} 10 | ports: 11 | - port: {{ .Values.imgproxy.service.port }} 12 | targetPort: 5001 13 | protocol: TCP 14 | name: http 15 | selector: 16 | {{- include "supabase.imgproxy.selectorLabels" . | nindent 4 }} 17 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/imgproxy/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.imgproxy.enabled -}} 2 | {{- if .Values.imgproxy.serviceAccount.create -}} 3 | apiVersion: v1 4 | kind: ServiceAccount 5 | metadata: 6 | name: {{ include "supabase.imgproxy.serviceAccountName" . }} 7 | labels: 8 | {{- include "supabase.labels" . | nindent 4 }} 9 | {{- with .Values.imgproxy.serviceAccount.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | {{- end }} 14 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/imgproxy/volume.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.imgproxy.enabled -}} 2 | {{- if .Values.imgproxy.persistence.enabled -}} 3 | apiVersion: v1 4 | kind: PersistentVolumeClaim 5 | metadata: 6 | name: {{ include "supabase.imgproxy.fullname" . }}-pvc 7 | labels: 8 | {{- include "supabase.labels" . | nindent 4 }} 9 | {{- with .Values.imgproxy.persistence.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | spec: 14 | {{- if .Values.imgproxy.persistence.storageClassName }} 15 | storageClassName: {{ .Values.imgproxy.persistence.storageClassName }} 16 | {{- end }} 17 | accessModes: 18 | {{- range .Values.imgproxy.persistence.accessModes }} 19 | - {{ . | quote }} 20 | {{- end }} 21 | resources: 22 | requests: 23 | storage: {{ .Values.imgproxy.persistence.size | quote }} 24 | {{- end }} 25 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/kong/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "supabase.kong.name" -}} 5 | {{- default (print .Chart.Name "-kong") .Values.kong.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "supabase.kong.fullname" -}} 14 | {{- if .Values.kong.fullnameOverride }} 15 | {{- .Values.kong.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default (print .Chart.Name "-kong") .Values.kong.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Selector labels 28 | */}} 29 | {{- define "supabase.kong.selectorLabels" -}} 30 | app.kubernetes.io/name: {{ include "supabase.kong.name" . }} 31 | app.kubernetes.io/instance: {{ .Release.Name }} 32 | {{- end }} 33 | 34 | {{/* 35 | Create the name of the service account to use 36 | */}} 37 | {{- define "supabase.kong.serviceAccountName" -}} 38 | {{- if .Values.kong.serviceAccount.create }} 39 | {{- default (include "supabase.kong.fullname" .) .Values.kong.serviceAccount.name }} 40 | {{- else }} 41 | {{- default "default" .Values.kong.serviceAccount.name }} 42 | {{- end }} 43 | {{- end }} 44 | -------------------------------------------------------------------------------- /charts/supabase/templates/kong/config.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.kong.enabled -}} 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: {{ include "supabase.kong.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | data: 9 | wrapper.sh: | 10 | #!/bin/bash 11 | 12 | set -euo pipefail 13 | 14 | echo "Replacing env placeholders of /usr/local/kong/kong.yml" 15 | 16 | sed \ 17 | -e "s/\${SUPABASE_ANON_KEY}/${SUPABASE_ANON_KEY}/" \ 18 | -e "s/\${SUPABASE_SERVICE_KEY}/${SUPABASE_SERVICE_KEY}/" \ 19 | -e "s/\${DASHBOARD_USERNAME}/${DASHBOARD_USERNAME}/" \ 20 | -e "s/\${DASHBOARD_PASSWORD}/${DASHBOARD_PASSWORD}/" \ 21 | /usr/local/kong/template.yml \ 22 | > /usr/local/kong/kong.yml 23 | 24 | exec /docker-entrypoint.sh kong docker-start 25 | template.yml: | 26 | _format_version: '2.1' 27 | _transform: true 28 | 29 | consumers: 30 | {{- if .Values.secret.dashboard }} 31 | - username: DASHBOARD 32 | {{- end }} 33 | - username: anon 34 | keyauth_credentials: 35 | - key: ${SUPABASE_ANON_KEY} 36 | - username: service_role 37 | keyauth_credentials: 38 | - key: ${SUPABASE_SERVICE_KEY} 39 | acls: 40 | - consumer: anon 41 | group: anon 42 | - consumer: service_role 43 | group: admin 44 | {{- if .Values.secret.dashboard }} 45 | basicauth_credentials: 46 | - consumer: DASHBOARD 47 | username: ${DASHBOARD_USERNAME} 48 | password: ${DASHBOARD_PASSWORD} 49 | {{- end }} 50 | services: 51 | {{- if .Values.auth.enabled }} 52 | - name: auth-v1-open 53 | url: http://{{ include "supabase.auth.fullname" . }}:{{ .Values.auth.service.port }}/verify 54 | routes: 55 | - name: auth-v1-open 56 | strip_path: true 57 | paths: 58 | - /auth/v1/verify 59 | plugins: 60 | - name: cors 61 | - name: auth-v1-open-callback 62 | url: http://{{ include "supabase.auth.fullname" . }}:{{ .Values.auth.service.port }}/callback 63 | routes: 64 | - name: auth-v1-open-callback 65 | strip_path: true 66 | paths: 67 | - /auth/v1/callback 68 | plugins: 69 | - name: cors 70 | - name: auth-v1-open-authorize 71 | url: http://{{ include "supabase.auth.fullname" . }}:{{ .Values.auth.service.port }}/authorize 72 | routes: 73 | - name: auth-v1-open-authorize 74 | strip_path: true 75 | paths: 76 | - /auth/v1/authorize 77 | plugins: 78 | - name: cors 79 | - name: auth-v1 80 | _comment: "GoTrue: /auth/v1/* -> http://{{ include "supabase.auth.fullname" . }}:{{ .Values.auth.service.port }}/*" 81 | url: http://{{ include "supabase.auth.fullname" . }}:{{ .Values.auth.service.port }} 82 | routes: 83 | - name: auth-v1-all 84 | strip_path: true 85 | paths: 86 | - /auth/v1/ 87 | plugins: 88 | - name: cors 89 | - name: key-auth 90 | config: 91 | hide_credentials: false 92 | - name: acl 93 | config: 94 | hide_groups_header: true 95 | allow: 96 | - admin 97 | - anon 98 | {{- end }} 99 | {{- if .Values.rest.enabled }} 100 | - name: rest-v1 101 | _comment: "PostgREST: /rest/v1/* -> http://{{ include "supabase.rest.fullname" . }}:{{ .Values.rest.service.port }}/*" 102 | url: http://{{ include "supabase.rest.fullname" . }}:{{ .Values.rest.service.port }}/ 103 | routes: 104 | - name: rest-v1-all 105 | strip_path: true 106 | paths: 107 | - /rest/v1/ 108 | plugins: 109 | - name: cors 110 | - name: key-auth 111 | config: 112 | hide_credentials: true 113 | - name: acl 114 | config: 115 | hide_groups_header: true 116 | allow: 117 | - admin 118 | - anon 119 | - name: graphql-v1 120 | _comment: 'PostgREST: /graphql/v1/* -> http://{{ include "supabase.rest.fullname" . }}:{{ .Values.rest.service.port }}/rpc/graphql' 121 | url: http://{{ include "supabase.rest.fullname" . }}:{{ .Values.rest.service.port }}/rpc/graphql 122 | routes: 123 | - name: graphql-v1-all 124 | strip_path: true 125 | paths: 126 | - /graphql/v1 127 | plugins: 128 | - name: cors 129 | - name: key-auth 130 | config: 131 | hide_credentials: true 132 | - name: request-transformer 133 | config: 134 | add: 135 | headers: 136 | - Content-Profile:graphql_public 137 | - name: acl 138 | config: 139 | hide_groups_header: true 140 | allow: 141 | - admin 142 | - anon 143 | {{- end }} 144 | {{- if .Values.realtime.enabled }} 145 | - name: realtime-v1 146 | _comment: "Realtime: /realtime/v1/* -> ws://{{ include "supabase.realtime.fullname" . }}:{{ .Values.realtime.service.port }}/socket/*" 147 | url: http://{{ include "supabase.realtime.fullname" . }}:{{ .Values.realtime.service.port }}/socket 148 | routes: 149 | - name: realtime-v1-all 150 | strip_path: true 151 | paths: 152 | - /realtime/v1/ 153 | plugins: 154 | - name: cors 155 | - name: key-auth 156 | config: 157 | hide_credentials: false 158 | - name: acl 159 | config: 160 | hide_groups_header: true 161 | allow: 162 | - admin 163 | - anon 164 | {{- end }} 165 | {{- if .Values.storage.enabled }} 166 | - name: storage-v1 167 | _comment: "Storage: /storage/v1/* -> http://{{ include "supabase.storage.fullname" . }}:{{ .Values.storage.service.port }}/*" 168 | url: http://{{ include "supabase.storage.fullname" . }}:{{ .Values.storage.service.port }}/ 169 | routes: 170 | - name: storage-v1-all 171 | strip_path: true 172 | paths: 173 | - /storage/v1/ 174 | plugins: 175 | - name: cors 176 | {{- end }} 177 | {{- if .Values.functions.enabled }} 178 | - name: functions-v1 179 | _comment: 'Edge Functions: /functions/v1/* -> http://{{ include "supabase.functions.fullname" . }}:{{ .Values.functions.service.port }}/*' 180 | url: http://functions:{{ .Values.functions.service.port }}/ 181 | routes: 182 | - name: functions-v1-all 183 | strip_path: true 184 | paths: 185 | - /functions/v1/ 186 | plugins: 187 | - name: cors 188 | {{- end }} 189 | {{- if .Values.analytics.enabled }} 190 | - name: analytics-v1 191 | _comment: 'Analytics: /analytics/v1/* -> http://{{ include "supabase.analytics.fullname" . }}:{{ .Values.analytics.service.port }}/*' 192 | url: http://{{ include "supabase.analytics.fullname" . }}:{{ .Values.analytics.service.port }}/ 193 | routes: 194 | - name: analytics-v1-all 195 | strip_path: true 196 | paths: 197 | - /analytics/v1/ 198 | {{- end }} 199 | {{- if .Values.meta.enabled }} 200 | - name: meta 201 | _comment: "pg-meta: /pg/* -> http://{{ include "supabase.meta.fullname" . }}:{{ .Values.meta.service.port }}/*" 202 | url: http://{{ include "supabase.meta.fullname" . }}:{{ .Values.meta.service.port }}/ 203 | routes: 204 | - name: meta-all 205 | strip_path: true 206 | paths: 207 | - /pg/ 208 | plugins: 209 | - name: key-auth 210 | config: 211 | hide_credentials: false 212 | - name: acl 213 | config: 214 | hide_groups_header: true 215 | allow: 216 | - admin 217 | {{- end }} 218 | - name: dashboard 219 | _comment: 'Studio: /* -> http://{{ include "supabase.studio.fullname" . }}:{{ .Values.studio.service.port }}/*' 220 | url: http://{{ include "supabase.studio.fullname" . }}:{{ .Values.studio.service.port }}/ 221 | routes: 222 | - name: dashboard-all 223 | strip_path: true 224 | paths: 225 | - / 226 | {{- if .Values.secret.dashboard }} 227 | plugins: 228 | - name: cors 229 | - name: basic-auth 230 | config: 231 | hide_credentials: true 232 | {{- end }} 233 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/kong/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.kong.enabled -}} 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: {{ include "supabase.kong.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | {{- if not .Values.kong.autoscaling.enabled }} 10 | replicas: {{ .Values.kong.replicaCount }} 11 | {{- end }} 12 | selector: 13 | matchLabels: 14 | {{- include "supabase.kong.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | {{- with .Values.kong.podAnnotations }} 18 | annotations: 19 | {{- toYaml . | nindent 8 }} 20 | {{- end }} 21 | labels: 22 | {{- include "supabase.kong.selectorLabels" . | nindent 8 }} 23 | spec: 24 | {{- with .Values.kong.imagePullSecrets }} 25 | imagePullSecrets: 26 | {{- toYaml . | nindent 8 }} 27 | {{- end }} 28 | serviceAccountName: {{ include "supabase.kong.serviceAccountName" . }} 29 | securityContext: 30 | {{- toYaml .Values.kong.podSecurityContext | nindent 8 }} 31 | containers: 32 | - name: {{ include "supabase.kong.name" $ }} 33 | securityContext: 34 | {{- toYaml .Values.kong.securityContext | nindent 12 }} 35 | image: "{{ .Values.kong.image.repository }}:{{ .Values.kong.image.tag | default .Chart.AppVersion }}" 36 | imagePullPolicy: {{ .Values.kong.image.pullPolicy }} 37 | command: ["/bin/bash"] 38 | args: ["/scripts/wrapper.sh"] 39 | env: 40 | {{- range $key, $value := .Values.kong.environment }} 41 | - name: {{ $key }} 42 | value: {{ $value | quote }} 43 | {{- end }} 44 | - name: SUPABASE_ANON_KEY 45 | valueFrom: 46 | secretKeyRef: 47 | {{- if .Values.secret.jwt.secretRef }} 48 | name: {{ .Values.secret.jwt.secretRef }} 49 | key: {{ .Values.secret.jwt.secretRefKey.anonKey | default "anonKey" }} 50 | {{- else }} 51 | name: {{ include "supabase.secret.jwt" . }} 52 | key: anonKey 53 | {{- end }} 54 | - name: SUPABASE_SERVICE_KEY 55 | valueFrom: 56 | secretKeyRef: 57 | {{- if .Values.secret.jwt.secretRef }} 58 | name: {{ .Values.secret.jwt.secretRef }} 59 | key: {{ .Values.secret.jwt.secretRefKey.serviceKey | default "serviceKey" }} 60 | {{- else }} 61 | name: {{ include "supabase.secret.jwt" . }} 62 | key: serviceKey 63 | {{- end }} 64 | {{- if .Values.secret.dashboard }} 65 | - name: DASHBOARD_USERNAME 66 | valueFrom: 67 | secretKeyRef: 68 | {{- if .Values.secret.dashboard.secretRef }} 69 | name: {{ .Values.secret.dashboard.secretRef }} 70 | key: {{ .Values.secret.dashboard.secretRefKey.username | default "username" }} 71 | {{- else }} 72 | name: {{ include "supabase.secret.dashboard" . }} 73 | key: username 74 | {{- end }} 75 | - name: DASHBOARD_PASSWORD 76 | valueFrom: 77 | secretKeyRef: 78 | {{- if .Values.secret.dashboard.secretRef }} 79 | name: {{ .Values.secret.dashboard.secretRef }} 80 | key: {{ .Values.secret.dashboard.secretRefKey.password | default "password" }} 81 | {{- else }} 82 | name: {{ include "supabase.secret.dashboard" . }} 83 | key: password 84 | {{- end }} 85 | {{- end }} 86 | {{- with .Values.kong.livenessProbe }} 87 | livenessProbe: 88 | {{- toYaml . | nindent 12 }} 89 | {{- end }} 90 | {{- with .Values.kong.readinessProbe }} 91 | readinessProbe: 92 | {{- toYaml . | nindent 12 }} 93 | {{- end }} 94 | ports: 95 | - name: http 96 | containerPort: 8000 97 | protocol: TCP 98 | {{- with .Values.kong.resources }} 99 | resources: 100 | {{- toYaml . | nindent 12 }} 101 | {{- end }} 102 | volumeMounts: 103 | - mountPath: /usr/local/kong/template.yml 104 | name: config 105 | subPath: template.yml 106 | - mountPath: /scripts 107 | name: wrapper 108 | {{- with .Values.kong.volumeMounts }} 109 | {{- toYaml . | nindent 12 }} 110 | {{- end }} 111 | {{- with .Values.kong.nodeSelector }} 112 | nodeSelector: 113 | {{- toYaml . | nindent 8 }} 114 | {{- end }} 115 | {{- with .Values.kong.affinity }} 116 | affinity: 117 | {{- toYaml . | nindent 8 }} 118 | {{- end }} 119 | {{- with .Values.kong.tolerations }} 120 | tolerations: 121 | {{- toYaml . | nindent 8 }} 122 | {{- end }} 123 | volumes: 124 | - name: config 125 | configMap: 126 | name: {{ include "supabase.kong.fullname" $ }} 127 | defaultMode: 0777 128 | items: 129 | - key: template.yml 130 | path: template.yml 131 | - name: wrapper 132 | configMap: 133 | name: {{ include "supabase.kong.fullname" $ }} 134 | defaultMode: 0777 135 | items: 136 | - key: wrapper.sh 137 | path: wrapper.sh 138 | {{- with .Values.kong.volumes }} 139 | {{- toYaml . | nindent 8 }} 140 | {{- end }} 141 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/kong/ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.kong.enabled -}} 2 | {{- if .Values.kong.ingress.enabled -}} 3 | {{- $fullName := include "supabase.kong.fullname" . -}} 4 | {{- $svcPort := .Values.kong.service.port -}} 5 | {{- if and .Values.kong.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} 6 | {{- if not (hasKey .Values.kong.ingress.annotations "kubernetes.io/ingress.class") }} 7 | {{- $_ := set .Values.kong.ingress.annotations "kubernetes.io/ingress.class" .Values.kong.ingress.className}} 8 | {{- end }} 9 | {{- end }} 10 | apiVersion: networking.k8s.io/v1 11 | kind: Ingress 12 | metadata: 13 | name: {{ $fullName }} 14 | labels: 15 | {{- include "supabase.labels" . | nindent 4 }} 16 | {{- with .Values.kong.ingress.annotations }} 17 | annotations: 18 | {{- toYaml . | nindent 4 }} 19 | {{- end }} 20 | spec: 21 | {{- if and .Values.kong.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} 22 | ingressClassName: {{ .Values.kong.ingress.className }} 23 | {{- end }} 24 | {{- if .Values.kong.ingress.tls }} 25 | tls: 26 | {{- range .Values.kong.ingress.tls }} 27 | - hosts: 28 | {{- range .hosts }} 29 | - {{ . | quote }} 30 | {{- end }} 31 | secretName: {{ .secretName }} 32 | {{- end }} 33 | {{- end }} 34 | rules: 35 | {{- range .Values.kong.ingress.hosts }} 36 | - host: {{ .host | quote }} 37 | http: 38 | paths: 39 | {{- range .paths }} 40 | - path: {{ .path }} 41 | {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} 42 | pathType: {{ .pathType }} 43 | {{- end }} 44 | backend: 45 | {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} 46 | service: 47 | name: {{ $fullName }} 48 | port: 49 | number: {{ $svcPort }} 50 | {{- else }} 51 | serviceName: {{ $fullName }} 52 | servicePort: {{ $svcPort }} 53 | {{- end }} 54 | {{- end }} 55 | {{- end }} 56 | {{- end }} 57 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/kong/service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.kong.enabled -}} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ include "supabase.kong.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | type: {{ .Values.kong.service.type }} 10 | ports: 11 | - port: {{ .Values.kong.service.port }} 12 | targetPort: 8000 13 | protocol: TCP 14 | name: http 15 | selector: 16 | {{- include "supabase.kong.selectorLabels" . | nindent 4 }} 17 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/kong/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.kong.enabled -}} 2 | {{- if .Values.kong.serviceAccount.create -}} 3 | apiVersion: v1 4 | kind: ServiceAccount 5 | metadata: 6 | name: {{ include "supabase.kong.serviceAccountName" . }} 7 | labels: 8 | {{- include "supabase.labels" . | nindent 4 }} 9 | {{- with .Values.kong.serviceAccount.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | {{- end }} 14 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/meta/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "supabase.meta.name" -}} 5 | {{- default (print .Chart.Name "-meta") .Values.meta.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "supabase.meta.fullname" -}} 14 | {{- if .Values.meta.fullnameOverride }} 15 | {{- .Values.meta.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default (print .Chart.Name "-meta") .Values.meta.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Selector labels 28 | */}} 29 | {{- define "supabase.meta.selectorLabels" -}} 30 | app.kubernetes.io/name: {{ include "supabase.meta.name" . }} 31 | app.kubernetes.io/instance: {{ .Release.Name }} 32 | {{- end }} 33 | 34 | {{/* 35 | Create the name of the service account to use 36 | */}} 37 | {{- define "supabase.meta.serviceAccountName" -}} 38 | {{- if .Values.meta.serviceAccount.create }} 39 | {{- default (include "supabase.meta.fullname" .) .Values.meta.serviceAccount.name }} 40 | {{- else }} 41 | {{- default "default" .Values.meta.serviceAccount.name }} 42 | {{- end }} 43 | {{- end }} 44 | -------------------------------------------------------------------------------- /charts/supabase/templates/meta/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.meta.enabled -}} 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: {{ include "supabase.meta.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | {{- if not .Values.meta.autoscaling.enabled }} 10 | replicas: {{ .Values.meta.replicaCount }} 11 | {{- end }} 12 | selector: 13 | matchLabels: 14 | {{- include "supabase.meta.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | {{- with .Values.meta.podAnnotations }} 18 | annotations: 19 | {{- toYaml . | nindent 8 }} 20 | {{- end }} 21 | labels: 22 | {{- include "supabase.meta.selectorLabels" . | nindent 8 }} 23 | spec: 24 | {{- with .Values.meta.imagePullSecrets }} 25 | imagePullSecrets: 26 | {{- toYaml . | nindent 8 }} 27 | {{- end }} 28 | serviceAccountName: {{ include "supabase.meta.serviceAccountName" . }} 29 | securityContext: 30 | {{- toYaml .Values.meta.podSecurityContext | nindent 8 }} 31 | containers: 32 | - name: {{ include "supabase.meta.name" $ }} 33 | securityContext: 34 | {{- toYaml .Values.meta.securityContext | nindent 12 }} 35 | image: "{{ .Values.meta.image.repository }}:{{ .Values.meta.image.tag | default .Chart.AppVersion }}" 36 | imagePullPolicy: {{ .Values.meta.image.pullPolicy }} 37 | env: 38 | {{- range $key, $value := .Values.meta.environment }} 39 | - name: {{ $key }} 40 | value: {{ $value | quote }} 41 | {{- end }} 42 | {{- if .Values.db.enabled }} 43 | - name: DB_HOST 44 | value: {{ include "supabase.db.fullname" . }} 45 | {{- end }} 46 | - name: DB_PASSWORD 47 | valueFrom: 48 | secretKeyRef: 49 | {{- if .Values.secret.db.secretRef }} 50 | name: {{ .Values.secret.db.secretRef }} 51 | key: {{ .Values.secret.db.secretRefKey.password | default "password" }} 52 | {{- else }} 53 | name: {{ include "supabase.secret.db" . }} 54 | key: password 55 | {{- end }} 56 | - name: DB_NAME 57 | valueFrom: 58 | secretKeyRef: 59 | {{- if .Values.secret.db.secretRef }} 60 | name: {{ .Values.secret.db.secretRef }} 61 | key: {{ .Values.secret.db.secretRefKey.database | default "database" }} 62 | {{- else }} 63 | name: {{ include "supabase.secret.db" . }} 64 | key: database 65 | {{- end }} 66 | - name: PG_META_DB_HOST 67 | value: $(DB_HOST) 68 | - name: PG_META_DB_PORT 69 | value: $(DB_PORT) 70 | - name: PG_META_DB_NAME 71 | value: $(DB_NAME) 72 | - name: PG_META_DB_USER 73 | value: $(DB_USER) 74 | - name: PG_META_DB_PASSWORD 75 | value: $(DB_PASSWORD) 76 | - name: PG_META_DB_SSL_MODE 77 | value: $(DB_SSL) 78 | {{- with .Values.meta.livenessProbe }} 79 | livenessProbe: 80 | {{- toYaml . | nindent 12 }} 81 | {{- end }} 82 | {{- with .Values.meta.readinessProbe }} 83 | readinessProbe: 84 | {{- toYaml . | nindent 12 }} 85 | {{- end }} 86 | ports: 87 | - name: http 88 | containerPort: 8080 89 | protocol: TCP 90 | {{- with .Values.meta.resources }} 91 | resources: 92 | {{- toYaml . | nindent 12 }} 93 | {{- end }} 94 | {{- with .Values.meta.volumeMounts }} 95 | volumeMounts: 96 | {{- toYaml . | nindent 12 }} 97 | {{- end }} 98 | {{- with .Values.meta.volumes }} 99 | volumes: 100 | {{- toYaml . | nindent 8 }} 101 | {{- end }} 102 | {{- with .Values.meta.nodeSelector }} 103 | nodeSelector: 104 | {{- toYaml . | nindent 8 }} 105 | {{- end }} 106 | {{- with .Values.meta.affinity }} 107 | affinity: 108 | {{- toYaml . | nindent 8 }} 109 | {{- end }} 110 | {{- with .Values.meta.tolerations }} 111 | tolerations: 112 | {{- toYaml . | nindent 8 }} 113 | {{- end }} 114 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/meta/service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.meta.enabled -}} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ include "supabase.meta.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | type: {{ .Values.meta.service.type }} 10 | ports: 11 | - port: {{ .Values.meta.service.port }} 12 | targetPort: 8080 13 | protocol: TCP 14 | name: http 15 | selector: 16 | {{- include "supabase.meta.selectorLabels" . | nindent 4 }} 17 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/meta/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.meta.enabled -}} 2 | {{- if .Values.meta.serviceAccount.create -}} 3 | apiVersion: v1 4 | kind: ServiceAccount 5 | metadata: 6 | name: {{ include "supabase.meta.serviceAccountName" . }} 7 | labels: 8 | {{- include "supabase.labels" . | nindent 4 }} 9 | {{- with .Values.meta.serviceAccount.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | {{- end }} 14 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/minio/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "supabase.minio.name" -}} 5 | {{- default (print .Chart.Name "-minio") .Values.minio.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "supabase.minio.fullname" -}} 14 | {{- if .Values.minio.fullnameOverride }} 15 | {{- .Values.minio.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default (print .Chart.Name "-minio") .Values.minio.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Selector labels 28 | */}} 29 | {{- define "supabase.minio.selectorLabels" -}} 30 | app.kubernetes.io/name: {{ include "supabase.minio.name" . }} 31 | app.kubernetes.io/instance: {{ .Release.Name }} 32 | {{- end }} 33 | 34 | {{/* 35 | Create the name of the service account to use 36 | */}} 37 | {{- define "supabase.minio.serviceAccountName" -}} 38 | {{- if .Values.minio.serviceAccount.create }} 39 | {{- default (include "supabase.minio.fullname" .) .Values.minio.serviceAccount.name }} 40 | {{- else }} 41 | {{- default "default" .Values.minio.serviceAccount.name }} 42 | {{- end }} 43 | {{- end }} 44 | -------------------------------------------------------------------------------- /charts/supabase/templates/minio/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.minio.enabled -}} 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: {{ include "supabase.minio.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | {{- if not .Values.minio.autoscaling.enabled }} 10 | replicas: {{ .Values.minio.replicaCount }} 11 | {{- end }} 12 | selector: 13 | matchLabels: 14 | {{- include "supabase.minio.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | {{- with .Values.minio.podAnnotations }} 18 | annotations: 19 | {{- toYaml . | nindent 8 }} 20 | {{- end }} 21 | labels: 22 | {{- include "supabase.minio.selectorLabels" . | nindent 8 }} 23 | spec: 24 | restartPolicy: Always 25 | {{- with .Values.minio.imagePullSecrets }} 26 | imagePullSecrets: 27 | {{- toYaml . | nindent 8 }} 28 | {{- end }} 29 | serviceAccountName: {{ include "supabase.minio.serviceAccountName" . }} 30 | securityContext: 31 | {{- toYaml .Values.minio.podSecurityContext | nindent 8 }} 32 | containers: 33 | - name: {{ include "supabase.minio.name" $ }} 34 | securityContext: 35 | {{- toYaml .Values.minio.securityContext | nindent 12 }} 36 | image: "{{ .Values.minio.image.repository }}:{{ .Values.minio.image.tag | default .Chart.AppVersion }}" 37 | imagePullPolicy: {{ .Values.minio.image.pullPolicy }} 38 | args: 39 | - server 40 | - --console-address 41 | - ":9001" 42 | - /data 43 | env: 44 | - name: MINIO_ROOT_USER 45 | valueFrom: 46 | secretKeyRef: 47 | name: {{ include "supabase.secret.s3" . }} 48 | key: keyId 49 | - name: MINIO_ROOT_PASSWORD 50 | valueFrom: 51 | secretKeyRef: 52 | name: {{ include "supabase.secret.s3" . }} 53 | key: accessKey 54 | {{- with .Values.minio.livenessProbe }} 55 | livenessProbe: 56 | {{- toYaml . | nindent 12 }} 57 | {{- end }} 58 | {{- with .Values.minio.readinessProbe }} 59 | readinessProbe: 60 | {{- toYaml . | nindent 12 }} 61 | {{- end }} 62 | ports: 63 | - name: http 64 | containerPort: 9000 65 | protocol: TCP 66 | {{- with .Values.minio.resources }} 67 | resources: 68 | {{- toYaml . | nindent 12 }} 69 | {{- end }} 70 | volumeMounts: 71 | {{- with .Values.minio.volumeMounts }} 72 | {{- toYaml . | nindent 12 }} 73 | {{- end }} 74 | - mountPath: /data 75 | name: minio-data 76 | {{- with .Values.minio.nodeSelector }} 77 | nodeSelector: 78 | {{- toYaml . | nindent 8 }} 79 | {{- end }} 80 | {{- with .Values.minio.affinity }} 81 | affinity: 82 | {{- toYaml . | nindent 8 }} 83 | {{- end }} 84 | {{- with .Values.minio.tolerations }} 85 | tolerations: 86 | {{- toYaml . | nindent 8 }} 87 | {{- end }} 88 | volumes: 89 | - name: minio-data 90 | {{- if .Values.minio.persistence.enabled }} 91 | persistentVolumeClaim: 92 | claimName: {{ include "supabase.minio.fullname" . }}-pvc 93 | {{- else }} 94 | emptyDir: 95 | medium: "" 96 | {{- end }} 97 | {{- with .Values.minio.volumes }} 98 | {{- toYaml . | nindent 8 }} 99 | {{- end }} 100 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/minio/service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.minio.enabled -}} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ include "supabase.minio.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | type: {{ .Values.minio.service.type }} 10 | ports: 11 | - port: {{ .Values.minio.service.port }} 12 | targetPort: 9000 13 | protocol: TCP 14 | name: http 15 | selector: 16 | {{- include "supabase.minio.selectorLabels" . | nindent 4 }} 17 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/minio/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.minio.enabled -}} 2 | {{- if .Values.minio.serviceAccount.create -}} 3 | apiVersion: v1 4 | kind: ServiceAccount 5 | metadata: 6 | name: {{ include "supabase.minio.serviceAccountName" . }} 7 | labels: 8 | {{- include "supabase.labels" . | nindent 4 }} 9 | {{- with .Values.minio.serviceAccount.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | {{- end }} 14 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/minio/volume.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.minio.enabled -}} 2 | {{- if .Values.minio.persistence.enabled -}} 3 | apiVersion: v1 4 | kind: PersistentVolumeClaim 5 | metadata: 6 | name: {{ include "supabase.minio.fullname" . }}-pvc 7 | labels: 8 | {{- include "supabase.labels" . | nindent 4 }} 9 | {{- with .Values.minio.persistence.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | spec: 14 | {{- if .Values.minio.persistence.minioClassName }} 15 | minioClassName: {{ .Values.minio.persistence.minioClassName }} 16 | {{- end }} 17 | accessModes: 18 | {{- range .Values.minio.persistence.accessModes }} 19 | - {{ . | quote }} 20 | {{- end }} 21 | resources: 22 | requests: 23 | storage: {{ .Values.minio.persistence.size | quote }} 24 | {{- end }} 25 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/realtime/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "supabase.realtime.name" -}} 5 | {{- default (print .Chart.Name "-realtime") .Values.realtime.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "supabase.realtime.fullname" -}} 14 | {{- if .Values.realtime.fullnameOverride }} 15 | {{- .Values.realtime.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default (print .Chart.Name "-realtime") .Values.realtime.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Selector labels 28 | */}} 29 | {{- define "supabase.realtime.selectorLabels" -}} 30 | app.kubernetes.io/name: {{ include "supabase.realtime.name" . }} 31 | app.kubernetes.io/instance: {{ .Release.Name }} 32 | {{- end }} 33 | 34 | {{/* 35 | Create the name of the service account to use 36 | */}} 37 | {{- define "supabase.realtime.serviceAccountName" -}} 38 | {{- if .Values.realtime.serviceAccount.create }} 39 | {{- default (include "supabase.realtime.fullname" .) .Values.realtime.serviceAccount.name }} 40 | {{- else }} 41 | {{- default "default" .Values.realtime.serviceAccount.name }} 42 | {{- end }} 43 | {{- end }} 44 | -------------------------------------------------------------------------------- /charts/supabase/templates/realtime/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.realtime.enabled -}} 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: {{ include "supabase.realtime.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | {{- if not .Values.realtime.autoscaling.enabled }} 10 | replicas: {{ .Values.realtime.replicaCount }} 11 | {{- end }} 12 | selector: 13 | matchLabels: 14 | {{- include "supabase.realtime.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | {{- with .Values.realtime.podAnnotations }} 18 | annotations: 19 | {{- toYaml . | nindent 8 }} 20 | {{- end }} 21 | labels: 22 | {{- include "supabase.realtime.selectorLabels" . | nindent 8 }} 23 | spec: 24 | {{- with .Values.realtime.imagePullSecrets }} 25 | imagePullSecrets: 26 | {{- toYaml . | nindent 8 }} 27 | {{- end }} 28 | serviceAccountName: {{ include "supabase.realtime.serviceAccountName" . }} 29 | securityContext: 30 | {{- toYaml .Values.realtime.podSecurityContext | nindent 8 }} 31 | initContainers: 32 | - name: init-db 33 | image: postgres:15-alpine 34 | imagePullPolicy: IfNotPresent 35 | env: 36 | - name: DB_HOST 37 | {{- if .Values.db.enabled }} 38 | value: {{ include "supabase.db.fullname" . | quote }} 39 | {{- else }} 40 | value: {{ .Values.auth.environment.DB_HOST | quote }} 41 | {{- end }} 42 | - name: DB_USER 43 | valueFrom: 44 | secretKeyRef: 45 | {{- if .Values.secret.db.secretRef }} 46 | name: {{ .Values.secret.db.secretRef }} 47 | key: {{ .Values.secret.db.secretRefKey.username | default "username" }} 48 | {{- else }} 49 | name: {{ include "supabase.secret.db" . }} 50 | key: username 51 | {{- end }} 52 | - name: DB_PORT 53 | value: {{ .Values.analytics.environment.DB_PORT | quote }} 54 | command: ["/bin/sh", "-c"] 55 | args: 56 | - | 57 | until pg_isready -h $(DB_HOST) -p $(DB_PORT) -U $(DB_USER); do 58 | echo "Waiting for database to start..." 59 | sleep 2 60 | done 61 | - echo "Database is ready" 62 | containers: 63 | - name: {{ include "supabase.realtime.name" $ }} 64 | securityContext: 65 | {{- toYaml .Values.realtime.securityContext | nindent 12 }} 66 | image: "{{ .Values.realtime.image.repository }}:{{ .Values.realtime.image.tag | default .Chart.AppVersion }}" 67 | imagePullPolicy: {{ .Values.realtime.image.pullPolicy }} 68 | command: ["/bin/sh"] 69 | args: ["-c", "/app/bin/migrate && /app/bin/realtime eval 'Realtime.Release.seeds(Realtime.Repo)' && /app/bin/server"] 70 | env: 71 | {{- range $key, $value := .Values.realtime.environment }} 72 | - name: {{ $key }} 73 | value: {{ $value | quote }} 74 | {{- end }} 75 | {{- if .Values.db.enabled }} 76 | - name: DB_HOST 77 | value: {{ include "supabase.db.fullname" . }} 78 | {{- end }} 79 | - name: DB_PASSWORD 80 | valueFrom: 81 | secretKeyRef: 82 | {{- if .Values.secret.db.secretRef }} 83 | name: {{ .Values.secret.db.secretRef }} 84 | key: {{ .Values.secret.db.secretRefKey.password | default "password" }} 85 | {{- else }} 86 | name: {{ include "supabase.secret.db" . }} 87 | key: password 88 | {{- end }} 89 | - name: DB_NAME 90 | valueFrom: 91 | secretKeyRef: 92 | {{- if .Values.secret.db.secretRef }} 93 | name: {{ .Values.secret.db.secretRef }} 94 | key: {{ .Values.secret.db.secretRefKey.database | default "database" }} 95 | {{- else }} 96 | name: {{ include "supabase.secret.db" . }} 97 | key: database 98 | {{- end }} 99 | - name: JWT_SECRET 100 | valueFrom: 101 | secretKeyRef: 102 | {{- if .Values.secret.jwt.secretRef }} 103 | name: {{ .Values.secret.jwt.secretRef }} 104 | key: {{ .Values.secret.jwt.secretRefKey.secret | default "secret" }} 105 | {{- else }} 106 | name: {{ include "supabase.secret.jwt" . }} 107 | key: secret 108 | {{- end }} 109 | - name: API_JWT_SECRET 110 | valueFrom: 111 | secretKeyRef: 112 | {{- if .Values.secret.jwt.secretRef }} 113 | name: {{ .Values.secret.jwt.secretRef }} 114 | key: {{ .Values.secret.jwt.secretRefKey.secret | default "secret" }} 115 | {{- else }} 116 | name: {{ include "supabase.secret.jwt" . }} 117 | key: secret 118 | {{- end }} 119 | {{- with .Values.realtime.livenessProbe }} 120 | livenessProbe: 121 | {{- toYaml . | nindent 12 }} 122 | {{- end }} 123 | {{- with .Values.realtime.readinessProbe }} 124 | readinessProbe: 125 | {{- toYaml . | nindent 12 }} 126 | {{- end }} 127 | ports: 128 | - name: http 129 | containerPort: 4000 130 | protocol: TCP 131 | {{- with .Values.realtime.resources }} 132 | resources: 133 | {{- toYaml . | nindent 12 }} 134 | {{- end }} 135 | {{- with .Values.realtime.volumeMounts }} 136 | volumeMounts: 137 | {{- toYaml . | nindent 12 }} 138 | {{- end }} 139 | {{- with .Values.realtime.volumes }} 140 | volumes: 141 | {{- toYaml . | nindent 8 }} 142 | {{- end }} 143 | {{- with .Values.realtime.nodeSelector }} 144 | nodeSelector: 145 | {{- toYaml . | nindent 8 }} 146 | {{- end }} 147 | {{- with .Values.realtime.affinity }} 148 | affinity: 149 | {{- toYaml . | nindent 8 }} 150 | {{- end }} 151 | {{- with .Values.realtime.tolerations }} 152 | tolerations: 153 | {{- toYaml . | nindent 8 }} 154 | {{- end }} 155 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/realtime/service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.realtime.enabled -}} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ include "supabase.realtime.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | type: {{ .Values.realtime.service.type }} 10 | ports: 11 | - port: {{ .Values.realtime.service.port }} 12 | targetPort: 4000 13 | protocol: TCP 14 | name: http 15 | selector: 16 | {{- include "supabase.realtime.selectorLabels" . | nindent 4 }} 17 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/realtime/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.realtime.enabled -}} 2 | {{- if .Values.realtime.serviceAccount.create -}} 3 | apiVersion: v1 4 | kind: ServiceAccount 5 | metadata: 6 | name: {{ include "supabase.realtime.serviceAccountName" . }} 7 | labels: 8 | {{- include "supabase.labels" . | nindent 4 }} 9 | {{- with .Values.realtime.serviceAccount.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | {{- end }} 14 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/rest/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "supabase.rest.name" -}} 5 | {{- default (print .Chart.Name "-rest") .Values.rest.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "supabase.rest.fullname" -}} 14 | {{- if .Values.rest.fullnameOverride }} 15 | {{- .Values.rest.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default (print .Chart.Name "-rest") .Values.rest.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Selector labels 28 | */}} 29 | {{- define "supabase.rest.selectorLabels" -}} 30 | app.kubernetes.io/name: {{ include "supabase.rest.name" . }} 31 | app.kubernetes.io/instance: {{ .Release.Name }} 32 | {{- end }} 33 | 34 | {{/* 35 | Create the name of the service account to use 36 | */}} 37 | {{- define "supabase.rest.serviceAccountName" -}} 38 | {{- if .Values.rest.serviceAccount.create }} 39 | {{- default (include "supabase.rest.fullname" .) .Values.rest.serviceAccount.name }} 40 | {{- else }} 41 | {{- default "default" .Values.rest.serviceAccount.name }} 42 | {{- end }} 43 | {{- end }} 44 | -------------------------------------------------------------------------------- /charts/supabase/templates/rest/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rest.enabled -}} 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: {{ include "supabase.rest.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | {{- if not .Values.rest.autoscaling.enabled }} 10 | replicas: {{ .Values.rest.replicaCount }} 11 | {{- end }} 12 | selector: 13 | matchLabels: 14 | {{- include "supabase.rest.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | {{- with .Values.rest.podAnnotations }} 18 | annotations: 19 | {{- toYaml . | nindent 8 }} 20 | {{- end }} 21 | labels: 22 | {{- include "supabase.rest.selectorLabels" . | nindent 8 }} 23 | spec: 24 | {{- with .Values.rest.imagePullSecrets }} 25 | imagePullSecrets: 26 | {{- toYaml . | nindent 8 }} 27 | {{- end }} 28 | serviceAccountName: {{ include "supabase.rest.serviceAccountName" . }} 29 | securityContext: 30 | {{- toYaml .Values.rest.podSecurityContext | nindent 8 }} 31 | containers: 32 | - name: {{ include "supabase.rest.name" $ }} 33 | securityContext: 34 | {{- toYaml .Values.rest.securityContext | nindent 12 }} 35 | image: "{{ .Values.rest.image.repository }}:{{ .Values.rest.image.tag | default .Chart.AppVersion }}" 36 | imagePullPolicy: {{ .Values.rest.image.pullPolicy }} 37 | env: 38 | {{- range $key, $value := .Values.rest.environment }} 39 | - name: {{ $key }} 40 | value: {{ $value | quote }} 41 | {{- end }} 42 | {{- if .Values.db.enabled }} 43 | - name: DB_HOST 44 | value: {{ include "supabase.db.fullname" . }} 45 | {{- end }} 46 | - name: DB_PASSWORD 47 | valueFrom: 48 | secretKeyRef: 49 | {{- if .Values.secret.db.secretRef }} 50 | name: {{ .Values.secret.db.secretRef }} 51 | key: {{ .Values.secret.db.secretRefKey.password | default "password" }} 52 | {{- else }} 53 | name: {{ include "supabase.secret.db" . }} 54 | key: password 55 | {{- end }} 56 | - name: DB_PASSWORD_ENC 57 | valueFrom: 58 | secretKeyRef: 59 | {{- if .Values.secret.db.secretRef }} 60 | name: {{ .Values.secret.db.secretRef }} 61 | key: {{ .Values.secret.db.secretRefKey.password | default "password" }} 62 | {{- else }} 63 | name: {{ include "supabase.secret.db" . }} 64 | key: password_encoded 65 | {{- end }} 66 | - name: DB_NAME 67 | valueFrom: 68 | secretKeyRef: 69 | {{- if .Values.secret.db.secretRef }} 70 | name: {{ .Values.secret.db.secretRef }} 71 | key: {{ .Values.secret.db.secretRefKey.database | default "database" }} 72 | {{- else }} 73 | name: {{ include "supabase.secret.db" . }} 74 | key: database 75 | {{- end }} 76 | - name: PGRST_DB_URI 77 | value: $(DB_DRIVER)://$(DB_USER):$(DB_PASSWORD_ENC)@$(DB_HOST):$(DB_PORT)/$(DB_NAME)?sslmode=$(DB_SSL) 78 | - name: PGRST_JWT_SECRET 79 | valueFrom: 80 | secretKeyRef: 81 | {{- if .Values.secret.jwt.secretRef }} 82 | name: {{ .Values.secret.jwt.secretRef }} 83 | key: {{ .Values.secret.jwt.secretRefKey.secret | default "secret" }} 84 | {{- else }} 85 | name: {{ include "supabase.secret.jwt" . }} 86 | key: secret 87 | {{- end }} 88 | - name: PGRST_APP_SETTINGS_JWT_SECRET 89 | valueFrom: 90 | secretKeyRef: 91 | {{- if .Values.secret.jwt.secretRef }} 92 | name: {{ .Values.secret.jwt.secretRef }} 93 | key: {{ .Values.secret.jwt.secretRefKey.secret | default "secret" }} 94 | {{- else }} 95 | name: {{ include "supabase.secret.jwt" . }} 96 | key: secret 97 | {{- end }} 98 | {{- with .Values.rest.livenessProbe }} 99 | livenessProbe: 100 | {{- toYaml . | nindent 12 }} 101 | {{- end }} 102 | {{- with .Values.rest.readinessProbe }} 103 | readinessProbe: 104 | {{- toYaml . | nindent 12 }} 105 | {{- end }} 106 | ports: 107 | - name: http 108 | containerPort: 3000 109 | protocol: TCP 110 | {{- with .Values.rest.resources }} 111 | resources: 112 | {{- toYaml . | nindent 12 }} 113 | {{- end }} 114 | {{- with .Values.rest.volumeMounts }} 115 | volumeMounts: 116 | {{- toYaml . | nindent 12 }} 117 | {{- end }} 118 | {{- with .Values.rest.volumes }} 119 | volumes: 120 | {{- toYaml . | nindent 8 }} 121 | {{- end }} 122 | {{- with .Values.rest.nodeSelector }} 123 | nodeSelector: 124 | {{- toYaml . | nindent 8 }} 125 | {{- end }} 126 | {{- with .Values.rest.affinity }} 127 | affinity: 128 | {{- toYaml . | nindent 8 }} 129 | {{- end }} 130 | {{- with .Values.rest.tolerations }} 131 | tolerations: 132 | {{- toYaml . | nindent 8 }} 133 | {{- end }} 134 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/rest/service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rest.enabled -}} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ include "supabase.rest.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | type: {{ .Values.rest.service.type }} 10 | ports: 11 | - port: {{ .Values.rest.service.port }} 12 | targetPort: 3000 13 | protocol: TCP 14 | name: http 15 | selector: 16 | {{- include "supabase.rest.selectorLabels" . | nindent 4 }} 17 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/rest/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rest.enabled -}} 2 | {{- if .Values.rest.serviceAccount.create -}} 3 | apiVersion: v1 4 | kind: ServiceAccount 5 | metadata: 6 | name: {{ include "supabase.rest.serviceAccountName" . }} 7 | labels: 8 | {{- include "supabase.labels" . | nindent 4 }} 9 | {{- with .Values.rest.serviceAccount.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | {{- end }} 14 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/secrets/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the JWT secret. 3 | */}} 4 | {{- define "supabase.secret.jwt" -}} 5 | {{- printf "%s-jwt" (include "supabase.fullname" .) }} 6 | {{- end -}} 7 | 8 | {{/* 9 | Expand the name of the SMTP secret. 10 | */}} 11 | {{- define "supabase.secret.smtp" -}} 12 | {{- printf "%s-smtp" (include "supabase.fullname" .) }} 13 | {{- end -}} 14 | 15 | {{/* 16 | Expand the name of the dashboard secret. 17 | */}} 18 | {{- define "supabase.secret.dashboard" -}} 19 | {{- printf "%s-dashboard" (include "supabase.fullname" .) }} 20 | {{- end -}} 21 | 22 | {{/* 23 | Expand the name of the database secret. 24 | */}} 25 | {{- define "supabase.secret.db" -}} 26 | {{- printf "%s-db" (include "supabase.fullname" .) }} 27 | {{- end -}} 28 | 29 | {{/* 30 | Expand the name of the analytics secret. 31 | */}} 32 | {{- define "supabase.secret.analytics" -}} 33 | {{- printf "%s-analytics" (include "supabase.fullname" .) }} 34 | {{- end -}} 35 | 36 | {{/* 37 | Expand the name of the s3 secret. 38 | */}} 39 | {{- define "supabase.secret.s3" -}} 40 | {{- printf "%s-s3" (include "supabase.fullname" .) }} 41 | {{- end -}} 42 | 43 | {{/* 44 | Check if both s3 keys are valid 45 | */}} 46 | {{- define "supabase.secret.s3.isValid" -}} 47 | {{- $isValid := "false" -}} 48 | {{- if .Values.secret.s3.keyId -}} 49 | {{- if .Values.secret.s3.accessKey -}} 50 | {{- printf "true" -}} 51 | {{- else -}} 52 | {{- printf "false" -}} 53 | {{- end -}} 54 | {{- else -}} 55 | {{- printf "false" -}} 56 | {{- end -}} 57 | {{- end -}} 58 | -------------------------------------------------------------------------------- /charts/supabase/templates/secrets/analytics.yaml: -------------------------------------------------------------------------------- 1 | {{- if not .Values.secret.analytics.secretRef }} 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: {{ include "supabase.secret.analytics" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | type: Opaque 9 | data: 10 | {{- range $key, $value := .Values.secret.analytics }} 11 | {{- if $value }} 12 | {{- if eq (typeOf $value) "string" }} 13 | {{ $key }}: {{ $value | b64enc }} 14 | {{- end }} 15 | {{- end }} 16 | {{- end }} 17 | {{- end }} 18 | -------------------------------------------------------------------------------- /charts/supabase/templates/secrets/dashboard.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.secret.dashboard }} 2 | {{- if not .Values.secret.dashboard.secretRef }} 3 | apiVersion: v1 4 | kind: Secret 5 | metadata: 6 | name: {{ include "supabase.secret.dashboard" . }} 7 | labels: 8 | {{- include "supabase.labels" . | nindent 4 }} 9 | type: Opaque 10 | data: 11 | {{- range $key, $value := .Values.secret.dashboard }} 12 | {{- if $value }} 13 | {{- if eq (typeOf $value) "string" }} 14 | {{ $key }}: {{ $value | b64enc }} 15 | {{- end }} 16 | {{- end }} 17 | {{- end }} 18 | {{- end }} 19 | {{- end }} 20 | -------------------------------------------------------------------------------- /charts/supabase/templates/secrets/db.yaml: -------------------------------------------------------------------------------- 1 | {{- if not .Values.secret.db.secretRef }} 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: {{ include "supabase.secret.db" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | type: Opaque 9 | data: 10 | {{- range $key, $value := .Values.secret.db }} 11 | {{- if $value }} 12 | {{- if or (eq (typeOf $value) "string") (eq (typeOf $value) "numeric") }} 13 | {{ $key }}: {{ $value | b64enc }} 14 | {{- end }} 15 | {{- end }} 16 | {{- end }} 17 | password_encoded: {{ .Values.secret.db.password | urlquery | b64enc }} 18 | {{- end }} 19 | -------------------------------------------------------------------------------- /charts/supabase/templates/secrets/jwt.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.secret.jwt }} 2 | {{- if not .Values.secret.jwt.secretRef }} 3 | apiVersion: v1 4 | kind: Secret 5 | metadata: 6 | name: {{ include "supabase.secret.jwt" . }} 7 | labels: 8 | {{- include "supabase.labels" . | nindent 4 }} 9 | type: Opaque 10 | data: 11 | {{- range $key, $value := .Values.secret.jwt }} 12 | {{- if $value }} 13 | {{- if eq (typeOf $value) "string" }} 14 | {{ $key }}: {{ $value | toString | b64enc }} 15 | {{- end }} 16 | {{- end }} 17 | {{- end }} 18 | {{- end }} 19 | {{- end }} 20 | -------------------------------------------------------------------------------- /charts/supabase/templates/secrets/s3.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.secret.s3 }} 2 | {{- if not .Values.secret.s3.secretRef }} 3 | apiVersion: v1 4 | kind: Secret 5 | metadata: 6 | name: {{ include "supabase.secret.s3" . }} 7 | labels: 8 | {{- include "supabase.labels" . | nindent 4 }} 9 | type: Opaque 10 | data: 11 | {{- range $key, $value := .Values.secret.s3 }} 12 | {{- if $value }} 13 | {{- if eq (typeOf $value) "string" }} 14 | {{ $key }}: {{ $value | toString | b64enc }} 15 | {{- end }} 16 | {{- end }} 17 | {{- end }} 18 | {{- end }} 19 | {{- end }} 20 | -------------------------------------------------------------------------------- /charts/supabase/templates/secrets/smtp.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.secret.smtp }} 2 | {{- if not .Values.secret.smtp.secretRef }} 3 | apiVersion: v1 4 | kind: Secret 5 | metadata: 6 | name: {{ include "supabase.secret.smtp" . }} 7 | labels: 8 | {{- include "supabase.labels" . | nindent 4 }} 9 | type: Opaque 10 | data: 11 | {{- range $key, $value := .Values.secret.smtp }} 12 | {{- if $value }} 13 | {{- if eq (typeOf $value) "string" }} 14 | {{ $key }}: {{ $value | b64enc }} 15 | {{- end }} 16 | {{- end }} 17 | {{- end }} 18 | {{- end }} 19 | {{- end }} 20 | -------------------------------------------------------------------------------- /charts/supabase/templates/storage/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "supabase.storage.name" -}} 5 | {{- default (print .Chart.Name "-storage") .Values.storage.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "supabase.storage.fullname" -}} 14 | {{- if .Values.storage.fullnameOverride }} 15 | {{- .Values.storage.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default (print .Chart.Name "-storage") .Values.storage.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Selector labels 28 | */}} 29 | {{- define "supabase.storage.selectorLabels" -}} 30 | app.kubernetes.io/name: {{ include "supabase.storage.name" . }} 31 | app.kubernetes.io/instance: {{ .Release.Name }} 32 | {{- end }} 33 | 34 | {{/* 35 | Create the name of the service account to use 36 | */}} 37 | {{- define "supabase.storage.serviceAccountName" -}} 38 | {{- if .Values.storage.serviceAccount.create }} 39 | {{- default (include "supabase.storage.fullname" .) .Values.storage.serviceAccount.name }} 40 | {{- else }} 41 | {{- default "default" .Values.storage.serviceAccount.name }} 42 | {{- end }} 43 | {{- end }} 44 | -------------------------------------------------------------------------------- /charts/supabase/templates/storage/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.storage.enabled -}} 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: {{ include "supabase.storage.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | {{- if not .Values.storage.autoscaling.enabled }} 10 | replicas: {{ .Values.storage.replicaCount }} 11 | {{- end }} 12 | selector: 13 | matchLabels: 14 | {{- include "supabase.storage.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | {{- with .Values.storage.podAnnotations }} 18 | annotations: 19 | {{- toYaml . | nindent 8 }} 20 | {{- end }} 21 | labels: 22 | {{- include "supabase.storage.selectorLabels" . | nindent 8 }} 23 | spec: 24 | restartPolicy: Always 25 | {{- with .Values.storage.imagePullSecrets }} 26 | imagePullSecrets: 27 | {{- toYaml . | nindent 8 }} 28 | {{- end }} 29 | serviceAccountName: {{ include "supabase.storage.serviceAccountName" . }} 30 | securityContext: 31 | {{- toYaml .Values.storage.podSecurityContext | nindent 8 }} 32 | initContainers: 33 | - name: init-db 34 | image: postgres:15-alpine 35 | imagePullPolicy: IfNotPresent 36 | env: 37 | - name: DB_HOST 38 | {{- if .Values.db.enabled }} 39 | value: {{ include "supabase.db.fullname" . | quote }} 40 | {{- else }} 41 | value: {{ .Values.auth.environment.DB_HOST | quote }} 42 | {{- end }} 43 | - name: DB_USER 44 | valueFrom: 45 | secretKeyRef: 46 | {{- if .Values.secret.db.secretRef }} 47 | name: {{ .Values.secret.db.secretRef }} 48 | key: {{ .Values.secret.db.secretRefKey.username | default "username" }} 49 | {{- else }} 50 | name: {{ include "supabase.secret.db" . }} 51 | key: username 52 | {{- end }} 53 | - name: DB_PORT 54 | value: {{ .Values.analytics.environment.DB_PORT | quote }} 55 | command: ["/bin/sh", "-c"] 56 | args: 57 | - | 58 | until pg_isready -h $(DB_HOST) -p $(DB_PORT) -U $(DB_USER); do 59 | echo "Waiting for database to start..." 60 | sleep 2 61 | done 62 | - echo "Database is ready" 63 | {{- if .Values.minio.enabled }} 64 | - env: 65 | - name: MINIO_ROOT_USER 66 | valueFrom: 67 | secretKeyRef: 68 | name: {{ include "supabase.secret.s3" . }} 69 | key: keyId 70 | - name: MINIO_ROOT_PASSWORD 71 | valueFrom: 72 | secretKeyRef: 73 | name: {{ include "supabase.secret.s3" . }} 74 | key: accessKey 75 | name: init-bucket 76 | image: minio/mc 77 | imagePullPolicy: IfNotPresent 78 | command: 79 | - /bin/sh 80 | - -c 81 | - | 82 | until /usr/bin/mc alias set supa-minio http://{{ include "supabase.minio.fullname" . }}:{{ .Values.minio.service.port }} $MINIO_ROOT_USER $MINIO_ROOT_PASSWORD; do 83 | echo "Waiting for minio to start..." 84 | sleep 2 85 | done 86 | /usr/bin/mc mb --ignore-existing supa-minio/stub 87 | {{- end }} 88 | containers: 89 | - name: {{ include "supabase.storage.name" $ }} 90 | securityContext: 91 | {{- toYaml .Values.storage.securityContext | nindent 12 }} 92 | image: "{{ .Values.storage.image.repository }}:{{ .Values.storage.image.tag | default .Chart.AppVersion }}" 93 | imagePullPolicy: {{ .Values.storage.image.pullPolicy }} 94 | env: 95 | {{- range $key, $value := .Values.storage.environment }} 96 | - name: {{ $key }} 97 | value: {{ $value | quote }} 98 | {{- end }} 99 | {{- if .Values.db.enabled }} 100 | - name: DB_HOST 101 | value: {{ include "supabase.db.fullname" . }} 102 | {{- end }} 103 | {{- if .Values.rest.enabled }} 104 | - name: POSTGREST_URL 105 | value: http://{{ include "supabase.rest.fullname" . }}:{{ .Values.rest.service.port }} 106 | {{- end }} 107 | - name: DB_PASSWORD 108 | valueFrom: 109 | secretKeyRef: 110 | {{- if .Values.secret.db.secretRef }} 111 | name: {{ .Values.secret.db.secretRef }} 112 | key: {{ .Values.secret.db.secretRefKey.password | default "password" }} 113 | {{- else }} 114 | name: {{ include "supabase.secret.db" . }} 115 | key: password 116 | {{- end }} 117 | - name: DB_PASSWORD_ENC 118 | valueFrom: 119 | secretKeyRef: 120 | {{- if .Values.secret.db.secretRef }} 121 | name: {{ .Values.secret.db.secretRef }} 122 | key: {{ .Values.secret.db.secretRefKey.password | default "password" }} 123 | {{- else }} 124 | name: {{ include "supabase.secret.db" . }} 125 | key: password_encoded 126 | {{- end }} 127 | - name: DB_NAME 128 | valueFrom: 129 | secretKeyRef: 130 | {{- if .Values.secret.db.secretRef }} 131 | name: {{ .Values.secret.db.secretRef }} 132 | key: {{ .Values.secret.db.secretRefKey.database | default "database" }} 133 | {{- else }} 134 | name: {{ include "supabase.secret.db" . }} 135 | key: database 136 | {{- end }} 137 | - name: DATABASE_URL 138 | value: $(DB_DRIVER)://$(DB_USER):$(DB_PASSWORD_ENC)@$(DB_HOST):$(DB_PORT)/$(DB_NAME)?search_path=auth&sslmode=$(DB_SSL) 139 | - name: PGRST_JWT_SECRET 140 | valueFrom: 141 | secretKeyRef: 142 | {{- if .Values.secret.jwt.secretRef }} 143 | name: {{ .Values.secret.jwt.secretRef }} 144 | key: {{ .Values.secret.jwt.secretRefKey.secret | default "secret" }} 145 | {{- else }} 146 | name: {{ include "supabase.secret.jwt" . }} 147 | key: secret 148 | {{- end }} 149 | - name: ANON_KEY 150 | valueFrom: 151 | secretKeyRef: 152 | {{- if .Values.secret.jwt.secretRef }} 153 | name: {{ .Values.secret.jwt.secretRef }} 154 | key: {{ .Values.secret.jwt.secretRefKey.anonKey | default "anonKey" }} 155 | {{- else }} 156 | name: {{ include "supabase.secret.jwt" . }} 157 | key: anonKey 158 | {{- end }} 159 | - name: SERVICE_KEY 160 | valueFrom: 161 | secretKeyRef: 162 | {{- if .Values.secret.jwt.secretRef }} 163 | name: {{ .Values.secret.jwt.secretRef }} 164 | key: {{ .Values.secret.jwt.secretRefKey.serviceKey | default "serviceKey" }} 165 | {{- else }} 166 | name: {{ include "supabase.secret.jwt" . }} 167 | key: serviceKey 168 | {{- end }} 169 | {{- if .Values.imgproxy.enabled }} 170 | - name: IMGPROXY_URL 171 | value: http://{{ include "supabase.imgproxy.fullname" . }}:{{ .Values.imgproxy.service.port | int }} 172 | {{- end }} 173 | {{- if eq (include "supabase.secret.s3.isValid" .) "true" }} 174 | - name: AWS_ACCESS_KEY_ID 175 | valueFrom: 176 | secretKeyRef: 177 | {{- if .Values.secret.s3.secretRef }} 178 | name: {{ .Values.secret.s3.secretRef }} 179 | key: {{ .Values.secret.s3.secretRefKey.keyId | default "keyId" }} 180 | {{- else }} 181 | name: {{ include "supabase.secret.s3" . }} 182 | key: keyId 183 | {{- end }} 184 | - name: AWS_SECRET_ACCESS_KEY 185 | valueFrom: 186 | secretKeyRef: 187 | {{- if .Values.secret.s3.secretRef }} 188 | name: {{ .Values.secret.s3.secretRef }} 189 | key: {{ .Values.secret.s3.secretRefKey.keyId | default "accessKey" }} 190 | {{- else }} 191 | name: {{ include "supabase.secret.s3" . }} 192 | key: accessKey 193 | {{- end }} 194 | {{- end }} 195 | {{- if .Values.minio.enabled }} 196 | - name: GLOBAL_S3_ENDPOINT 197 | value: http://{{ include "supabase.minio.fullname" . }}:{{ default 9000 .Values.minio.service.port }} 198 | {{- end }} 199 | {{- with .Values.storage.livenessProbe }} 200 | livenessProbe: 201 | {{- toYaml . | nindent 12 }} 202 | {{- end }} 203 | {{- with .Values.storage.readinessProbe }} 204 | readinessProbe: 205 | {{- toYaml . | nindent 12 }} 206 | {{- end }} 207 | ports: 208 | - name: http 209 | containerPort: 5000 210 | protocol: TCP 211 | {{- with .Values.storage.resources }} 212 | resources: 213 | {{- toYaml . | nindent 12 }} 214 | {{- end }} 215 | volumeMounts: 216 | {{- with .Values.storage.volumeMounts }} 217 | {{- toYaml . | nindent 12 }} 218 | {{- end }} 219 | - mountPath: /var/lib/storage 220 | name: storage-data 221 | {{- with .Values.storage.nodeSelector }} 222 | nodeSelector: 223 | {{- toYaml . | nindent 8 }} 224 | {{- end }} 225 | {{- with .Values.storage.affinity }} 226 | affinity: 227 | {{- toYaml . | nindent 8 }} 228 | {{- end }} 229 | {{- with .Values.storage.tolerations }} 230 | tolerations: 231 | {{- toYaml . | nindent 8 }} 232 | {{- end }} 233 | volumes: 234 | - name: storage-data 235 | {{- if .Values.storage.persistence.enabled }} 236 | persistentVolumeClaim: 237 | claimName: {{ include "supabase.storage.fullname" . }}-pvc 238 | {{- else }} 239 | emptyDir: 240 | medium: "" 241 | {{- end }} 242 | {{- with .Values.storage.volumes }} 243 | {{- toYaml . | nindent 8 }} 244 | {{- end }} 245 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/storage/service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.storage.enabled -}} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ include "supabase.storage.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | type: {{ .Values.storage.service.type }} 10 | ports: 11 | - port: {{ .Values.storage.service.port }} 12 | targetPort: 5000 13 | protocol: TCP 14 | name: http 15 | selector: 16 | {{- include "supabase.storage.selectorLabels" . | nindent 4 }} 17 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/storage/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.storage.enabled -}} 2 | {{- if .Values.storage.serviceAccount.create -}} 3 | apiVersion: v1 4 | kind: ServiceAccount 5 | metadata: 6 | name: {{ include "supabase.storage.serviceAccountName" . }} 7 | labels: 8 | {{- include "supabase.labels" . | nindent 4 }} 9 | {{- with .Values.storage.serviceAccount.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | {{- end }} 14 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/storage/volume.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.storage.enabled -}} 2 | {{- if .Values.storage.persistence.enabled -}} 3 | apiVersion: v1 4 | kind: PersistentVolumeClaim 5 | metadata: 6 | name: {{ include "supabase.storage.fullname" . }}-pvc 7 | labels: 8 | {{- include "supabase.labels" . | nindent 4 }} 9 | {{- with .Values.storage.persistence.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | spec: 14 | {{- if .Values.storage.persistence.storageClassName }} 15 | storageClassName: {{ .Values.storage.persistence.storageClassName }} 16 | {{- end }} 17 | accessModes: 18 | {{- range .Values.storage.persistence.accessModes }} 19 | - {{ . | quote }} 20 | {{- end }} 21 | resources: 22 | requests: 23 | storage: {{ .Values.storage.persistence.size | quote }} 24 | {{- end }} 25 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/studio/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "supabase.studio.name" -}} 5 | {{- default (print .Chart.Name "-studio") .Values.studio.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "supabase.studio.fullname" -}} 14 | {{- if .Values.studio.fullnameOverride }} 15 | {{- .Values.studio.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default (print .Chart.Name "-studio") .Values.studio.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Selector labels 28 | */}} 29 | {{- define "supabase.studio.selectorLabels" -}} 30 | app.kubernetes.io/name: {{ include "supabase.studio.name" . }} 31 | app.kubernetes.io/instance: {{ .Release.Name }} 32 | {{- end }} 33 | 34 | {{/* 35 | Create the name of the service account to use 36 | */}} 37 | {{- define "supabase.studio.serviceAccountName" -}} 38 | {{- if .Values.studio.serviceAccount.create }} 39 | {{- default (include "supabase.studio.fullname" .) .Values.studio.serviceAccount.name }} 40 | {{- else }} 41 | {{- default "default" .Values.studio.serviceAccount.name }} 42 | {{- end }} 43 | {{- end }} 44 | -------------------------------------------------------------------------------- /charts/supabase/templates/studio/deployment.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.studio.enabled -}} 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: {{ include "supabase.studio.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | {{- if not .Values.studio.autoscaling.enabled }} 10 | replicas: {{ .Values.studio.replicaCount }} 11 | {{- end }} 12 | selector: 13 | matchLabels: 14 | {{- include "supabase.studio.selectorLabels" . | nindent 6 }} 15 | template: 16 | metadata: 17 | {{- with .Values.studio.podAnnotations }} 18 | annotations: 19 | {{- toYaml . | nindent 8 }} 20 | {{- end }} 21 | labels: 22 | {{- include "supabase.studio.selectorLabels" . | nindent 8 }} 23 | spec: 24 | {{- with .Values.studio.imagePullSecrets }} 25 | imagePullSecrets: 26 | {{- toYaml . | nindent 8 }} 27 | {{- end }} 28 | serviceAccountName: {{ include "supabase.studio.serviceAccountName" . }} 29 | securityContext: 30 | {{- toYaml .Values.studio.podSecurityContext | nindent 8 }} 31 | containers: 32 | - name: {{ include "supabase.studio.name" $ }} 33 | securityContext: 34 | {{- toYaml .Values.studio.securityContext | nindent 12 }} 35 | image: "{{ .Values.studio.image.repository }}:{{ .Values.studio.image.tag | default .Chart.AppVersion }}" 36 | imagePullPolicy: {{ .Values.studio.image.pullPolicy }} 37 | env: 38 | {{- range $key, $value := .Values.studio.environment }} 39 | - name: {{ $key }} 40 | value: {{ $value | quote }} 41 | {{- end }} 42 | {{- if .Values.kong.enabled }} 43 | - name: SUPABASE_URL 44 | value: http://{{ include "supabase.kong.fullname" . }}:{{ .Values.kong.service.port }} 45 | {{- end }} 46 | {{- if .Values.meta.enabled }} 47 | - name: STUDIO_PG_META_URL 48 | value: http://{{ include "supabase.meta.fullname" . }}:{{ .Values.meta.service.port }} 49 | {{- end }} 50 | - name: SUPABASE_ANON_KEY 51 | valueFrom: 52 | secretKeyRef: 53 | {{- if .Values.secret.jwt.secretRef }} 54 | name: {{ .Values.secret.jwt.secretRef }} 55 | key: {{ .Values.secret.jwt.secretRefKey.anonKey | default "anonKey" }} 56 | {{- else }} 57 | name: {{ include "supabase.secret.jwt" . }} 58 | key: anonKey 59 | {{- end }} 60 | - name: SUPABASE_SERVICE_KEY 61 | valueFrom: 62 | secretKeyRef: 63 | {{- if .Values.secret.jwt.secretRef }} 64 | name: {{ .Values.secret.jwt.secretRef }} 65 | key: {{ .Values.secret.jwt.secretRefKey.serviceKey | default "serviceKey" }} 66 | {{- else }} 67 | name: {{ include "supabase.secret.jwt" . }} 68 | key: serviceKey 69 | {{- end }} 70 | {{- if .Values.analytics.enabled }} 71 | - name: LOGFLARE_URL 72 | value: http://{{ include "supabase.analytics.fullname" . }}:{{ .Values.analytics.service.port }} 73 | - name: LOGFLARE_API_KEY 74 | valueFrom: 75 | secretKeyRef: 76 | name: {{ include "supabase.secret.analytics" . }} 77 | key: apiKey 78 | {{- end }} 79 | {{- with .Values.studio.livenessProbe }} 80 | livenessProbe: 81 | {{- toYaml . | nindent 12 }} 82 | {{- end }} 83 | {{- with .Values.studio.readinessProbe }} 84 | readinessProbe: 85 | {{- toYaml . | nindent 12 }} 86 | {{- end }} 87 | ports: 88 | - name: http 89 | containerPort: 3000 90 | protocol: TCP 91 | {{- with .Values.studio.resources }} 92 | resources: 93 | {{- toYaml . | nindent 12 }} 94 | {{- end }} 95 | {{- with .Values.studio.volumeMounts }} 96 | volumeMounts: 97 | {{- toYaml . | nindent 12 }} 98 | {{- end }} 99 | {{- with .Values.studio.volumes }} 100 | volumes: 101 | {{- toYaml . | nindent 8 }} 102 | {{- end }} 103 | {{- with .Values.studio.nodeSelector }} 104 | nodeSelector: 105 | {{- toYaml . | nindent 8 }} 106 | {{- end }} 107 | {{- with .Values.studio.affinity }} 108 | affinity: 109 | {{- toYaml . | nindent 8 }} 110 | {{- end }} 111 | {{- with .Values.studio.tolerations }} 112 | tolerations: 113 | {{- toYaml . | nindent 8 }} 114 | {{- end }} 115 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/studio/service.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.studio.enabled -}} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: {{ include "supabase.studio.fullname" . }} 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | spec: 9 | type: {{ .Values.studio.service.type }} 10 | ports: 11 | - port: {{ .Values.studio.service.port }} 12 | targetPort: 3000 13 | protocol: TCP 14 | name: http 15 | selector: 16 | {{- include "supabase.studio.selectorLabels" . | nindent 4 }} 17 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/studio/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.studio.enabled -}} 2 | {{- if .Values.studio.serviceAccount.create -}} 3 | apiVersion: v1 4 | kind: ServiceAccount 5 | metadata: 6 | name: {{ include "supabase.studio.serviceAccountName" . }} 7 | labels: 8 | {{- include "supabase.labels" . | nindent 4 }} 9 | {{- with .Values.studio.serviceAccount.annotations }} 10 | annotations: 11 | {{- toYaml . | nindent 4 }} 12 | {{- end }} 13 | {{- end }} 14 | {{- end }} -------------------------------------------------------------------------------- /charts/supabase/templates/test/analytics.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.analytics.enabled -}} 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: {{ include "supabase.fullname" . }}-test-analytics 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | annotations: 9 | "helm.sh/hook": test 10 | spec: 11 | ttlSecondsAfterFinished: 100 12 | template: 13 | spec: 14 | containers: 15 | - name: test-analytics 16 | image: kdevup/curljq 17 | imagePullPolicy: IfNotPresent 18 | command: 19 | - /bin/bash 20 | - -c 21 | - | 22 | curl -sfo /dev/null \ 23 | http://{{ include "supabase.analytics.fullname" . }}:{{ .Values.analytics.service.port }}/health 24 | echo "Sevice {{ include "supabase.analytics.fullname" . }} is healthy." 25 | restartPolicy: Never 26 | {{- end }} 27 | -------------------------------------------------------------------------------- /charts/supabase/templates/test/auth.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.auth.enabled -}} 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: {{ include "supabase.fullname" . }}-test-auth 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | annotations: 9 | "helm.sh/hook": test 10 | spec: 11 | ttlSecondsAfterFinished: 100 12 | template: 13 | spec: 14 | containers: 15 | - name: test-auth 16 | image: kdevup/curljq 17 | imagePullPolicy: IfNotPresent 18 | command: 19 | - /bin/bash 20 | - -c 21 | - | 22 | curl -sfo /dev/null \ 23 | http://{{ include "supabase.auth.fullname" . }}:{{ .Values.auth.service.port }}/health 24 | echo "Sevice {{ include "supabase.auth.fullname" . }} is healthy." 25 | restartPolicy: Never 26 | {{- end }} 27 | -------------------------------------------------------------------------------- /charts/supabase/templates/test/db.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.db.enabled -}} 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: {{ include "supabase.fullname" . }}-test-db 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | annotations: 9 | "helm.sh/hook": test 10 | spec: 11 | ttlSecondsAfterFinished: 100 12 | template: 13 | spec: 14 | containers: 15 | - command: 16 | - /bin/sh 17 | - -c 18 | - | 19 | pg_isready -h $(DB_HOST) -p $(DB_PORT) -U $(DB_USER) || $(echo "\e[0;31mFailed to connect to the database." && exit 1) 20 | echo "Database is ready" 21 | env: 22 | - name: DB_HOST 23 | {{- if .Values.db.enabled }} 24 | value: {{ include "supabase.db.fullname" . | quote }} 25 | {{- else }} 26 | value: {{ .Values.auth.environment.DB_HOST | quote }} 27 | {{- end }} 28 | - name: DB_USER 29 | valueFrom: 30 | secretKeyRef: 31 | {{- if .Values.secret.db.secretRef }} 32 | name: {{ .Values.secret.db.secretRef }} 33 | key: {{ .Values.secret.db.secretRefKey.username | default "username" }} 34 | {{- else }} 35 | name: {{ include "supabase.secret.db" . }} 36 | key: username 37 | {{- end }} 38 | - name: DB_PORT 39 | value: {{ .Values.auth.environment.DB_PORT | quote }} 40 | image: postgres:15-alpine 41 | imagePullPolicy: IfNotPresent 42 | name: test-db 43 | restartPolicy: Never 44 | {{- end }} 45 | -------------------------------------------------------------------------------- /charts/supabase/templates/test/imgproxy.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.imgproxy.enabled -}} 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: {{ include "supabase.fullname" . }}-test-imgproxy 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | annotations: 9 | "helm.sh/hook": test 10 | spec: 11 | ttlSecondsAfterFinished: 100 12 | template: 13 | spec: 14 | containers: 15 | - name: test-imgproxy 16 | image: kdevup/curljq 17 | imagePullPolicy: IfNotPresent 18 | command: 19 | - /bin/bash 20 | - -c 21 | - | 22 | curl -sfo /dev/null \ 23 | http://{{ include "supabase.imgproxy.fullname" . }}:{{ .Values.imgproxy.service.port }}/health 24 | echo "Sevice {{ include "supabase.imgproxy.fullname" . }} is healthy." 25 | restartPolicy: Never 26 | {{- end }} 27 | -------------------------------------------------------------------------------- /charts/supabase/templates/test/kong.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.kong.enabled -}} 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: {{ include "supabase.fullname" . }}-test-kong 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | annotations: 9 | "helm.sh/hook": test 10 | spec: 11 | ttlSecondsAfterFinished: 100 12 | template: 13 | spec: 14 | containers: 15 | - env: 16 | - name: DASHBOARD_USERNAME 17 | valueFrom: 18 | secretKeyRef: 19 | key: username 20 | name: {{ include "supabase.fullname" . }}-dashboard 21 | - name: DASHBOARD_PASSWORD 22 | valueFrom: 23 | secretKeyRef: 24 | key: password 25 | name: {{ include "supabase.fullname" . }}-dashboard 26 | name: test-kong 27 | image: kdevup/curljq 28 | imagePullPolicy: IfNotPresent 29 | command: 30 | - /bin/bash 31 | - -c 32 | - | 33 | echo "Attempting to access dashboard with provided credentials..." 34 | curl -sL --fail \ 35 | -o /dev/null \ 36 | "http://${DASHBOARD_USERNAME}:${DASHBOARD_PASSWORD}@{{ include "supabase.kong.fullname" . }}:{{ .Values.kong.service.port }}" \ 37 | || ( echo -e "\e[0;31mFailed to get a valid response." && exit 1 ) 38 | echo "Successfully connected." 39 | restartPolicy: Never 40 | {{- end }} 41 | -------------------------------------------------------------------------------- /charts/supabase/templates/test/meta.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.meta.enabled -}} 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: {{ include "supabase.fullname" . }}-test-meta 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | annotations: 9 | "helm.sh/hook": test 10 | spec: 11 | ttlSecondsAfterFinished: 100 12 | template: 13 | spec: 14 | containers: 15 | - name: test-meta 16 | image: kdevup/curljq 17 | imagePullPolicy: IfNotPresent 18 | command: 19 | - /bin/bash 20 | - -c 21 | - | 22 | curl -sfo /dev/null \ 23 | http://{{ include "supabase.meta.fullname" . }}:{{ .Values.meta.service.port }}/health 24 | echo "Sevice {{ include "supabase.meta.fullname" . }} is healthy." 25 | restartPolicy: Never 26 | {{- end }} 27 | -------------------------------------------------------------------------------- /charts/supabase/templates/test/minio.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.minio.enabled -}} 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: {{ include "supabase.fullname" . }}-test-minio 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | annotations: 9 | "helm.sh/hook": test 10 | spec: 11 | ttlSecondsAfterFinished: 100 12 | template: 13 | spec: 14 | containers: 15 | - name: test-minio 16 | image: kdevup/curljq 17 | command: 18 | - /bin/bash 19 | - -c 20 | - | 21 | curl -sfo /dev/null \ 22 | http://{{ include "supabase.minio.fullname" . }}:{{ .Values.minio.service.port }}/minio/health/live 23 | echo "Sevice {{ include "supabase.minio.fullname" . }} is healthy." 24 | restartPolicy: Never 25 | {{- end }} 26 | -------------------------------------------------------------------------------- /charts/supabase/templates/test/realtime.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.realtime.enabled -}} 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: {{ include "supabase.fullname" . }}-test-realtime 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | annotations: 9 | "helm.sh/hook": test 10 | spec: 11 | ttlSecondsAfterFinished: 100 12 | template: 13 | spec: 14 | containers: 15 | - name: test-realtime 16 | image: kdevup/curljq 17 | imagePullPolicy: IfNotPresent 18 | command: 19 | - /bin/bash 20 | - -c 21 | - | 22 | curl -sfo /dev/null \ 23 | http://{{ include "supabase.realtime.fullname" . }}:{{ .Values.realtime.service.port }} 24 | echo "Sevice {{ include "supabase.realtime.fullname" . }} is healthy." 25 | restartPolicy: Never 26 | {{- end }} 27 | -------------------------------------------------------------------------------- /charts/supabase/templates/test/rest.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.rest.enabled -}} 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: {{ include "supabase.fullname" . }}-test-rest 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | annotations: 9 | "helm.sh/hook": test 10 | spec: 11 | ttlSecondsAfterFinished: 100 12 | template: 13 | spec: 14 | containers: 15 | - name: test-rest 16 | image: kdevup/curljq 17 | imagePullPolicy: IfNotPresent 18 | command: 19 | - /bin/bash 20 | - -c 21 | - | 22 | curl -sfo /dev/null \ 23 | http://{{ include "supabase.rest.fullname" . }}:{{ .Values.rest.service.port }} 24 | echo "Sevice {{ include "supabase.rest.fullname" . }} is healthy." 25 | restartPolicy: Never 26 | {{- end }} 27 | -------------------------------------------------------------------------------- /charts/supabase/templates/test/secretrefs.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.debug }} 2 | {{- if .Values.debug.secretRef }} 3 | {{- if .Values.secret.jwt.secretRef }} 4 | apiVersion: v1 5 | kind: Secret 6 | metadata: 7 | name: {{ .Values.secret.jwt.secretRef }} 8 | labels: 9 | {{- include "supabase.labels" . | nindent 4 }} 10 | annotations: 11 | helm.sh/hook: pre-install 12 | type: Opaque 13 | data: 14 | anonKey: ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5QWdDaUFnSUNBaWNtOXNaU0k2SUNKaGJtOXVJaXdLSUNBZ0lDSnBjM01pT2lBaWMzVndZV0poYzJVdFpHVnRieUlzQ2lBZ0lDQWlhV0YwSWpvZ01UWTBNVGMyT1RJd01Dd0tJQ0FnSUNKbGVIQWlPaUF4TnprNU5UTTFOakF3Q24wLmRjX1g1aVJfVlBfcVQwenNpeWpfSV9PWjJUOUZ0UlUyQkJOV044QnU0R0U= 15 | serviceKey: ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5QWdDaUFnSUNBaWNtOXNaU0k2SUNKelpYSjJhV05sWDNKdmJHVWlMQW9nSUNBZ0ltbHpjeUk2SUNKemRYQmhZbUZ6WlMxa1pXMXZJaXdLSUNBZ0lDSnBZWFFpT2lBeE5qUXhOelk1TWpBd0xBb2dJQ0FnSW1WNGNDSTZJREUzT1RrMU16VTJNREFLZlEuRGFZbE5Fb1VyckVuMklnN3RxaWJTLVBISzV2Z3VzYmNibzdYMzZYVnQ0UQ== 16 | secret: eW91ci1zdXBlci1zZWNyZXQtand0LXRva2VuLXdpdGgtYXQtbGVhc3QtMzItY2hhcmFjdGVycy1sb25n 17 | {{- end }} 18 | {{- if .Values.secret.smtp.secretRef }} 19 | --- 20 | apiVersion: v1 21 | kind: Secret 22 | metadata: 23 | name: {{ .Values.secret.smtp.secretRef }} 24 | labels: 25 | {{- include "supabase.labels" . | nindent 4 }} 26 | annotations: 27 | helm.sh/hook: pre-install 28 | type: Opaque 29 | data: 30 | username: eW91ci1tYWlsQGV4YW1wbGUuY29t 31 | password: ZXhhbXBsZTEyMzQ1Ng== 32 | {{- end }} 33 | {{- if .Values.secret.dashboard.secretRef }} 34 | --- 35 | apiVersion: v1 36 | kind: Secret 37 | metadata: 38 | name: {{ .Values.secret.dashboard.secretRef }} 39 | labels: 40 | {{- include "supabase.labels" . | nindent 4 }} 41 | annotations: 42 | helm.sh/hook: pre-install 43 | type: Opaque 44 | data: 45 | username: c3VwYWJhc2U= 46 | password: dGhpc19wYXNzd29yZF9pc19pbnNlY3VyZV9hbmRfc2hvdWxkX2JlX3VwZGF0ZWQ= 47 | {{- end }} 48 | {{- if .Values.secret.db.secretRef }} 49 | --- 50 | apiVersion: v1 51 | kind: Secret 52 | metadata: 53 | name: {{ .Values.secret.db.secretRef }} 54 | labels: 55 | {{- include "supabase.labels" . | nindent 4 }} 56 | annotations: 57 | helm.sh/hook: pre-install 58 | type: Opaque 59 | data: 60 | username: cG9zdGdyZXM= 61 | password: ZXhhbXBsZTEyMzQ1Ng== 62 | database: cG9zdGdyZXM= 63 | {{- end }} 64 | {{- if .Values.secret.analytics.secretRef }} 65 | --- 66 | apiVersion: v1 67 | kind: Secret 68 | metadata: 69 | name: {{ .Values.secret.analytics.secretRef }} 70 | labels: 71 | {{- include "supabase.labels" . | nindent 4 }} 72 | annotations: 73 | helm.sh/hook: pre-install 74 | type: Opaque 75 | data: 76 | apiKey: eW91ci1zdXBlci1zZWNyZXQtYW5kLWxvbmctbG9nZmxhcmUta2V5 77 | {{- end }} 78 | {{- end }} 79 | {{- end }} 80 | -------------------------------------------------------------------------------- /charts/supabase/templates/test/storage.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.storage.enabled -}} 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: {{ include "supabase.fullname" . }}-test-storage 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | annotations: 9 | "helm.sh/hook": test 10 | spec: 11 | ttlSecondsAfterFinished: 100 12 | template: 13 | spec: 14 | containers: 15 | - name: test-storage 16 | image: kdevup/curljq 17 | imagePullPolicy: IfNotPresent 18 | command: 19 | - /bin/bash 20 | - -c 21 | - | 22 | curl -sfo /dev/null \ 23 | http://{{ include "supabase.storage.fullname" . }}:{{ .Values.storage.service.port }}/status 24 | echo "Sevice {{ include "supabase.storage.fullname" . }} is healthy." 25 | restartPolicy: Never 26 | {{- end }} 27 | -------------------------------------------------------------------------------- /charts/supabase/templates/test/studio.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.studio.enabled -}} 2 | apiVersion: batch/v1 3 | kind: Job 4 | metadata: 5 | name: {{ include "supabase.fullname" . }}-test-studio 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | annotations: 9 | "helm.sh/hook": test 10 | spec: 11 | ttlSecondsAfterFinished: 100 12 | template: 13 | spec: 14 | containers: 15 | - name: test-studio 16 | image: kdevup/curljq 17 | imagePullPolicy: IfNotPresent 18 | command: 19 | - /bin/bash 20 | - -c 21 | - | 22 | curl -sfo /dev/null \ 23 | http://{{ include "supabase.studio.fullname" . }}:{{ .Values.studio.service.port }}/api/profile 24 | echo "Sevice {{ include "supabase.studio.fullname" . }} is healthy." 25 | restartPolicy: Never 26 | {{- end }} 27 | -------------------------------------------------------------------------------- /charts/supabase/templates/vector/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "supabase.vector.name" -}} 5 | {{- default (print .Chart.Name "-vector") .Values.vector.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "supabase.vector.fullname" -}} 14 | {{- if .Values.vector.fullnameOverride }} 15 | {{- .Values.vector.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default (print .Chart.Name "-vector") .Values.vector.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Selector labels 28 | */}} 29 | {{- define "supabase.vector.selectorLabels" -}} 30 | app.kubernetes.io/name: {{ include "supabase.vector.name" . }} 31 | app.kubernetes.io/instance: {{ .Release.Name }} 32 | {{- end }} 33 | 34 | {{/* 35 | Create the name of the service account to use 36 | */}} 37 | {{- define "supabase.vector.serviceAccountName" -}} 38 | {{- if .Values.vector.serviceAccount.create }} 39 | {{- default (include "supabase.vector.fullname" .) .Values.vector.serviceAccount.name }} 40 | {{- else }} 41 | {{- default "default" .Values.vector.serviceAccount.name }} 42 | {{- end }} 43 | {{- end }} 44 | -------------------------------------------------------------------------------- /charts/supabase/templates/vector/config.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.vector.enabled }} 2 | apiVersion: v1 3 | kind: ConfigMap 4 | metadata: 5 | name: {{ include "supabase.vector.fullname" . }}-config 6 | labels: 7 | {{- include "supabase.labels" . | nindent 4 }} 8 | data: 9 | secret.sh: | 10 | #!/bin/sh 11 | cat << EOF 12 | { 13 | "logflare_api_key": { 14 | "value": "$LOGFLARE_API_KEY", 15 | "error": null 16 | } 17 | } 18 | EOF 19 | vector.yml: | 20 | secret: 21 | credentials: 22 | type: exec 23 | command: 24 | - /etc/vector/secret.sh 25 | 26 | api: 27 | enabled: true 28 | address: 0.0.0.0:{{ .Values.vector.service.port }} 29 | 30 | sources: 31 | kubernetes_host: 32 | type: kubernetes_logs 33 | extra_label_selector: app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/name!={{ include "supabase.vector.name" . }} 34 | 35 | transforms: 36 | project_logs: 37 | type: remap 38 | inputs: 39 | - kubernetes_host 40 | source: |- 41 | .project = "default" 42 | .event_message = del(.message) 43 | .appname = del(.kubernetes.container_name) 44 | del(.file) 45 | del(.kubernetes) 46 | del(.source_type) 47 | del(.stream) 48 | router: 49 | type: route 50 | inputs: 51 | - project_logs 52 | route: 53 | kong: '.appname == {{ include "supabase.kong.name" . | quote }}' 54 | auth: '.appname == {{ include "supabase.auth.name" . | quote }}' 55 | rest: '.appname == {{ include "supabase.rest.name" . | quote }}' 56 | realtime: '.appname == {{ include "supabase.realtime.name" . | quote }}' 57 | storage: '.appname == {{ include "supabase.storage.name" . | quote }}' 58 | functions: '.appname == {{ include "supabase.functions.name" . | quote }}' 59 | db: '.appname == {{ include "supabase.db.name" . | quote }}' 60 | # Ignores non nginx errors since they are related with kong booting up 61 | kong_logs: 62 | type: remap 63 | inputs: 64 | - router.kong 65 | source: |- 66 | req, err = parse_nginx_log(.event_message, "combined") 67 | if err == null { 68 | .timestamp = req.timestamp 69 | .metadata.request.headers.referer = req.referer 70 | .metadata.request.headers.user_agent = req.agent 71 | .metadata.request.headers.cf_connecting_ip = req.client 72 | .metadata.request.method = req.method 73 | .metadata.request.path = req.path 74 | .metadata.request.protocol = req.protocol 75 | .metadata.response.status_code = req.status 76 | } 77 | if err != null { 78 | abort 79 | } 80 | # Ignores non nginx errors since they are related with kong booting up 81 | kong_err: 82 | type: remap 83 | inputs: 84 | - router.kong 85 | source: |- 86 | .metadata.request.method = "GET" 87 | .metadata.response.status_code = 200 88 | parsed, err = parse_nginx_log(.event_message, "error") 89 | if err == null { 90 | .timestamp = parsed.timestamp 91 | .severity = parsed.severity 92 | .metadata.request.host = parsed.host 93 | .metadata.request.headers.cf_connecting_ip = parsed.client 94 | url, err = split(parsed.request, " ") 95 | if err == null { 96 | .metadata.request.method = url[0] 97 | .metadata.request.path = url[1] 98 | .metadata.request.protocol = url[2] 99 | } 100 | } 101 | if err != null { 102 | abort 103 | } 104 | # Gotrue logs are structured json strings which frontend parses directly. But we keep metadata for consistency. 105 | auth_logs: 106 | type: remap 107 | inputs: 108 | - router.auth 109 | source: |- 110 | parsed, err = parse_json(.event_message) 111 | if err == null { 112 | .metadata.timestamp = parsed.time 113 | .metadata = merge!(.metadata, parsed) 114 | } 115 | # PostgREST logs are structured so we separate timestamp from message using regex 116 | rest_logs: 117 | type: remap 118 | inputs: 119 | - router.rest 120 | source: |- 121 | parsed, err = parse_regex(.event_message, r'^(?P