feat: introduce updated helm chart (#4896)

Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
This commit is contained in:
Piyush Jain
2025-03-13 15:00:17 +05:30
committed by GitHub
parent aecedfd082
commit f227c9e97e
32 changed files with 2492 additions and 1146 deletions

17
.gitignore vendored
View File

@@ -55,3 +55,20 @@ apps/web/public/js
packages/database/migrations
branch.json
.vercel
# Terraform
infra/terraform/.terraform/
**/.terraform.lock.hcl
**/terraform.tfstate
**/terraform.tfstate.*
**/crash.log
**/override.tf
**/override.tf.json
**/*.tfvars
**/*.tfvars.json
**/.terraformrc
**/terraform.rc
# IntelliJ IDEA
/.idea/
/*.iml

View File

@@ -1,154 +1,217 @@
---
title: "Kubernetes Deployment"
description: "Deploy Formbricks on a Kubernetes cluster using Helm."
description: "Deploy the new Helm chart on a Kubernetes cluster using Helm."
icon: "circle-nodes"
---
This guide explains how to deploy Formbricks on a Kubernetes cluster using Helm. The primary focus is on deploying Formbricks pods in a production-ready environment with external database services.
# **🚀 Kubernetes Deployment Guide**
## Prerequisites
This guide explains how to deploy the **Formbricks Helm Chart** on a Kubernetes cluster using Helm. It provides configuration options for **internal** and **external** databases, caching services, and secrets management.
Before you begin, ensure that:
---
- You have a running Kubernetes cluster (AWS EKS, GCP GKE, Azure AKS, Minikube, etc.)
- An Ingress controller (e.g., Traefik, Nginx) is configured
- You have Helm installed on your local machine
- For production environments, you have access to external PostgreSQL and Redis services
## **📌 Prerequisites**
Ensure you have the following before proceeding:
> **Important:** Running multiple Formbricks pods in a cluster setup requires a Formbricks Enterprise license. With the Community Edition, only a single Formbricks pod is supported. Redis is required when deploying multiple Formbricks pods for proper session handling and caching.
- A running Kubernetes cluster (EKS, GKE, AKS, Minikube, etc.)
- An **Ingress Controller** (e.g., Traefik, Nginx)
- **Helm installed** on your local machine
- **Production setup requires managed PostgreSQL and Redis services**
## Basic Installation
> **Note:** Redis is required for **session handling** when deploying multiple pods.
### Step 1: Clone the Formbricks Helm Chart
---
## **1⃣ Installation Steps**
### **🔹 Step 1: Clone the Helm Chart**
```sh
git clone https://github.com/formbricks/formbricks.git
cd formbricks/helm-chart
git clone https://github.com/formbricks/formbricks
cd helm-chart
```
### Step 2: Deploy Formbricks
For a basic deployment with a single pod (Community Edition) and PostgreSQL running in the cluster:
### **🔹 Step 2: Install with Default Configuration**
```sh
helm install my-formbricks ./ \
--namespace formbricks \
--set redis.enabled=false \
--create-namespace
helm install formbricks ./ -n formbricks --create-namespace
```
By default:
- PostgreSQL and Redis **are deployed within the cluster**.
- Secrets **are dynamically generated** and stored as Kubernetes Secrets.
## Production Deployment
For production environments, we recommend using managed database and cache services like AWS RDS for PostgreSQL and AWS ElastiCache for Redis:
### **🔹 Step 3: Install with an Enterprise License**
```sh
helm install my-formbricks ./ \
--namespace formbricks \
--create-namespace \
--set replicaCount=3 \
--set postgresql.enabled=false \
--set postgresql.externalUrl="postgresql://user:password@your-postgres-host:5432/formbricks" \
--set redis.enabled=false \
--set redis.externalUrl="redis://your-redis-host:6379"
helm install formbricks ./ -n formbricks --create-namespace --set enterprise.licenseKey="YOUR_LICENSE_KEY"
```
> **Note:** The above multi-pod configuration requires a Formbricks Enterprise license. Redis is enabled and configured to support multiple Formbricks pods.
---
## Verify Installation
## **2⃣ Configuring Secrets**
### Check Running Services
### **🔹 Using Kubernetes Secrets (Default)**
By default, **secrets are stored as Kubernetes Secrets**.
The chart automatically generates **random values** for required secrets.
Modify `values.yaml`:
```yaml
secret:
enabled: true
```
---
### **🔹 Using External Secrets (AWS Secrets Manager, Vault, etc.)**
To use an **external secrets manager**, enable `externalSecret` in `values.yaml`:
```yaml
secret:
enabled: false # Disable default secret generation
externalSecret:
enabled: true
secretStore:
name: aws-secrets-manager
kind: ClusterSecretStore
refreshInterval: "1h"
files:
redis:
data:
REDIS_PASSWORD:
remoteRef:
key: "prod/formbricks/secrets"
property: REDIS_PASSWORD
postgres:
data:
POSTGRES_ADMIN_PASSWORD:
remoteRef:
key: "prod/formbricks/secrets"
property: POSTGRES_ADMIN_PASSWORD
POSTGRES_USER_PASSWORD:
remoteRef:
key: "prod/formbricks/secrets"
property: POSTGRES_USER_PASSWORD
app-secrets:
data:
DATABASE_URL:
remoteRef:
key: "prod/formbricks/secrets"
property: DATABASE_URL
REDIS_URL:
remoteRef:
key: "prod/formbricks/secrets"
property: REDIS_URL
ENCRYPTION_KEY:
remoteRef:
key: "prod/formbricks/secrets"
property: ENCRYPTION_KEY
```
📌 **Ensure ExternalSecrets Operator is installed:**
[https://external-secrets.io/latest/](https://external-secrets.io/latest/)
Install with:
```sh
kubectl get pods -n formbricks
kubectl get svc -n formbricks
kubectl get ingress -n formbricks
helm install formbricks ./ -n formbricks --create-namespace -f values.yaml
```
> **Note:** The Formbricks application pod may take some time to reach a stable state as it runs database migrations during startup.
---
### Access Formbricks
## **3⃣ Configuring PostgreSQL and Redis**
- If running locally with Minikube:
```sh
minikube service my-formbricks -n formbricks
```
- If deployed on a cloud cluster, make sure to set up your ingress controller properly and visit the domain or IP address associated with your ingress.
### **🔹 Using Managed PostgreSQL and Redis**
For production, we recommend using **managed database and cache services**.
## Upgrading Formbricks
Modify `values.yaml`:
```yaml
postgresql:
enabled: false
externalDatabaseUrl: "postgresql://user:password@your-postgres-host:5432/mydb"
To upgrade your Formbricks deployment, use:
```bash
# From the helm-chart directory
helm upgrade my-formbricks ./ --namespace formbricks
redis:
enabled: false
externalRedisUrl: "redis://your-redis-host:6379"
```
Install with:
```sh
helm install formbricks ./ -n formbricks --create-namespace -f values.yaml
```
### Common Upgrade Scenarios
---
#### 1. Updating Environment Variables
### **🔹 Using In-Cluster PostgreSQL and Redis (Default)**
By default, PostgreSQL and Redis are **deployed inside the cluster**.
To **ensure in-cluster deployment**, use:
```bash
helm upgrade my-formbricks ./ --namespace formbricks \
--set env.SMTP_HOST=new-smtp.example.com \
--set env.SMTP_PORT=587 \
--set env.NEW_CUSTOM_VAR=newvalue
```yaml
postgresql:
enabled: true
redis:
enabled: true
```
Apply with:
```sh
helm install formbricks ./ -n formbricks --create-namespace -f values.yaml
```
#### 2. Scaling Resources
---
```bash
helm upgrade my-formbricks ./ --namespace formbricks \
--set resources.limits.cpu=1 \
--set resources.limits.memory=2Gi \
--set resources.requests.cpu=500m \
--set resources.requests.memory=1Gi
## **4⃣ Upgrading the Deployment**
To apply changes:
```sh
helm upgrade formbricks ./ -n formbricks
```
#### 3. Updating Autoscaling Configuration
```bash
helm upgrade my-formbricks ./ --namespace formbricks \
--set autoscaling.enabled=true \
--set autoscaling.minReplicas=3 \
--set autoscaling.maxReplicas=10 \
--set autoscaling.metrics[0].resource.target.averageUtilization=75
### **🔹 Scaling Resources**
```sh
helm upgrade formbricks ./ -n formbricks --set deployment.resources.limits.cpu=2 --set deployment.resources.limits.memory=4Gi
```
> **Note:** Enabling autoscaling requires a Formbricks Enterprise license and proper Redis configuration.
#### 4. Changing Database Connection
```bash
helm upgrade my-formbricks ./ --namespace formbricks \
--set postgresql.enabled=false \
--set postgresql.externalUrl="postgresql://newuser:newpassword@external-postgres-host:5432/newdatabase"
### **🔹 Enabling Autoscaling**
```sh
helm upgrade formbricks ./ -n formbricks --set autoscaling.enabled=true --set autoscaling.minReplicas=3 --set autoscaling.maxReplicas=10
```
## Advanced Configuration Options
---
For advanced configurations including:
## **5⃣ Key Configuration Values**
- Deploying PostgreSQL and Redis within your Kubernetes cluster
- Configuring Traefik ingress controller
- Setting up high availability
- Customizing autoscaling behavior
| Field | Description | Default Value |
|--------------------------------|--------------------------------------|--------------|
| `deployment.replicas` | Number of application replicas | `1` |
| `deployment.image.repository` | Docker image repository | `"ghcr.io/formbricks/formbricks"` |
| `deployment.image.tag` | Docker image tag | `"latest"` |
| `autoscaling.enabled` | Enable autoscaling | `false` |
| `postgresql.enabled` | Deploy PostgreSQL in cluster | `true` |
| `postgresql.externalDatabaseUrl` | External PostgreSQL URL | `""` |
| `redis.enabled` | Deploy Redis in cluster | `true` |
| `redis.externalRedisUrl` | External Redis URL | `""` |
| `externalSecret.enabled` | Enable external secrets manager | `false` |
Please refer to the complete Helm chart documentation at:
[https://github.com/formbricks/formbricks/tree/main/helm-chart](https://github.com/formbricks/formbricks/tree/main/helm-chart)
📌 **Refer to the Helm chart repository for full configuration options.**
## Key Configuration Values
---
| Field | Description | Default |
| ------------------------- | ----------------------------- | ------------------------------- |
| `replicaCount` | Number of Formbricks replicas | `1` |
| `image.repository` | Docker image repository | `ghcr.io/formbricks/formbricks` |
| `image.tag` | Docker image tag | `"2.6.0"` |
| `resources.limits.cpu` | CPU resource limit | `500m` |
| `resources.limits.memory` | Memory resource limit | `1Gi` |
| `autoscaling.enabled` | Enable autoscaling | `false` |
| `postgresql.enabled` | Deploy PostgreSQL in cluster | `true` |
| `postgresql.externalUrl` | External PostgreSQL URL | `""` |
| `redis.enabled` | Deploy Redis in cluster | `false` |
| `redis.externalUrl` | External Redis URL | `""` |
## **6⃣ Uninstalling the Deployment**
To remove the deployment:
```sh
helm uninstall formbricks -n formbricks
```
For the complete list of configuration options, please refer to the Formbricks Helm chart repository.
### **Removing Persistent Volumes (PVCs)**
By default, **PVCs are not deleted** with Helm.
To manually remove them:
```sh
kubectl delete pvc --all -n formbricks
```
To completely delete the namespace:
```sh
kubectl delete namespace formbricks
```
---
## **📢 Additional Notes**
- **Ingress Setup:** If using an ingress controller, make sure to configure `ingress.enabled: true` in `values.yaml`.
- **Environment Variables:** Pass custom environment variables via `envFrom` in `values.yaml`.
- **Backup Strategy:** Ensure you have a backup policy for PostgreSQL if running in-cluster.
🚀 **Your Formbricks deployment is now ready!** 🚀

View File

@@ -1,12 +1,9 @@
dependencies:
- name: postgresql
repository: https://charts.bitnami.com/bitnami
version: 15.5.36
repository: oci://registry-1.docker.io/bitnamicharts
version: 16.4.16
- name: redis
repository: https://charts.bitnami.com/bitnami
version: 20.1.5
- name: traefik
repository: https://helm.traefik.io/traefik
version: 32.0.0
digest: sha256:21923a92e214351c3f96348fe0c479cc6e98e7828d75d41edc1ab73839dd39ce
generated: "2024-09-27T13:48:24.815107+03:00"
repository: oci://registry-1.docker.io/bitnamicharts
version: 20.11.2
digest: sha256:6233567e6d133fd87585de7cb11f835125ab649fc7979eac7b17d4b2881f54dc
generated: "2025-03-06T15:48:20.190945+05:30"

View File

@@ -1,19 +1,30 @@
apiVersion: v2
name: formbricks
description: A Helm chart for Formbricks with PostgreSQL, Redis, Traefik, and cert-manager
description: A Helm chart for Formbricks with PostgreSQL, Redis
type: application
version: 0.1.2
appVersion: "1.0.0"
# Helm chart Version
version: 3.3.1
appVersion: v3.3.1
keywords:
- formbricks
- postgresql
- redis
home: https://formbricks.com/docs/self-hosting/setup/kubernetes
maintainers:
- name: Formbricks
email: info@formbricks.com
dependencies:
- name: postgresql
version: 15.5.36
repository: https://charts.bitnami.com/bitnami
version: "16.4.16"
repository: "oci://registry-1.docker.io/bitnamicharts"
condition: postgresql.enabled
- name: redis
version: 20.1.5
repository: https://charts.bitnami.com/bitnami
version: 20.11.2
repository: "oci://registry-1.docker.io/bitnamicharts"
condition: redis.enabled
- name: traefik
version: 32.0.0
repository: https://helm.traefik.io/traefik
condition: traefik.enabled

View File

@@ -1,706 +1,156 @@
<div id="top"></div>
<p align="center">
<a href="https://formbricks.com">
<img width="120" alt="Open Source Privacy First Experience Management Solution Qualtrics Alternative Logo" src="https://github.com/formbricks/formbricks/assets/72809645/0086704f-bee7-4d38-9cc8-fa42ee59e004">
</a>
<h3 align="center">Formbricks</h3>
<p align="center">
Harvest user-insights, build irresistible experiences.
<br />
<a href="https://formbricks.com/">Website</a>
</p>
</p>
# Formbricks Helm Chart: Comprehensive Documentation
- [Formbricks Helm Chart: Comprehensive Documentation](#formbricks-helm-chart-comprehensive-documentation)
- [Introduction](#introduction)
- [Prerequisites](#prerequisites)
- [Chart Components](#chart-components)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Usage Examples](#usage-examples)
- [Scaling PostgreSQL and Redis](#scaling-postgresql-and-redis)
- [Configuration](#configuration)
- [Environment Variables](#environment-variables)
- [Scaling](#scaling)
- [With Auto Scaling (Kubernetes Metrics Server Requirement)](#with-auto-scaling-kubernetes-metrics-server-requirement)
- [Customizing Autoscaling](#customizing-autoscaling)
- [Kubernetes Metrics Server Requirement](#kubernetes-metrics-server-requirement)
- [Advanced Autoscaling Configuration](#advanced-autoscaling-configuration)
- [Upgrading Formbricks](#upgrading-formbricks)
- [Upgrade Process](#upgrade-process)
- [Common Upgrade Scenarios](#common-upgrade-scenarios)
- [1. Updating Environment Variables](#1-updating-environment-variables)
- [2. Enabling or Disabling Features](#2-enabling-or-disabling-features)
- [3. Scaling Resources](#3-scaling-resources)
- [4. Updating Autoscaling Configuration](#4-updating-autoscaling-configuration)
- [5. Changing Database Credentials](#5-changing-database-credentials)
- [Using a Values File for Complex Upgrades](#using-a-values-file-for-complex-upgrades)
- [Support](#support)
- [Full Values Documentation](#full-values-documentation)
- [✍️ Contribution](#-contribution)
- [MicroK8s Installation and Formbricks Deployment](#microk8s-installation-and-formbricks-deployment)
- [MicroK8s Quick Setup](#microk8s-quick-setup)
- [Deploying Formbricks on MicroK8s](#deploying-formbricks-on-microk8s)
## Introduction
This Helm chart deploys Formbricks, an advanced open-source form builder and survey tool, along with its required dependencies (PostgreSQL and Redis) on a Kubernetes cluster. It also includes an optional Traefik ingress controller for easy access and SSL termination.
## Prerequisites
Before installing the Formbricks Helm chart, ensure you have the following:
- Kubernetes cluster version 1.24 or later
- Helm version 3.2.0 or later
- Dynamic volume provisioning support in the underlying infrastructure (for PostgreSQL persistence)
- Familiarity with Kubernetes concepts and Helm charts
## Chart Components
This Helm chart deploys the following components:
1. **Formbricks Application**: The core Formbricks service.
2. **PostgreSQL Database**: (Optional) A relational database for Formbricks data.
3. **Redis**: (Optional) An in-memory data structure store for caching.
4. **Traefik Ingress Controller**: (Optional) A modern HTTP reverse proxy and load balancer.
## Installation
### Quick Start
To quickly deploy Formbricks with default settings:
1. clone the formbricks repository and navigate to the helm-chart directory:
```bash
git clone https://github.com/formbricks/formbricks.git
cd formbricks/helm-chart
```
2. Deploy Formbricks
```bash
helm install my-formbricks ./ \
--namespace formbricks \
--create-namespace \
--set replicaCount=2
```
This will deploy Formbricks with default settings, including a new PostgreSQL instance, Redis and Traefik disabled.
### Verify and Access Formbricks
After deploying Formbricks, you can verify the installation and access the application:
1. Check the Running Services:
```bash
kubectl get pods -n formbricks
kubectl get svc -n formbricks
kubectl get ingress -n formbricks
```
> **Note:** The Formbricks application pod may take some time to reach a stable state as it runs database migrations during startup.
2. Access Formbricks:
- If running locally with **Minikube**:
```bash
minikube service my-formbricks -n formbricks
```
- If deployed on a **cloud cluster**, visit:
```
https://formbricks.example.com
```
(Replace with your configured hostname)
### Usage Examples
Here are various examples of how to install and configure the Formbricks Helm chart:
1. **Default Installation with Traefik enabled and Custom Hostname**:
<details>
<summary>Option 1: Installation without SSL (Not recommended for production)</summary>
```bash
helm install my-formbricks formbricks/formbricks \
--namespace formbricks \
--create-namespace \
--set traefik.enabled=true \
--set hostname=forms.example.com
```
````
This command enables Traefik and sets a custom hostname. Replace `forms.example.com` with your actual domain name.
</details>
<details>
<summary>Option 2: Installation with SSL (Recommended for production)</summary>
1. First, download the values file:
```bash
helm show values formbricks/formbricks > values.yaml
```
2. Open the `values.yaml` file in a text editor and make the following changes:
```yaml
traefik:
enabled: true
additionalArguments:
- "--certificatesresolvers.letsencrypt.acme.email=your-email@example.com"
```
Replace `your-email@example.com` with a valid email address where you want to receive Let's Encrypt notifications.
3. Install Formbricks with the updated values file:
```bash
helm install my-formbricks formbricks/formbricks \
-f values.yaml \
--namespace formbricks \
--create-namespace \
--set hostname=forms.example.com
```
This command enables Traefik, sets a custom hostname, and uses the configured email address for Let's Encrypt. Remember to replace `forms.example.com` with your actual domain name.
</details>
These installation options provide flexibility in setting up Formbricks with Traefik. The SSL option is recommended for production environments to ensure secure communications.
2. **Community Advanced:**
Provision a whole community setup with Formbricks, Postgres, Custom Domain with SSL
```bash
helm install formbricks formbricks/formbricks \
--namespace formbricks \
--create-namespace \
--set postgres.enabled=true \
--set traefik.enabled=true \
--set hostname=forms.example.com \
--set email=your-mail@example.com
```
3. **Cluster Advanced:**
Provision a ready to use cluster for enterprise customers with Formbricks (3 pods), Postgres, Redis and Custom Domain with SSL
```bash
helm install formbricks formbricks/formbricks \
--namespace formbricks \
--create-namespace \
--set replicaCount=3
--set redis.enabled=true \
--set traefik.enabled=true \
--set hostname=forms.example.com \
--set email=your-mail@example.com
```
4. **Installation with Redis and PostgreSQL Disabled, Using External Services**:
```bash
helm install my-formbricks formbricks/formbricks \
--namespace formbricks \
--create-namespace \
--set postgresql.enabled=false \
--set postgresql.externalUrl=postgresql://user:password@your-postgres-url:5432/dbname \
--set redis.enabled=false \
--set redis.externalUrl=redis://your-redis-url:6379
```
5. **High Availability Setup**:
```bash
helm install my-formbricks formbricks/formbricks \
--namespace formbricks \
--create-namespace \
--set replicaCount=3
```
This command:
1. Deploys the Formbricks application with 3 replicas.
2. Enables PostgreSQL and Redis with default settings.
#### Scaling PostgreSQL and Redis
For advanced configuration and scaling of PostgreSQL and Redis, refer to their respective Helm chart documentation:
- PostgreSQL Helm Chart: https://github.com/bitnami/charts/tree/master/bitnami/postgresql
- Redis Helm Chart: https://github.com/bitnami/charts/tree/master/bitnami/redis
These documents provide detailed information on scaling and configuring high availability for each component.
4. **Custom Configuration with Environment Variables**:
```bash
helm install my-formbricks formbricks/formbricks \
--namespace formbricks \
--create-namespace \
--set env.SMTP_HOST=smtp.example.com \
--set env.SMTP_PORT=587 \
--set env.SMTP_USER=user@example.com \
--set env.SMTP_PASSWORD=password123 \
--set env.SMTP_AUTHENTICATED=1
```
5. **Installation with Custom Resource Limits**:
```bash
helm install my-formbricks formbricks/formbricks \
--namespace formbricks \
--create-namespace \
--set resources.limits.cpu=1 \
--set resources.limits.memory=1Gi \
--set resources.requests.cpu=500m \
--set resources.requests.memory=512Mi
```
### Configuration
For detailed configuration options, please refer to the [Full Values Documentation](#full-values-documentation) section at the end of this document.
## Environment Variables
Formbricks supports various environment variables for configuration. Here are some key variables:
| Variable | Description | Required | Default |
| ----------------- | -------------------------------- | -------- | ----------------------- |
| `WEBAPP_URL` | Base URL of the site | Yes | `http://localhost:3000` |
| `NEXTAUTH_URL` | Location of the auth server | Yes | `http://localhost:3000` |
| `DATABASE_URL` | Database URL with credentials | Yes | - |
| `NEXTAUTH_SECRET` | Secret for NextAuth | Yes | (Generated) |
| `ENCRYPTION_KEY` | Secret for data encryption | Yes | (Generated) |
| `CRON_SECRET` | API Secret for running cron jobs | Yes | (Generated) |
| `...` | ... | ... | ... |
For a comprehensive list of supported environment variables, refer to the [Formbricks Configuration Documentation](https://formbricks.com/docs/self-hosting/configuration).
## Scaling
```bash
kubectl scale deployment my-formbricks --replicas=5 -n formbricks
```
This command scales the Formbricks deployment to 5 replicas. Replace `my-formbricks` with your actual deployment name if different.
### With Auto Scaling (Kubernetes Metrics Server Requirement)
The Formbricks Helm chart includes support for Horizontal Pod Autoscaling (HPA) to automatically adjust the number of pods based on CPU utilization. This feature is enabled by default and can be customized to suit your specific needs.
```bash
helm install my-formbricks formbricks/formbricks --namespace formbricks --create-namespace \
--set autoscaling.enabled=true
```
This configuration sets up autoscaling with a minimum of 2 replicas and a maximum of 5 replicas, targeting an average CPU utilization of 80%
### Customizing Autoscaling
To adjust the autoscaling settings, you can modify the values in your `values.yaml` file or use the `--set` flag when installing or upgrading the chart. Here are some common customizations:
1. Change the minimum and maximum number of replicas:
```bash
helm install my-formbricks formbricks/formbricks \
--set autoscaling.enabled=true \
--set autoscaling.minReplicas=3 \
--set autoscaling.maxReplicas=10
```
2. Adjust the target CPU utilization:
```bash
helm install my-formbricks formbricks/formbricks \
--set autoscaling.enabled=true \
--set autoscaling.metrics[0].resource.target.averageUtilization=70
```
3. Disable autoscaling:
```bash
helm upgrade my-formbricks formbricks/formbricks \
--set autoscaling.enabled=false
```
### Kubernetes Metrics Server Requirement
For autoscaling to function properly, the Kubernetes Metrics Server must be installed in your cluster. The Metrics Server collects resource metrics from Kubelets and exposes them in the Kubernetes API server through the Metrics API.
If you don't have the Metrics Server installed, you can typically add it using the following command:
```bash
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
```
For more detailed information on installing and configuring the Metrics Server, please refer to the [official Kubernetes Metrics Server documentation](https://github.com/kubernetes-sigs/metrics-server).
### Advanced Autoscaling Configuration
The Formbricks Helm chart uses Kubernetes HPA v2, which allows for more advanced scaling behaviors. You can customize the `behavior` section in the `values.yaml` file to fine-tune how your application scales up and down. For more information on advanced HPA configurations, refer to the [Kubernetes HPA documentation](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/).
## Upgrading Formbricks
This section provides guidance on how to upgrade your Formbricks deployment using Helm, including examples of common upgrade scenarios.
### Upgrade Process
To upgrade your Formbricks deployment, use the `helm upgrade` command. Always ensure you have the latest version of the Formbricks Helm chart by running `helm repo update` before upgrading.
```bash
helm repo update
helm upgrade my-formbricks formbricks/formbricks --namespace formbricks
```
### Common Upgrade Scenarios
#### 1. Updating Environment Variables
To update or add new environment variables, use the `--set` flag with the `env` prefix:
```bash
helm upgrade my-formbricks formbricks/formbricks \
--set env.SMTP_HOST=new-smtp.example.com \
--set env.SMTP_PORT=587 \
--set env.NEW_CUSTOM_VAR=newvalue
```
This command updates the SMTP host and port, and adds a new custom environment variable.
#### 2. Enabling or Disabling Features
You can enable or disable features by updating their respective values:
```bash
# Disable Redis
helm upgrade my-formbricks formbricks/formbricks --set redis.enabled=false
# Enable Redis
helm upgrade my-formbricks formbricks/formbricks --set redis.enabled=true
```
#### 3. Scaling Resources
To adjust resource allocation:
```bash
helm upgrade my-formbricks formbricks/formbricks \
--set resources.limits.cpu=1 \
--set resources.limits.memory=2Gi \
--set resources.requests.cpu=500m \
--set resources.requests.memory=1Gi
```
#### 4. Updating Autoscaling Configuration
To modify autoscaling settings:
```bash
helm upgrade my-formbricks formbricks/formbricks \
--set autoscaling.minReplicas=3 \
--set autoscaling.maxReplicas=10 \
--set autoscaling.metrics[0].resource.target.averageUtilization=75
```
#### 5. Changing Database Credentials
To update PostgreSQL database credentials:
To switch from the built-in PostgreSQL to an external database or update the external database credentials:
```bash
helm upgrade my-formbricks formbricks/formbricks \
--set postgresql.enabled=false \
--set postgresql.externalUrl="postgresql://newuser:newpassword@external-postgres-host:5432/newdatabase"
```
This command disables the built-in PostgreSQL and configures Formbricks to use an external PostgreSQL database. Make sure your external database is set up and accessible before making this change.
### Using a Values File for Complex Upgrades
For more complex upgrades or when you need to change multiple values, it's recommended to use a values file:
1. Create a file named `upgrade-values.yaml` with your desired changes:
```yaml
env:
SMTP_HOST: new-smtp.example.com
SMTP_PORT: "587"
resources:
limits:
cpu: 1
memory: 2Gi
autoscaling:
minReplicas: 3
maxReplicas: 10
traefik:
enabled: true
postgresql:
auth:
username: newuser
password: newpassword
database: newdatabase
```
2. Apply the upgrade using the values file:
```bash
helm upgrade my-formbricks formbricks/formbricks -f upgrade-values.yaml
```
Remember to always backup your data before performing upgrades, especially when modifying database-related settings.
## Support
For support with the Formbricks Helm chart:
- Open an issue on the [Formbricks GitHub repository](https://github.com/formbricks/formbricks)
- Get help on [Github Discussions](https://github.com/formbricks/formbricks/discussions)
- For enterprise support, contact us at hola@formbricks.com
## Full Values Documentation
Below is a comprehensive list of all configurable values in the Formbricks Helm chart:
| Field | Description | Default |
| ----------------------------------------------------------- | ------------------------------------------ | ------------------------------- |
| `image.repository` | Docker image repository for Formbricks | `ghcr.io/formbricks/formbricks` |
| `image.pullPolicy` | Image pull policy | `IfNotPresent` |
| `image.tag` | Docker image tag | `"2.6.0"` |
| `service.type` | Kubernetes service type | `ClusterIP` |
| `service.port` | Kubernetes service port | `80` |
| `service.targetPort` | Container port to expose | `3000` |
| `resources.limits.cpu` | CPU resource limit | `500m` |
| `resources.limits.memory` | Memory resource limit | `1Gi` |
| `resources.requests.cpu` | Memory resource request | `null` |
| `resources.requests.memory` | Memory resource request | `null` |
| `autoscaling.enabled` | Enable autoscaling | `false` |
| `autoscaling.minReplicas` | Minimum number of replicas | `1` |
| `autoscaling.maxReplicas` | Maximum number of replicas | `5` |
| `autoscaling.metrics[0].type` | Type of metric for autoscaling | `Resource` |
| `autoscaling.metrics[0].resource.name` | Resource name for autoscaling metric | `cpu` |
| `autoscaling.metrics[0].resource.target.type` | Target type for autoscaling | `Utilization` |
| `autoscaling.metrics[0].resource.target.averageUtilization` | Average utilization target for autoscaling | `80` |
| `autoscaling.behavior.scaleDown.stabilizationWindowSeconds` | Stabilization window for scaling down | `300` |
| `autoscaling.behavior.scaleUp.stabilizationWindowSeconds` | Stabilization window for scaling up | `0` |
| `replicaCount` | Number of replicas | `1` |
| `formbricksConfig.nextAuthSecret` | NextAuth secret | `""` |
| `formbricksConfig.encryptionKey` | Encryption key | `""` |
| `formbricksConfig.cronSecret` | Cron secret | `""` |
| `env` | Additional environment variables | `{}` |
| `hostname` | Hostname for Formbricks | `""` |
| `traefik.enabled` | Enable Traefik ingress | `false` |
| `traefik.ingressRoute.dashboard.enabled` | Enable Traefik dashboard | `false` |
| `traefik.additionalArguments` | Additional arguments for Traefik | [See values.yaml] |
| `traefik.tls.enabled` | Enable TLS for Traefik | `true` |
| `traefik.tls.certResolver` | Cert resolver for Traefik | `letsencrypt` |
| `traefik.ports.web.port` | HTTP port for Traefik | `80` |
| `traefik.ports.websecure.port` | HTTPS port for Traefik | `443` |
| `traefik.persistence.enabled` | Enable persistence for Traefik | `true` |
| `traefik.persistence.size` | Size of persistent volume for Traefik | `128Mi` |
| `traefik.podSecurityContext.fsGroup` | fsGroup for Traefik pods | `0` |
| `traefik.hostNetwork` | Use host network for Traefik | `true` |
| `traefik.securityContext` | Security context for Traefik | [See values.yaml] |
| `redis.enabled` | Enable Redis | `true` |
| `redis.externalUrl` | External Redis URL | `""` |
| `redis.architecture` | Redis architecture | `standalone` |
| `redis.auth.enabled` | Enable Redis authentication | `true` |
| `redis.auth.password` | Redis password | `redispassword` |
| `redis.master.persistence.enabled` | Enable persistence for Redis master | `false` |
| `redis.replica.replicaCount` | Number of Redis replicas | `0` |
| `postgresql.enabled` | Enable PostgreSQL | `true` |
| `postgresql.externalUrl` | External PostgreSQL URL | `""` |
| `postgresql.auth.username` | PostgreSQL username | `formbricks` |
| `postgresql.auth.password` | PostgreSQL password | `formbrickspassword` |
| `postgresql.auth.database` | PostgreSQL database name | `formbricks` |
| `postgresql.primary.persistence.enabled` | Enable persistence for PostgreSQL | `true` |
| `postgresql.primary.persistence.size` | Size of persistent volume for PostgreSQL | `10Gi` |
This table provides a comprehensive overview of all configurable fields in the Formbricks Helm chart, along with their descriptions and default values. Users can refer to this table to understand what each field does and how they can customize their Formbricks deployment.
## Full Values Documentation
Below is a comprehensive list of all configurable values in the Formbricks Helm chart:
```yaml
image:
repository: ghcr.io/formbricks/formbricks
pullPolicy: IfNotPresent
tag: "2.6.0"
service:
type: ClusterIP
port: 80
targetPort: 3000
resources:
limits:
cpu: 500m
memory: 1Gi
autoscaling:
enabled: false
minReplicas: 2
maxReplicas: 5
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 80
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 100
periodSeconds: 15
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
- type: Pods
value: 4
periodSeconds: 15
selectPolicy: Max
replicaCount: 1
formbricksConfig:
nextAuthSecret: ""
encryptionKey: ""
cronSecret: ""
env: {}
hostname: ""
traefik:
enabled: false
ingressRoute:
dashboard:
enabled: false
additionalArguments:
- "--providers.file.filename=/config/traefik.toml"
tls:
enabled: true
certResolver: letsencrypt
ports:
web:
port: 80
websecure:
port: 443
tls:
enabled: true
certResolver: letsencrypt
persistence:
enabled: true
name: traefik-acme
accessMode: ReadWriteOnce
size: 128Mi
path: /data
podSecurityContext:
fsGroup: 0
hostNetwork: true
securityContext:
capabilities:
drop:
- ALL
add:
- NET_ADMIN
- NET_BIND_SERVICE
- NET_BROADCAST
- NET_RAW
runAsUser: 0
runAsGroup: 0
runAsNonRoot: false
readOnlyRootFilesystem: true
redis:
enabled: false
externalUrl: ""
architecture: standalone
auth:
enabled: true
password: redispassword
master:
persistence:
enabled: false
replica:
replicaCount: 0
postgresql:
enabled: false
externalUrl: ""
auth:
username: formbricks
password: formbrickspassword
database: formbricks
primary:
persistence:
enabled: true
size: 10Gi
```
You can customize these values by creating a `values.yaml` file or by using the `--set` flag when running `helm install` or `helm upgrade`.
## ✍️ Contribution
We are very happy if you are interested in contributing to Formbricks 🤗
Here are a few options:
- Star this repo.
- Create issues every time you feel something is missing or goes wrong.
- Upvote issues with 👍 reaction so we know what the demand for a particular issue is to prioritize it within the roadmap.
Please check out [our contribution guide](https://formbricks.com/docs/developer-docs/contributing/get-started) and our [list of open issues](https://github.com/formbricks/formbricks/issues) for more information.
## MicroK8s Installation and Formbricks Deployment
### MicroK8s Quick Setup
1. Install MicroK8s:
```bash
sudo snap install microk8s --classic
```
2. Enable necessary add-ons:
```bash
microk8s enable dns storage ingress helm3
```
### Deploying Formbricks on MicroK8s
1. Add the Formbricks Helm repository:
```bash
microk8s helm3 repo add formbricks https://charts.formbricks.com
microk8s helm3 repo update
```
2. Install Formbricks:
```bash
microk8s helm3 install my-formbricks formbricks/formbricks --namespace formbricks --create-namespace
```
For more detailed information on MicroK8s, including advanced configuration and usage, please refer to the [official MicroK8s documentation](https://microk8s.io/docs).
For Formbricks Helm chart configuration options, see the [Configuration](#configuration) and [Full Values Documentation](#full-values-documentation) sections of this document.
```
````
# formbricks
![Version: 3.3.1](https://img.shields.io/badge/Version-3.3.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v3.3.1](https://img.shields.io/badge/AppVersion-v3.3.1-informational?style=flat-square)
A Helm chart for Formbricks with PostgreSQL, Redis
**Homepage:** <https://formbricks.com/docs/self-hosting/setup/kubernetes>
## Maintainers
| Name | Email | Url |
| ---- | ------ | --- |
| Formbricks | <info@formbricks.com> | |
## Requirements
| Repository | Name | Version |
|------------|------|---------|
| oci://registry-1.docker.io/bitnamicharts | postgresql | 16.4.16 |
| oci://registry-1.docker.io/bitnamicharts | redis | 20.11.2 |
## Values
| Key | Type | Default | Description |
|-----|------|---------|-------------|
| autoscaling.additionalLabels | object | `{}` | |
| autoscaling.annotations | object | `{}` | |
| autoscaling.enabled | bool | `true` | |
| autoscaling.maxReplicas | int | `10` | |
| autoscaling.metrics[0].resource.name | string | `"cpu"` | |
| autoscaling.metrics[0].resource.target.averageUtilization | int | `60` | |
| autoscaling.metrics[0].resource.target.type | string | `"Utilization"` | |
| autoscaling.metrics[0].type | string | `"Resource"` | |
| autoscaling.metrics[1].resource.name | string | `"memory"` | |
| autoscaling.metrics[1].resource.target.averageUtilization | int | `60` | |
| autoscaling.metrics[1].resource.target.type | string | `"Utilization"` | |
| autoscaling.metrics[1].type | string | `"Resource"` | |
| autoscaling.minReplicas | int | `1` | |
| componentOverride | string | `""` | |
| cronJob.enabled | bool | `false` | |
| cronJob.jobs | object | `{}` | |
| deployment.additionalLabels | object | `{}` | |
| deployment.additionalPodAnnotations | object | `{}` | |
| deployment.additionalPodLabels | object | `{}` | |
| deployment.affinity | object | `{}` | |
| deployment.annotations | object | `{}` | |
| deployment.args | list | `[]` | |
| deployment.command | list | `[]` | |
| deployment.containerSecurityContext.readOnlyRootFilesystem | bool | `true` | |
| deployment.containerSecurityContext.runAsNonRoot | bool | `true` | |
| deployment.env.EMAIL_VERIFICATION_DISABLED.value | string | `"1"` | |
| deployment.env.PASSWORD_RESET_DISABLED.value | string | `"1"` | |
| deployment.envFrom | string | `nil` | |
| deployment.image.digest | string | `""` | |
| deployment.image.pullPolicy | string | `"IfNotPresent"` | |
| deployment.image.repository | string | `"ghcr.io/formbricks/formbricks"` | |
| deployment.imagePullSecrets | string | `""` | |
| deployment.nodeSelector | object | `{}` | |
| deployment.ports.http.containerPort | int | `3000` | |
| deployment.ports.http.exposed | bool | `true` | |
| deployment.ports.http.protocol | string | `"TCP"` | |
| deployment.ports.metrics.containerPort | int | `9464` | |
| deployment.ports.metrics.exposed | bool | `true` | |
| deployment.ports.metrics.protocol | string | `"TCP"` | |
| deployment.probes.livenessProbe.failureThreshold | int | `5` | |
| deployment.probes.livenessProbe.httpGet.path | string | `"/health"` | |
| deployment.probes.livenessProbe.httpGet.port | int | `3000` | |
| deployment.probes.livenessProbe.initialDelaySeconds | int | `10` | |
| deployment.probes.livenessProbe.periodSeconds | int | `10` | |
| deployment.probes.livenessProbe.successThreshold | int | `1` | |
| deployment.probes.livenessProbe.timeoutSeconds | int | `5` | |
| deployment.probes.readinessProbe.failureThreshold | int | `5` | |
| deployment.probes.readinessProbe.httpGet.path | string | `"/health"` | |
| deployment.probes.readinessProbe.httpGet.port | int | `3000` | |
| deployment.probes.readinessProbe.initialDelaySeconds | int | `10` | |
| deployment.probes.readinessProbe.periodSeconds | int | `10` | |
| deployment.probes.readinessProbe.successThreshold | int | `1` | |
| deployment.probes.readinessProbe.timeoutSeconds | int | `5` | |
| deployment.probes.startupProbe.failureThreshold | int | `30` | |
| deployment.probes.startupProbe.periodSeconds | int | `10` | |
| deployment.probes.startupProbe.tcpSocket.port | int | `3000` | |
| deployment.reloadOnChange | bool | `false` | |
| deployment.replicas | int | `1` | |
| deployment.resources.limits.memory | string | `"2Gi"` | |
| deployment.resources.requests.cpu | string | `"1"` | |
| deployment.resources.requests.memory | string | `"1Gi"` | |
| deployment.revisionHistoryLimit | int | `2` | |
| deployment.securityContext | object | `{}` | |
| deployment.strategy.type | string | `"RollingUpdate"` | |
| deployment.tolerations | list | `[]` | |
| deployment.topologySpreadConstraints | list | `[]` | |
| enterprise.enabled | bool | `false` | |
| enterprise.licenseKey | string | `""` | |
| externalSecret.enabled | bool | `false` | |
| externalSecret.files | object | `{}` | |
| externalSecret.refreshInterval | string | `"1h"` | |
| externalSecret.secretStore.kind | string | `"ClusterSecretStore"` | |
| externalSecret.secretStore.name | string | `"aws-secrets-manager"` | |
| ingress.annotations | object | `{}` | |
| ingress.enabled | bool | `false` | |
| ingress.hosts[0].host | string | `"k8s.formbricks.com"` | |
| ingress.hosts[0].paths[0].path | string | `"/"` | |
| ingress.hosts[0].paths[0].pathType | string | `"Prefix"` | |
| ingress.hosts[0].paths[0].serviceName | string | `"formbricks"` | |
| ingress.ingressClassName | string | `"alb"` | |
| nameOverride | string | `""` | |
| partOfOverride | string | `""` | |
| postgresql.auth.database | string | `"formbricks"` | |
| postgresql.auth.existingSecret | string | `"formbricks-app-secrets"` | |
| postgresql.auth.secretKeys.adminPasswordKey | string | `"POSTGRES_ADMIN_PASSWORD"` | |
| postgresql.auth.secretKeys.userPasswordKey | string | `"POSTGRES_USER_PASSWORD"` | |
| postgresql.auth.username | string | `"formbricks"` | |
| postgresql.enabled | bool | `true` | |
| postgresql.externalDatabaseUrl | string | `""` | |
| postgresql.fullnameOverride | string | `"formbricks-postgresql"` | |
| postgresql.global.security.allowInsecureImages | bool | `true` | |
| postgresql.image.repository | string | `"pgvector/pgvector"` | |
| postgresql.image.tag | string | `"0.8.0-pg17"` | |
| postgresql.primary.containerSecurityContext.enabled | bool | `true` | |
| postgresql.primary.containerSecurityContext.readOnlyRootFilesystem | bool | `false` | |
| postgresql.primary.containerSecurityContext.runAsUser | int | `1001` | |
| postgresql.primary.networkPolicy.enabled | bool | `false` | |
| postgresql.primary.persistence.enabled | bool | `true` | |
| postgresql.primary.persistence.size | string | `"10Gi"` | |
| postgresql.primary.podSecurityContext.enabled | bool | `true` | |
| postgresql.primary.podSecurityContext.fsGroup | int | `1001` | |
| postgresql.primary.podSecurityContext.runAsUser | int | `1001` | |
| rbac.enabled | bool | `false` | |
| rbac.serviceAccount.additionalLabels | object | `{}` | |
| rbac.serviceAccount.annotations | object | `{}` | |
| rbac.serviceAccount.enabled | bool | `false` | |
| rbac.serviceAccount.name | string | `""` | |
| redis.architecture | string | `"standalone"` | |
| redis.auth.enabled | bool | `true` | |
| redis.auth.existingSecret | string | `"formbricks-app-secrets"` | |
| redis.auth.existingSecretPasswordKey | string | `"REDIS_PASSWORD"` | |
| redis.enabled | bool | `true` | |
| redis.externalRedisUrl | string | `""` | |
| redis.fullnameOverride | string | `"formbricks-redis"` | |
| redis.master.persistence.enabled | bool | `true` | |
| redis.networkPolicy.enabled | bool | `false` | |
| secret.enabled | bool | `true` | |
| service.additionalLabels | object | `{}` | |
| service.annotations | object | `{}` | |
| service.enabled | bool | `true` | |
| service.ports | list | `[]` | |
| service.type | string | `"ClusterIP"` | |
| serviceMonitor.additionalLabels | string | `nil` | |
| serviceMonitor.annotations | string | `nil` | |
| serviceMonitor.enabled | bool | `true` | |
| serviceMonitor.endpoints[0].interval | string | `"5s"` | |
| serviceMonitor.endpoints[0].path | string | `"/metrics"` | |
| serviceMonitor.endpoints[0].port | string | `"metrics"` | |
----------------------------------------------
Autogenerated from chart metadata using [helm-docs v1.14.2](https://github.com/norwoodj/helm-docs/releases/v1.14.2)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,97 +1,161 @@
NOTES:
Thank you for installing Formbricks! Here's how you can access and manage your deployment:
1. Accessing Your Application:
{{- if .Values.traefik.enabled }}
Traefik is enabled for ingress routing.
Your application should be available at: https://{{ .Values.hostname }}
Note: Ensure your DNS is properly configured to point to your cluster's IP.
{{- else if contains "ClusterIP" .Values.service.type }}
Your application is running inside the cluster with ClusterIP service type.
To access it locally, run the following command:
kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ include "formbricks.fullname" . }} 8080:{{ .Values.service.port }}
Then visit http://localhost:8080 in your browser.
{{ .Release.Name | camelcase }} with {{ .Values.deployment.image.repository }}:{{ .Values.deployment.image.tag }} has been deployed successfully on {{ template "formbricks.namespace" .}} namespace !
Here's how you can access and manage your deployment:
---
Accessing Your Application:
{{- if .Values.ingress.enabled }}
Your application is accessible via the configured Ingress.
```sh
kubectl get ingress {{ include "formbricks.name" . }} -n {{ .Release.Namespace }} -o jsonpath='{.items[*].spec.rules[*].host}' | tr ' ' '\n'
```
Ensure that your DNS points to the cluster's Ingress Controller.
{{- else if contains "LoadBalancer" .Values.service.type }}
Your application is exposed via a LoadBalancer.
Run the following to get the external IP:
```sh
kubectl get svc {{ include "formbricks.name" . }} -n {{ .Release.Namespace }}
```
{{- else if contains "NodePort" .Values.service.type }}
Your application is accessible via NodePort.
Run the following to get the assigned port:
```sh
kubectl get svc {{ include "formbricks.name" . }} -n {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}"
```
Then access the service at: `http://<NodeIP>:<NodePort>`
{{- else }}
Your application is running inside the cluster (ClusterIP service type).
To access it locally, run:
```sh
kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ include "formbricks.name" . }} 3000
```
Then visit: **http://localhost:3000**
{{- end }}
2. Database (PostgreSQL) Access:
---
Database (PostgreSQL) Access:
{{- if .Values.postgresql.enabled }}
PostgreSQL is deployed within your cluster.
To get the PostgreSQL password, run:
kubectl get secret --namespace {{ .Release.Namespace }} {{ .Release.Name }}-postgresql -o jsonpath="{.data.postgres-password}" | base64 --decode
Database connection details:
- Host: {{ .Release.Name }}-postgresql
- Port: 5432
- Database: {{ .Values.postgresql.auth.database }}
- Username: {{ .Values.postgresql.auth.username }}
{{- else if .Values.postgresql.externalUrl }}
Retrieve the password using:
```sh
kubectl get secret --namespace {{ .Release.Namespace }} {{ include "formbricks.name" . }}-app-secrets -o jsonpath="{.data.POSTGRES_USER_PASSWORD}" | base64 --decode
```
Connection details:
- **Host**: `{{ include "formbricks.name" . }}-postgresql`
- **Port**: `5432`
- **Database**: `{{ .Values.postgresql.auth.database }}`
- **Username**: `{{ .Values.postgresql.auth.username }}`
{{- else if .Values.postgresql.externalDatabaseUrl }}
You're using an external PostgreSQL database.
Connection URL: {{ .Values.postgresql.externalUrl }}
Connection URL:
```sh
echo "{{ .Values.postgresql.externalDatabaseUrl }}"
```
{{- end }}
3. Redis Access:
---
Redis Access:
{{- if .Values.redis.enabled }}
Redis is deployed within your cluster.
To get the Redis password, run:
kubectl get secret --namespace {{ .Release.Namespace }} {{ .Release.Name }}-redis -o jsonpath="{.data.redis-password}" | base64 --decode
Redis connection details:
- Host: {{ .Release.Name }}-redis-master
- Port: 6379
{{- else if .Values.redis.externalUrl }}
Retrieve the password using:
```sh
kubectl get secret --namespace {{ .Release.Namespace }} {{ include "formbricks.name" . }}-app-secrets -o jsonpath="{.data.REDIS_PASSWORD}" | base64 --decode
```
Connection details:
- **Host**: `{{ include "formbricks.name" . }}-redis-master`
- **Port**: `6379`
{{- else if .Values.redis.externalRedisUrl }}
You're using an external Redis instance.
Connection URL: {{ .Values.redis.externalUrl }}
Connection URL:
```sh
echo "{{ .Values.redis.externalRedisUrl }}"
```
{{- else }}
Redis is not enabled in your current configuration.
Redis is not enabled in this deployment.
{{- end }}
4. Environment Variables:
The following environment variables have been automatically generated:
- NEXTAUTH_SECRET: A random 32-character string
- ENCRYPTION_KEY: A random 32-character string
- CRON_SECRET: A random 32-character string
---
To view these secrets, run:
kubectl get secret --namespace {{ .Release.Namespace }} {{ include "formbricks.fullname" . }}-secrets -o jsonpath="{.data.NEXTAUTH_SECRET}" | base64 --decode
kubectl get secret --namespace {{ .Release.Namespace }} {{ include "formbricks.fullname" . }}-secrets -o jsonpath="{.data.ENCRYPTION_KEY}" | base64 --decode
kubectl get secret --namespace {{ .Release.Namespace }} {{ include "formbricks.fullname" . }}-secrets -o jsonpath="{.data.CRON_SECRET}" | base64 --decode
Environment Variables:
The following environment variables have been automatically generated:
- `NEXTAUTH_SECRET`: A random 32-character string
- `ENCRYPTION_KEY`: A random 32-character string
- `CRON_SECRET`: A random 32-character string
- 'EMAIL_VERIFICATION_DISABLED': 1 # By Default email verification is disabled, configure SMTP settings to enable(https://formbricks.com/docs/self-hosting/configuration/smtp)
- 'PASSWORD_RESET_DISABLED': 1 # By Default password reset is disabled, configure SMTP settings to enable(https://formbricks.com/docs/self-hosting/configuration/smtp)
Retrieve them using:
```sh
kubectl get secret --namespace {{ .Release.Namespace }} {{ include "formbricks.name" . }}-app-secrets -o jsonpath="{.data.NEXTAUTH_SECRET}" | base64 --decode
kubectl get secret --namespace {{ .Release.Namespace }} {{ include "formbricks.name" . }}-app-secrets -o jsonpath="{.data.ENCRYPTION_KEY}" | base64 --decode
kubectl get secret --namespace {{ .Release.Namespace }} {{ include "formbricks.name" . }}-app-secrets -o jsonpath="{.data.CRON_SECRET}" | base64 --decode
```
---
Scaling:
5. Scaling:
{{- if .Values.autoscaling.enabled }}
Horizontal Pod Autoscaling is enabled.
- Minimum replicas: {{ .Values.autoscaling.minReplicas }}
- Maximum replicas: {{ .Values.autoscaling.maxReplicas }}
- Target CPU utilization: {{ .Values.autoscaling.metrics.averageUtilization }}%
To check the current status of the HPA, run:
kubectl get hpa -n {{ .Release.Namespace }} {{ include "formbricks.fullname" . }}
Horizontal Pod Autoscaling (HPA) is enabled.
- **Min Replicas**: `{{ .Values.autoscaling.minReplicas }}`
- **Max Replicas**: `{{ .Values.autoscaling.maxReplicas }}`
Check HPA status:
```sh
kubectl get hpa -n {{ .Release.Namespace }} {{ include "formbricks.name" . }}
```
{{- else }}
Horizontal Pod Autoscaling is not enabled. Your deployment has a fixed number of {{ .Values.replicaCount }} replicas.
To scale manually, use:
kubectl scale deployment -n {{ .Release.Namespace }} {{ include "formbricks.fullname" . }} --replicas=<desired_number>
HPA is **not enabled**. Your deployment has a fixed number of `{{ .Values.replicaCount }}` replicas.
Manually scale using:
```sh
kubectl scale deployment -n {{ .Release.Namespace }} {{ include "formbricks.name" . }} --replicas=<desired_number>
```
{{- end }}
6. Persistence:
- PostgreSQL data is persisted with a {{ .Values.postgresql.primary.persistence.size }} storage.
---
External Secrets:
{{- if .Values.externalSecret.enabled }}
External secrets are enabled.
Ensure that your `SecretStore` or `ClusterSecretStore` is configured properly.
- Secret Store Name: `{{ .Values.externalSecret.secretStore.name }}`
- Refresh Interval: `{{ .Values.externalSecret.refreshInterval }}`
Verify the external secret:
```sh
kubectl get externalsecrets -n {{ .Release.Namespace }}
```
{{- else }}
External secrets are **not enabled**.
{{- end }}
---
Persistence:
{{- if .Values.postgresql.enabled }}
PostgreSQL data is persisted with `{{ .Values.postgresql.primary.persistence.size }}` storage.
{{- end }}
{{- if .Values.redis.enabled }}
- Redis data is not persisted (persistence is disabled).
Redis data is persisted with `{{ .Values.redis.master.persistence.size }}` storage..
{{- end }}
7. Traefik Configuration:
{{- if .Values.traefik.enabled }}
Traefik is configured with the following settings:
- TLS enabled with Let's Encrypt
- HTTP to HTTPS redirect enabled
- ACME challenge type: HTTP
- Entrypoints: web (80) and websecure (443)
{{- else }}
Traefik is not enabled in your current configuration.
{{- end }}
---
8. Formbricks Documentation and Support:
For more information, advanced configuration options, and support, please visit:
- Official Formbricks website: https://formbricks.com
- Documentation: https://formbricks.com/docs
Formbricks Documentation and Support:
If you encounter any issues or have questions, please refer to the Formbricks documentation
or reach out to the Formbricks community for support.
For more information, advanced configurations, and support, visit:
- **Official Website**: https://formbricks.com
- **Documentation**: https://formbricks.com/docs
For troubleshooting, refer to the documentation or community support.
---

View File

@@ -1,51 +1,141 @@
{{/*
Expand the name of the chart.
This function ensures that the chart name is either taken from `nameOverride` or defaults to `.Chart.Name`.
It also truncates the name to a maximum of 63 characters and removes trailing hyphens.
*/}}
{{- define "formbricks.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).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "formbricks.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
Define the application version to be used in labels.
The version is taken from `.Values.deployment.image.tag` if provided, otherwise it defaults to `.Chart.Version`.
It ensures the version only contains alphanumeric characters, underscores, dots, or hyphens, replacing any invalid characters with a hyphen.
*/}}
{{- define "formbricks.version" -}}
{{- $appVersion := default .Chart.Version .Values.deployment.image.tag -}}
{{- regexReplaceAll "[^a-zA-Z0-9_\\.\\-]" $appVersion "-" | trunc 63 | trimSuffix "-" -}}
{{- end }}
{{/*
Generate a chart name and version string to be used in Helm chart labels.
This follows the format: `<ChartName>-<ChartVersion>`, replacing `+` with `_` and truncating to 63 characters.
*/}}
{{- define "formbricks.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
Common labels applied to Kubernetes resources.
These labels help identify and manage the application.
*/}}
{{- define "formbricks.labels" -}}
helm.sh/chart: {{ include "formbricks.chart" . }}
# Selector labels
{{ include "formbricks.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
# Application version label
{{- with include "formbricks.version" . }}
app.kubernetes.io/version: {{ . | quote }}
{{- end }}
# Managed by Helm
app.kubernetes.io/managed-by: {{ .Release.Service }}
# Part of label, defaults to the chart name if `partOfOverride` is not provided.
app.kubernetes.io/part-of: {{ .Values.partOfOverride | default (include "formbricks.name" .) }}
{{- end }}
{{/*
Selector labels
Selector labels used for identifying workloads in Kubernetes.
These labels ensure that selectors correctly map to the deployed resources.
*/}}
{{- define "formbricks.selectorLabels" -}}
app.kubernetes.io/name: {{ include "formbricks.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/component: {{ .Values.componentOverride | default (include "formbricks.name" .) }}
{{- end }}
{{/*
Renders a value that contains a Helm template.
Usage:
{{ include "formbricks.tplvalues.render" ( dict "value" .Values.path.to.the.Value "context" $) }}
This function allows rendering values dynamically.
*/}}
{{- define "formbricks.tplvalues.render" -}}
{{- if typeIs "string" .value }}
{{- tpl .value .context }}
{{- else }}
{{- tpl (.value | toYaml) .context }}
{{- end }}
{{- end }}
{{/*
Allow the release namespace to be overridden.
If `namespaceOverride` is provided, it will be used; otherwise, it defaults to `.Release.Namespace`.
*/}}
{{- define "formbricks.namespace" -}}
{{- default .Release.Namespace .Values.namespaceOverride -}}
{{- end -}}
{{- define "formbricks.postgresAdminPassword" -}}
{{- $secret := (lookup "v1" "Secret" .Release.Namespace (printf "%s-app-secrets" (include "formbricks.name" .))) }}
{{- if and $secret (index $secret.data "POSTGRES_ADMIN_PASSWORD") }}
{{- index $secret.data "POSTGRES_ADMIN_PASSWORD" | b64dec -}}
{{- else }}
{{- randAlphaNum 16 -}}
{{- end -}}
{{- end }}
{{- define "formbricks.postgresUserPassword" -}}
{{- $secret := (lookup "v1" "Secret" .Release.Namespace (printf "%s-app-secrets" (include "formbricks.name" .))) }}
{{- if and $secret (index $secret.data "POSTGRES_USER_PASSWORD") }}
{{- index $secret.data "POSTGRES_USER_PASSWORD" | b64dec -}}
{{- else }}
{{- randAlphaNum 16 -}}
{{- end -}}
{{- end }}
{{- define "formbricks.redisPassword" -}}
{{- $secret := (lookup "v1" "Secret" .Release.Namespace (printf "%s-app-secrets" (include "formbricks.name" .))) }}
{{- if and $secret (index $secret.data "REDIS_PASSWORD") }}
{{- index $secret.data "REDIS_PASSWORD" | b64dec -}}
{{- else }}
{{- randAlphaNum 16 -}}
{{- end -}}
{{- end }}
{{- define "formbricks.cronSecret" -}}
{{- $secret := (lookup "v1" "Secret" .Release.Namespace (printf "%s-app-secrets" (include "formbricks.name" .))) }}
{{- if $secret }}
{{- index $secret.data "CRON_SECRET" | b64dec -}}
{{- else }}
{{- randAlphaNum 32 -}}
{{- end -}}
{{- end }}
{{- define "formbricks.encryptionKey" -}}
{{- $secret := (lookup "v1" "Secret" .Release.Namespace (printf "%s-app-secrets" (include "formbricks.name" .))) }}
{{- if $secret }}
{{- index $secret.data "ENCRYPTION_KEY" | b64dec -}}
{{- else }}
{{- randAlphaNum 32 -}}
{{- end -}}
{{- end }}
{{- define "formbricks.nextAuthSecret" -}}
{{- $secret := (lookup "v1" "Secret" .Release.Namespace (printf "%s-app-secrets" (include "formbricks.name" .))) }}
{{- if $secret }}
{{- index $secret.data "NEXTAUTH_SECRET" | b64dec -}}
{{- else }}
{{- randAlphaNum 32 -}}
{{- end -}}
{{- end }}

View File

@@ -0,0 +1,102 @@
{{- if (.Values.cronJob).enabled }}
{{- range $name, $job := .Values.cronJob.jobs }}
---
apiVersion: {{ if $.Capabilities.APIVersions.Has "batch/v1/CronJob" }}batch/v1{{ else }}batch/v1beta1{{ end }}
kind: CronJob
metadata:
name: {{ $name }}
labels:
# Standard labels for tracking CronJobs
{{- include "formbricks.labels" $ | nindent 4 }}
# Additional labels if specified
{{- if $job.additionalLabels }}
{{- toYaml $job.additionalLabels | indent 4 }}
{{- end }}
# Additional annotations if specified
{{- if $job.annotations }}
annotations:
{{- toYaml $job.annotations | indent 4 }}
{{- end }}
spec:
# Define the execution schedule for the job
schedule: {{ $job.schedule | quote }}
# Kubernetes 1.27+ supports time zones for CronJobs
{{- if ge (int $.Capabilities.KubeVersion.Minor) 27 }}
{{- if $job.timeZone }}
timeZone: {{ $job.timeZone }}
{{- end }}
{{- end }}
# Define job retention policies
{{- if $job.successfulJobsHistoryLimit }}
successfulJobsHistoryLimit: {{ $job.successfulJobsHistoryLimit }}
{{- end }}
{{- if $job.failedJobsHistoryLimit }}
failedJobsHistoryLimit: {{ $job.failedJobsHistoryLimit }}
{{- end }}
# Define concurrency policy
{{- if $job.concurrencyPolicy }}
concurrencyPolicy: {{ $job.concurrencyPolicy }}
{{- end }}
jobTemplate:
spec:
{{- with $job.activeDeadlineSeconds }}
activeDeadlineSeconds: {{ . }}
{{- end }}
{{- if not (kindIs "invalid" $job.backoffLimit) }}
backoffLimit: {{ $job.backoffLimit }}
{{- end }}
template:
metadata:
labels:
{{- include "formbricks.labels" $ | nindent 12 }}
# Additional pod-level labels
{{- with $job.additionalPodLabels }}
{{- toYaml . | nindent 12 }}
{{- end }}
# Additional annotations
{{- with $job.additionalPodAnnotations }}
annotations: {{- toYaml . | nindent 12 }}
{{- end }}
spec:
# Define the service account if RBAC is enabled
{{- if $.Values.rbac.enabled }}
serviceAccountName: {{ template "formbricks.name" $ }}
{{- end }}
# Define the job container
containers:
- name: {{ $name }}
image: "{{ required "Image repository is undefined" $job.image.repository }}:{{ $job.image.tag | default "latest" }}"
imagePullPolicy: {{ $job.image.imagePullPolicy | default "IfNotPresent" }}
# Environment variables from values
{{- with $job.env }}
env:
{{- range $key, $value := $job.env }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}
{{- end }}
# Define command and arguments if specified
{{- with $job.command }}
command: {{- toYaml . | indent 14 }}
{{- end }}
{{- with $job.args }}
args: {{- toYaml . | indent 14 }}
{{- end }}
restartPolicy: {{ $job.restartPolicy | default "OnFailure" }}
{{- end }}
{{- end }}

View File

@@ -1,34 +1,182 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "formbricks.fullname" . }}
name: {{ include "formbricks.name" . }}
labels:
{{- include "formbricks.labels" . | nindent 4 }}
{{- if .Values.deployment.additionalLabels }}
{{- toYaml .Values.deployment.additionalLabels | nindent 4 }}
{{- end }}
{{- if or .Values.deployment.annotations .Values.deployment.reloadOnChange }}
annotations:
{{- if .Values.deployment.annotations }}
{{- toYaml .Values.deployment.annotations | nindent 4 }}
{{- end }}
{{- end }}
spec:
replicas: {{ .Values.replicaCount }}
{{- if .Values.deployment.replicas }}
replicas: {{ .Values.deployment.replicas }}
{{- end }}
selector:
matchLabels:
{{- include "formbricks.selectorLabels" . | nindent 6 }}
{{- if .Values.deployment.strategy }}
strategy:
{{- toYaml .Values.deployment.strategy | nindent 4 }}
{{- end }}
{{- if not (kindIs "invalid" .Values.deployment.revisionHistoryLimit) }}
revisionHistoryLimit: {{ .Values.deployment.revisionHistoryLimit }}
{{- end }}
template:
metadata:
labels:
{{- include "formbricks.selectorLabels" . | nindent 8 }}
{{- if .Values.deployment.additionalPodLabels }}
{{- toYaml .Values.deployment.additionalPodLabels | nindent 8 }}
{{- end }}
{{- if .Values.deployment.disableIstioInject }}
sidecar.istio.io/inject: "false"
{{- end }}
{{- if .Values.deployment.additionalPodAnnotations }}
annotations:
{{- toYaml .Values.deployment.additionalPodAnnotations | nindent 8 }}
{{- end }}
spec:
{{- if .Values.deployment.nodeSelector }}
nodeSelector:
{{- toYaml .Values.deployment.nodeSelector | nindent 8 }}
{{- end }}
{{- if .Values.deployment.tolerations }}
tolerations:
{{- toYaml .Values.deployment.tolerations | nindent 8 }}
{{- end }}
{{- if .Values.deployment.affinity }}
affinity:
{{- toYaml .Values.deployment.affinity | nindent 8 }}
{{- end }}
{{- if .Values.deployment.topologySpreadConstraints }}
topologySpreadConstraints:
{{- toYaml .Values.deployment.topologySpreadConstraints | nindent 10 }}
{{- end }}
{{- if .Values.deployment.imagePullSecrets }}
imagePullSecrets:
{{- toYaml .Values.deployment.imagePullSecrets | nindent 8 }}
{{- end }}
{{- if .Values.deployment.hostNetwork }}
hostNetwork: true
{{- end }}
{{- if .Values.rbac.serviceAccount.enabled }}
serviceAccountName: {{ .Values.rbac.serviceAccount.name | default (include "formbricks.name" .) }}
{{- end }}
{{- if .Values.deployment.securityContext }}
securityContext:
{{ toYaml .Values.deployment.securityContext | indent 8 }}
{{- end }}
terminationGracePeriodSeconds: {{ .Values.deployment.terminationGracePeriodSeconds | default 30 }}
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
- name: {{ template "formbricks.name" . }}
image: "{{ .Values.deployment.image.repository }}:{{ .Values.deployment.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.deployment.image.pullPolicy }}
{{- if .Values.deployment.command }}
command:
{{- toYaml .Values.deployment.command | nindent 12 }}
{{- end }}
{{- if .Values.deployment.args }}
args:
{{- toYaml .Values.deployment.args | nindent 12 }}
{{- end }}
{{- if .Values.deployment.ports }}
ports:
- name: http
containerPort: 3000
protocol: TCP
envFrom:
- secretRef:
name: {{ include "formbricks.fullname" . }}-secrets
env:
{{- range $key, $value := .Values.env }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- range $name, $config := .Values.deployment.ports }}
- name: {{ $name | quote }}
containerPort: {{ $config.containerPort | default $config.port }}
protocol: {{ $config.protocol | default "TCP" | quote }}
{{- end }}
{{- end }}
{{- if .Values.deployment.envFrom }}
envFrom:
{{- range $value := .Values.deployment.envFrom }}
{{- if (eq .type "configmap") }}
- configMapRef:
{{- if .name }}
name: {{ include "formbricks.tplvalues.render" ( dict "value" $value.name "context" $ ) }}
{{- else if .nameSuffix }}
name: {{ template "formbricks.name" $ }}-{{ include "formbricks.tplvalues.render" ( dict "value" $value.nameSuffix "context" $ ) }}
{{- else }}
name: {{ template "formbricks.name" $ }}
{{- end }}
{{- end }}
{{- if (eq .type "secret") }}
- secretRef:
{{- if .name }}
name: {{ include "formbricks.tplvalues.render" ( dict "value" $value.name "context" $ ) }}
{{- else if .nameSuffix }}
name: {{ template "formbricks.name" $ }}-{{ include "formbricks.tplvalues.render" ( dict "value" $value.nameSuffix "context" $ ) }}
{{- else }}
name: {{ template "formbricks.name" $ }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
env:
{{- if and (.Values.enterprise.enabled) (ne .Values.enterprise.licenseKey "") }}
- name: ENTERPRISE_LICENSE_KEY
valueFrom:
secretKeyRef:
name: {{ template "formbricks.name" . }}-app-secrets
key: ENTERPRISE_LICENSE_KEY
{{- else if and (.Values.enterprise.enabled) (eq .Values.enterprise.licenseKey "") }}
- name: ENTERPRISE_LICENSE_KEY
valueFrom:
secretKeyRef:
name: {{ template "formbricks.name" . }}-app-secrets
key: ENTERPRISE_LICENSE_KEY
{{- end }}
- name: REDIS_URL
valueFrom:
secretKeyRef:
name: {{ template "formbricks.name" . }}-app-secrets
key: REDIS_URL
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: {{ template "formbricks.name" . }}-app-secrets
key: DATABASE_URL
- name: CRON_SECRET
valueFrom:
secretKeyRef:
name: {{ template "formbricks.name" . }}-app-secrets
key: CRON_SECRET
- name: ENCRYPTION_KEY
valueFrom:
secretKeyRef:
name: {{ template "formbricks.name" . }}-app-secrets
key: ENCRYPTION_KEY
- name: NEXTAUTH_SECRET
valueFrom:
secretKeyRef:
name: {{ template "formbricks.name" . }}-app-secrets
key: NEXTAUTH_SECRET
{{- range $key, $value := .Values.deployment.env }}
- name: {{ include "formbricks.tplvalues.render" ( dict "value" $key "context" $ ) }}
{{ include "formbricks.tplvalues.render" ( dict "value" $value "context" $ ) | indent 10 }}
{{- end }}
{{- if .Values.deployment.resources }}
resources:
{{- toYaml .Values.resources | nindent 12 }}
{{- toYaml .Values.deployment.resources | nindent 12 }}
{{- end }}
{{- with .Values.deployment.probes }}
{{- if .livenessProbe }}
livenessProbe:
{{- toYaml .livenessProbe | nindent 12 }}
{{- end }}
{{- if .readinessProbe }}
readinessProbe:
{{- toYaml .readinessProbe | nindent 12 }}
{{- end }}
{{- if .startupProbe }}
startupProbe:
{{- toYaml .startupProbe | nindent 12 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,52 @@
{{- if (.Values.externalSecret).enabled }}
{{- range $nameSuffix, $data := .Values.externalSecret.files }}
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: {{ template "formbricks.name" $ }}-{{ $nameSuffix }}
labels:
{{- include "formbricks.labels" $ | nindent 4 }}
spec:
refreshInterval: {{ $.Values.externalSecret.refreshInterval }}
{{- if and (not $data.data) (not $data.dataFrom) }}
{{- fail "Data or datafrom not specified for secret {{ template 'formbricks.name' $ }}-{{ $nameSuffix }} " }}
{{- end }}
{{- if $data.data }}
data:
{{- range $secretKey, $remoteRef := $data.data}}
- secretKey: {{ $secretKey }}
{{ toYaml $remoteRef | indent 6}}
{{- end }}
{{- end }}
{{- if $data.dataFrom }}
dataFrom:
- extract:
{{ toYaml $data.dataFrom | indent 6 }}
{{- end }}
{{- if $data.secretStore }}
secretStoreRef:
name: {{ $data.secretStore.name }}
kind: {{ $data.secretStore.kind | default "SecretStore" }}
{{- else }}
secretStoreRef:
name: {{ $.Values.externalSecret.secretStore.name }}
kind: {{ $.Values.externalSecret.secretStore.kind | default "SecretStore" }}
{{- end}}
target:
name: {{ template "formbricks.name" $ }}-{{ $nameSuffix }}
template:
type: {{ $data.type | default "Opaque" }}
{{- if or $data.annotations $data.labels}}
metadata:
{{- if $data.annotations }}
annotations:
{{ toYaml $data.annotations | indent 10 }}
{{- end }}
{{- if $data.labels }}
labels:
{{ toYaml $data.labels | indent 10 }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -1,39 +1,33 @@
{{- if .Values.autoscaling.enabled }}
---
{{- if .Capabilities.APIVersions.Has "autoscaling/v2/HorizontalPodAutoscaler" }}
apiVersion: autoscaling/v2
{{- else }}
apiVersion: autoscaling/v2beta2
{{- end }}
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "formbricks.fullname" . }}
name: {{ template "formbricks.name" . }}
labels:
{{- include "formbricks.labels" . | nindent 4 }}
{{- with .Values.autoscaling.additionalLabels }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- if .Values.autoscaling.annotations }}
annotations:
{{- toYaml .Values.autoscaling.annotations | nindent 4 }}
{{- end }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "formbricks.fullname" . }}
name: {{ template "formbricks.name" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- toYaml .Values.autoscaling.metrics | nindent 4 }}
{{- if .Values.autoscaling.behavior }}
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 100
periodSeconds: 15
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
- type: Pods
value: 4
periodSeconds: 15
selectPolicy: Max
{{- end }}
{{- toYaml .Values.autoscaling.behavior | nindent 4 }}
{{- end }}
{{- end }}

View File

@@ -1,23 +1,45 @@
{{- if .Values.traefik.enabled -}}
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
{{- if (.Values.ingress).enabled -}}
{{- $applicationNameTpl := include "formbricks.name" . -}}
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "formbricks.fullname" . }}
name: {{ template "formbricks.name" . }}
namespace: {{ include "formbricks.namespace" . }}
labels:
{{- include "formbricks.labels" . | nindent 4 }}
{{- with .Values.traefik.ingressRoute.annotations }}
{{- include "formbricks.labels" $ | nindent 4 }}
{{- if .Values.ingress.additionalLabels }}
{{ toYaml .Values.ingress.additionalLabels | indent 4 }}
{{- end }}
{{- if .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{ toYaml .Values.ingress.annotations | indent 4 }}
{{- end }}
spec:
entryPoints:
- websecure
routes:
- match: Host(`{{ .Values.hostname }}`)
kind: Rule
services:
- name: {{ include "formbricks.fullname" . }}
port: {{ .Values.service.port }}
{{- if .Values.ingress.ingressClassName }}
ingressClassName: {{ .Values.ingress.ingressClassName }}
{{- end}}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ tpl .host $ }}
http:
paths:
{{- if .paths }}
{{- range .paths }}
- path: {{ .path }}
pathType: {{ default "ImplementationSpecific" (.pathType) }}
backend:
service:
name: {{ default $applicationNameTpl (.serviceName) }}
port:
name: {{ default "http" (.servicePort) }}
{{- end }}
{{- else }}
{{ fail "Specify paths for ingress host, check values.yaml" }}
{{- end }}
{{- end -}}
{{- if .Values.ingress.tls }}
tls:
certResolver: letsencrypt
{{- end }}
{{ include "formbricks.tplvalues.render" (dict "value" .Values.ingress.tls "context" $) | indent 3 }}
{{- end -}}
{{- end -}}

