diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4e76626d2c..d016c10520 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -50,3 +50,15 @@ jobs: env: DOCKER_USER: ${{ secrets.DOCKER_USERNAME }} DOCKER_PASSWORD: ${{ secrets.DOCKER_API_KEY }} + + - uses: azure/setup-helm@v1 + id: install + + - run: yarn release:helm + + - name: Run chart-releaser + uses: helm/chart-releaser-action@v1.1.0 + with: + charts_dir: docs + env: + CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" \ No newline at end of file diff --git a/.gitignore b/.gitignore index b2a2021cc9..3a5fc5dc7b 100644 --- a/.gitignore +++ b/.gitignore @@ -55,7 +55,7 @@ typings/ .node_repl_history # Output of 'npm pack' -*.tgz +# *.tgz # Yarn Integrity file .yarn-integrity @@ -91,4 +91,4 @@ hosting/.generated-envoy.dev.yaml # Sublime text *.sublime-project -*.sublime-workspace \ No newline at end of file +*.sublime-workspace diff --git a/docs/budibase-0.1.0.tgz b/docs/budibase-0.1.0.tgz new file mode 100644 index 0000000000..7873874ab0 Binary files /dev/null and b/docs/budibase-0.1.0.tgz differ diff --git a/docs/budibase-0.1.1.tgz b/docs/budibase-0.1.1.tgz new file mode 100644 index 0000000000..b38527c4a4 Binary files /dev/null and b/docs/budibase-0.1.1.tgz differ diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000000..0fa6060f8f --- /dev/null +++ b/docs/index.html @@ -0,0 +1,9 @@ + + + Budibase Helm Chart Repo + + +

Budibase Charts Repo

+

Point Helm at this repo to see charts.

