Add focalboard

This commit is contained in:
dvirlabs 2025-07-24 05:04:37 +03:00
parent 6e70468ae1
commit eb673c4f8e
15 changed files with 504 additions and 0 deletions

View File

@ -0,0 +1,21 @@
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: focalboard
namespace: argocd
spec:
project: dev-tools
source:
repoURL: 'https://git.dvirlabs.com/dvirlabs/dev-tools.git'
targetRevision: HEAD
path: charts/focalboard
helm:
valueFiles:
- ../../manifests/focalboard/values.yaml
destination:
server: https://kubernetes.default.svc
namespace: dev-tools
syncPolicy:
automated:
prune: true
selfHeal: true

View File

@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/

View File

@ -0,0 +1,11 @@
apiVersion: v2
appVersion: 0.6.7
description: Focalboard Server
keywords:
- focalboard
- mattermost
maintainers:
- name: stafot
name: focalboard
type: application
version: 0.5.0

View File

@ -0,0 +1,63 @@
Focalboard Helm Chart
====================================================
This is the Helm chart for the [Focalboard](https://www.focalboard.com/).
Focalboard is an open source, self-hosted alternative to Trello, Notion, and Asana.
It helps define, organize, track and manage work across individuals and teams.
The Focalboard source code lives [here](https://github.com/mattermost/focalboard).
# 1. Prerequisites
## 1.1 Kubernetes Cluster
You need a running Kubernetes cluster v1.16+. If you do not have one, find options and installation instructions here:
https://kubernetes.io/docs/setup/pick-right-solution/
## 1.2 Helm
See: https://docs.helm.sh/using_helm/#quickstart
We recommend installing Helm v3.5.3 or later.
Once Helm is installed and initialized, run the following:
```bash
helm repo add mattermost https://helm.mattermost.com
```
##1.3 Run locally
```bash
git clone git@github.com:mattermost/mattermost-helm.git (or use a fork of yours)
cd charts/focalboard
helm install focalboard . -n focalboard -f values.yaml
```
# 2. Configuration
To start, copy [focalboard/values.yaml](https://github.com/mattermost/mattermost-helm/blob/master/charts/focalboard/values.yaml) and name it `config.yaml`. This will be your configuration file for the Focalboard Helm chart.
# 3. Install Focalboard
You can launch the Mattermost push proxy chart with:
```bash
$ helm repo add mattermost https://helm.mattermost.com
$ helm install mattermost/focalboard
```
To list options for focalboard:
```bash
$ helm inspect values mattermost/focalboard
```
# 4. Developing
If you are going to modify the helm charts, it is helpful to use `--dry-run` (doesn't do an actual deployment) and `--debug` (print the generated config files) when running `helm install`.
Helm has partial support for pulling values out of a subchart via the requirements.yaml. It also has limited support for pushing values into subcharts. It does not support using templating inside a values.yaml file.
We recommend using [kind](https://github.com/kubernetes-sigs/kind) for local development if you do not have access to Kubernetes cluster running in the cloud.

View File

@ -0,0 +1,22 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range $host := .Values.ingress.hosts }}
{{- range .paths }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
{{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "focalboard.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "focalboard.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "focalboard.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "focalboard.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 80:$CONTAINER_PORT
echo "Visit http://127.0.0.1:80 to use your application"
{{- end }}

View File

@ -0,0 +1,62 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "focalboard.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 "focalboard.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 "focalboard.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "focalboard.labels" -}}
helm.sh/chart: {{ include "focalboard.chart" . }}
{{ include "focalboard.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "focalboard.selectorLabels" -}}
app.kubernetes.io/name: {{ include "focalboard.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "focalboard.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "focalboard.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,62 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "focalboard.fullname" . }}
labels:
{{- include "focalboard.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
{{- include "focalboard.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "focalboard.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "focalboard.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: 8000
protocol: TCP
resources:
{{- toYaml .Values.resources | nindent 12 }}
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
{{- if .Values.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ template "focalboard.fullname" . }}
{{- else }}
emptyDir: {}
{{- end -}}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}

View File

@ -0,0 +1,52 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "focalboard.fullname" . -}}
{{- $svcPort := .Values.service.port -}}
{{- if .Capabilities.APIVersions.Has "networking.k8s.io/v1" -}}
apiVersion: networking.k8s.io/v1
{{- else if .Capabilities.APIVersions.Has "networking.k8s.io/v1beta1" -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
{{- include "focalboard.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
{{- if $.Capabilities.APIVersions.Has "networking.k8s.io/v1" }}
backend:
service:
name: {{ $fullName }}
port:
number: {{ $svcPort }}
pathType: Prefix
{{- else }}
backend:
serviceName: {{ $fullName }}
servicePort: {{ $svcPort }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}

View File

@ -0,0 +1,23 @@
{{- if .Values.persistence.enabled }}
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: {{ template "focalboard.fullname" . }}
labels:
app: {{ template "focalboard.fullname" . }}
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
heritage: "{{ .Release.Service }}"
annotations:
{{- if .Values.persistence.storageClass }}
volume.beta.kubernetes.io/storage-class: {{ .Values.persistence.storageClass | quote }}
{{- else }}
volume.alpha.kubernetes.io/storage-class: default
{{- end }}
spec:
accessModes:
- {{ .Values.persistence.accessMode | quote }}
resources:
requests:
storage: {{ .Values.persistence.size | quote }}
{{- end }}

View File

@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "focalboard.fullname" . }}
labels:
{{- include "focalboard.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "focalboard.selectorLabels" . | nindent 4 }}

View File

@ -0,0 +1,12 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "focalboard.serviceAccountName" . }}
labels:
{{- include "focalboard.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}

View File

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

View File

@ -0,0 +1,86 @@
# Default values for focalboard.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
# NOTE: At the moment focalboard supports only 1 replica deployment.
replicaCount: 1
image:
repository: mattermost/focalboard
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: "0.6.7"
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
# Specifies whether a service account should be created
create: true
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
podAnnotations: {}
podSecurityContext: {}
# fsGroup: 2000
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
service:
type: ClusterIP
port: 80
ingress:
enabled: false
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
- host: focalboard.example.com
paths:
- path: /
backend:
serviceName: focalboard
servicePort: 80
tls: []
# - secretName: chart-example-tls
# hosts:
# - chart-example.local
## Persist data to a persitent volume
persistence:
enabled: false
## If defined, volume.beta.kubernetes.io/storage-class: <storageClass>
## Default: volume.alpha.kubernetes.io/storage-class: default
##
# storageClass:
# accessMode: ReadWriteOnce
# size: 8Gi
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
nodeSelector: {}
tolerations: []
affinity: {}

View File

@ -0,0 +1,2 @@
enabled: true
hostname: focalboard.dvirlabs.com

View File

@ -0,0 +1,35 @@
ingress:
enabled: true
hostname: focalboard.dvirlabs.com
ingressClassName: traefik
annotations:
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
tls: true
extraTls:
- hosts:
- focalboard.dvirlabs.com
secretName: focalboard-cert
service:
type: ClusterIP
focalboard:
username: admin@dvirlabs.com
password: "admin1234"
postgresql:
enabled: true
auth:
username: focalboard
password: focalboard
database: focalboard
primary:
persistence:
size: 10Gi
persistence:
enabled: true
accessModes:
- ReadWriteOnce
size: 5Gi