View File

@@ -1,19 +1,37 @@
{{- if and (.Values.secret) (.Values.secret.enabled) }}
{{- $postgresAdminPassword := include "formbricks.postgresAdminPassword" . }}
{{- $postgresUserPassword := include "formbricks.postgresUserPassword" . }}
{{- $redisPassword := include "formbricks.redisPassword" . }}
---
apiVersion: v1
kind: Secret
metadata:
name: {{ include "formbricks.fullname" . }}-secrets
type: Opaque
stringData:
{{- if .Values.postgresql.externalUrl }}
DATABASE_URL: {{ .Values.postgresql.externalUrl }}
{{- else if .Values.postgresql.enabled }}
DATABASE_URL: postgresql://{{ .Values.postgresql.auth.username }}:{{ .Values.postgresql.auth.password }}@{{ .Release.Name }}-postgresql:5432/{{ .Values.postgresql.auth.database }}
name: {{ template "formbricks.name" . }}-app-secrets
labels:
{{- include "formbricks.labels" . | nindent 4 }}
data:
{{- if .Values.redis.enabled }}
REDIS_URL: {{ printf "redis://:%s@formbricks-redis-master:6379" $redisPassword | b64enc }}
{{- else }}
REDIS_URL: {{ .Values.redis.externalRedisUrl | b64enc }}
{{- end }}
{{- if .Values.redis.externalUrl }}
REDIS_URL: {{ .Values.redis.externalUrl }}
{{- else if .Values.redis.enabled }}
REDIS_URL: redis://:{{ .Values.redis.auth.password }}@{{ .Release.Name }}-redis-master:6379
{{- if .Values.postgresql.enabled }}
DATABASE_URL: {{ printf "postgresql://formbricks:%s@formbricks-postgresql/formbricks" $postgresUserPassword | b64enc }}
{{- else }}
DATABASE_URL: {{ .Values.postgresql.externalDatabaseUrl | b64enc }}
{{- end }}
NEXTAUTH_SECRET: {{ .Values.formbricksConfig.nextAuthSecret | default (randAlphaNum 32) | quote }}
ENCRYPTION_KEY: {{ .Values.formbricksConfig.encryptionKey | default (randAlphaNum 32) | quote }}
CRON_SECRET: {{ .Values.formbricksConfig.cronSecret | default (randAlphaNum 32) | quote }}
CRON_SECRET: {{ include "formbricks.cronSecret" . | b64enc }}
ENCRYPTION_KEY: {{ include "formbricks.encryptionKey" . | b64enc }}
NEXTAUTH_SECRET: {{ include "formbricks.nextAuthSecret" . | b64enc }}
{{- if and (.Values.enterprise.licenseKey) (ne .Values.enterprise.licenseKey "") }}
ENTERPRISE_LICENSE_KEY: {{ .Values.enterprise.licenseKey | b64enc }}
{{- end }}
{{- if .Values.redis.enabled }}
REDIS_PASSWORD: {{ $redisPassword | b64enc }}
{{- end }}
{{- if .Values.postgresql.enabled }}
POSTGRES_ADMIN_PASSWORD: {{ $postgresAdminPassword | b64enc }}
POSTGRES_USER_PASSWORD: {{ $postgresUserPassword | b64enc }}
{{- end }}
{{- end }}