+ + \ No newline at end of file diff --git a/docs/index.yaml b/docs/index.yaml new file mode 100644 index 0000000000..4e064f3dd0 --- /dev/null +++ b/docs/index.yaml @@ -0,0 +1,54 @@ +apiVersion: v1 +entries: + budibase: + - apiVersion: v2 + appVersion: 0.9.56 + created: "2021-08-18T18:41:52.640176+01:00" + dependencies: + - condition: services.couchdb.enabled + name: couchdb + repository: https://apache.github.io/couchdb-helm + version: 3.3.4 + - name: ingress-nginx + repository: https://github.com/kubernetes/ingress-nginx + version: 3.35.0 + description: Budibase is an open source low-code platform, helping thousands of teams build apps for their workplace in minutes. + digest: 8dc4f2ed4d98cad5adf25936aefea680042d3e4e17832f846b961fd8708ad192 + keywords: + - low-code + - database + - cluster + name: budibase + sources: + - https://github.com/Budibase/budibase + - https://budibase.com + type: application + urls: + - https://budibase.github.io/budibase/budibase-0.1.1.tgz + version: 0.1.1 + - apiVersion: v2 + appVersion: 0.9.56 + created: "2021-08-18T18:41:52.635603+01:00" + dependencies: + - condition: services.couchdb.enabled + name: couchdb + repository: https://apache.github.io/couchdb-helm + version: 3.3.4 + - name: ingress-nginx + repository: https://github.com/kubernetes/ingress-nginx + version: 3.35.0 + description: Budibase is an open source low-code platform, helping thousands of teams build apps for their workplace in minutes. + digest: 08031b0803cce0eff64472e569d454d9176119c8207aa9873a9c95ee66cc7d3f + keywords: + - low-code + - database + - cluster + name: budibase + sources: + - https://github.com/Budibase/budibase + - https://budibase.com + type: application + urls: + - https://budibase.github.io/budibase/budibase-0.1.0.tgz + version: 0.1.0 +generated: "2021-08-18T18:41:52.629415+01:00" diff --git a/hosting/kubernetes/budibase/.helmignore b/hosting/kubernetes/budibase/.helmignore new file mode 100644 index 0000000000..0e8a0eb36f --- /dev/null +++ b/hosting/kubernetes/budibase/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/hosting/kubernetes/budibase/Chart.yaml b/hosting/kubernetes/budibase/Chart.yaml new file mode 100644 index 0000000000..bcba5f5059 --- /dev/null +++ b/hosting/kubernetes/budibase/Chart.yaml @@ -0,0 +1,40 @@ +apiVersion: v2 +name: budibase +description: Budibase is an open source low-code platform, helping thousands of teams build apps for their workplace in minutes. +keywords: +- low-code +- database +- cluster +sources: +- https://github.com/Budibase/budibase +- https://budibase.com + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.1 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "0.9.56" + +dependencies: + - name: couchdb + version: 3.3.4 + repository: https://apache.github.io/couchdb-helm + condition: services.couchdb.enabled + - name: ingress-nginx + version: 3.35.0 + repository: https://github.com/kubernetes/ingress-nginx diff --git a/hosting/kubernetes/budibase/README.md b/hosting/kubernetes/budibase/README.md new file mode 100644 index 0000000000..9de545d36a --- /dev/null +++ b/hosting/kubernetes/budibase/README.md @@ -0,0 +1,182 @@ +# Budibase + +[Budibase](https://posthog.com/) Budibase is an open source low-code platform, helping thousands of teams build apps for their workplace in minutes. + +## TL;DR; +```console +$ cd chart +$ helm install budibase . +``` + +## Introduction + +This chart bootstraps a [Budibase](https://budibase.com/) deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + + + +## Prerequisites + +- helm v3 or above +- Kubernetes 1.4+ +- PV provisioner support in the underlying infrastructure (with persistence storage enabled) + +## Installing the Chart + +To install the chart with the release name `budi-release`: + +```console +$ helm install budi-release . +``` + +The command deploys PostHog on the Kubernetes cluster in the default configuration. The [configuration](#configuration) section lists the parameters that can be configured during installation. + +> **Tip**: List all releases using `helm list` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` deployment: + +```console +$ helm delete my-release +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +> **Warning**: Jobs are not deleted automatically. They need to be manually deleted + +```console +$ kubectl delete job/posthog-migrate +``` + +## Configuration + +The following table lists the configurable parameters of the PostHog chart and their default values. + +Dependent charts can also have values overwritten. Preface values with postgresql.* + +Parameter | Description | Default +:--------------------------------------------------- | :--------------------------------------------------------------------------------------------------------- | :--------------------------------------------------- +`image.repository` | PostHog image | `posthog/posthog` +`image.tag` | PostHog image tag | `latest` +`image.pullPolicy` | Image pull policy | `Always` +`image.imagePullSecrets` | Specify image pull secrets | `[]` +`posthogSecret` | Specify SECRET_KEY. If isn't specified it will be generated automatically. | `nil` +`disableSecureSslRedirect` | Specify DISABLE_SECURE_SSL_REDIRECT. | `1` +`useSecureCookies` | Specify SECURE_COOKIES. | `0` +`web.podAnnotations` | Web pod annotations | `{}` +`web.podLabels` | Web pod extra labels | `{}` +`web.replicacount` | Amount of web pods to run | `1` +`web.resources.limits` | Web resource limits | `{cpu: 500m, memory: 500Mi}` +`web.resources.requests` | Web resource requests | `{cpu: 300m, memory: 300Mi}` +`web.env` | Additional web environment variables | `[]` +`web.nodeSelector` | Node labels for web pod assignment | `{}` +`web.affinity` | Affinity settings for web pod assignment | `{}` +`web.schedulerName` | Name of an alternate scheduler for web pod | `nil` +`web.tolerations` | Toleration labels for web pod assignment | `[]` +`web.livenessProbe.failureThreshold` | The liveness probe failure threshold | `5` +`web.livenessProbe.initialDelaySeconds` | The liveness probe initial delay seconds | `50` +`web.livenessProbe.periodSeconds` | The liveness probe period seconds | `10` +`web.livenessProbe.successThreshold` | The liveness probe success threshold | `1` +`web.livenessProbe.timeoutSeconds` | The liveness probe timeout seconds | `2` +`web.readinessProbe.failureThreshold` | The readiness probe failure threshold | `10` +`web.readinessProbe.initialDelaySeconds` | The readiness probe initial delay seconds | `50` +`web.readinessProbe.periodSeconds` | The readiness probe period seconds | `10` +`web.readinessProbe.successThreshold` | The readiness probe success threshold | `1` +`web.readinessProbe.timeoutSeconds` | The readiness probe timeout seconds | `2` +`web.priorityClassName` | The priorityClassName on web deployment | `nil` +`web.hpa.enabled` | Boolean to create a HorizontalPodAutoscaler for web deployment | `false` +`web.hpa.cputhreshold` | CPU threshold percent for the web HorizontalPodAutoscaler | `60` +`web.hpa.minpods` | Min pods for the web HorizontalPodAutoscaler | `1` +`web.hpa.maxpods` | Max pods for the web HorizontalPodAutoscaler | `10` +`email.from_email` | Emails are sent are from | `tim@posthog.com` +`email.host` | SMTP host for sending email | `smtp` +`email.port` | SMTP port | `578` +`email.user` | SMTP user | `nil` +`email.password` | SMTP password | `nil` +`email.use_tls` | SMTP TLS for security | `false` +`email.use_ssl` | SMTP SSL for security | `false` +`email.existingSecret` | SMTP password from an existing secret | `nil` +`email.existingSecretKey` | Key to get from the `email.existingSecret` secret | `smtp-password` +`service.type` | Kubernetes service type | `LoadBalancer` +`service.name` | Kubernetes service name | `posthog` +`service.externalPort` | Kubernetes external service port | `8000` +`service.internalPort` | Kubernetes internal service port | `8000` +`service.annotations` | Service annotations | `{}` +`service.nodePort` | Kubernetes service NodePort port | Randomly chosen by Kubernetes +`service.loadBalancerSourceRanges` | Allow list for the load balancer | `nil` +`ingress.enabled` | Enable ingress controller resource | `false` +`ingress.annotations` | Ingress annotations | `{}` +`ingress.hostname` | URL to address your PostHog installation | `posthog.local` +`ingress.path` | path to address your PostHog installation | `/` +`ingress.tls` | Ingress TLS configuration | `[]` +`postgresql.enabled` | Deploy postgres server (see below) | `true` +`postgresql.postgresqlDatabase` | Postgres database name | `posthog` +`postgresql.postgresqlUsername` | Postgres username | `postgres` +`postgresql.postgresqlHost` | External postgres host | `nil` +`postgresql.postgresqlPassword` | External/Internal postgres password | `postgres` +`postgresql.postgresqlPort` | External postgres port | `5432` +`postgresql.existingSecret` | Name of existing secret to use for the PostgreSQL password | `nil` +`postgresql.existingSecretKey` | Key to get from the `postgresql.existingSecret` secret | `postgresql-password` | `nil` +`redis.enabled` | Deploy redis server (see below) | `true` +`redis.host` | External redis host | `nil` +`redis.password` | External redis password | `nil` +`redis.port` | External redis port | `6379` +`redis.existingSecret` | Name of existing secret to use for the Redis password | `nil` +`redis.existingSecretKey` | Key to get from the `redis.existingSecret` secret | `redis-password` +`metrics.enabled` | Start an exporter for posthog metrics | `false` +`metrics.nodeSelector` | Node labels for metrics pod assignment | `{}` +`metrics.tolerations` | Toleration labels for metrics pod assignment | `[]` +`metrics.affinity` | Affinity settings for metrics pod | `{}` +`metrics.schedulerName` | Name of an alternate scheduler for metrics pod | `nil` +`metrics.podLabels` | Labels for metrics pod | `nil` +`metrics.resources` | Metrics resource requests/limit | `{}` +`metrics.service.type` | Kubernetes service type for metrics service | `ClusterIP` +`metrics.service.labels` | Additional labels for metrics service | `{}` +`metrics.image.repository` | Metrics exporter image repository | `prom/statsd-exporter` +`metrics.image.tag` | Metrics exporter image tag | `v0.10.5` +`metrics.image.PullPolicy` | Metrics exporter image pull policy | `IfNotPresent` +`metrics.serviceMonitor.enabled` | if `true`, creates a Prometheus Operator ServiceMonitor (also requires `metrics.enabled` to be `true`) | `false` +`metrics.serviceMonitor.namespace` | Optional namespace which Prometheus is running in | `nil` +`metrics.serviceMonitor.interval` | How frequently to scrape metrics (use by default, falling back to Prometheus' default) | `nil` +`metrics.serviceMonitor.selector` | Default to kube-prometheus install (CoreOS recommended), but should be set according to Prometheus install | `{ prometheus: kube-prometheus }` +`hooks.affinity` | Affinity settings for hooks pods | `{}` +`hooks.migrate.resources.limits` | Hook job resource limits | `{memory: 1000Mi}` +`hooks.migrate.resources.requests` | Hook job resource requests | `{memory: 1000Mi}` +`hooks.migrate.hookAnnotation` | Hook lifecycle annotation value | `post-install,post-upgrade` +`serviceAccount.name` | name of the ServiceAccount to be used by access-controlled resources | autogenerated +`serviceAccount.create` | Configures if a ServiceAccount with this name should be created | `true` +`serviceAccount.annotations` | Configures annotation for the ServiceAccount | `{}` +`env` | Additional environment variables applied to all deployments (web, worker, beat, plugin-server) | `[]` + +Dependent charts can also have values overwritten. Preface values with "postgresql." + +Specify each parameter using the `--set key=value[,key=value]` argument to `helm install`. For example, + +```console +$ helm install \ + --set persistence.enabled=false,email.host=email \ + my-release . +``` + +Alternatively, a YAML file that specifies the values for the above parameters can be provided while installing the chart. For example, + +```console +$ helm install -f my-values.yaml my-release . +``` + +## PostgreSQL + +By default, PostgreSQL is installed as part of the chart. To use an external PostgreSQL server set `postgresql.enabled` to `false` and then set `postgresql.postgresHost` and `postgresql.postgresqlPassword`. The other options (`postgresql.postgresqlDatabase`, `postgresql.postgresqlUsername` and `postgresql.postgresqlPort`) may also want changing from their default values. + +To avoid issues when upgrading this chart, provide `postgresql.postgresqlPassword` for subsequent upgrades. This is due to an issue in the PostgreSQL chart where password will be overwritten with randomly generated passwords otherwise. See https://github.com/helm/charts/tree/master/stable/postgresql#upgrade for more detail. + +## Redis + +By default, Redis is installed as part of the chart. To use an external Redis server/cluster set `redis.enabled` to `false` and then set `redis.host`. If your redis cluster uses password define it with `redis.password`, otherwise just omit it. Check the table above for more configuration options. + +To avoid issues when upgrading this chart, provide `redis.password` for subsequent upgrades. Otherwise the redis pods will get recreated on every update, potentially incurring some downtime. + +## Ingress + +This chart provides support for Ingress resource. If you have an available Ingress Controller such as Nginx or Traefik you maybe want to set `ingress.enabled` to true and choose an `ingress.hostname` for the URL. Then, you should be able to access the installation using that address. + diff --git a/hosting/kubernetes/budibase/charts/couchdb/Chart.yaml b/hosting/kubernetes/budibase/charts/couchdb/Chart.yaml new file mode 100755 index 0000000000..74ae734a17 --- /dev/null +++ b/hosting/kubernetes/budibase/charts/couchdb/Chart.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +appVersion: 3.1.0 +description: A database featuring seamless multi-master sync, that scales from big + data to mobile, with an intuitive HTTP/JSON API and designed for reliability. +home: https://couchdb.apache.org/ +icon: http://couchdb.apache.org/CouchDB-visual-identity/logo/CouchDB-couch-symbol.svg +keywords: +- couchdb +- database +- nosql +maintainers: +- email: kocolosk@apache.org + name: kocolosk +- email: willholley@apache.org + name: willholley +name: couchdb +sources: +- https://github.com/apache/couchdb-docker +version: 3.3.4 diff --git a/hosting/kubernetes/budibase/charts/couchdb/README.md b/hosting/kubernetes/budibase/charts/couchdb/README.md new file mode 100755 index 0000000000..3227123d06 --- /dev/null +++ b/hosting/kubernetes/budibase/charts/couchdb/README.md @@ -0,0 +1,244 @@ +# CouchDB + +Apache CouchDB is a database featuring seamless multi-master sync, that scales +from big data to mobile, with an intuitive HTTP/JSON API and designed for +reliability. + +This chart deploys a CouchDB cluster as a StatefulSet. It creates a ClusterIP +Service in front of the Deployment for load balancing by default, but can also +be configured to deploy other Service types or an Ingress Controller. The +default persistence mechanism is simply the ephemeral local filesystem, but +production deployments should set `persistentVolume.enabled` to `true` to attach +storage volumes to each Pod in the Deployment. + +## TL;DR + +```bash +$ helm repo add couchdb https://apache.github.io/couchdb-helm +$ helm install couchdb/couchdb \ + --set allowAdminParty=true \ + --set couchdbConfig.couchdb.uuid=$(curl https://www.uuidgenerator.net/api/version4 2>/dev/null | tr -d -) +``` + +## Prerequisites + +- Kubernetes 1.9+ with Beta APIs enabled +- Ingress requires Kubernetes 1.14+ + +## Installing the Chart + +To install the chart with the release name `my-release`: + +Add the CouchDB Helm repository: + +```bash +$ helm repo add couchdb https://apache.github.io/couchdb-helm +``` + +Afterwards install the chart replacing the UUID +`decafbaddecafbaddecafbaddecafbad` with a custom one: + +```bash +$ helm install \ + --name my-release \ + --set couchdbConfig.couchdb.uuid=decafbaddecafbaddecafbaddecafbad \ + couchdb/couchdb +``` + +This will create a Secret containing the admin credentials for the cluster. +Those credentials can be retrieved as follows: + +```bash +$ kubectl get secret my-release-couchdb -o go-template='{{ .data.adminPassword }}' | base64 --decode +``` + +If you prefer to configure the admin credentials directly you can create a +Secret containing `adminUsername`, `adminPassword` and `cookieAuthSecret` keys: + +```bash +$ kubectl create secret generic my-release-couchdb --from-literal=adminUsername=foo --from-literal=adminPassword=bar --from-literal=cookieAuthSecret=baz +``` + +If you want to set the `adminHash` directly to achieve consistent salts between +different nodes you need to addionally add the key `password.ini` to the secret: + +```bash +$ kubectl create secret generic my-release-couchdb \ + --from-literal=adminUsername=foo \ + --from-literal=cookieAuthSecret=baz \ + --from-file=./my-password.ini +``` + +With the following contents in `my-password.ini`: + +``` +[admins] +foo = +``` + +and then install the chart while overriding the `createAdminSecret` setting: + +```bash +$ helm install \ + --name my-release \ + --set createAdminSecret=false \ + --set couchdbConfig.couchdb.uuid=decafbaddecafbaddecafbaddecafbad \ + couchdb/couchdb +``` + +This Helm chart deploys CouchDB on the Kubernetes cluster in a default +configuration. The [configuration](#configuration) section lists +the parameters that can be configured during installation. + +> **Tip**: List all releases using `helm list` + +## Uninstalling the Chart + +To uninstall/delete the `my-release` Deployment: + +```bash +$ helm delete my-release +``` + +The command removes all the Kubernetes components associated with the chart and +deletes the release. + +## Upgrading an existing Release to a new major version + +A major chart version change (like v0.2.3 -> v1.0.0) indicates that there is an +incompatible breaking change needing manual actions. + +### Upgrade to 3.0.0 + +Since version 3.0.0 setting the CouchDB server instance UUID is mandatory. +Therefore you need to generate a UUID and supply it as a value during the +upgrade as follows: + +```bash +$ helm upgrade \ + --reuse-values \ + --set couchdbConfig.couchdb.uuid= \ + couchdb/couchdb +``` + +## Migrating from stable/couchdb + +This chart replaces the `stable/couchdb` chart previously hosted by Helm and continues the +version semantics. You can upgrade directly from `stable/couchdb` to this chart using: + +```bash +$ helm repo add couchdb https://apache.github.io/couchdb-helm +$ helm upgrade my-release couchdb/couchdb +``` + +## Configuration + +The following table lists the most commonly configured parameters of the +CouchDB chart and their default values: + +| Parameter | Description | Default | +|---------------------------------|-------------------------------------------------------|----------------------------------------| +| `clusterSize` | The initial number of nodes in the CouchDB cluster | 3 | +| `couchdbConfig` | Map allowing override elements of server .ini config | *See below* | +| `allowAdminParty` | If enabled, start cluster without admin account | false (requires creating a Secret) | +| `createAdminSecret` | If enabled, create an admin account and cookie secret | true | +| `schedulerName` | Name of the k8s scheduler (other than default) | `nil` | +| `erlangFlags` | Map of flags supplied to the underlying Erlang VM | name: couchdb, setcookie: monster +| `persistentVolume.enabled` | Boolean determining whether to attach a PV to each node | false +| `persistentVolume.size` | If enabled, the size of the persistent volume to attach | 10Gi +| `enableSearch` | Adds a sidecar for Lucene-powered text search | false | + +You can set the values of the `couchdbConfig` map according to the +[official configuration][4]. The following shows the map's default values and +required options to set: + +| Parameter | Description | Default | +|---------------------------------|--------------------------------------------------------------------|----------------------------------------| +| `couchdb.uuid` | UUID for this CouchDB server instance ([Required in a cluster][5]) | | +| `chttpd.bind_address` | listens on all interfaces when set to any | any | +| `chttpd.require_valid_user` | disables all the anonymous requests to the port 5984 when true | false | + +A variety of other parameters are also configurable. See the comments in the +`values.yaml` file for further details: + +| Parameter | Default | +|--------------------------------------|----------------------------------------| +| `adminUsername` | admin | +| `adminPassword` | auto-generated | +| `adminHash` | | +| `cookieAuthSecret` | auto-generated | +| `image.repository` | couchdb | +| `image.tag` | 3.1.0 | +| `image.pullPolicy` | IfNotPresent | +| `searchImage.repository` | kocolosk/couchdb-search | +| `searchImage.tag` | 0.1.0 | +| `searchImage.pullPolicy` | IfNotPresent | +| `initImage.repository` | busybox | +| `initImage.tag` | latest | +| `initImage.pullPolicy` | Always | +| `ingress.enabled` | false | +| `ingress.hosts` | chart-example.local | +| `ingress.annotations` | | +| `ingress.path` | / | +| `ingress.tls` | | +| `persistentVolume.accessModes` | ReadWriteOnce | +| `persistentVolume.storageClass` | Default for the Kube cluster | +| `podManagementPolicy` | Parallel | +| `affinity` | | +| `annotations` | | +| `tolerations` | | +| `resources` | | +| `service.annotations` | | +| `service.enabled` | true | +| `service.type` | ClusterIP | +| `service.externalPort` | 5984 | +| `dns.clusterDomainSuffix` | cluster.local | +| `networkPolicy.enabled` | true | +| `serviceAccount.enabled` | true | +| `serviceAccount.create` | true | +| `serviceAccount.imagePullSecrets` | | +| `sidecars` | {} | +| `livenessProbe.enabled` | true | +| `livenessProbe.failureThreshold` | 3 | +| `livenessProbe.initialDelaySeconds` | 0 | +| `livenessProbe.periodSeconds` | 10 | +| `livenessProbe.successThreshold` | 1 | +| `livenessProbe.timeoutSeconds` | 1 | +| `readinessProbe.enabled` | true | +| `readinessProbe.failureThreshold` | 3 | +| `readinessProbe.initialDelaySeconds` | 0 | +| `readinessProbe.periodSeconds` | 10 | +| `readinessProbe.successThreshold` | 1 | +| `readinessProbe.timeoutSeconds` | 1 | + +## Feedback, Issues, Contributing + +General feedback is welcome at our [user][1] or [developer][2] mailing lists. + +Apache CouchDB has a [CONTRIBUTING][3] file with details on how to get started +with issue reporting or contributing to the upkeep of this project. In short, +use GitHub Issues, do not report anything on Docker's website. + +## Non-Apache CouchDB Development Team Contributors + +- [@natarajaya](https://github.com/natarajaya) +- [@satchpx](https://github.com/satchpx) +- [@spanato](https://github.com/spanato) +- [@jpds](https://github.com/jpds) +- [@sebastien-prudhomme](https://github.com/sebastien-prudhomme) +- [@stepanstipl](https://github.com/sebastien-stepanstipl) +- [@amatas](https://github.com/amatas) +- [@Chimney42](https://github.com/Chimney42) +- [@mattjmcnaughton](https://github.com/mattjmcnaughton) +- [@mainephd](https://github.com/mainephd) +- [@AdamDang](https://github.com/AdamDang) +- [@mrtyler](https://github.com/mrtyler) +- [@kevinwlau](https://github.com/kevinwlau) +- [@jeyenzo](https://github.com/jeyenzo) +- [@Pinpin31.](https://github.com/Pinpin31) + +[1]: http://mail-archives.apache.org/mod_mbox/couchdb-user/ +[2]: http://mail-archives.apache.org/mod_mbox/couchdb-dev/ +[3]: https://github.com/apache/couchdb/blob/master/CONTRIBUTING.md +[4]: https://docs.couchdb.org/en/stable/config/index.html +[5]: https://docs.couchdb.org/en/latest/setup/cluster.html#preparing-couchdb-nodes-to-be-joined-into-a-cluster diff --git a/hosting/kubernetes/budibase/charts/couchdb/ci/required-values.yaml b/hosting/kubernetes/budibase/charts/couchdb/ci/required-values.yaml new file mode 100755 index 0000000000..79589d2e04 --- /dev/null +++ b/hosting/kubernetes/budibase/charts/couchdb/ci/required-values.yaml @@ -0,0 +1,3 @@ +couchdbConfig: + couchdb: + uuid: "decafbaddecafbaddecafbaddecafbad" diff --git a/hosting/kubernetes/budibase/charts/couchdb/ci/sidecar.yaml b/hosting/kubernetes/budibase/charts/couchdb/ci/sidecar.yaml new file mode 100755 index 0000000000..aa570bdf74 --- /dev/null +++ b/hosting/kubernetes/budibase/charts/couchdb/ci/sidecar.yaml @@ -0,0 +1,9 @@ +sidecars: + - name: foo + image: "busybox" + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: "0.1" + memory: 10Mi + command: ['while true; do echo "foo"; sleep 5; done;'] diff --git a/hosting/kubernetes/budibase/charts/couchdb/password.ini b/hosting/kubernetes/budibase/charts/couchdb/password.ini new file mode 100755 index 0000000000..4ce8445aae --- /dev/null +++ b/hosting/kubernetes/budibase/charts/couchdb/password.ini @@ -0,0 +1,2 @@ +[admins] +{{ .Values.adminUsername }} = {{ .Values.adminHash }} diff --git a/hosting/kubernetes/budibase/charts/couchdb/templates/NOTES.txt b/hosting/kubernetes/budibase/charts/couchdb/templates/NOTES.txt new file mode 100755 index 0000000000..a3658bd37f --- /dev/null +++ b/hosting/kubernetes/budibase/charts/couchdb/templates/NOTES.txt @@ -0,0 +1,20 @@ +Apache CouchDB is starting. Check the status of the Pods using: + + kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "couchdb.name" . }},release={{ .Release.Name }}" + +Once all of the Pods are fully Ready, execute the following command to create +some required system databases: + + kubectl exec --namespace {{ .Release.Namespace }} {{ if not .Values.allowAdminParty }}-it {{ end }}{{ template "couchdb.fullname" . }}-0 -c couchdb -- \ + curl -s \ + http://127.0.0.1:5984/_cluster_setup \ + -X POST \ + -H "Content-Type: application/json" \ +{{- if .Values.allowAdminParty }} + -d '{"action": "finish_cluster"}' +{{- else }} + -d '{"action": "finish_cluster"}' \ + -u +{{- end }} + +Then it's time to relax. diff --git a/hosting/kubernetes/budibase/charts/couchdb/templates/_helpers.tpl b/hosting/kubernetes/budibase/charts/couchdb/templates/_helpers.tpl new file mode 100755 index 0000000000..f9d013e487 --- /dev/null +++ b/hosting/kubernetes/budibase/charts/couchdb/templates/_helpers.tpl @@ -0,0 +1,81 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "couchdb.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "couchdb.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- printf "%s-%s" .Values.fullnameOverride .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +In the event that we create both a headless service and a traditional one, +ensure that the latter gets a unique name. +*/}} +{{- define "couchdb.svcname" -}} +{{- if .Values.fullnameOverride -}} +{{- printf "%s-svc-%s" .Values.fullnameOverride .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-svc-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +Create a random string if the supplied key does not exist +*/}} +{{- define "couchdb.defaultsecret" -}} +{{- if . -}} +{{- . | b64enc | quote -}} +{{- else -}} +{{- randAlphaNum 20 | b64enc | quote -}} +{{- end -}} +{{- end -}} + +{{/* +Labels used to define Pods in the CouchDB statefulset +*/}} +{{- define "couchdb.ss.selector" -}} +app: {{ template "couchdb.name" . }} +release: {{ .Release.Name }} +{{- end -}} + +{{/* +Generates a comma delimited list of nodes in the cluster +*/}} +{{- define "couchdb.seedlist" -}} +{{- $nodeCount := min 5 .Values.clusterSize | int }} + {{- range $index0 := until $nodeCount -}} + {{- $index1 := $index0 | add1 -}} + {{ $.Values.erlangFlags.name }}@{{ template "couchdb.fullname" $ }}-{{ $index0 }}.{{ template "couchdb.fullname" $ }}.{{ $.Release.Namespace }}.svc.{{ $.Values.dns.clusterDomainSuffix }}{{ if ne $index1 $nodeCount }},{{ end }} + {{- end -}} +{{- end -}} + +{{/* +If serviceAccount.name is specified, use that, else use the couchdb instance name +*/}} +{{- define "couchdb.serviceAccount" -}} +{{- if .Values.serviceAccount.name -}} +{{- .Values.serviceAccount.name }} +{{- else -}} +{{- template "couchdb.fullname" . -}} +{{- end -}} +{{- end -}} + +{{/* +Fail if couchdbConfig.couchdb.uuid is undefined +*/}} +{{- define "couchdb.uuid" -}} +{{- required "A value for couchdbConfig.couchdb.uuid must be set" (.Values.couchdbConfig.couchdb | default dict).uuid -}} +{{- end -}} \ No newline at end of file diff --git a/hosting/kubernetes/budibase/charts/couchdb/templates/configmap.yaml b/hosting/kubernetes/budibase/charts/couchdb/templates/configmap.yaml new file mode 100755 index 0000000000..a6a20e0574 --- /dev/null +++ b/hosting/kubernetes/budibase/charts/couchdb/templates/configmap.yaml @@ -0,0 +1,23 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ template "couchdb.fullname" . }} + labels: + app: {{ template "couchdb.name" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + heritage: {{ .Release.Service | quote }} + release: {{ .Release.Name | quote }} +data: + inifile: | + {{ $couchdbConfig := dict "couchdb" (dict "uuid" (include "couchdb.uuid" .)) -}} + {{- $couchdbConfig := merge $couchdbConfig .Values.couchdbConfig -}} + {{- range $section, $settings := $couchdbConfig -}} + {{ printf "[%s]" $section }} + {{ range $key, $value := $settings -}} + {{ printf "%s = %s" $key ($value | toString) }} + {{ end }} + {{ end }} + + seedlistinifile: | + [cluster] + seedlist = {{ template "couchdb.seedlist" . }} diff --git a/hosting/kubernetes/budibase/charts/couchdb/templates/headless.yaml b/hosting/kubernetes/budibase/charts/couchdb/templates/headless.yaml new file mode 100755 index 0000000000..0ce3ef0f35 --- /dev/null +++ b/hosting/kubernetes/budibase/charts/couchdb/templates/headless.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ template "couchdb.fullname" . }} + labels: + app: {{ template "couchdb.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + clusterIP: None + publishNotReadyAddresses: true + ports: + - name: couchdb + port: 5984 + selector: +{{ include "couchdb.ss.selector" . | indent 4 }} diff --git a/hosting/kubernetes/budibase/charts/couchdb/templates/ingress.yaml b/hosting/kubernetes/budibase/charts/couchdb/templates/ingress.yaml new file mode 100755 index 0000000000..c547847ce5 --- /dev/null +++ b/hosting/kubernetes/budibase/charts/couchdb/templates/ingress.yaml @@ -0,0 +1,33 @@ +{{- if .Values.ingress.enabled -}} +{{- $serviceName := include "couchdb.fullname" . -}} +{{- $servicePort := .Values.service.externalPort -}} +{{- $path := .Values.ingress.path | quote -}} +apiVersion: networking.k8s.io/v1beta1 +kind: Ingress +metadata: + name: {{ template "couchdb.fullname" . }} + labels: + app: {{ template "couchdb.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} + annotations: + {{- range $key, $value := .Values.ingress.annotations }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + rules: + {{- range $host := .Values.ingress.hosts }} + - host: {{ $host }} + http: + paths: + - path: {{ $path }} + backend: + serviceName: {{ $serviceName }} + servicePort: {{ $servicePort }} + {{- end -}} + {{- if .Values.ingress.tls }} + tls: +{{ toYaml .Values.ingress.tls | indent 4 }} + {{- end -}} +{{- end -}} diff --git a/hosting/kubernetes/budibase/charts/couchdb/templates/networkpolicy.yaml b/hosting/kubernetes/budibase/charts/couchdb/templates/networkpolicy.yaml new file mode 100755 index 0000000000..2830708bef --- /dev/null +++ b/hosting/kubernetes/budibase/charts/couchdb/templates/networkpolicy.yaml @@ -0,0 +1,31 @@ + +{{- if .Values.networkPolicy.enabled }} +kind: NetworkPolicy +apiVersion: networking.k8s.io/v1 +metadata: + name: {{ template "couchdb.fullname" . }} + labels: + app: {{ template "couchdb.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + podSelector: + matchLabels: +{{ include "couchdb.ss.selector" . | indent 6 }} + ingress: + - ports: + - protocol: TCP + port: 5984 + - ports: + - protocol: TCP + port: 9100 + - protocol: TCP + port: 4369 + from: + - podSelector: + matchLabels: +{{ include "couchdb.ss.selector" . | indent 14 }} + policyTypes: + - Ingress +{{- end }} diff --git a/hosting/kubernetes/budibase/charts/couchdb/templates/secrets.yaml b/hosting/kubernetes/budibase/charts/couchdb/templates/secrets.yaml new file mode 100755 index 0000000000..92f55c6d6b --- /dev/null +++ b/hosting/kubernetes/budibase/charts/couchdb/templates/secrets.yaml @@ -0,0 +1,19 @@ +{{- if .Values.createAdminSecret -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "couchdb.fullname" . }} + labels: + app: {{ template "couchdb.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +type: Opaque +data: + adminUsername: {{ template "couchdb.defaultsecret" .Values.adminUsername }} + adminPassword: {{ template "couchdb.defaultsecret" .Values.adminPassword }} + cookieAuthSecret: {{ template "couchdb.defaultsecret" .Values.cookieAuthSecret }} +{{- if .Values.adminHash }} + password.ini: {{ tpl (.Files.Get "password.ini") . | b64enc }} +{{- end -}} +{{- end -}} diff --git a/hosting/kubernetes/budibase/charts/couchdb/templates/service.yaml b/hosting/kubernetes/budibase/charts/couchdb/templates/service.yaml new file mode 100755 index 0000000000..6d0382477d --- /dev/null +++ b/hosting/kubernetes/budibase/charts/couchdb/templates/service.yaml @@ -0,0 +1,23 @@ +{{- if .Values.service.enabled -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ template "couchdb.svcname" . }} + labels: + app: {{ template "couchdb.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- if .Values.service.annotations }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +{{- end }} +spec: + ports: + - port: {{ .Values.service.externalPort }} + protocol: TCP + targetPort: 5984 + type: {{ .Values.service.type }} + selector: +{{ include "couchdb.ss.selector" . | indent 4 }} +{{- end -}} diff --git a/hosting/kubernetes/budibase/charts/couchdb/templates/serviceaccount.yaml b/hosting/kubernetes/budibase/charts/couchdb/templates/serviceaccount.yaml new file mode 100755 index 0000000000..bb82799a49 --- /dev/null +++ b/hosting/kubernetes/budibase/charts/couchdb/templates/serviceaccount.yaml @@ -0,0 +1,15 @@ +{{- if .Values.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "couchdb.serviceAccount" . }} + labels: + app: {{ template "couchdb.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +{{- if .Values.serviceAccount.imagePullSecrets }} +imagePullSecrets: +{{ toYaml .Values.serviceAccount.imagePullSecrets }} +{{- end }} +{{- end }} diff --git a/hosting/kubernetes/budibase/charts/couchdb/templates/statefulset.yaml b/hosting/kubernetes/budibase/charts/couchdb/templates/statefulset.yaml new file mode 100755 index 0000000000..6225fbe98c --- /dev/null +++ b/hosting/kubernetes/budibase/charts/couchdb/templates/statefulset.yaml @@ -0,0 +1,202 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ template "couchdb.fullname" . }} + labels: + app: {{ template "couchdb.name" . }} + chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }} + release: {{ .Release.Name }} + heritage: {{ .Release.Service }} +spec: + replicas: {{ .Values.clusterSize }} + serviceName: {{ template "couchdb.fullname" . }} + podManagementPolicy: {{ .Values.podManagementPolicy }} + selector: + matchLabels: +{{ include "couchdb.ss.selector" . | indent 6 }} + template: + metadata: + labels: +{{ include "couchdb.ss.selector" . | indent 8 }} +{{- with .Values.annotations }} + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} +{{ toYaml . | indent 8 }} +{{- end }} + spec: + {{- if .Values.schedulerName }} + schedulerName: "{{ .Values.schedulerName }}" + {{- end }} + {{- if .Values.serviceAccount.enabled }} + serviceAccountName: {{ template "couchdb.serviceAccount" . }} + {{- end }} + initContainers: + - name: init-copy + image: "{{ .Values.initImage.repository }}:{{ .Values.initImage.tag }}" + imagePullPolicy: {{ .Values.initImage.pullPolicy }} + command: ['sh','-c','cp /tmp/chart.ini /default.d; cp /tmp/seedlist.ini /default.d; ls -lrt /default.d;'] + volumeMounts: + - name: config + mountPath: /tmp/ + - name: config-storage + mountPath: /default.d +{{- if .Values.adminHash }} + - name: admin-hash-copy + image: "{{ .Values.initImage.repository }}:{{ .Values.initImage.tag }}" + imagePullPolicy: {{ .Values.initImage.pullPolicy }} + command: ['sh','-c','cp /tmp/password.ini /local.d/ ;'] + volumeMounts: + - name: admin-password + mountPath: /tmp/password.ini + subPath: "password.ini" + - name: local-config-storage + mountPath: /local.d +{{- end }} + containers: + - name: couchdb + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - name: couchdb + containerPort: 5984 + - name: epmd + containerPort: 4369 + - containerPort: 9100 + env: +{{- if not .Values.allowAdminParty }} + - name: COUCHDB_USER + valueFrom: + secretKeyRef: + name: {{ template "couchdb.fullname" . }} + key: adminUsername + - name: COUCHDB_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "couchdb.fullname" . }} + key: adminPassword + - name: COUCHDB_SECRET + valueFrom: + secretKeyRef: + name: {{ template "couchdb.fullname" . }} + key: cookieAuthSecret +{{- end }} + - name: ERL_FLAGS + value: "{{ range $k, $v := .Values.erlangFlags }} -{{ $k }} {{ $v }} {{ end }}" +{{- if .Values.livenessProbe.enabled }} + livenessProbe: +{{- if .Values.couchdbConfig.chttpd.require_valid_user }} + exec: + command: + - sh + - -c + - curl -G --silent --fail -u ${COUCHDB_USER}:${COUCHDB_PASSWORD} http://localhost:5984/_up +{{- else }} + httpGet: + path: /_up + port: 5984 +{{- end }} + failureThreshold: {{ .Values.livenessProbe.failureThreshold }} + initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.livenessProbe.periodSeconds }} + successThreshold: {{ .Values.livenessProbe.successThreshold }} + timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }} +{{- end }} +{{- if .Values.readinessProbe.enabled }} + readinessProbe: +{{- if .Values.couchdbConfig.chttpd.require_valid_user }} + exec: + command: + - sh + - -c + - curl -G --silent --fail -u ${COUCHDB_USER}:${COUCHDB_PASSWORD} http://localhost:5984/_up +{{- else }} + httpGet: + path: /_up + port: 5984 +{{- end }} + failureThreshold: {{ .Values.readinessProbe.failureThreshold }} + initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }} + periodSeconds: {{ .Values.readinessProbe.periodSeconds }} + successThreshold: {{ .Values.readinessProbe.successThreshold }} + timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }} +{{- end }} + resources: +{{ toYaml .Values.resources | indent 12 }} + volumeMounts: + - name: config-storage + mountPath: /opt/couchdb/etc/default.d +{{- if .Values.adminHash }} + - name: local-config-storage + mountPath: /opt/couchdb/etc/local.d +{{- end }} + - name: database-storage + mountPath: /opt/couchdb/data +{{- if .Values.enableSearch }} + - name: clouseau + image: "{{ .Values.searchImage.repository }}:{{ .Values.searchImage.tag }}" + imagePullPolicy: {{ .Values.searchImage.pullPolicy }} + volumeMounts: + - name: database-storage + mountPath: /opt/couchdb-search/data +{{- end }} +{{- if .Values.sidecars }} +{{ toYaml .Values.sidecars | indent 8}} +{{- end }} +{{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} +{{- end }} +{{- with .Values.tolerations }} + tolerations: +{{ toYaml . | indent 8 }} +{{- end }} +{{- with .Values.affinity }} + affinity: +{{ toYaml . | indent 8 }} +{{- end }} + volumes: + - name: config-storage + emptyDir: {} + - name: config + configMap: + name: {{ template "couchdb.fullname" . }} + items: + - key: inifile + path: chart.ini + - key: seedlistinifile + path: seedlist.ini + +{{- if .Values.adminHash }} + - name: local-config-storage + emptyDir: {} + - name: admin-password + secret: + secretName: {{ template "couchdb.fullname" . }} +{{- end -}} + +{{- if not .Values.persistentVolume.enabled }} + - name: database-storage + emptyDir: {} +{{- else }} + volumeClaimTemplates: + - metadata: + name: database-storage + labels: + app: {{ template "couchdb.name" . }} + release: {{ .Release.Name }} + spec: + accessModes: + {{- range .Values.persistentVolume.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistentVolume.size | quote }} + {{- if .Values.persistentVolume.storageClass }} + {{- if (eq "-" .Values.persistentVolume.storageClass) }} + storageClassName: "" + {{- else }} + storageClassName: "{{ .Values.persistentVolume.storageClass }}" + {{- end }} + {{- end }} +{{- end }} diff --git a/hosting/kubernetes/budibase/charts/couchdb/values.yaml b/hosting/kubernetes/budibase/charts/couchdb/values.yaml new file mode 100755 index 0000000000..5a5025f816 --- /dev/null +++ b/hosting/kubernetes/budibase/charts/couchdb/values.yaml @@ -0,0 +1,201 @@ +## clusterSize is the initial size of the CouchDB cluster. +clusterSize: 3 + +## If allowAdminParty is enabled the cluster will start up without any database +## administrator account; i.e., all users will be granted administrative +## access. Otherwise, the system will look for a Secret called +## -couchdb containing `adminUsername`, `adminPassword` and +## `cookieAuthSecret` keys. See the `createAdminSecret` flag. +## ref: https://kubernetes.io/docs/concepts/configuration/secret/ +allowAdminParty: false + +## If createAdminSecret is enabled a Secret called -couchdb will +## be created containing auto-generated credentials. Users who prefer to set +## these values themselves have a couple of options: +## +## 1) The `adminUsername`, `adminPassword`, `adminHash`, and `cookieAuthSecret` +## can be defined directly in the chart's values. Note that all of a chart's +## values are currently stored in plaintext in a ConfigMap in the tiller +## namespace. +## +## 2) This flag can be disabled and a Secret with the required keys can be +## created ahead of time. +createAdminSecret: true + +# adminUsername: budibase +# adminPassword: budibase +# adminHash: -pbkdf2-this_is_not_necessarily_secure_either +# cookieAuthSecret: admin + +## When enabled, will deploy a networkpolicy that allows CouchDB pods to +## communicate with each other for clustering and ingress on port 5984 +networkPolicy: + enabled: true + +## Use an alternate scheduler, e.g. "stork". +## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/ +## +# schedulerName: + +# Use a service account +serviceAccount: + enabled: true + create: true +# name: +# imagePullSecrets: +# - name: myimagepullsecret + +## The storage volume used by each Pod in the StatefulSet. If a +## persistentVolume is not enabled, the Pods will use `emptyDir` ephemeral +## local storage. Setting the storageClass attribute to "-" disables dynamic +## provisioning of Persistent Volumes; leaving it unset will invoke the default +## provisioner. +persistentVolume: + enabled: false + accessModes: + - ReadWriteOnce + size: 10Gi + storageClass: "" + +## The CouchDB image +image: + repository: couchdb + tag: 3.1.0 + pullPolicy: IfNotPresent + +## Experimental integration with Lucene-powered fulltext search +searchImage: + repository: kocolosk/couchdb-search + tag: 0.2.0 + pullPolicy: IfNotPresent + +## Flip this to flag to include the Search container in each Pod +enableSearch: true + +initImage: + repository: busybox + tag: latest + pullPolicy: Always + +## CouchDB is happy to spin up cluster nodes in parallel, but if you encounter +## problems you can try setting podManagementPolicy to the StatefulSet default +## `OrderedReady` +podManagementPolicy: Parallel + +## To better tolerate Node failures, we can prevent Kubernetes scheduler from +## assigning more than one Pod of CouchDB StatefulSet per Node using podAntiAffinity. +affinity: {} + # podAntiAffinity: + # requiredDuringSchedulingIgnoredDuringExecution: + # - labelSelector: + # matchExpressions: + # - key: "app" + # operator: In + # values: + # - couchdb + # topologyKey: "kubernetes.io/hostname" + +## Optional pod annotations +annotations: {} + +## Optional tolerations +tolerations: [] + +## A StatefulSet requires a headless Service to establish the stable network +## identities of the Pods, and that Service is created automatically by this +## chart without any additional configuration. The Service block below refers +## to a second Service that governs how clients connect to the CouchDB cluster. +service: + # annotations: + enabled: true + type: ClusterIP + externalPort: 5984 + +## An Ingress resource can provide name-based virtual hosting and TLS +## termination among other things for CouchDB deployments which are accessed +## from outside the Kubernetes cluster. +## ref: https://kubernetes.io/docs/concepts/services-networking/ingress/ +ingress: + enabled: false + hosts: + - chart-example.local + path: / + annotations: [] + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + tls: + # Secrets must be manually created in the namespace. + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +## Optional resource requests and limits for the CouchDB container +## ref: http://kubernetes.io/docs/user-guide/compute-resources/ +resources: + {} + # requests: + # cpu: 100m + # memory: 128Mi + # limits: + # cpu: 56 + # memory: 256Gi + +## erlangFlags is a map that is passed to the Erlang VM as flags using the +## ERL_FLAGS env. `name` and `setcookie` flags are minimally required to +## establish connectivity between cluster nodes. +## ref: http://erlang.org/doc/man/erl.html#init_flags +erlangFlags: + name: couchdb + setcookie: monster + +## couchdbConfig will override default CouchDB configuration settings. +## The contents of this map are reformatted into a .ini file laid down +## by a ConfigMap object. +## ref: http://docs.couchdb.org/en/latest/config/index.html +couchdbConfig: + couchdb: + uuid: budibase-couchdb # REQUIRED: Unique identifier for this CouchDB server instance + # cluster: + # q: 8 # Create 8 shards for each database + chttpd: + bind_address: any + # chttpd.require_valid_user disables all the anonymous requests to the port + # 5984 when is set to true. + require_valid_user: false + +# Kubernetes local cluster domain. +# This is used to generate FQDNs for peers when joining the CouchDB cluster. +dns: + clusterDomainSuffix: cluster.local + +## Configure liveness and readiness probe values +## Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes +livenessProbe: + enabled: true + failureThreshold: 3 + initialDelaySeconds: 0 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 +readinessProbe: + enabled: true + failureThreshold: 3 + initialDelaySeconds: 0 + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 1 + +# Configure arbitrary sidecar containers for CouchDB pods created by the +# StatefulSet +sidecars: {} + # - name: foo + # image: "busybox" + # imagePullPolicy: IfNotPresent + # resources: + # requests: + # cpu: "0.1" + # memory: 10Mi + # command: ['echo "foo";'] + # volumeMounts: + # - name: database-storage + # mountPath: /opt/couchdb/data/ diff --git a/hosting/kubernetes/budibase/charts/ingress-nginx-3.35.0.tgz b/hosting/kubernetes/budibase/charts/ingress-nginx-3.35.0.tgz new file mode 100644 index 0000000000..ee5214c497 Binary files /dev/null and b/hosting/kubernetes/budibase/charts/ingress-nginx-3.35.0.tgz differ diff --git a/hosting/kubernetes/budibase/templates/NOTES.txt b/hosting/kubernetes/budibase/templates/NOTES.txt new file mode 100644 index 0000000000..2ace0aa38d --- /dev/null +++ b/hosting/kubernetes/budibase/templates/NOTES.txt @@ -0,0 +1,22 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "budibase.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "budibase.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "budibase.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "budibase.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/hosting/kubernetes/budibase/templates/_helpers.tpl b/hosting/kubernetes/budibase/templates/_helpers.tpl new file mode 100644 index 0000000000..3b0853e19f --- /dev/null +++ b/hosting/kubernetes/budibase/templates/_helpers.tpl @@ -0,0 +1,83 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "budibase.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "budibase.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- printf "%s-%s" .Values.fullnameOverride .Chart.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} + +{{/* +CouchDB secret identifier +*/}} +{{- define "couchdb.fullname" -}} +{{- $name := "couchdb" -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Internal DNS +*/}} +{{- define "budibase.serviceDns" -}} +{{- printf "%s.%s.%s" .Release.Namespace "svc" .Values.services.dns -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "budibase.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "budibase.labels" -}} +helm.sh/chart: {{ include "budibase.chart" . }} +{{ include "budibase.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "budibase.selectorLabels" -}} +app.kubernetes.io/name: {{ include "budibase.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "budibase.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "budibase.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Create a random string if the supplied key does not exist +*/}} +{{- define "budibase.defaultsecret" -}} +{{- if . -}} +{{- . | b64enc | quote -}} +{{- else -}} +{{- randAlphaNum 20 | b64enc | quote -}} +{{- end -}} +{{- end -}} \ No newline at end of file diff --git a/hosting/kubernetes/budibase/templates/app-service-deployment.yaml b/hosting/kubernetes/budibase/templates/app-service-deployment.yaml new file mode 100644 index 0000000000..daee03620f --- /dev/null +++ b/hosting/kubernetes/budibase/templates/app-service-deployment.yaml @@ -0,0 +1,101 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + kompose.cmd: kompose convert + kompose.version: 1.21.0 (992df58d8) + creationTimestamp: null + labels: + io.kompose.service: app-service + name: app-service +spec: + replicas: {{ .Values.services.apps.replicaCount }} + selector: + matchLabels: + io.kompose.service: app-service + strategy: + type: Recreate + template: + metadata: + annotations: + kompose.cmd: kompose convert + kompose.version: 1.21.0 (992df58d8) + creationTimestamp: null + labels: + io.kompose.service: app-service + spec: + containers: + - env: + - name: BUDIBASE_ENVIRONMENT + value: {{ .Values.globals.budibaseEnv }} + - name: COUCH_DB_URL + {{ if .Values.services.couchdb.url }} + value: {{ .Values.services.couchdb.url }} + {{ else }} + value: http://{{ .Release.Name }}-svc-couchdb:{{ .Values.services.couchdb.port }} + {{ end }} + - name: COUCH_DB_USER + valueFrom: + secretKeyRef: + name: {{ template "couchdb.fullname" . }} + key: adminUsername + - name: COUCH_DB_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "couchdb.fullname" . }} + key: adminPassword + - name: ENABLE_ANALYTICS + value: {{ .Values.globals.enableAnalytics | quote }} + - name: INTERNAL_API_KEY + valueFrom: + secretKeyRef: + name: {{ template "budibase.fullname" . }} + key: internalApiKey + - name: JWT_SECRET + valueFrom: + secretKeyRef: + name: {{ template "budibase.fullname" . }} + key: jwtSecret + - name: LOG_LEVEL + value: {{ .Values.services.apps.logLevel | default "info" | quote }} + - name: MINIO_ACCESS_KEY + valueFrom: + secretKeyRef: + name: {{ template "budibase.fullname" . }} + key: objectStoreAccess + - name: MINIO_SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ template "budibase.fullname" . }} + key: objectStoreSecret + - name: MINIO_URL + {{ if .Values.services.objectStore.url }} + value: {{ .Values.services.objectStore.url }} + {{ else }} + value: http://minio-service:{{ .Values.services.objectStore.port }} + {{ end }} + - name: PORT + value: {{ .Values.services.apps.port | quote }} + - name: REDIS_PASSWORD + value: {{ .Values.services.redis.password }} + - name: REDIS_URL + {{ if .Values.services.redis.url }} + value: {{ .Values.services.redis.url }} + {{ else }} + value: redis-service:{{ .Values.services.redis.port }} + {{ end }} + - name: SELF_HOSTED + value: {{ .Values.globals.selfHosted | quote }} + - name: SENTRY_DSN + value: {{ .Values.globals.sentryDSN }} + - name: WORKER_URL + value: worker-service:{{ .Values.services.worker.port }} + image: budibase/apps + imagePullPolicy: Always + name: bbapps + ports: + - containerPort: {{ .Values.services.apps.port }} + resources: {} + restartPolicy: Always + serviceAccountName: "" +status: {} diff --git a/hosting/kubernetes/budibase/templates/app-service-service.yaml b/hosting/kubernetes/budibase/templates/app-service-service.yaml new file mode 100644 index 0000000000..5247b4de09 --- /dev/null +++ b/hosting/kubernetes/budibase/templates/app-service-service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + annotations: + kompose.cmd: kompose convert + kompose.version: 1.21.0 (992df58d8) + creationTimestamp: null + labels: + io.kompose.service: app-service + name: app-service +spec: + ports: + - name: {{ .Values.services.apps.port | quote }} + port: {{ .Values.services.apps.port }} + targetPort: {{ .Values.services.apps.port }} + selector: + io.kompose.service: app-service +status: + loadBalancer: {} diff --git a/hosting/kubernetes/budibase/templates/hpa.yaml b/hosting/kubernetes/budibase/templates/hpa.yaml new file mode 100644 index 0000000000..2f901b4664 --- /dev/null +++ b/hosting/kubernetes/budibase/templates/hpa.yaml @@ -0,0 +1,28 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2beta1 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "budibase.fullname" . }} + labels: + {{- include "budibase.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "budibase.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/hosting/kubernetes/budibase/templates/ingress.yaml b/hosting/kubernetes/budibase/templates/ingress.yaml new file mode 100644 index 0000000000..4de295e18a --- /dev/null +++ b/hosting/kubernetes/budibase/templates/ingress.yaml @@ -0,0 +1,61 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "budibase.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "budibase.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ .backend.service.name }} + port: + number: {{ .backend.service.port.number }} + {{- else }} + serviceName: {{ .backend.service.name }} + servicePort: {{ .backend.service.port.number }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/hosting/kubernetes/budibase/templates/minio-data-persistentvolumeclaim.yaml b/hosting/kubernetes/budibase/templates/minio-data-persistentvolumeclaim.yaml new file mode 100644 index 0000000000..d122ad0a3e --- /dev/null +++ b/hosting/kubernetes/budibase/templates/minio-data-persistentvolumeclaim.yaml @@ -0,0 +1,16 @@ +{{- if .Values.services.objectStore.minio }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + creationTimestamp: null + labels: + io.kompose.service: minio-data + name: minio-data +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .Values.services.objectStore.storage }} +status: {} +{{- end }} \ No newline at end of file diff --git a/hosting/kubernetes/budibase/templates/minio-service-deployment.yaml b/hosting/kubernetes/budibase/templates/minio-service-deployment.yaml new file mode 100644 index 0000000000..a23d0c1d89 --- /dev/null +++ b/hosting/kubernetes/budibase/templates/minio-service-deployment.yaml @@ -0,0 +1,70 @@ +{{- if .Values.services.objectStore.minio }} +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + kompose.cmd: kompose convert + kompose.version: 1.21.0 (992df58d8) + creationTimestamp: null + labels: + io.kompose.service: minio-service + name: minio-service +spec: + replicas: 1 + selector: + matchLabels: + io.kompose.service: minio-service + strategy: + type: Recreate + template: + metadata: + annotations: + kompose.cmd: kompose convert + kompose.version: 1.21.0 (992df58d8) + creationTimestamp: null + labels: + io.kompose.service: minio-service + spec: + containers: + - args: + - server + - /data + env: + - name: MINIO_BROWSER + value: {{ .Values.services.objectStore.browser | quote }} + - name: MINIO_ACCESS_KEY + valueFrom: + secretKeyRef: + name: {{ template "budibase.fullname" . }} + key: objectStoreAccess + - name: MINIO_SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ template "budibase.fullname" . }} + key: objectStoreSecret + image: minio/minio + imagePullPolicy: "" + livenessProbe: + exec: + command: + - curl + - -f + - http://localhost:9000/minio/health/live + failureThreshold: 3 + periodSeconds: 30 + timeoutSeconds: 20 + name: minio-service + ports: + - containerPort: {{ .Values.services.objectStore.port }} + resources: {} + volumeMounts: + - mountPath: /data + name: minio-data + restartPolicy: Always + serviceAccountName: "" + volumes: + - name: minio-data + persistentVolumeClaim: + claimName: minio-data +status: {} +{{- end }} \ No newline at end of file diff --git a/hosting/kubernetes/budibase/templates/minio-service-service.yaml b/hosting/kubernetes/budibase/templates/minio-service-service.yaml new file mode 100644 index 0000000000..cfdb22002b --- /dev/null +++ b/hosting/kubernetes/budibase/templates/minio-service-service.yaml @@ -0,0 +1,21 @@ +{{- if .Values.services.objectStore.minio }} +apiVersion: v1 +kind: Service +metadata: + annotations: + kompose.cmd: kompose convert + kompose.version: 1.21.0 (992df58d8) + creationTimestamp: null + labels: + io.kompose.service: minio-service + name: minio-service +spec: + ports: + - name: {{ .Values.services.objectStore.port | quote }} + port: {{ .Values.services.objectStore.port }} + targetPort: {{ .Values.services.objectStore.port }} + selector: + io.kompose.service: minio-service +status: + loadBalancer: {} +{{- end }} \ No newline at end of file diff --git a/hosting/kubernetes/budibase/templates/proxy-service-deployment.yaml b/hosting/kubernetes/budibase/templates/proxy-service-deployment.yaml new file mode 100644 index 0000000000..0f802da843 --- /dev/null +++ b/hosting/kubernetes/budibase/templates/proxy-service-deployment.yaml @@ -0,0 +1,38 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + kompose.cmd: kompose convert + kompose.version: 1.21.0 (992df58d8) + creationTimestamp: null + labels: + app.kubernetes.io/name: budibase-proxy + name: proxy-service +spec: + replicas: {{ .Values.services.proxy.replicaCount }} + selector: + matchLabels: + app.kubernetes.io/name: budibase-proxy + strategy: + type: Recreate + template: + metadata: + annotations: + kompose.cmd: kompose convert + kompose.version: 1.21.0 (992df58d8) + creationTimestamp: null + labels: + app.kubernetes.io/name: budibase-proxy + spec: + containers: + - image: budibase/proxy + imagePullPolicy: "" + name: proxy-service + ports: + - containerPort: {{ .Values.services.proxy.port }} + resources: {} + volumeMounts: + restartPolicy: Always + serviceAccountName: "" + volumes: +status: {} diff --git a/hosting/kubernetes/budibase/templates/proxy-service-service.yaml b/hosting/kubernetes/budibase/templates/proxy-service-service.yaml new file mode 100644 index 0000000000..8f14d97862 --- /dev/null +++ b/hosting/kubernetes/budibase/templates/proxy-service-service.yaml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: Service +metadata: + annotations: + kompose.cmd: kompose convert + kompose.version: 1.21.0 (992df58d8) + creationTimestamp: null + labels: + app.kubernetes.io/name: budibase-proxy + name: proxy-service +spec: + type: NodePort + ports: + - port: {{ .Values.services.proxy.port }} + targetPort: {{ .Values.services.proxy.port }} + protocol: TCP + selector: + app.kubernetes.io/name: budibase-proxy +status: + loadBalancer: {} diff --git a/hosting/kubernetes/budibase/templates/redis-data-persistentvolumeclaim.yaml b/hosting/kubernetes/budibase/templates/redis-data-persistentvolumeclaim.yaml new file mode 100644 index 0000000000..2cb5ee8eab --- /dev/null +++ b/hosting/kubernetes/budibase/templates/redis-data-persistentvolumeclaim.yaml @@ -0,0 +1,16 @@ +{{- if .Values.services.redis.enabled }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + creationTimestamp: null + labels: + io.kompose.service: redis-data + name: redis-data +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .Values.services.redis.storage }} +status: {} +{{- end }} \ No newline at end of file diff --git a/hosting/kubernetes/budibase/templates/redis-service-deployment.yaml b/hosting/kubernetes/budibase/templates/redis-service-deployment.yaml new file mode 100644 index 0000000000..9235b0b11d --- /dev/null +++ b/hosting/kubernetes/budibase/templates/redis-service-deployment.yaml @@ -0,0 +1,49 @@ +{{- if .Values.services.redis.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + kompose.cmd: kompose convert + kompose.version: 1.21.0 (992df58d8) + creationTimestamp: null + labels: + io.kompose.service: redis-service + name: redis-service +spec: + replicas: {{ .Values.services.redis.replicaCount }} + selector: + matchLabels: + io.kompose.service: redis-service + strategy: + type: Recreate + template: + metadata: + annotations: + kompose.cmd: kompose convert + kompose.version: 1.21.0 (992df58d8) + creationTimestamp: null + labels: + io.kompose.service: redis-service + spec: + containers: + - args: + - redis-server + - --requirepass + - {{ .Values.services.redis.password }} + image: redis + imagePullPolicy: "" + name: redis-service + ports: + - containerPort: {{ .Values.services.redis.port }} + resources: {} + volumeMounts: + - mountPath: /data + name: redis-data + restartPolicy: Always + serviceAccountName: "" + volumes: + - name: redis-data + persistentVolumeClaim: + claimName: redis-data +status: {} +{{- end }} \ No newline at end of file diff --git a/hosting/kubernetes/budibase/templates/redis-service-service.yaml b/hosting/kubernetes/budibase/templates/redis-service-service.yaml new file mode 100644 index 0000000000..55ca40ed88 --- /dev/null +++ b/hosting/kubernetes/budibase/templates/redis-service-service.yaml @@ -0,0 +1,21 @@ +{{- if .Values.services.redis.enabled }} +apiVersion: v1 +kind: Service +metadata: + annotations: + kompose.cmd: kompose convert + kompose.version: 1.21.0 (992df58d8) + creationTimestamp: null + labels: + io.kompose.service: redis-service + name: redis-service +spec: + ports: + - name: {{ .Values.services.redis.port | quote }} + port: {{ .Values.services.redis.port }} + targetPort: {{ .Values.services.redis.port }} + selector: + io.kompose.service: redis-service +status: + loadBalancer: {} +{{- end }} \ No newline at end of file diff --git a/hosting/kubernetes/budibase/templates/secrets.yaml b/hosting/kubernetes/budibase/templates/secrets.yaml new file mode 100644 index 0000000000..1c0a914ed3 --- /dev/null +++ b/hosting/kubernetes/budibase/templates/secrets.yaml @@ -0,0 +1,17 @@ +{{- if .Values.globals.createSecrets -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "budibase.fullname" . }} + labels: + app: {{ template "budibase.fullname" . }} + chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" + release: "{{ .Release.Name }}" + heritage: "{{ .Release.Service }}" +type: Opaque +data: + internalApiKey: {{ template "budibase.defaultsecret" .Values.globals.internalApiKey }} + jwtSecret: {{ template "budibase.defaultsecret" .Values.globals.jwtSecret }} + objectStoreAccess: {{ template "budibase.defaultsecret" .Values.services.objectStore.accessKey }} + objectStoreSecret: {{ template "budibase.defaultsecret" .Values.services.objectStore.secretKey }} +{{- end -}} diff --git a/hosting/kubernetes/budibase/templates/service.yaml b/hosting/kubernetes/budibase/templates/service.yaml new file mode 100644 index 0000000000..be4d932b59 --- /dev/null +++ b/hosting/kubernetes/budibase/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "budibase.fullname" . }} + labels: + {{- include "budibase.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "budibase.selectorLabels" . | nindent 4 }} \ No newline at end of file diff --git a/hosting/kubernetes/budibase/templates/serviceaccount.yaml b/hosting/kubernetes/budibase/templates/serviceaccount.yaml new file mode 100644 index 0000000000..1aa1020088 --- /dev/null +++ b/hosting/kubernetes/budibase/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "budibase.serviceAccountName" . }} + labels: + {{- include "budibase.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/hosting/kubernetes/budibase/templates/tests/test-connection.yaml b/hosting/kubernetes/budibase/templates/tests/test-connection.yaml new file mode 100644 index 0000000000..ecd1f361de --- /dev/null +++ b/hosting/kubernetes/budibase/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "budibase.fullname" . }}-test-connection" + labels: + {{- include "budibase.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "budibase.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/hosting/kubernetes/budibase/templates/worker-service-deployment.yaml b/hosting/kubernetes/budibase/templates/worker-service-deployment.yaml new file mode 100644 index 0000000000..1af289f4aa --- /dev/null +++ b/hosting/kubernetes/budibase/templates/worker-service-deployment.yaml @@ -0,0 +1,94 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + annotations: + kompose.cmd: kompose convert + kompose.version: 1.21.0 (992df58d8) + creationTimestamp: null + labels: + io.kompose.service: worker-service + name: worker-service +spec: + replicas: {{ .Values.services.worker.replicaCount }} + + selector: + matchLabels: + io.kompose.service: worker-service + strategy: + type: Recreate + template: + metadata: + annotations: + kompose.cmd: kompose convert + kompose.version: 1.21.0 (992df58d8) + creationTimestamp: null + labels: + io.kompose.service: worker-service + spec: + containers: + - env: + - name: CLUSTER_PORT + value: {{ .Values.services.worker.port | quote }} + - name: COUCH_DB_USER + valueFrom: + secretKeyRef: + name: {{ template "couchdb.fullname" . }} + key: adminUsername + - name: COUCH_DB_PASSWORD + valueFrom: + secretKeyRef: + name: {{ template "couchdb.fullname" . }} + key: adminPassword + - name: COUCH_DB_URL + {{ if .Values.services.couchdb.url }} + value: {{ .Values.services.couchdb.url }} + {{ else }} + value: http://{{ .Release.Name }}-svc-couchdb:{{ .Values.services.couchdb.port }} + {{ end }} + - name: INTERNAL_API_KEY + valueFrom: + secretKeyRef: + name: {{ template "budibase.fullname" . }} + key: internalApiKey + - name: JWT_SECRET + valueFrom: + secretKeyRef: + name: {{ template "budibase.fullname" . }} + key: jwtSecret + - name: MINIO_ACCESS_KEY + valueFrom: + secretKeyRef: + name: {{ template "budibase.fullname" . }} + key: objectStoreAccess + - name: MINIO_SECRET_KEY + valueFrom: + secretKeyRef: + name: {{ template "budibase.fullname" . }} + key: objectStoreSecret + - name: MINIO_URL + {{ if .Values.services.objectStore.url }} + value: {{ .Values.services.objectStore.url }} + {{ else }} + value: http://minio-service:{{ .Values.services.objectStore.port }} + {{ end }} + - name: PORT + value: {{ .Values.services.worker.port | quote }} + - name: REDIS_PASSWORD + value: {{ .Values.services.redis.password | quote }} + - name: REDIS_URL + {{ if .Values.services.redis.url }} + value: {{ .Values.services.redis.url }} + {{ else }} + value: redis-service:{{ .Values.services.redis.port }} + {{ end }} + - name: SELF_HOSTED + value: {{ .Values.globals.selfHosted | quote }} + image: budibase/worker + imagePullPolicy: Always + name: bbworker + ports: + - containerPort: {{ .Values.services.worker.port }} + resources: {} + restartPolicy: Always + serviceAccountName: "" +status: {} diff --git a/hosting/kubernetes/budibase/templates/worker-service-service.yaml b/hosting/kubernetes/budibase/templates/worker-service-service.yaml new file mode 100644 index 0000000000..a79ba1e04b --- /dev/null +++ b/hosting/kubernetes/budibase/templates/worker-service-service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + annotations: + kompose.cmd: kompose convert + kompose.version: 1.21.0 (992df58d8) + creationTimestamp: null + labels: + io.kompose.service: worker-service + name: worker-service +spec: + ports: + - name: {{ .Values.services.worker.port | quote }} + port: {{ .Values.services.worker.port }} + targetPort: {{ .Values.services.worker.port }} + selector: + io.kompose.service: worker-service +status: + loadBalancer: {} diff --git a/hosting/kubernetes/budibase/values.yaml b/hosting/kubernetes/budibase/values.yaml new file mode 100644 index 0000000000..e5ce7f141f --- /dev/null +++ b/hosting/kubernetes/budibase/values.yaml @@ -0,0 +1,140 @@ +# Default values for budibase. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [] +nameOverride: "" +# fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 10000 + +ingress: + enabled: true + certificateArn: "" + className: "" + annotations: + kubernetes.io/ingress.class: nginx + hosts: + - host: # change if using custom domain + paths: + - path: / + pathType: Prefix + backend: + service: + name: proxy-service + port: + number: 10000 + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 100 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +globals: + budibaseEnv: PRODUCTION + enableAnalytics: false + posthogToken: "" + sentryDSN: "" + logLevel: info + selfHosted: 1 + createSecrets: true # creates an internal API key, JWT secrets and redis password for you + + # if createSecrets is set to false, you can hard-code your secrets here + internalApiKey: "" + jwtSecret: "" + + +services: + dns: cluster.local + + proxy: + port: 10000 + replicaCount: 1 + + apps: + port: 4002 + replicaCount: 1 + logLevel: info + + worker: + port: 4001 + replicaCount: 1 + + couchdb: + enabled: true + replicaCount: 3 + url: "" # only change if pointing to existing couch server + user: "" # only change if pointing to existing couch server + password: "" # only change if pointing to existing couch server + port: 5984 + storage: 100Mi + + redis: + enabled: true # disable if using external redis + port: 6379 + replicaCount: 1 + url: "" # only change if pointing to existing redis cluster and enabled: false + password: "budibase" # recommended to override if using built-in redis + storage: 100Mi + + objectStore: + minio: true + browser: true + port: 9000 + replicaCount: 1 + accessKey: "" # AWS_ACCESS_KEY if using S3 or existing minio access key + secretKey: "" # AWS_SECRET_ACCESS_KEY if using S3 or existing minio secret + url: "" # only change if pointing to existing minio cluster and minio: false + storage: 100Mi + diff --git a/hosting/kubernetes/envoy/Dockerfile b/hosting/kubernetes/envoy/Dockerfile new file mode 100644 index 0000000000..96334fa723 --- /dev/null +++ b/hosting/kubernetes/envoy/Dockerfile @@ -0,0 +1,4 @@ +FROM envoyproxy/envoy:v1.16-latest +COPY envoy.yaml /etc/envoy/envoy.yaml +RUN chmod go+r /etc/envoy/envoy.yaml + diff --git a/hosting/kubernetes/envoy/envoy.yaml b/hosting/kubernetes/envoy/envoy.yaml new file mode 100644 index 0000000000..0e7859d887 --- /dev/null +++ b/hosting/kubernetes/envoy/envoy.yaml @@ -0,0 +1,125 @@ +static_resources: + listeners: + - name: main_listener + address: + socket_address: { address: 0.0.0.0, port_value: 10000 } + filter_chains: + - filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + stat_prefix: ingress + codec_type: auto + route_config: + name: local_route + virtual_hosts: + - name: local_services + domains: ["*"] + routes: + - match: { prefix: "/app/" } + route: + cluster: app-service + prefix_rewrite: "/" + + - match: { prefix: "/builder/" } + route: + cluster: app-service + + - match: { prefix: "/builder" } + route: + cluster: app-service + + - match: { prefix: "/app_" } + route: + cluster: app-service + + # special case for worker admin API + - match: { prefix: "/api/admin/" } + route: + cluster: worker-service + + - match: { path: "/" } + route: + cluster: app-service + + # special case for when API requests are made, can just forward, not to minio + - match: { prefix: "/api/" } + route: + cluster: app-service + + - match: { prefix: "/worker/" } + route: + cluster: worker-service + prefix_rewrite: "/" + + - match: { prefix: "/db/" } + route: + cluster: couchdb-service + prefix_rewrite: "/" + + # minio is on the default route because this works + # best, minio + AWS SDK doesn't handle path proxy + - match: { prefix: "/" } + route: + cluster: minio-service + + http_filters: + - name: envoy.filters.http.router + + clusters: + - name: app-service + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + load_assignment: + cluster_name: app-service + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: app-service.budibase.svc.cluster.local + port_value: 4002 + + - name: minio-service + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + load_assignment: + cluster_name: minio-service + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: minio-service.budibase.svc.cluster.local + port_value: 9000 + + - name: worker-service + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + load_assignment: + cluster_name: worker-service + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: worker-service.budibase.svc.cluster.local + port_value: 4001 + + - name: couchdb-service + connect_timeout: 0.25s + type: strict_dns + lb_policy: round_robin + load_assignment: + cluster_name: couchdb-service + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: couchdb-service.budibase.svc.cluster.local + port_value: 5984 + diff --git a/package.json b/package.json index 5532cf87a9..552b8d1b0d 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "test:e2e:ci": "lerna run cy:ci", "build:docker": "lerna run build:docker && cd hosting/scripts/linux/ && ./release-to-docker-hub.sh && cd -", "build:docker:develop": "node scripts/pinVersions && lerna run build:docker && cd hosting/scripts/linux/ && ./release-to-docker-hub.sh develop && cd -", + "release:helm": "./scripts/release_helm_chart.sh", "multi:enable": "lerna run multi:enable", "multi:disable": "lerna run multi:disable" } diff --git a/packages/server/src/utilities/index.js b/packages/server/src/utilities/index.js index 8da98e99e4..dec17ab284 100644 --- a/packages/server/src/utilities/index.js +++ b/packages/server/src/utilities/index.js @@ -2,7 +2,7 @@ const env = require("../environment") const { OBJ_STORE_DIRECTORY } = require("../constants") const { sanitizeKey } = require("@budibase/auth/src/objectStore") -const BB_CDN = "https://cdn.app.budi.live/assets" +const BB_CDN = "https://cdn.budi.live" exports.wait = ms => new Promise(resolve => setTimeout(resolve, ms)) diff --git a/scripts/release_helm_chart.sh b/scripts/release_helm_chart.sh new file mode 100755 index 0000000000..b1594cca91 --- /dev/null +++ b/scripts/release_helm_chart.sh @@ -0,0 +1,3 @@ +cd docs +helm package ../hosting/kubernetes/budibase +helm repo index . --url https://budibase.github.io/budibase \ No newline at end of file