Kubernetes and OpenShift
Overview
This guide covers deploying Flagsmith on Kubernetes or OpenShift using our Helm charts.
Check out our Kubernetes Chart Repository on GitHub and our published Helm Charts.
OpenShift
Support for our OpenShift Operator is only available with an Enterprise plan.
Flagsmith runs on the OpenShift platform via our Helm charts. The rest of this guide is applicable for both Kubernetes and OpenShift.
Quick Start Deployment
Basic Installation
This is the simplest way to get Flagsmith running for testing or development.
helm repo add flagsmith https://flagsmith.github.io/flagsmith-charts/
helm install -n flagsmith --create-namespace flagsmith flagsmith/flagsmith
kubectl -n flagsmith port-forward svc/flagsmith-frontend 8080:8080
Then view http://localhost:8080
in a browser. This will install the chart using default options in a new namespace called flagsmith
.
Using Custom Values (Optional)
Refer to the chart's default values.yaml
file to learn which values are expected by the chart. You can use it as a reference for building your own values file:
wget https://raw.githubusercontent.com/Flagsmith/flagsmith-charts/main/charts/flagsmith/values.yaml
helm install -n flagsmith --create-namespace flagsmith flagsmith/flagsmith -f values.yaml
We would suggest only doing this when running the platform locally, and recommend reading the Helm docs for installation, upgrading and values for further information.
The above is a quick way of gaining access to Flagsmith, but in many cases you will need to configure ingress to work with an ingress controller.
Port forwarding
In a terminal, run:
kubectl -n [flagsmith-namespace] port-forward svc/[flagsmith-release-name]-frontend 8080:8080
Then access http://localhost:8080
in a browser.
In a cluster that has an ingress controller, using the frontend proxy
In this configuration, API requests are proxied by the frontend. This is simpler to configure but introduces some latency.
Set the following values for Flagsmith, with changes as needed to accommodate your ingress controller and any associated DNS changes.
For example, in the charts/flagsmith/values.yaml
file:
ingress:
frontend:
enabled: true
hosts:
- flagsmith.[MYDOMAIN]
Then, once any out-of-cluster DNS or CDN changes have been applied, access https://flagsmith.[MYDOMAIN]
in a browser.
In a cluster that has an ingress controller, using separate ingresses for frontend and API
Set the following values for Flagsmith, with changes as needed to accommodate your ingress controller and any associated DNS changes. Also, set the FLAGSMITH_API_URL
environment variable such that the URL is reachable from a browser accessing the frontend.
For example, in the charts/flagsmith/values.yaml
file:
ingress:
frontend:
enabled: true
hosts:
- flagsmith.[MYDOMAIN]
api:
enabled: true
hosts:
- host: flagsmith.[MYDOMAIN]
paths:
- /api/
- /health/
- /admin/
- /static/admin/
frontend:
extraEnv:
FLAGSMITH_API_URL: 'https://flagsmith.[MYDOMAIN]/api/v1/'
Then, once any out-of-cluster DNS or CDN changes have been applied, access https://flagsmith.[MYDOMAIN]
in a browser.
Minikube ingress
(See [https://kubernetes.io/docs/tasks/access-application-cluster/ingress-minikube/] for more details.)
If using minikube, enable ingress with minikube addons enable ingress
.
Then set the following values for Flagsmith in the charts/flagsmith/values.yaml
file:
ingress:
frontend:
enabled: true
hosts:
- flagsmith.local
and apply. This will create two ingress resources.
Run minikube ip
. Set this IP and flagsmith.local
in your /etc/hosts
, for example:
192.168.99.99 flagsmith.local
Then access http://flagsmith.local
in a browser.
Provided Database configuration
By default, the chart creates its own PostgreSQL server within the cluster, referencing https://github.com/helm/charts/tree/master/stable/postgresql for the service.
We recommend running an externally managed database in production, either by deploying your own PostgreSQL instance in your cluster or using a service like AWS RDS.
You can provide configuration options to the PostgreSQL database by modifying the values. For example, the below changes the max_connections in the charts/flagsmith/values.yaml
file:
postgresql:
enabled: true
postgresqlConfiguration:
max_connections: '200' # override the default max_connections of 100
External Database configuration
To connect the Flagsmith API to an external PostgreSQL server, set the values under databaseExternal
. For example, in the charts/flagsmith/values.yaml
file:
postgresql:
enabled: false # turn off the chart-managed PostgreSQL
databaseExternal:
enabled: true
# Can specify the full URL
url: 'postgres://myuser:mypass@myhost:5432/mydbname'
# Or can specify each part (url takes precedence if set)
type: postgres
host: myhost
port: 5432
database: mydbname
username: myuser
password: mypass
# Or can specify a pre-existing k8s secret containing the database URL
urlFromExistingSecret:
enabled: true
name: my-precreated-db-config
key: DB_URL
Due to a bug in Python's urllib module, passwords containing [
, ]
or #
characters must be URL-encoded.
For example:
postgres://user:pass[word@localhost/flagsmith
should be provided as:
postgres://user:pass%5Bword@localhost/flagsmith
Environment variables
It's important to define a secretKey
value in your Helm chart when running in Kubernetes. Use a password manager to generate a random hash and set this so that all the API nodes are running with an identical DJANGO_SECRET_KEY
.
If you are using our Helm charts and don't provide a secretKey
, one will be generated for you and shared across the running pods, but this will change upon redeployment, which you probably don't want to happen.
The chart handles most environment variables required, but see the API readme for all available configuration options. These can be set using api.extraEnv
. For example, in the charts/flagsmith/values.yaml
file:
api:
extraEnv:
LOG_LEVEL: DEBUG
Resource allocation
By default, no resource limits or requests are set.
TODO: recommend some defaults
Replicas
By default, 1 replica of each of the frontend and API is used.
Deployment strategy
For each of the deployments, you can set deploymentStrategy
. By default this is unset, meaning you get the default
Kubernetes behaviour, but you can set this to an object to adjust this. See
[https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy].
For example, in the charts/flagsmith/values.yaml
file:
api:
deploymentStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: '50%'
PgBouncer
By default, Flagsmith connects directly to the database - either in-cluster or external. You can enable PgBouncer with pgbouncer.enabled: true
to have Flagsmith connect to PgBouncer, and zPgBouncer connect to the database.
All-in-one Docker image
The Docker image at [https://hub.docker.com/r/flagsmith/flagsmith/] contains both the API and the frontend. To make use of this, set the following values:
api:
image:
repository: flagsmith/flagsmith # or some other repository hosting the combined image
tag: 2.14 # or some other tag that exists in that repository
separateApiAndFrontend: false
This switches off the Kubernetes deployment for the frontend. However, the ingress and service are retained, but all requests are handled by the API deployment.
InfluxDB
By default, Flagsmith uses PostgreSQL to store time series data. You can alternatively use InfluxDB to track:
- SDK API traffic
- SDK Flag Evaluations
You need to perform some additional steps to configure InfluxDB..
Task Processor
The task processor itself is documented here. See the table below for the values to set to configure the task processor using the Helm chart.
Chart Values
The following table lists the configurable parameters of the chart and their default values.
Parameter | Description | Default |
---|---|---|
api.image.repository | Docker image repository for Flagsmith API | flagsmith/flagsmith-api |
api.image.tag | Docker image tag for Flagsmith API | appVersion |
api.image.imagePullPolicy | IfNotPresent | |
api.image.imagePullSecrets | [] | |
api.separateApiAndFrontend | Set to false if using flagsmith/flagsmith image for the API | true |
api.replicacount | Number of replicas for the Flagsmith API, null to unset | 1 |
api.deploymentStrategy | See "Deployment strategy" above | |
api.resources | Resources per pod for the Flagsmith API | {} |
api.podLabels | Additional labels to apply to pods for the Flagsmith API | {} |
api.extraEnv | Extra environment variables to set for the Flagsmith API | {} |
api.secretKey | See secretKey docs above | null |
api.secretKeyFromExistingSecret.enabled | Set to true to use a secret key stored in an existing k8s secret | false |
api.secretKeyFromExistingSecret.name | The name of the secret key k8s secret | null |
api.secretKeyFromExistingSecret.key | The key of the secret key in the k8s secret | null |
api.nodeSelector | {} | |
api.tolerations | [] | |
api.affinity | {} | |
api.podSecurityContext | {} | |
api.defaultPodSecurityContext.enabled | Whether to use the default security context | true |
api.livenessProbe.failureThreshold | 5 | |
api.livenessProbe.initialDelaySeconds | 10 | |
api.livenessProbe.periodSeconds | 10 | |
api.livenessProbe.successThreshold | 1 | |
api.livenessProbe.timeoutSeconds | 2 | |
api.logging.format | Outputted log format, either json or generic | generic |
api.readinessProbe.failureThreshold | 10 | |
api.readinessProbe.initialDelaySeconds | 10 | |
api.readinessProbe.periodSeconds | 10 | |
api.readinessProbe.successThreshold | 1 | |
api.readinessProbe.timeoutSeconds | 2 | |
api.dbWaiter.image.repository | willwill/wait-for-it | |
api.dbWaiter.image.tag | latest | |
api.dbWaiter.image.imagePullPolicy | IfNotPresent | |
api.dbWaiter.timeoutSeconds | Time before init container will retry | 30 |
frontend.enabled | Whether the Flagsmith frontend is enabled | true |
frontend.image.repository | Docker image repository for Flagsmith frontend | flagsmith/flagsmith-frontend |
frontend.image.tag | Docker image tag for Flagsmith frontend | appVersion |
frontend.image.imagePullPolicy | IfNotPresent | |
frontend.image.imagePullSecrets | [] | |
frontend.replicacount | Number of replicas for the Flagsmith frontend, null to unset | 1 |
frontend.deploymentStrategy | See "Deployment strategy" above | |
frontend.resources | Resources per pod for the Flagsmith frontend | {} |
frontend.apiProxy.enabled | Proxy API requests to the API service within the cluster | true |
frontend.extraEnv | Extra environment variables to set for the Flagsmith frontend | {} |
frontend.nodeSelector | {} | |
frontend.tolerations | [] | |
frontend.affinity | {} | |
api.podSecurityContext | {} | |
api.defaultPodSecurityContext.enabled | Whether to use the default security context | true |
frontend.livenessProbe.failureThreshold | 20 | |
frontend.livenessProbe.initialDelaySeconds | 20 | |
frontend.livenessProbe.periodSeconds | 10 | |
frontend.livenessProbe.successThreshold | 1 | |
frontend.livenessProbe.timeoutSeconds | 10 | |
frontend.readinessProbe.failureThreshold | 20 | |
frontend.readinessProbe.initialDelaySeconds | 20 | |
frontend.readinessProbe.periodSeconds | 10 | |
frontend.readinessProbe.successThreshold | 1 | |
frontend.readinessProbe.timeoutSeconds | 10 | |
taskProcessor.image.repository | (same as for api.image ) | |
taskProcessor.image.tag | (same as for api.image ) | |
taskProcessor.image.imagePullPolicy | (same as for api.image ) | |
taskProcessor.image.imagePullSecrets | (same as for api.image ) | |
taskProcessor.enabled | Whether to run the task processor | false |
taskProcessor.replicacount | 1 | |
taskProcessor.sleepIntervalMs | Passed as --sleepintervalms to the task processor | |
taskProcessor.numThreads | Passed as --numthreads to the task processor | |
taskProcessor.gracePeriodMs | Passed as --graceperiodms to the task processor | |
taskProcessor.queuePopSize | Passed as --queuepopsize to the task processor | |
taskProcessor.livenessProbe.failureThreshold | 5 | |
taskProcessor.livenessProbe.initialDelaySeconds | 5 | |
taskProcessor.livenessProbe.periodSeconds | 10 | |
taskProcessor.livenessProbe.successThreshold | 1 | |
taskProcessor.livenessProbe.timeoutSeconds | 2 | |
taskProcessor.readinessProbe.failureThreshold | 10 | |
taskProcessor.readinessProbe.initialDelaySeconds | 1 | |
taskProcessor.readinessProbe.periodSeconds | 10 | |
taskProcessor.readinessProbe.successThreshold | 1 | |
taskProcessor.readinessProbe.timeoutSeconds | 2 | |
taskProcessor.podAnnotations | {} | |
taskProcessor.resources | {} | |
taskProcessor.podLabels | {} | |
taskProcessor.nodeSelector | {} | |
taskProcessor.tolerations | [] | |
taskProcessor.affinity | {} | |
taskProcessor.podSecurityContext | {} | |
taskProcessor.defaultPodSecurityContext.enabled | Whether to use the default security context | true |
devPostgresql.enabled | If true , creates in-cluster PostgreSQL database | true |
postgresql.serviceAccount.enabled | Creates a service account for the PostgreSQL pod | true |
nameOverride | flagsmith-postgres | |
postgresqlDatabase | flagsmith | |
postgresqlUsername | postgres | |
postgresqlPassword | flagsmith | |
databaseExternal.enabled | Use an external database. Specify database URL, or all parts. | false |
databaseExternal.url | See schema. | |
databaseExternal.type | Note: Only PostgreSQL supported by default images. | postgres |
databaseExternal.port | 5432 | |
databaseExternal.database | Name of the database within the server | |
databaseExternal.username | ||
databaseExternal.password | ||
databaseExternal.urlFromExistingSecret.enabled | Reference an existing secret containing the database URL. | |
databaseExternal.urlFromExistingSecret.name | Name of referenced secret | |
databaseExternal.urlFromExistingSecret.key | Key within the referenced secret to use | |
influxdb2.enabled | true | |
influxdb2.nameOverride | influxdb | |
influxdb2.image.repository | Docker image repository for InfluxDB | quay.io/influxdb/influxdb |
influxdb2.image.tag | Docker image tag for InfluxDB | v2.0.2 |
influxdb2.image.imagePullPolicy | IfNotPresent | |
influxdb2.image.imagePullSecrets | [] | |
influxdb2.adminUser.organization | influxdata | |
influxdb2.adminUser.bucket | default | |
influxdb2.adminUser.user | admin | |
influxdb2.adminUser.password | randomly generated | |
influxdb2.adminUser.token | randomly generated | |
influxdb2.persistence.enabled | false | |
influxdb.resources | Resources per pod for the InfluxDB | {} |
influxdb.nodeSelector | {} | |
influxdb.tolerations | [] | |
influxdb.affinity | {} | |
influxdbExternal.enabled | Use an InfluxDB not managed by this chart | false |
influxdbExternal.url | ||
influxdbExternal.bucket | ||
influxdbExternal.organization | ||
influxdbExternal.token | ||
influxdbExternal.tokenFromExistingSecret.enabled | Use reference to a k8s secret not managed by this chart | false |
influxdbExternal.tokenFromExistingSecret.name | Referenced secret name | |
influxdbExternal.tokenFromExistingSecret.key | Key within the referenced secret to use | |
pgbouncer.enabled | false | |
pgbouncer.image.repository | bitnami/pgbouncer | |
pgbouncer.image.tag | 1.16.0 | |
pgbouncer.image.imagePullPolicy | IfNotPresent | |
pgbouncer.image.imagePullSecrets | [] | |
pgbouncer.replicaCount | Number of replicas for PgBouncer, null to unset | 1 |
pgbouncer.deploymentStrategy | See "Deployment strategy" above | |
pgbouncer.podAnnotations | {} | |
pgbouncer.resources | {} | |
pgbouncer.podLabels | {} | |
pgbouncer.extraEnv | {} | |
pgbouncer.nodeSelector | {} | |
pgbouncer.tolerations | [] | |
pgbouncer.affinity | {} | |
pgbouncer.podSecurityContext | {} | |
pgbouncer.securityContext | {} | |
pgbouncer.defaultSecurityContext.enabled | true | |
pgbouncer.defaultSecurityContext | {} | |
pgbouncer.livenessProbe.failureThreshold | 5 | |
pgbouncer.livenessProbe.initialDelaySeconds | 5 | |
pgbouncer.livenessProbe.periodSeconds | 10 | |
pgbouncer.livenessProbe.successThreshold | 1 | |
pgbouncer.livenessProbe.timeoutSeconds | 2 | |
pgbouncer.readinessProbe.failureThreshold | 10 | |
pgbouncer.readinessProbe.initialDelaySeconds | 1 | |
pgbouncer.readinessProbe.periodSeconds | 10 | |
pgbouncer.readinessProbe.successThreshold | 1 | |
pgbouncer.readinessProbe.timeoutSeconds | 2 | |
service.influxdb.externalPort | 8080 | |
service.api.type | ClusterIP | |
service.api.port | 8000 | |
service.frontend.type | ClusterIP | |
service.frontend.port | 8080 | |
ingress.frontend.enabled | false | |
ingress.frontend.ingressClassName | ||
ingress.frontend.annotations | {} | |
ingress.frontend.hosts | List of hostnames for frontend ingress | [chart-example.local] |
ingress.frontend.tls | [] | |
ingress.api.enabled | false | |
ingress.api.ingressClassName | ||
ingress.api.annotations | {} | |
ingress.api.hosts[].host | chart-example.local | |
ingress.api.hosts[].paths | [] | |
ingress.api.tls | [] | |
api.statsd.enabled | Enable statsd metric reporting from gunicorn. | false |
api.statsd.host | Host URL to receive statsd metrics | null |
api.statsd.hostFromNodeIp | Set as true to use the node IP as the statsd host instead | false |
api.statsd.port | Host port to receive statsd metrics | 8125 |
api.statsd.prefix | Prefix to add to metric IDs | flagsmith.api |
common.labels | Labels to add to all resources | {} |
common.annotations | Annotations to add to all resources | {} |
Key Upgrade Notes
- 0.37.0: upgrades the bundled in-cluster PostgreSQL. This makes no effort to preserve data in the bundled in-cluster PostgreSQL if it is in use. This also renames the bundled in-cluster PostgreSQL to have
dev-postgresql
in the name, to signify that it exists such that the chart can be deployed self-contained, but that this PostgreSQL instance is treated as disposable. All Flagsmith installations for which the data is not disposable should use an externally managed database.
Development and Contributing
Requirements
Helm version > 3.0.2
Running Locally
You can test and run the application locally on macOS using minikube
like this:
# Install Docker for Desktop and then:
brew install minikube
minikube start --memory 8192 --cpus 4
helm install flagsmith --debug ./flagsmith
minikube dashboard
Test Chart Installation
Install Chart without building a package:
helm install flagsmith --debug ./flagsmith
Run template and check Kubernetes resources are made:
helm template flagsmith flagsmith --debug -f flagsmith/values.yaml
Build Chart Package
To build chart package run:
helm package ./flagsmith