View File

@@ -1,15 +1,55 @@
{{- if (.Values.service).enabled }}
---
apiVersion: v1
kind: Service
metadata:
name: {{ include "formbricks.fullname" . }}
name: {{ template "formbricks.name" . }}
labels:
# Standard labels for tracking the service
{{- include "formbricks.labels" . | nindent 4 }}
# Additional labels from values
{{- if .Values.service.additionalLabels }}
{{- toYaml .Values.service.additionalLabels | nindent 4 }}
{{- end }}
# Annotations for service configuration
{{- if .Values.service.annotations }}
annotations:
{{- include "formbricks.tplvalues.render" ( dict "value" .Values.service.annotations "context" $ ) | nindent 4 }}
{{- end }}
spec:
# Define the service type (ClusterIP, NodePort, LoadBalancer)
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: {{ .Values.service.targetPort | default 3000 }}
protocol: TCP
name: http
# Define how the service selects pods
selector:
{{- include "formbricks.selectorLabels" . | nindent 4 }}
{{- include "formbricks.selectorLabels" . | nindent 4 }}
# Include additional pod labels if defined
{{- if .Values.deployment.podLabels }}
{{- toYaml .Values.deployment.podLabels | nindent 4 }}
{{- end }}
# Define the exposed service ports
ports:
{{- range $name, $config := .Values.deployment.ports }}
{{- if $config.exposed }}
- name: {{ $name }}
protocol: {{ default "TCP" $config.protocol | quote }}
port: {{ default $config.port $config.containerPort }}
targetPort: {{ default $config.port $config.containerPort }}
# Define NodePort if service type is NodePort
{{- if $config.nodePort }}
nodePort: {{ $config.nodePort }}
{{- end }}
{{- end }}
{{- end }}
# Include additional manually defined service ports
{{- if .Values.service.ports }}
{{- toYaml .Values.service.ports | nindent 4 }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,22 @@
{{- if and .Values.rbac.enabled .Values.rbac.serviceAccount.enabled }}
---
apiVersion: v1
kind: ServiceAccount
metadata:
# Define the ServiceAccount name, either from values or generated
name: {{ default (include "formbricks.name" .) .Values.rbac.serviceAccount.name }}
labels:
# Standard labels for tracking the service account
{{- include "formbricks.labels" . | nindent 4 }}
# Additional labels if provided
{{- with .Values.rbac.serviceAccount.additionalLabels }}
{{- toYaml . | nindent 4 }}
{{- end }}
# Optional annotations for the service account
annotations:
{{- with .Values.rbac.serviceAccount.annotations }}
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View File

@@ -1,15 +0,0 @@
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "formbricks.fullname" . }}-test-connection"
labels:
{{- include "formbricks.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "formbricks.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: Never

View File

@@ -1,8 +0,0 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: traefik-config
data:
traefik.toml: |
[certificatesResolvers.letsencrypt.acme]
email = {{ .Values.email }}

View File

@@ -1,148 +1,293 @@
image:
repository: ghcr.io/formbricks/formbricks
pullPolicy: IfNotPresent
tag: v3.2.0
# Override the name for the application.
# If not set, the chart name will be used.
nameOverride: ""
service:
type: ClusterIP
port: 80
targetPort: 3000
# Override the name of the application component.
# Defaults to the same value as nameOverride.
componentOverride: ""
resources:
limits:
cpu: 500m
memory: 1Gi
# Override the application "part-of" label.
# Defaults to the chart name if not set.
partOfOverride: ""
autoscaling:
##########################################################
# Enterprise Configuration
##########################################################
enterprise:
enabled: false
minReplicas: 2
maxReplicas: 5
licenseKey: ""
##########################################################
# Deployment Configuration
##########################################################
deployment:
# Deployment strategy configuration
strategy:
type: RollingUpdate # Type of deployment strategy (RollingUpdate/Recreate)
# rollingUpdate:
# maxSurge: 25%
# maxUnavailable: 25%
# Automatically reload deployment when ConfigMaps or Secrets change
reloadOnChange: false
# NodeSelector for scheduling pods on specific nodes
nodeSelector: {}
# Additional labels for Deployment
additionalLabels: {}
# Additional pod labels to be used in the Service's label selector
additionalPodLabels: {}
# Deployment annotations
annotations: {}
# Additional pod annotations
additionalPodAnnotations: {}
# Number of replicas
replicas: 1
# Image pull secrets for private container registries
imagePullSecrets: ""
# Environment variables from ConfigMaps or Secrets
envFrom:
# app-secrets:
# type: secret
# nameSuffix: app-secrets
# Environment variables passed to the app container
env:
EMAIL_VERIFICATION_DISABLED:
value: "1"
PASSWORD_RESET_DISABLED:
value: "1"
# Tolerations for scheduling pods on tainted nodes
tolerations: []
# Pod affinity and anti-affinity rules
affinity: {}
# Topology spread constraints for better scheduling
topologySpreadConstraints: []
# Number of previous ReplicaSet versions to retain
revisionHistoryLimit: 2
# Application container image
image:
repository: "ghcr.io/formbricks/formbricks"
digest: "" # If set, digest takes precedence over the tag
pullPolicy: IfNotPresent
# Health probes configuration
probes:
startupProbe:
failureThreshold: 30
periodSeconds: 10
tcpSocket:
port: 3000
readinessProbe:
failureThreshold: 5
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
initialDelaySeconds: 10
httpGet:
path: /health
port: 3000
livenessProbe:
failureThreshold: 5
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
initialDelaySeconds: 10
httpGet:
path: /health
port: 3000
# Resource requests and limits
resources:
limits:
memory: 2Gi
requests:
memory: 1Gi
cpu: "1"
# Container security context
containerSecurityContext:
readOnlyRootFilesystem: true
runAsNonRoot: true
# Pod security context
securityContext: {}
# Command override
command: []
# Arguments override
args: []
# Container ports
ports:
http:
containerPort: 3000
protocol: TCP
exposed: true
metrics:
containerPort: 9464
protocol: TCP
exposed: true
##########################################################
# Horizontal Pod Autoscaler (HPA)
##########################################################
autoscaling:
enabled: true # Enable/disable HPA
additionalLabels: {} # Additional labels for the HPA resource
annotations: {} # Annotations for HPA
minReplicas: 1 # Minimum number of replicas
maxReplicas: 10 # Maximum number of replicas
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 80
behavior:
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Percent
value: 100
periodSeconds: 15
scaleUp:
stabilizationWindowSeconds: 0
policies:
- type: Percent
value: 100
periodSeconds: 15
- type: Pods
value: 4
periodSeconds: 15
selectPolicy: Max
averageUtilization: 60
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 60
replicaCount: 1
##########################################################
# Service Configuration
##########################################################
service:
enabled: true # Enable/disable Kubernetes Service
additionalLabels: {} # Additional labels for Service
annotations: {} # Annotations for Service
type: ClusterIP # Service type (ClusterIP, NodePort, LoadBalancer)
ports: [] # Additional ports
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
successThreshold: 1
##########################################################
# Role-Based Access Control (RBAC)
##########################################################
rbac:
enabled: false # Enable/disable RBAC
serviceAccount:
enabled: false # Enable/disable ServiceAccount
name: "" # Custom ServiceAccount name
additionalLabels: {} # Additional labels
annotations: {} # Annotations
formbricksConfig:
nextAuthSecret: ""
encryptionKey: ""
cronSecret: ""
##########################################################
# Cron Job Configuration
##########################################################
cronJob:
enabled: false # Enable/disable CronJobs
jobs: {} # Define cron jobs
env: {}
hostname: ""
email: ""
traefik:
##########################################################
# Kubernetes Secret Configuration (Quick Start)
##########################################################
secret:
enabled: true
ingressRoute:
dashboard:
enabled: false
additionalArguments:
- "--certificatesresolvers.letsencrypt.acme.email=your-email@example.com"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--certificatesresolvers.letsencrypt.acme.storage=/data/acme.json"
- "--certificatesresolvers.letsencrypt.acme.caserver=https://acme-v02.api.letsencrypt.org/directory"
- "--log.level=DEBUG"
- "--entrypoints.web.http.redirections.entryPoint.to=websecure"
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
- "--entrypoints.web.http.redirections.entryPoint.permanent=true"
- "--providers.file.filename=/config/traefik.toml"
volumes:
- name: traefik-config
mountPath: "/config"
type: configMap
tls:
enabled: true
certResolver: letsencrypt
ports:
web:
port: 80
websecure:
port: 443
tls:
enabled: true
certResolver: letsencrypt
persistence:
enabled: true
name: traefik-acme
accessMode: ReadWriteOnce
size: 128Mi
path: /data
podSecurityContext:
fsGroup: 0
hostNetwork: true
securityContext:
capabilities:
drop:
- ALL
add:
- NET_ADMIN
- NET_BIND_SERVICE
- NET_BROADCAST
- NET_RAW
runAsUser: 0
runAsGroup: 0
runAsNonRoot: false
readOnlyRootFilesystem: true
##########################################################
# External Secrets Configuration
##########################################################
externalSecret:
enabled: false # Enable/disable ExternalSecrets
secretStore:
name: aws-secrets-manager # Secret store reference name
kind: ClusterSecretStore # Type of secret store
refreshInterval: "1h" # Frequency of secret sync
files: {}
##########################################################
# Ingress Configuration
##########################################################
ingress:
enabled: false # Enable/disable Ingress
ingressClassName: alb # Specify the Ingress class
hosts:
- host: k8s.formbricks.com
paths:
- path: /
pathType: "Prefix"
serviceName: "formbricks"
annotations: {} # Ingress annotations
##########################################################
# Redis Configuration
##########################################################
redis:
enabled: false
externalUrl: ""
enabled: true # Enable/disable Redis
externalRedisUrl: ""
fullnameOverride: "formbricks-redis"
architecture: standalone
auth:
enabled: true
password: redispassword
existingSecret: "formbricks-app-secrets"
existingSecretPasswordKey: "REDIS_PASSWORD"
networkPolicy:
enabled: false
master:
persistence:
enabled: false
replica:
replicaCount: 0
enabled: true
postgresql:
##########################################################
# Service Monitor to collect Prometheus metrices
##########################################################
serviceMonitor:
enabled: true
# Additional labels
additionalLabels:
# key: value
# Additional annotations
annotations:
# key: value
# List of the endpoints of service from which prometheus will scrape data
endpoints:
- interval: 5s
path: /metrics
port: metrics
##########################################################
# PostgreSQL Configuration
##########################################################
postgresql:
enabled: true # Enable/disable PostgreSQL
externalDatabaseUrl: ""
global:
security:
allowInsecureImages: true
fullnameOverride: "formbricks-postgresql"
image:
repository: pgvector/pgvector
tag: 0.8.0-pg17
auth:
username: formbricks
password: formbrickspassword
database: formbricks
existingSecret: "formbricks-app-secrets"
secretKeys:
adminPasswordKey: "POSTGRES_ADMIN_PASSWORD"
userPasswordKey: "POSTGRES_USER_PASSWORD"
primary:
networkPolicy:
enabled: false
persistence:
enabled: true
size: 10Gi

164
infra/terraform/.terraform.lock.hcl generated Normal file
View File

@@ -0,0 +1,164 @@
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/hashicorp/aws" {
version = "5.89.0"
constraints = ">= 5.46.0, >= 5.79.0, >= 5.83.0"
hashes = [
"h1:rFvk42jJEKiSUhK1cbERfNgYm4mD+8tq0ZcxCwpXSJs=",
"zh:0e55784d6effc33b9098ffab7fb77a242e0223a59cdcf964caa0be94d14684af",
"zh:23c64f3eaeffcafb007c89db3dfca94c8adf06b120af55abddaca55a6c6c924c",
"zh:338f620133cb607ce980f1725a0a78f61cbd42f4c601808ec1ee01a6c16c9811",
"zh:6ab0499172f17484d7b39924cf06782789df1473d31ebae0c7f3294f6e7a1227",
"zh:6dcde3e29e538cdf80971cbdce3b285056fd0e31dd64b02d2dcdf4c02f21d0a9",
"zh:75c9b594d77c9125bfb1aaf3fbd77a49e392841d53029b5726eb71d64de1233e",
"zh:7b334c23091e7b4c142e378416586292197c40a31a5bdb3b29c4f9afddd286f0",
"zh:991bbba72e5eb6eb351f466d68080992f5b0495f862a6723f386d1b4c965aa7d",
"zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
"zh:9bd2f12eef4a5dceafc211ab3b9a63f0e3e224007a60c1bbb842f76e0377033d",
"zh:b1ac1eb3b3e1a79fa5e5ad3364615f23b9ee0b093ceeb809fd386a4d40e7abb4",
"zh:cea91f43151b30c428c441b97c3b98bf1e5fb72ef72f6971308e3895e23437f4",
"zh:d3f000a1696a43d8186a516aace7d476d1fd76443627980504133477e19c8ecb",
"zh:d6f526fbbb3e51b3acc3b9640a158f7acc4a089632fca8ec6db430b450673f25",
"zh:e0c542950f96c93e761d50602e449fef8447f1389a6d5242a0a7dc9b06826d0b",
]
}
provider "registry.terraform.io/hashicorp/cloudinit" {
version = "2.3.6"
constraints = ">= 2.0.0"
hashes = [
"h1:afnqn3XPnO40laFt+SVHPPKsg1j3HXT0VAO0xBVvmrY=",
"zh:1321b5ddede56be3f9b35bf75d7cda79adcb357fad62eb8677b6595e0baaa6cd",
"zh:265d66e61b9cd16ca1182ebf094cc0a08fb3687e8193a1dbac6899b16c237151",
"zh:3875c3a20e082ac55d5ff24bcaf7133ebc90c7f999fd0fb37cf0f0003474c94c",
"zh:68ce41ccd07757c451682703840cae1ec270ed5275cd491bbf8279782dfcbb73",
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
"zh:8dca3bb3f85ff8ac4d1b3f93975dcb751ed788396c56ebf0c3737ce1a4c60492",
"zh:9339bdaa99939291cedf543861353c8e7171ec5231c0dfacaa9bdb3338978dab",
"zh:a8510c2256e9a78697910bb5542aeca457c81225ea88130335f6d14a36a36c74",
"zh:af7ed71b8fceb60a5e3b7fa663be171e0bd41bb0af30e0e1f06a004c7b584e4a",
"zh:bc9de0f921b69d07f5fc1ea65f8af71d8d1a7053aafb500788b30bfce64b8fbe",
"zh:bccd0a49f161a91660d7d30dd6b389e6820f29752ccf351f10a3297c96973823",
"zh:c69321caca20009abead617f888a67aca990276cb7388b738b19157b88749190",
]
}
provider "registry.terraform.io/hashicorp/helm" {
version = "2.17.0"
constraints = "~> 2.17"
hashes = [
"h1:kQMkcPVvHOguOqnxoEU2sm1ND9vCHiT8TvZ2x6v/Rsw=",
"zh:06fb4e9932f0afc1904d2279e6e99353c2ddac0d765305ce90519af410706bd4",
"zh:104eccfc781fc868da3c7fec4385ad14ed183eb985c96331a1a937ac79c2d1a7",
"zh:129345c82359837bb3f0070ce4891ec232697052f7d5ccf61d43d818912cf5f3",
"zh:3956187ec239f4045975b35e8c30741f701aa494c386aaa04ebabffe7749f81c",
"zh:66a9686d92a6b3ec43de3ca3fde60ef3d89fb76259ed3313ca4eb9bb8c13b7dd",
"zh:88644260090aa621e7e8083585c468c8dd5e09a3c01a432fb05da5c4623af940",
"zh:a248f650d174a883b32c5b94f9e725f4057e623b00f171936dcdcc840fad0b3e",
"zh:aa498c1f1ab93be5c8fbf6d48af51dc6ef0f10b2ea88d67bcb9f02d1d80d3930",
"zh:bf01e0f2ec2468c53596e027d376532a2d30feb72b0b5b810334d043109ae32f",
"zh:c46fa84cc8388e5ca87eb575a534ebcf68819c5a5724142998b487cb11246654",
"zh:d0c0f15ffc115c0965cbfe5c81f18c2e114113e7a1e6829f6bfd879ce5744fbb",
"zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
]
}
provider "registry.terraform.io/hashicorp/kubernetes" {
version = "2.36.0"
constraints = "~> 2.36"
hashes = [
"h1:94wlXkBzfXwyLVuJVhMdzK+VGjFnMjdmFkYhQ1RUFhI=",
"zh:07f38fcb7578984a3e2c8cf0397c880f6b3eb2a722a120a08a634a607ea495ca",
"zh:1adde61769c50dbb799d8bf8bfd5c8c504a37017dfd06c7820f82bcf44ca0d39",
"zh:39707f23ab58fd0e686967c0f973c0f5a39c14d6ccfc757f97c345fdd0cd4624",
"zh:4cc3dc2b5d06cc22d1c734f7162b0a8fdc61990ff9efb64e59412d65a7ccc92a",
"zh:8382dcb82ba7303715b5e67939e07dd1c8ecddbe01d12f39b82b2b7d7357e1d9",
"zh:88e8e4f90034186b8bfdea1b8d394621cbc46a064ff2418027e6dba6807d5227",
"zh:a6276a75ad170f76d88263fdb5f9558998bf3a3f7650d7bd3387b396410e59f3",
"zh:bc816c7e0606e5df98a0c7634b240bb0c8100c3107b8b17b554af702edc6a0c5",
"zh:cb2f31d58f37020e840af52755c18afd1f09a833c4903ac59270ab440fab57b7",
"zh:ee0d103b8d0089fb1918311683110b4492a9346f0471b136af46d3b019576b22",
"zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
"zh:f688b9ec761721e401f6859c19c083e3be20a650426f4747cd359cdc079d212a",
]
}
provider "registry.terraform.io/hashicorp/null" {
version = "3.2.3"
constraints = ">= 3.0.0"
hashes = [
"h1:I0Um8UkrMUb81Fxq/dxbr3HLP2cecTH2WMJiwKSrwQY=",
"zh:22d062e5278d872fe7aed834f5577ba0a5afe34a3bdac2b81f828d8d3e6706d2",
"zh:23dead00493ad863729495dc212fd6c29b8293e707b055ce5ba21ee453ce552d",
"zh:28299accf21763ca1ca144d8f660688d7c2ad0b105b7202554ca60b02a3856d3",
"zh:55c9e8a9ac25a7652df8c51a8a9a422bd67d784061b1de2dc9fe6c3cb4e77f2f",
"zh:756586535d11698a216291c06b9ed8a5cc6a4ec43eee1ee09ecd5c6a9e297ac1",
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
"zh:9d5eea62fdb587eeb96a8c4d782459f4e6b73baeece4d04b4a40e44faaee9301",
"zh:a6355f596a3fb8fc85c2fb054ab14e722991533f87f928e7169a486462c74670",
"zh:b5a65a789cff4ada58a5baffc76cb9767dc26ec6b45c00d2ec8b1b027f6db4ed",
"zh:db5ab669cf11d0e9f81dc380a6fdfcac437aea3d69109c7aef1a5426639d2d65",
"zh:de655d251c470197bcbb5ac45d289595295acb8f829f6c781d4a75c8c8b7c7dd",
"zh:f5c68199f2e6076bce92a12230434782bf768103a427e9bb9abee99b116af7b5",
]
}
provider "registry.terraform.io/hashicorp/random" {
version = "3.7.1"
hashes = [
"h1:t152MY0tQH4a8fLzTtEWx70ITd3azVOrFDn/pQblbto=",
"zh:3193b89b43bf5805493e290374cdda5132578de6535f8009547c8b5d7a351585",
"zh:3218320de4be943e5812ed3de995946056db86eb8d03aa3f074e0c7316599bef",
"zh:419861805a37fa443e7d63b69fb3279926ccf98a79d256c422d5d82f0f387d1d",
"zh:4df9bd9d839b8fc11a3b8098a604b9b46e2235eb65ef15f4432bde0e175f9ca6",
"zh:5814be3f9c9cc39d2955d6f083bae793050d75c572e70ca11ccceb5517ced6b1",
"zh:63c6548a06de1231c8ee5570e42ca09c4b3db336578ded39b938f2156f06dd2e",
"zh:697e434c6bdee0502cc3deb098263b8dcd63948e8a96d61722811628dce2eba1",
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
"zh:a0b8e44927e6327852bbfdc9d408d802569367f1e22a95bcdd7181b1c3b07601",
"zh:b7d3af018683ef22794eea9c218bc72d7c35a2b3ede9233b69653b3c782ee436",
"zh:d63b911d618a6fe446c65bfc21e793a7663e934b2fef833d42d3ccd38dd8d68d",
"zh:fa985cd0b11e6d651f47cff3055f0a9fd085ec190b6dbe99bf5448174434cdea",
]
}
provider "registry.terraform.io/hashicorp/time" {
version = "0.12.1"
constraints = ">= 0.9.0"
hashes = [
"h1:JzYsPugN8Fb7C4NlfLoFu7BBPuRVT2/fCOdCaxshveI=",
"zh:090023137df8effe8804e81c65f636dadf8f9d35b79c3afff282d39367ba44b2",
"zh:26f1e458358ba55f6558613f1427dcfa6ae2be5119b722d0b3adb27cd001efea",
"zh:272ccc73a03384b72b964918c7afeb22c2e6be22460d92b150aaf28f29a7d511",
"zh:438b8c74f5ed62fe921bd1078abe628a6675e44912933100ea4fa26863e340e9",
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
"zh:85c8bd8eefc4afc33445de2ee7fbf33a7807bc34eb3734b8eefa4e98e4cddf38",
"zh:98bbe309c9ff5b2352de6a047e0ec6c7e3764b4ed3dfd370839c4be2fbfff869",
"zh:9c7bf8c56da1b124e0e2f3210a1915e778bab2be924481af684695b52672891e",
"zh:d2200f7f6ab8ecb8373cda796b864ad4867f5c255cff9d3b032f666e4c78f625",
"zh:d8c7926feaddfdc08d5ebb41b03445166df8c125417b28d64712dccd9feef136",
"zh:e2412a192fc340c61b373d6c20c9d805d7d3dee6c720c34db23c2a8ff0abd71b",
"zh:e6ac6bba391afe728a099df344dbd6481425b06d61697522017b8f7a59957d44",
]
}
provider "registry.terraform.io/hashicorp/tls" {
version = "4.0.6"
constraints = ">= 3.0.0"
hashes = [
"h1:n3M50qfWfRSpQV9Pwcvuse03pEizqrmYEryxKky4so4=",
"zh:10de0d8af02f2e578101688fd334da3849f56ea91b0d9bd5b1f7a243417fdda8",
"zh:37fc01f8b2bc9d5b055dc3e78bfd1beb7c42cfb776a4c81106e19c8911366297",
"zh:4578ca03d1dd0b7f572d96bd03f744be24c726bfd282173d54b100fd221608bb",
"zh:6c475491d1250050765a91a493ef330adc24689e8837a0f07da5a0e1269e11c1",
"zh:81bde94d53cdababa5b376bbc6947668be4c45ab655de7aa2e8e4736dfd52509",
"zh:abdce260840b7b050c4e401d4f75c7a199fafe58a8b213947a258f75ac18b3e8",
"zh:b754cebfc5184873840f16a642a7c9ef78c34dc246a8ae29e056c79939963c7a",
"zh:c928b66086078f9917aef0eec15982f2e337914c5c4dbc31dd4741403db7eb18",
"zh:cded27bee5f24de6f2ee0cfd1df46a7f88e84aaffc2ecbf3ff7094160f193d50",
"zh:d65eb3867e8f69aaf1b8bb53bd637c99c6b649ba3db16ded50fa9a01076d1a27",
"zh:ecb0c8b528c7a619fa71852bb3fb5c151d47576c5aab2bf3af4db52588722eeb",
"zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c",
]
}

View File

@@ -0,0 +1,177 @@
# ################################################################################
# # GitOps Bridge: Bootstrap
# ################################################################################
# locals {
# addons = {
# enable_cert_manager = true
# enable_external_dns = true
# enable_istio = false
# enable_istio_ingress = false
# enable_external_secrets = true
# enable_metrics_server = false
# enable_keda = false
# enable_aws_load_balancer_controller = true
# enable_aws_ebs_csi_resources = false
# enable_velero = false
# enable_observability = false
# enable_karpenter = true
# }
#
# addons_default_versions = {
# cert_manager = "v1.17.1"
# external_dns = "1.15.2"
# karpenter = "1.3.0"
# external_secrets = "0.14.3"
# aws_load_balancer_controller = "1.10.0"
# # keda = "2.16.0"
# # istio = "1.23.3"
# }
#
# addons_metadata = merge(
# # module.addons.gitops_metadata
# {
# aws_cluster_name = module.eks.cluster_name
# aws_region = data.aws_region.selected.name
# aws_account_id = data.aws_caller_identity.current.account_id
# aws_vpc_id = module.vpc.vpc_id
# }
# )
#
# argocd_apps = {
# eks-addons = {
# project = "default"
# repo_url = var.addons_repo_url
# target_revision = var.addons_target_revision
# addons_repo_revision = var.addons_target_revision
# path = var.addons_repo_path
# values = merge({
# addons_repo_revision = var.addons_target_revision
# certManager = {
# enabled = local.addons.enable_cert_manager
# iamRoleArn = try(module.addons.gitops_metadata.cert_manager_iam_role_arn, "")
# values = try(yamldecode(join("\n", var.cert_manager_helm_config.values)), {})
# chartVersion = try(var.cert_manager_helm_config.chart_version, local.addons_default_versions.cert_manager)
# }
# externalDNS = {
# enabled = local.addons.enable_external_dns
# iamRoleArn = try(module.addons.gitops_metadata.external_dns_iam_role_arn, "")
# values = try(yamldecode(join("\n", var.external_dns_helm_config.values)), {})
# chartVersion = try(var.external_dns_helm_config.chart_version, local.addons_default_versions.external_dns)
# }
# externalSecrets = {
# enabled = local.addons.enable_external_secrets
# iamRoleArn = try(module.addons.gitops_metadata.external_secrets_iam_role_arn, "")
# values = try(yamldecode(join("\n", var.external_secrets_helm_config.values)), {})
# chartVersion = try(var.external_secrets_helm_config.chart_version, local.addons_default_versions.external_secrets)
# }
# karpenter = {
# enabled = true
# iamRoleArn = try(module.addons.gitops_metadata.karpenter_iam_role_arn, "")
# values = try(yamldecode(join("\n", var.karpenter_helm_config.values)), {})
# chartVersion = try(var.karpenter_helm_config.chart_version, local.addons_default_versions.karpenter)
# enableCrdWebhookConfig = true
# clusterName = module.eks.cluster_name
# clusterEndpoint = module.eks.cluster_endpoint
# interruptionQueue = try(module.addons.gitops_metadata.karpenter_interruption_queue, null)
# nodeIamRoleName = try(module.addons.gitops_metadata.karpenter_node_iam_role_arn, null)
# }
# loadBalancerController = {
# enabled = local.addons.enable_aws_load_balancer_controller
# iamRoleArn = try(module.addons.gitops_metadata.aws_load_balancer_controller_iam_role_arn, "")
# values = try(yamldecode(join("\n", var.aws_load_balancer_controller_helm_config.values)), {})
# clusterName = module.eks.cluster_name
# chartVersion = try(var.aws_load_balancer_controller_helm_config.chart_version, local.addons_default_versions.aws_load_balancer_controller)
# vpcId = module.vpc.vpc_id
# }
# })
# }
# workloads = {
# project = "default"
# repo_url = var.workloads_repo_url
# target_revision = var.workloads_target_revision
# addons_repo_revision = var.workloads_target_revision
# path = var.workloads_repo_path
# values = merge({
# addons_repo_revision = var.workloads_target_revision
# formbricks = {
# certificateArn = try(module.acm.acm_certificate_arn, "")
# ingressHost = "app.k8s.formbricks.com"
# env = {
# TEST = {
# value = "test "
# }
# }
# }
# })
# }
# }
# }
#
# variable "enable_gitops_bridge_bootstrap" {
# default = true
# }
#
# module "gitops_bridge_bootstrap" {
# count = var.enable_gitops_bridge_bootstrap ? 1 : 0
# source = "../modules/argocd-gitops-bridge"
#
# cluster = {
# metadata = local.addons_metadata
# }
# argocd = {
# chart_version = "7.8.7"
# values = [
# <<-EOT
# global:
# nodeSelector:
# CriticalAddonsOnly: "true"
# tolerations:
# - key: "CriticalAddonsOnly"
# operator: "Exists"
# effect: "NoSchedule"
# configs:
# params:
# server.insecure: true
# EOT
# ]
# }
# apps = local.argocd_apps
# }
#
# ###############################################################################
# # EKS Blueprints Addons
# ###############################################################################
# module "addons" {
# source = "../modules/addons"
# oidc_provider_arn = module.eks.oidc_provider_arn
# aws_region = data.aws_region.selected.name
# aws_account_id = data.aws_caller_identity.current.account_id
# aws_partition = data.aws_partition.current.partition
# cluster_name = module.eks.cluster_name
# cluster_endpoint = module.eks.cluster_endpoint
# cluster_certificate_authority_data = module.eks.cluster_certificate_authority_data
# cluster_token = data.aws_eks_cluster_auth.eks.token
# cluster_version = module.eks.cluster_version
# vpc_id = module.vpc.vpc_id
# node_security_group_id = module.eks.node_security_group_id
# cluster_security_group_id = module.eks.cluster_security_group_id
#
# # Using GitOps Bridge
# create_kubernetes_resources = var.enable_gitops_bridge_bootstrap ? false : true
#
# # Cert Manager
# enable_cert_manager = local.addons.enable_cert_manager
#
# # External DNS
# enable_external_dns = local.addons.enable_external_dns
#
# # Karpenter
# enable_karpenter = local.addons.enable_karpenter
#
# # External Secrets
# enable_external_secrets = local.addons.enable_external_secrets
#
# # Load Balancer Controller
# enable_aws_load_balancer_controller = local.addons.enable_aws_load_balancer_controller
#
# }

12
infra/terraform/data.tf Normal file
View File

@@ -0,0 +1,12 @@
data "aws_region" "selected" {}
data "aws_caller_identity" "current" {}
data "aws_availability_zones" "available" {}
data "aws_partition" "current" {}
data "aws_eks_cluster_auth" "eks" {
name = module.eks.cluster_name
}
data "aws_ecrpublic_authorization_token" "token" {
provider = aws.virginia
}

30
infra/terraform/iam.tf Normal file
View File

@@ -0,0 +1,30 @@
################################################################################
# GitHub OIDC Provider
# Note: This is one per AWS account
################################################################################
module "iam_github_oidc_provider" {
source = "terraform-aws-modules/iam/aws//modules/iam-github-oidc-provider"
version = "5.54.0"
tags = local.tags
}
################################################################################
# GitHub OIDC Role
################################################################################
module "iam_github_oidc_role" {
source = "terraform-aws-modules/iam/aws//modules/iam-github-oidc-role"
version = "5.54.0"
name = "${local.name}-github"
subjects = [
"repo:formbricks/*:*",
]
policies = {
Administrator = "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
}
tags = local.tags
}

668
infra/terraform/main.tf Normal file
View File

@@ -0,0 +1,668 @@
locals {
project = "formbricks"
environment = "prod"
name = "${local.project}-${local.environment}"
vpc_cidr = "10.0.0.0/16"
azs = slice(data.aws_availability_zones.available.names, 0, 3)
tags = {
Project = local.project
Environment = local.environment
MangedBy = "Terraform"
Blueprint = local.name
}
domain = "k8s.formbricks.com"
karpetner_helm_version = "1.3.1"
karpenter_namespace = "karpenter"
}
################################################################################
# Route53 Hosted Zone
################################################################################
module "route53_zones" {
source = "terraform-aws-modules/route53/aws//modules/zones"
version = "4.1.0"
zones = {
"k8s.formbricks.com" = {
comment = "${local.domain} (testing)"
tags = {
Name = local.domain
}
}
}
}
output "route53_ns_records" {
value = module.route53_zones.route53_zone_name_servers
}
module "acm" {
source = "terraform-aws-modules/acm/aws"
version = "5.1.1"
domain_name = local.domain
zone_id = module.route53_zones.route53_zone_zone_id[local.domain]
subject_alternative_names = [
"*.${local.domain}",
]
validation_method = "DNS"
tags = local.tags
}
################################################################################
# VPC
################################################################################
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.19.0"
name = "${local.name}-vpc"
cidr = local.vpc_cidr
azs = local.azs
private_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 4, k)] # /20
public_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 48)] # Public LB /24
intra_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 52)] # eks interface /24
database_subnets = [for k, v in local.azs : cidrsubnet(local.vpc_cidr, 8, k + 56)] # RDS / Elastic cache /24
database_subnet_group_name = "${local.name}-subnet-group"
enable_nat_gateway = true
single_nat_gateway = true
public_subnet_tags = {
"kubernetes.io/role/elb" = 1
}
private_subnet_tags = {
"kubernetes.io/role/internal-elb" = 1
# Tags subnets for Karpenter auto-discovery
"karpenter.sh/discovery" = "${local.name}-eks"
}
tags = local.tags
}
################################################################################
# VPC Endpoints Module
################################################################################
module "vpc_vpc-endpoints" {
source = "terraform-aws-modules/vpc/aws//modules/vpc-endpoints"
version = "5.19.0"
vpc_id = module.vpc.vpc_id
endpoints = {
"s3" = {
service = "s3"
service_type = "Gateway"
route_table_ids = flatten([
module.vpc.intra_route_table_ids,
module.vpc.private_route_table_ids,
module.vpc.public_route_table_ids
])
tags = { Name = "s3-vpc-endpoint" }
}
}
tags = local.tags
}
################################################################################
# PostgreSQL Serverless v2
################################################################################
data "aws_rds_engine_version" "postgresql" {
engine = "aurora-postgresql"
version = "16.4"
}
resource "random_password" "postgres" {
length = 20
special = false
}
module "rds-aurora" {
source = "terraform-aws-modules/rds-aurora/aws"
version = "9.12.0"
name = "${local.name}-postgres"
engine = data.aws_rds_engine_version.postgresql.engine
engine_mode = "provisioned"
engine_version = data.aws_rds_engine_version.postgresql.version
storage_encrypted = true
master_username = "formbricks"
master_password = random_password.postgres.result
manage_master_user_password = false
vpc_id = module.vpc.vpc_id
db_subnet_group_name = module.vpc.database_subnet_group_name
security_group_rules = {
vpc_ingress = {
cidr_blocks = module.vpc.private_subnets_cidr_blocks
}
}
performance_insights_enabled = true
apply_immediately = true
skip_final_snapshot = true
enable_http_endpoint = true
serverlessv2_scaling_configuration = {
min_capacity = 0
max_capacity = 10
seconds_until_auto_pause = 3600
}
instance_class = "db.serverless"
instances = {
one = {}
}
tags = local.tags
}
################################################################################
# ElastiCache Module
################################################################################
resource "random_password" "valkey" {
length = 20
special = false
}
module "elasticache" {
source = "terraform-aws-modules/elasticache/aws"
version = "1.4.1"
replication_group_id = "${local.name}-valkey"
engine = "valkey"
engine_version = "7.2"
node_type = "cache.m7g.large"
transit_encryption_enabled = true
auth_token = random_password.valkey.result
maintenance_window = "sun:05:00-sun:09:00"
apply_immediately = true
# Security Group
vpc_id = module.vpc.vpc_id
security_group_rules = {
ingress_vpc = {
# Default type is `ingress`
# Default port is based on the default engine port
description = "VPC traffic"
cidr_ipv4 = module.vpc.vpc_cidr_block
}
}
# Subnet Group
subnet_group_name = "${local.name}-valkey"
subnet_group_description = "${title(local.name)} subnet group"
subnet_ids = module.vpc.database_subnets
# Parameter Group
create_parameter_group = true
parameter_group_name = "${local.name}-valkey"
parameter_group_family = "valkey7"
parameter_group_description = "${title(local.name)} parameter group"
parameters = [
{
name = "latency-tracking"
value = "yes"
}
]
tags = local.tags
}
################################################################################
# EKS Module
################################################################################
module "ebs_csi_driver_irsa" {
source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
version = "~> 5.52"
role_name_prefix = "${local.name}-ebs-csi-driver-"
attach_ebs_csi_policy = true
oidc_providers = {
main = {
provider_arn = module.eks.oidc_provider_arn
namespace_service_accounts = ["kube-system:ebs-csi-controller-sa"]
}
}
tags = local.tags
}
module "eks" {
source = "terraform-aws-modules/eks/aws"
version = "20.33.1"
cluster_name = "${local.name}-eks"
cluster_version = "1.32"
enable_cluster_creator_admin_permissions = true
cluster_endpoint_public_access = true
cluster_addons = {
coredns = {
most_recent = true
}
eks-pod-identity-agent = {
most_recent = true
}
aws-ebs-csi-driver = {
most_recent = true
service_account_role_arn = module.ebs_csi_driver_irsa.iam_role_arn
}
kube-proxy = {
most_recent = true
}
vpc-cni = {
most_recent = true
}
}
vpc_id = module.vpc.vpc_id
subnet_ids = module.vpc.private_subnets
control_plane_subnet_ids = module.vpc.intra_subnets
eks_managed_node_groups = {
system = {
ami_type = "BOTTLEROCKET_ARM_64"
instance_types = ["t4g.small"]
min_size = 2
max_size = 3
desired_size = 2
labels = {
CriticalAddonsOnly = "true"
"karpenter.sh/controller" = "true"
}
taints = {
addons = {
key = "CriticalAddonsOnly"
value = "true"
effect = "NO_SCHEDULE"
},
}
}
}
node_security_group_tags = merge(local.tags, {
# NOTE - if creating multiple security groups with this module, only tag the
# security group that Karpenter should utilize with the following tag
# (i.e. - at most, only one security group should have this tag in your account)
"karpenter.sh/discovery" = "${local.name}-eks"
})
tags = local.tags
}
module "karpenter" {
source = "terraform-aws-modules/eks/aws//modules/karpenter"
version = "20.34.0"
cluster_name = module.eks.cluster_name
enable_v1_permissions = true
# Name needs to match role name passed to the EC2NodeClass
node_iam_role_use_name_prefix = false
node_iam_role_name = local.name
create_pod_identity_association = true
namespace = local.karpenter_namespace
# Used to attach additional IAM policies to the Karpenter node IAM role
node_iam_role_additional_policies = {
AmazonSSMManagedInstanceCore = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}
tags = local.tags
}
output "karpenter_node_role" {
value = module.karpenter.node_iam_role_name
}
resource "helm_release" "karpenter_crds" {
name = "karpenter-crds"
repository = "oci://public.ecr.aws/karpenter"
repository_username = data.aws_ecrpublic_authorization_token.token.user_name
repository_password = data.aws_ecrpublic_authorization_token.token.password
chart = "karpenter-crd"
version = "1.3.1"
namespace = local.karpenter_namespace
values = [
<<-EOT
webhook:
enabled: true
serviceNamespace: ${local.karpenter_namespace}
EOT
]
}
resource "helm_release" "karpenter" {
name = "karpenter"
repository = "oci://public.ecr.aws/karpenter"
repository_username = data.aws_ecrpublic_authorization_token.token.user_name
repository_password = data.aws_ecrpublic_authorization_token.token.password
chart = "karpenter"
version = "1.3.1"
namespace = local.karpenter_namespace
skip_crds = true
values = [
<<-EOT
nodeSelector:
karpenter.sh/controller: 'true'
dnsPolicy: Default
settings:
clusterName: ${module.eks.cluster_name}
clusterEndpoint: ${module.eks.cluster_endpoint}
interruptionQueue: ${module.karpenter.queue_name}
EOT
]
}
resource "kubernetes_manifest" "ec2_node_class" {
manifest = {
apiVersion = "karpenter.k8s.aws/v1"
kind = "EC2NodeClass"
metadata = {
name = "default"
}
spec = {
amiSelectorTerms = [
{
alias = "bottlerocket@latest"
}
]
role = module.karpenter.node_iam_role_name
subnetSelectorTerms = [
{
tags = {
"karpenter.sh/discovery" = "${local.name}-eks"
}
}
]
securityGroupSelectorTerms = [
{
tags = {
"karpenter.sh/discovery" = "${local.name}-eks"
}
}
]
tags = {
"karpenter.sh/discovery" = "${local.name}-eks"
}
}
}
}
resource "kubernetes_manifest" "node_pool" {
manifest = {
apiVersion = "karpenter.sh/v1"
kind = "NodePool"
metadata = {
name = "default"
}
spec = {
template = {
spec = {
nodeClassRef = {
group = "karpenter.k8s.aws"
kind = "EC2NodeClass"
name = "default"
}
requirements = [
{
key = "karpenter.k8s.aws/instance-family"
operator = "In"
values = ["c8g", "c7g", "m8g", "m7g", "r8g", "r7g"]
},
{
key = "karpenter.k8s.aws/instance-cpu"
operator = "In"
values = ["2", "4", "8"]
},
{
key = "karpenter.k8s.aws/instance-hypervisor"
operator = "In"
values = ["nitro"]
}
]
}
}
limits = {
cpu = 100
}
disruption = {
consolidationPolicy = "WhenEmpty"
consolidateAfter = "30s"
}
}
}
}
module "eks_blueprints_addons" {
source = "aws-ia/eks-blueprints-addons/aws"
version = "~> 1"
cluster_name = module.eks.cluster_name
cluster_endpoint = module.eks.cluster_endpoint
cluster_version = module.eks.cluster_version
oidc_provider_arn = module.eks.oidc_provider_arn
enable_metrics_server = true
metrics_server = {
chart_version = "3.12.2"
}
enable_aws_load_balancer_controller = true
aws_load_balancer_controller = {
chart_version = "1.10.0"
values = [
<<-EOT
vpcId: ${module.vpc.vpc_id}
EOT
]
}
enable_external_dns = true
external_dns_route53_zone_arns = [module.route53_zones.route53_zone_zone_arn[local.domain]]
external_dns = {
chart_version = "1.15.2"
}
enable_cert_manager = false
cert_manager = {
chart_version = "v1.17.1"
values = [
<<-EOT
installCRDs: false
crds:
enabled: true
keep: true
EOT
]
}
enable_external_secrets = true
external_secrets = {
chart_version = "0.14.3"
}
tags = local.tags
}
### Formbricks App
module "s3-bucket" {
source = "terraform-aws-modules/s3-bucket/aws"
version = "4.6.0"
bucket_prefix = "formbricks-"
force_destroy = true
control_object_ownership = true
object_ownership = "BucketOwnerPreferred"
}
module "iam_policy" {
source = "terraform-aws-modules/iam/aws//modules/iam-policy"
version = "5.53.0"
name_prefix = "formbricks-"
path = "/"
description = "Policy for fombricks app"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"s3:*",
]
Resource = [
module.s3-bucket.s3_bucket_arn,
"${module.s3-bucket.s3_bucket_arn}/*"
]
}
]
})
}
module "formkey-aws-access" {
source = "terraform-aws-modules/iam/aws//modules/iam-role-for-service-accounts-eks"
version = "5.53.0"
role_name_prefix = "formbricks-"
role_policy_arns = {
"formbricks" = module.iam_policy.arn
}
assume_role_condition_test = "StringLike"
oidc_providers = {
eks = {
provider_arn = module.eks.oidc_provider_arn
namespace_service_accounts = ["formbricks:*"]
}
}
}
resource "helm_release" "formbricks" {
name = "formbricks"
namespace = "formbricks"
chart = "${path.module}/../../helm-chart"
max_history = 5
values = [
<<-EOT
postgresql:
enabled: false
redis:
enabled: false
ingress:
enabled: true
ingressClassName: alb
hosts:
- host: "app.${local.domain}"
paths:
- path: /
pathType: "Prefix"
serviceName: "formbricks"
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP": 80}, {"HTTPS": 443}]'
alb.ingress.kubernetes.io/ssl-redirect: "443"
alb.ingress.kubernetes.io/certificate-arn: ${module.acm.acm_certificate_arn}
alb.ingress.kubernetes.io/healthcheck-path: "/health"
alb.ingress.kubernetes.io/group.name: formbricks
alb.ingress.kubernetes.io/ssl-policy: "ELBSecurityPolicy-TLS13-1-2-2021-06"
secret:
enabled: false
rbac:
enabled: true
serviceAccount:
enabled: true
name: formbricks
annotations:
eks.amazonaws.com/role-arn: ${module.formkey-aws-access.iam_role_arn}
serviceMonitor:
enabled: true
deployment:
image:
repository: "ghcr.io/formbricks/formbricks-experimental"
tag: "open-telemetry-for-prometheus"
pullPolicy: Always
env:
S3_BUCKET_NAME:
value: ${module.s3-bucket.s3_bucket_id}
RATE_LIMITING_DISABLED:
value: "1"
envFrom:
app-parameters:
type: secret
nameSuffix: {RELEASE.name}-app-parameters
annotations:
deployed_at: ${timestamp()}
externalSecret:
enabled: true # Enable/disable ExternalSecrets
secretStore:
name: aws-secrets-manager
kind: ClusterSecretStore
refreshInterval: "1h"
files:
app-parameters:
dataFrom:
key: "/prod/formbricks/env"
secretStore:
name: aws-parameter-store
kind: ClusterSecretStore
app-secrets:
data:
DATABASE_URL:
remoteRef:
key: "prod/formbricks/secrets"
property: DATABASE_URL
REDIS_URL:
remoteRef:
key: "prod/formbricks/secrets"
property: REDIS_URL
CRON_SECRET:
remoteRef:
key: "prod/formbricks/secrets"
property: CRON_SECRET
ENCRYPTION_KEY:
remoteRef:
key: "prod/formbricks/secrets"
property: ENCRYPTION_KEY
NEXTAUTH_SECRET:
remoteRef:
key: "prod/formbricks/secrets"
property: NEXTAUTH_SECRET
ENTERPRISE_LICENSE_KEY:
remoteRef:
key: "prod/formbricks/enterprise"
property: ENTERPRISE_LICENSE_KEY
EOT
]
}
# secrets password/keys

View File

@@ -0,0 +1,31 @@
provider "aws" {
region = "eu-central-1"
}
provider "aws" {
region = "us-east-1"
alias = "virginia"
}
terraform {
backend "s3" {
bucket = "715841356175-terraform"
key = "terraform.tfstate"
region = "eu-central-1"
dynamodb_table = "terraform-lock"
}
}
provider "kubernetes" {
host = module.eks.cluster_endpoint
cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
token = data.aws_eks_cluster_auth.eks.token
}
provider "helm" {
kubernetes {
host = module.eks.cluster_endpoint
cluster_ca_certificate = base64decode(module.eks.cluster_certificate_authority_data)
token = data.aws_eks_cluster_auth.eks.token
}
}

View File

@@ -0,0 +1,33 @@
# Generate random secrets for formbricks
resource "random_password" "nextauth_secret" {
length = 32
special = false
}
resource "random_password" "encryption_key" {
length = 32
special = false
}
resource "random_password" "cron_secret" {
length = 32
special = false
}
# Create the first AWS Secrets Manager secret for environment variables
resource "aws_secretsmanager_secret" "formbricks_app_secrets" {
name = "prod/formbricks/secrets"
}
resource "aws_secretsmanager_secret_version" "formbricks_app_secrets" {
secret_id = aws_secretsmanager_secret.formbricks_app_secrets.id
secret_string = jsonencode({
NEXTAUTH_SECRET = random_password.nextauth_secret.result
ENCRYPTION_KEY = random_password.encryption_key.result
CRON_SECRET = random_password.cron_secret.result
DATABASE_URL = "postgres://formbricks:${random_password.postgres.result}@${module.rds-aurora.cluster_endpoint}/formbricks"
REDIS_URL = "rediss://:${random_password.valkey.result}@${module.elasticache.replication_group_primary_endpoint_address}:6379"
})
}

View File

@@ -0,0 +1 @@
#

View File

@@ -0,0 +1,18 @@
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.46"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.36"
}
helm = {
source = "hashicorp/helm"
version = "~> 2.17"
}
}
}