mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-17 13:05:32 +09:00
feat(deploy): add a complete fluxer helm chart (#3436)
This commit is contained in:
1 parent
fb58447ba1
commit
8e39380ee6
80 files changed
+5128
-3078
No files matched your search
@@ -0,0 +1,183 @@
|
|||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
name: Helm chart
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- deploy/helm/**
|
||||||
|
- deploy/self-hosting/Caddyfile
|
||||||
|
- .github/workflows/helm.yaml
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
paths:
|
||||||
|
- deploy/helm/**
|
||||||
|
- deploy/self-hosting/Caddyfile
|
||||||
|
- .github/workflows/helm.yaml
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
render:
|
||||||
|
name: Lint and render with Helm ${{ matrix.helm }}
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
timeout-minutes: 15
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- helm: v3.19.0
|
||||||
|
sha256: a7f81ce08007091b86d8bd696eb4d86b8d0f2e1b9f6c714be62f82f96a594496
|
||||||
|
- helm: v4.2.4
|
||||||
|
sha256: c306b46f719b0a4da32d0f78ee21bf90ce8d602f15b22ab753f0674d1670a7f3
|
||||||
|
env:
|
||||||
|
CHART: deploy/helm/fluxer
|
||||||
|
KUBECONFORM_VERSION: v0.7.0
|
||||||
|
KUBECONFORM_SHA256: c31518ddd122663b3f3aa874cfe8178cb0988de944f29c74a0b9260920d115d3
|
||||||
|
CRD_CATALOG: https://raw.githubusercontent.com/datreeio/CRDs-catalog/63669a570e231d4f1f8396d229a1de512bcf0a34/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json
|
||||||
|
steps:
|
||||||
|
- name: Checkout fluxer
|
||||||
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
|
||||||
|
with:
|
||||||
|
persist-credentials: false
|
||||||
|
|
||||||
|
- name: Install Helm and kubeconform
|
||||||
|
env:
|
||||||
|
HELM_VERSION: ${{ matrix.helm }}
|
||||||
|
HELM_SHA256: ${{ matrix.sha256 }}
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
mkdir -p "$RUNNER_TEMP/bin"
|
||||||
|
cd "$RUNNER_TEMP"
|
||||||
|
curl -fsSLo helm.tgz "https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz"
|
||||||
|
echo "${HELM_SHA256} helm.tgz" | sha256sum -c -
|
||||||
|
tar -xzf helm.tgz linux-amd64/helm
|
||||||
|
mv linux-amd64/helm bin/helm
|
||||||
|
curl -fsSLo kubeconform.tgz "https://github.com/yannh/kubeconform/releases/download/${KUBECONFORM_VERSION}/kubeconform-linux-amd64.tar.gz"
|
||||||
|
echo "${KUBECONFORM_SHA256} kubeconform.tgz" | sha256sum -c -
|
||||||
|
tar -xzf kubeconform.tgz kubeconform
|
||||||
|
mv kubeconform bin/kubeconform
|
||||||
|
echo "$RUNNER_TEMP/bin" >> "$GITHUB_PATH"
|
||||||
|
|
||||||
|
- name: Lint, render and validate every CI values file
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
command -v helm kubeconform python3
|
||||||
|
python3 -c 'import yaml'
|
||||||
|
helm version --short
|
||||||
|
shopt -s nullglob
|
||||||
|
files=("$CHART"/ci/*.yaml)
|
||||||
|
if [ "${#files[@]}" -eq 0 ]; then
|
||||||
|
echo "::error::no values files under $CHART/ci"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
for values in "${files[@]}"; do
|
||||||
|
echo "::group::$values"
|
||||||
|
helm lint --strict "$CHART" -f "$values"
|
||||||
|
helm template fluxer "$CHART" -n fluxer -f "$values" \
|
||||||
|
--api-versions cert-manager.io/v1 --api-versions gateway.networking.k8s.io/v1 > rendered.yaml
|
||||||
|
kubeconform -strict -summary -kubernetes-version 1.29.0 \
|
||||||
|
-schema-location default -schema-location "$CRD_CATALOG" rendered.yaml
|
||||||
|
if grep -qi 'example\.com' rendered.yaml; then
|
||||||
|
echo "::error::$values renders example.com"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if grep -Eqi 'change_?me' rendered.yaml; then
|
||||||
|
echo "::error::$values renders a CHANGE_ME placeholder"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "::endgroup::"
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Check the guards
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
expect_failure() {
|
||||||
|
local message=$1
|
||||||
|
shift
|
||||||
|
if output=$(helm template fluxer "$CHART" "$@" 2>&1); then
|
||||||
|
echo "::error::rendered with $*"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! grep -qF "$message" <<<"$output"; then
|
||||||
|
echo "::error::expected \"$message\" for $*, got: $output"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
d=domain=chat.example.test
|
||||||
|
expect_failure "domain must be set"
|
||||||
|
expect_failure "is a placeholder" --set $d --set secrets.values.FLUXER_SUDO_MODE_SECRET=CHANGE_ME
|
||||||
|
expect_failure "is a placeholder" --set $d --set-string 'secrets.extra.FLUXER_STRIPE_SECRET_KEY=<change-me>'
|
||||||
|
expect_failure "at least 32 characters" --set $d --set secrets.values.FLUXER_GATEWAY_RPC_AUTH_TOKEN=short
|
||||||
|
expect_failure "letters and digits only" --set $d --set-string 'secrets.values.FLUXER_VALKEY_PASSWORD=0123456789abcdef0123456789abcd:@'
|
||||||
|
expect_failure "worker.replicas must be 1" --set $d --set worker.replicas=2
|
||||||
|
expect_failure "at least 32 bytes" --set $d --set secrets.values.FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64=c2hvcnQ=
|
||||||
|
expect_failure "set postgres.external.host" --set $d --set postgres.enabled=false
|
||||||
|
expect_failure "set together" --set $d --set secrets.values.FLUXER_VAPID_PUBLIC_KEY=abc
|
||||||
|
expect_failure "is a secret and would be stored in plain text" --set $d --set env.FLUXER_EMAIL_SMTP_PASSWORD=not-a-real-password
|
||||||
|
expect_failure "is a secret and would be stored in plain text" --set $d --set api.env.FLUXER_STRIPE_SECRET_KEY=not-a-real-key
|
||||||
|
expect_failure "holds a password" --set $d --set-string 'env.FLUXER_SEARCH_URL=https://user:[email protected]'
|
||||||
|
expect_failure "Set livekit.nodeCIDRs" --set $d --set networkPolicy.ingressNamespaceSelector.matchLabels.name=ingress
|
||||||
|
expect_failure "set livekit.external.publicUrl" --set $d --set livekit.enabled=false --set livekit.external.url=http://livekit.voice.svc:7880
|
||||||
|
expect_failure "reserve a public address" --set $d --set livekit.expose=loadBalancer
|
||||||
|
|
||||||
|
- name: Check that a chart version bump restarts nothing
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
cp -R "$CHART" "$RUNNER_TEMP/bumped"
|
||||||
|
sed -e 's/^version: .*/version: 99.0.0/' -e 's/^appVersion: .*/appVersion: "bumped"/' "$CHART/Chart.yaml" > "$RUNNER_TEMP/bumped/Chart.yaml"
|
||||||
|
helm template fluxer "$CHART" -n fluxer -f "$CHART/ci/existing-secret-values.yaml" > before.yaml
|
||||||
|
helm template fluxer "$RUNNER_TEMP/bumped" -n fluxer -f "$CHART/ci/existing-secret-values.yaml" > after.yaml
|
||||||
|
python3 - before.yaml after.yaml <<'PY'
|
||||||
|
import sys, yaml
|
||||||
|
def pods(path):
|
||||||
|
out = {}
|
||||||
|
for doc in yaml.safe_load_all(open(path)):
|
||||||
|
if doc and doc.get('kind') in ('Deployment', 'StatefulSet'):
|
||||||
|
spec = doc['spec']
|
||||||
|
out[f"{doc['kind']}/{doc['metadata']['name']}"] = (spec['template'], spec['selector'], spec.get('volumeClaimTemplates'))
|
||||||
|
return out
|
||||||
|
before, after = pods(sys.argv[1]), pods(sys.argv[2])
|
||||||
|
if len(before) < 20:
|
||||||
|
sys.exit(f'only {len(before)} workloads rendered')
|
||||||
|
changed = sorted(name for name in before.keys() | after.keys() if before.get(name) != after.get(name))
|
||||||
|
if changed:
|
||||||
|
sys.exit('a chart version bump changes the pod template of: ' + ', '.join(changed))
|
||||||
|
print(f'{len(before)} workloads keep their pod template across a chart version bump')
|
||||||
|
PY
|
||||||
|
|
||||||
|
- name: Check the default resource requests
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
helm template fluxer "$CHART" -n fluxer -f "$CHART/ci/default-values.yaml" > rendered.yaml
|
||||||
|
python3 - rendered.yaml <<'PY'
|
||||||
|
import sys, yaml
|
||||||
|
def cpu(v):
|
||||||
|
v = str(v)
|
||||||
|
return float(v[:-1]) if v.endswith('m') else float(v) * 1000
|
||||||
|
units = {'Ki': 2**10, 'Mi': 2**20, 'Gi': 2**30}
|
||||||
|
def mem(v):
|
||||||
|
v = str(v)
|
||||||
|
for unit, factor in units.items():
|
||||||
|
if v.endswith(unit):
|
||||||
|
return float(v[:-len(unit)]) * factor
|
||||||
|
return float(v)
|
||||||
|
total_cpu = total_mem = 0
|
||||||
|
for doc in yaml.safe_load_all(open(sys.argv[1])):
|
||||||
|
if not doc or doc.get('kind') not in ('Deployment', 'StatefulSet'):
|
||||||
|
continue
|
||||||
|
replicas = doc['spec'].get('replicas', 1)
|
||||||
|
for container in doc['spec']['template']['spec']['containers']:
|
||||||
|
requests = (container.get('resources') or {}).get('requests') or {}
|
||||||
|
if 'cpu' not in requests or 'memory' not in requests:
|
||||||
|
sys.exit(f"{doc['kind']}/{doc['metadata']['name']} has a container without cpu and memory requests")
|
||||||
|
total_cpu += replicas * cpu(requests['cpu'])
|
||||||
|
total_mem += replicas * mem(requests['memory'])
|
||||||
|
print(f"requests: {total_cpu:.0f}m cpu, {total_mem / 2**30:.2f}Gi memory")
|
||||||
|
if total_cpu > 1200 or total_mem > 4.5 * 2**30:
|
||||||
|
sys.exit('the default install requests more than 1200m cpu or 4.5Gi memory')
|
||||||
|
PY
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
apiVersion: v2
|
|
||||||
name: fluxer-api
|
|
||||||
description: Fluxer HTTP API and background job workers
|
|
||||||
type: application
|
|
||||||
version: 0.1.0
|
|
||||||
appVersion: "v1"
|
|
||||||
@@ -1,244 +0,0 @@
|
|||||||
{{- define "fluxer-api.chart" -}}
|
|
||||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-api.selectorLabels" -}}
|
|
||||||
app.kubernetes.io/name: {{ .name }}
|
|
||||||
app.kubernetes.io/instance: {{ .root.Release.Name }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-api.labels" -}}
|
|
||||||
{{ include "fluxer-api.selectorLabels" . }}
|
|
||||||
app.kubernetes.io/component: {{ .component }}
|
|
||||||
app.kubernetes.io/part-of: fluxer
|
|
||||||
app.kubernetes.io/managed-by: {{ .root.Release.Service }}
|
|
||||||
helm.sh/chart: {{ include "fluxer-api.chart" .root }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-api.image" -}}
|
|
||||||
{{- $g := .root.Values.image | default dict -}}
|
|
||||||
{{- $i := .w.image | default dict -}}
|
|
||||||
{{- $repo := $i.repository -}}
|
|
||||||
{{- if not $repo -}}
|
|
||||||
{{- $repo = printf "%s/%s" (required "image.registry is required" $g.registry) ($i.name | default "fluxer-api") -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- $tag := required "image.tag is required" ($i.tag | default $g.tag) -}}
|
|
||||||
{{- if $i.digest -}}
|
|
||||||
{{- printf "%s:%s@%s" $repo $tag $i.digest | quote -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- printf "%s:%s" $repo $tag | quote -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-api.pick" -}}
|
|
||||||
{{- $v := ternary (get .w .key) (get .root.Values .key) (hasKey .w .key) -}}
|
|
||||||
{{- if $v }}
|
|
||||||
{{- toYaml $v }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-api.str" -}}
|
|
||||||
{{- if and (kindIs "float64" .) (eq . (floor .)) -}}
|
|
||||||
{{- int64 . | toString | quote -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- toString . | quote -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-api.env" -}}
|
|
||||||
{{- $env := dict -}}
|
|
||||||
{{- range $k, $val := .root.Values.env | default dict }}
|
|
||||||
{{- $_ := set $env $k $val }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range $k, $val := .w.env | default dict }}
|
|
||||||
{{- $_ := set $env $k $val }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range $k, $val := $env }}
|
|
||||||
{{- if not (kindIs "invalid" $val) }}
|
|
||||||
- name: {{ $k }}
|
|
||||||
value: {{ include "fluxer-api.str" $val }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .w.buildVersion }}
|
|
||||||
- name: BUILD_VERSION
|
|
||||||
value: {{ include "fluxer-api.str" . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with concat (.root.Values.extraEnv | default list) (.w.extraEnv | default list) }}
|
|
||||||
{{ toYaml . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-api.topologySpread" -}}
|
|
||||||
{{- $tscs := ternary .w.topologySpreadConstraints .root.Values.topologySpreadConstraints (hasKey .w "topologySpreadConstraints") -}}
|
|
||||||
{{- range $tscs }}
|
|
||||||
{{- $c := deepCopy . }}
|
|
||||||
{{- if not $c.labelSelector }}
|
|
||||||
{{- $_ := set $c "labelSelector" (dict "matchLabels" (include "fluxer-api.selectorLabels" $ | fromYaml)) }}
|
|
||||||
{{- end }}
|
|
||||||
- {{- toYaml $c | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-api.pdb" -}}
|
|
||||||
{{- with .w.pdb }}
|
|
||||||
---
|
|
||||||
apiVersion: policy/v1
|
|
||||||
kind: PodDisruptionBudget
|
|
||||||
metadata:
|
|
||||||
name: {{ $.name }}-pdb
|
|
||||||
namespace: {{ $.root.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-api.labels" $ | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
{{- toYaml . | nindent 2 }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "fluxer-api.selectorLabels" $ | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-api.hpa" -}}
|
|
||||||
{{- with .w.hpa }}
|
|
||||||
---
|
|
||||||
apiVersion: autoscaling/v2
|
|
||||||
kind: HorizontalPodAutoscaler
|
|
||||||
metadata:
|
|
||||||
name: {{ $.name }}
|
|
||||||
namespace: {{ $.root.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-api.labels" $ | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
scaleTargetRef:
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
name: {{ $.name }}
|
|
||||||
minReplicas: {{ required (printf "%s.hpa.minReplicas is required" $.name) .minReplicas }}
|
|
||||||
maxReplicas: {{ required (printf "%s.hpa.maxReplicas is required" $.name) .maxReplicas }}
|
|
||||||
{{- with .targetCPUUtilizationPercentage }}
|
|
||||||
metrics:
|
|
||||||
- type: Resource
|
|
||||||
resource:
|
|
||||||
name: cpu
|
|
||||||
target:
|
|
||||||
type: Utilization
|
|
||||||
averageUtilization: {{ . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .behavior }}
|
|
||||||
behavior:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-api.deployment" -}}
|
|
||||||
{{- $root := .root -}}
|
|
||||||
{{- $v := $root.Values -}}
|
|
||||||
{{- $w := .w -}}
|
|
||||||
{{- $envFrom := concat ($v.envFrom | default list) ($w.envFrom | default list) -}}
|
|
||||||
{{- $podAnnotations := merge (dict) ($w.podAnnotations | default dict) ($v.podAnnotations | default dict) -}}
|
|
||||||
{{- $wProbes := $w.probes | default dict -}}
|
|
||||||
{{- $gProbes := .probes | default dict -}}
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: {{ .name }}
|
|
||||||
namespace: {{ $root.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-api.labels" . | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
{{- if not $w.hpa }}
|
|
||||||
replicas: {{ if kindIs "invalid" $w.replicas }}1{{ else }}{{ int $w.replicas }}{{ end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if not (kindIs "invalid" $w.minReadySeconds) }}
|
|
||||||
minReadySeconds: {{ int $w.minReadySeconds }}
|
|
||||||
{{- end }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "fluxer-api.selectorLabels" . | nindent 6 }}
|
|
||||||
{{- with include "fluxer-api.pick" (dict "root" $root "w" $w "key" "strategy") }}
|
|
||||||
strategy:
|
|
||||||
{{- . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-api.labels" . | nindent 8 }}
|
|
||||||
{{- with $podAnnotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
{{- with include "fluxer-api.pick" (dict "root" $root "w" $w "key" "imagePullSecrets") }}
|
|
||||||
imagePullSecrets:
|
|
||||||
{{- . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-api.pick" (dict "root" $root "w" $w "key" "podSecurityContext") }}
|
|
||||||
securityContext:
|
|
||||||
{{- . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if not (kindIs "invalid" $w.terminationGracePeriodSeconds) }}
|
|
||||||
terminationGracePeriodSeconds: {{ int $w.terminationGracePeriodSeconds }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-api.pick" (dict "root" $root "w" $w "key" "nodeSelector") }}
|
|
||||||
nodeSelector:
|
|
||||||
{{- . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-api.pick" (dict "root" $root "w" $w "key" "affinity") }}
|
|
||||||
affinity:
|
|
||||||
{{- . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-api.pick" (dict "root" $root "w" $w "key" "tolerations") }}
|
|
||||||
tolerations:
|
|
||||||
{{- . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-api.topologySpread" . | trim }}
|
|
||||||
topologySpreadConstraints:
|
|
||||||
{{- . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
containers:
|
|
||||||
- name: {{ .name }}
|
|
||||||
image: {{ include "fluxer-api.image" . }}
|
|
||||||
imagePullPolicy: {{ ($w.image | default dict).pullPolicy | default ($v.image | default dict).pullPolicy | default "IfNotPresent" }}
|
|
||||||
{{- with .command }}
|
|
||||||
command:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-api.env" . | trim }}
|
|
||||||
env:
|
|
||||||
{{- . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $envFrom }}
|
|
||||||
envFrom:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
containerPort: 8080
|
|
||||||
{{- with $w.lifecycle }}
|
|
||||||
lifecycle:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range $probe := list "startup" "liveness" "readiness" }}
|
|
||||||
{{- with hasKey $wProbes $probe | ternary (get $wProbes $probe) (get $gProbes $probe) }}
|
|
||||||
{{ $probe }}Probe:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.resources }}
|
|
||||||
resources:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-api.pick" (dict "root" $root "w" $w "key" "securityContext") }}
|
|
||||||
securityContext:
|
|
||||||
{{- . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.extraVolumeMounts }}
|
|
||||||
volumeMounts:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.extraVolumes }}
|
|
||||||
volumes:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
{{- range $name, $w := .Values.api }}
|
|
||||||
{{- if not (kindIs "invalid" $w) }}
|
|
||||||
{{- $ctx := dict "root" $ "name" $name "w" $w "component" "api" "probes" ($.Values.probes | default dict) }}
|
|
||||||
{{ include "fluxer-api.deployment" $ctx }}
|
|
||||||
{{ include "fluxer-api.hpa" $ctx }}
|
|
||||||
{{ include "fluxer-api.pdb" $ctx }}
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: {{ $name }}
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-api.labels" $ctx | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
type: ClusterIP
|
|
||||||
selector:
|
|
||||||
{{- include "fluxer-api.selectorLabels" $ctx | nindent 4 }}
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
port: 8080
|
|
||||||
targetPort: http
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{{- range $name, $w := .Values.workers }}
|
|
||||||
{{- if not (kindIs "invalid" $w) }}
|
|
||||||
{{- $ctx := dict "root" $ "name" $name "w" $w "component" "worker" "command" (list "node" "dist/WorkerEntrypoint.js") "probes" (dict) }}
|
|
||||||
{{ include "fluxer-api.deployment" $ctx }}
|
|
||||||
{{ include "fluxer-api.hpa" $ctx }}
|
|
||||||
{{ include "fluxer-api.pdb" $ctx }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
image:
|
|
||||||
registry: ghcr.io/fluxerapp
|
|
||||||
tag: v1
|
|
||||||
pullPolicy: IfNotPresent
|
|
||||||
|
|
||||||
imagePullSecrets: []
|
|
||||||
|
|
||||||
env:
|
|
||||||
NODE_ENV: production
|
|
||||||
FLUXER_ENV: production
|
|
||||||
FLUXER_PUBLIC_ORIGIN: https://web.example.com
|
|
||||||
FLUXER_API_ENDPOINT: https://api.example.com
|
|
||||||
FLUXER_GATEWAY_ENDPOINT: wss://gateway.example.com
|
|
||||||
FLUXER_MEDIA_ENDPOINT: https://media.example.com
|
|
||||||
FLUXER_ADMIN_ENDPOINT: https://admin.example.com
|
|
||||||
FLUXER_MEDIA_PROXY_UPLOAD_RELAY_ENDPOINT: https://uploads.example.com
|
|
||||||
FLUXER_INTERNAL_MEDIA_PROXY_ENDPOINT: http://media-proxy:8080
|
|
||||||
FLUXER_KV_URL: redis://valkey:6379/0
|
|
||||||
FLUXER_NATS_URL: nats://nats:4222
|
|
||||||
FLUXER_NATS_JETSTREAM_URL: nats://nats:4222
|
|
||||||
|
|
||||||
extraEnv: []
|
|
||||||
|
|
||||||
envFrom:
|
|
||||||
- secretRef:
|
|
||||||
name: fluxer-env
|
|
||||||
|
|
||||||
podAnnotations: {}
|
|
||||||
|
|
||||||
podSecurityContext:
|
|
||||||
runAsNonRoot: true
|
|
||||||
seccompProfile:
|
|
||||||
type: RuntimeDefault
|
|
||||||
|
|
||||||
securityContext:
|
|
||||||
allowPrivilegeEscalation: false
|
|
||||||
|
|
||||||
probes:
|
|
||||||
startup:
|
|
||||||
httpGet:
|
|
||||||
path: /_health
|
|
||||||
port: http
|
|
||||||
periodSeconds: 10
|
|
||||||
failureThreshold: 30
|
|
||||||
liveness:
|
|
||||||
httpGet:
|
|
||||||
path: /_health
|
|
||||||
port: http
|
|
||||||
readiness:
|
|
||||||
httpGet:
|
|
||||||
path: /_health
|
|
||||||
port: http
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
type: RollingUpdate
|
|
||||||
|
|
||||||
topologySpreadConstraints: []
|
|
||||||
|
|
||||||
nodeSelector: {}
|
|
||||||
|
|
||||||
tolerations: []
|
|
||||||
|
|
||||||
affinity: {}
|
|
||||||
|
|
||||||
api:
|
|
||||||
api:
|
|
||||||
replicas: 1
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
cpu: 250m
|
|
||||||
memory: 1Gi
|
|
||||||
limits:
|
|
||||||
memory: 2560Mi
|
|
||||||
|
|
||||||
workers:
|
|
||||||
worker:
|
|
||||||
replicas: 1
|
|
||||||
env:
|
|
||||||
FLUXER_API_WORKER_MODE: all_lanes
|
|
||||||
FLUXER_API_WORKER_ENABLE_CRON_SCHEDULER: "true"
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
cpu: 250m
|
|
||||||
memory: 1Gi
|
|
||||||
limits:
|
|
||||||
memory: 2560Mi
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
apiVersion: v2
|
|
||||||
name: fluxer-gateway
|
|
||||||
description: A Helm chart for the Fluxer realtime gateway.
|
|
||||||
type: application
|
|
||||||
version: 0.1.0
|
|
||||||
appVersion: "v1"
|
|
||||||
@@ -1,280 +0,0 @@
|
|||||||
{{- define "gateway.selectorLabels" -}}
|
|
||||||
app.kubernetes.io/name: {{ .name }}
|
|
||||||
app.kubernetes.io/instance: {{ .root.Release.Name }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "gateway.labels" -}}
|
|
||||||
{{ include "gateway.selectorLabels" . }}
|
|
||||||
{{- with .component }}
|
|
||||||
app.kubernetes.io/component: {{ . }}
|
|
||||||
{{- end }}
|
|
||||||
app.kubernetes.io/part-of: fluxer
|
|
||||||
app.kubernetes.io/managed-by: {{ .root.Release.Service }}
|
|
||||||
helm.sh/chart: {{ printf "%s-%s" .root.Chart.Name .root.Chart.Version | replace "+" "_" }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "gateway.headlessName" -}}
|
|
||||||
{{ printf "%s-headless" .Release.Name }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "gateway.pick" -}}
|
|
||||||
{{- $v := get .root.Values .key }}
|
|
||||||
{{- if hasKey .w .key }}
|
|
||||||
{{- $v = get .w .key }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $v }}
|
|
||||||
{{- toYaml . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "gateway.string" -}}
|
|
||||||
{{- if and (kindIs "float64" .) (eq . (float64 (int64 .))) }}
|
|
||||||
{{- int64 . | toString }}
|
|
||||||
{{- else }}
|
|
||||||
{{- toString . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "gateway.envList" -}}
|
|
||||||
{{- $env := deepCopy (.root.Values.env | default dict) }}
|
|
||||||
{{- range $k, $v := .w.env | default dict }}
|
|
||||||
{{- if kindIs "invalid" $v }}
|
|
||||||
{{- $_ := unset $env $k }}
|
|
||||||
{{- else }}
|
|
||||||
{{- $_ := set $env $k $v }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range $k, $v := $env }}
|
|
||||||
{{- if not (kindIs "invalid" $v) }}
|
|
||||||
- name: {{ $k }}
|
|
||||||
value: {{ include "gateway.string" $v | quote }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with concat (.root.Values.extraEnv | default list) (.w.extraEnv | default list) }}
|
|
||||||
{{ toYaml . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "gateway.envFrom" -}}
|
|
||||||
{{- with concat (.root.Values.envFrom | default list) (.w.envFrom | default list) }}
|
|
||||||
{{- toYaml . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "gateway.podAnnotations" -}}
|
|
||||||
{{- with merge (deepCopy (.w.podAnnotations | default dict)) (deepCopy (.root.Values.podAnnotations | default dict)) }}
|
|
||||||
{{- toYaml . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "gateway.probes" -}}
|
|
||||||
{{- $global := .root.Values.probes | default dict }}
|
|
||||||
{{- $own := .w.probes | default dict }}
|
|
||||||
{{- range $probe := list "startup" "liveness" "readiness" }}
|
|
||||||
{{- $p := get $global $probe }}
|
|
||||||
{{- if hasKey $own $probe }}
|
|
||||||
{{- $p = get $own $probe }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $p }}
|
|
||||||
{{ $probe }}Probe:
|
|
||||||
{{- toYaml . | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "gateway.topologySpreadConstraints" -}}
|
|
||||||
{{- $out := list }}
|
|
||||||
{{- range include "gateway.pick" (dict "root" .root "w" .w "key" "topologySpreadConstraints") | fromYamlArray }}
|
|
||||||
{{- $c := deepCopy . }}
|
|
||||||
{{- if not (hasKey $c "labelSelector") }}
|
|
||||||
{{- $_ := set $c "labelSelector" (dict "matchLabels" (include "gateway.selectorLabels" $ | fromYaml)) }}
|
|
||||||
{{- end }}
|
|
||||||
{{- $out = append $out $c }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $out }}
|
|
||||||
{{- toYaml . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "gateway.image" -}}
|
|
||||||
{{- $img := .w.image | default dict }}
|
|
||||||
{{- $v := .root.Values.image }}
|
|
||||||
{{- $repo := $img.repository | default (printf "%s/%s" $v.registry ($img.name | default "fluxer-gateway")) }}
|
|
||||||
{{- $ref := printf "%s:%s" $repo ($img.tag | default $v.tag) }}
|
|
||||||
{{- with $img.digest }}
|
|
||||||
{{- $ref = printf "%s@%s" $ref . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- $ref | quote }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "gateway.replicas" -}}
|
|
||||||
{{- if kindIs "invalid" .w.replicas }}1{{ else }}{{ .w.replicas }}{{ end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "gateway.env" -}}
|
|
||||||
{{- $root := .root }}
|
|
||||||
{{- $w := .w -}}
|
|
||||||
{{- with $w.role }}
|
|
||||||
- name: FLUXER_GATEWAY_ROLE
|
|
||||||
value: {{ . | quote }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if not (kindIs "invalid" $w.buildVersion) }}
|
|
||||||
- name: BUILD_VERSION
|
|
||||||
value: {{ include "gateway.string" $w.buildVersion | quote }}
|
|
||||||
{{- end }}
|
|
||||||
- name: POD_IP
|
|
||||||
valueFrom:
|
|
||||||
fieldRef:
|
|
||||||
apiVersion: v1
|
|
||||||
fieldPath: status.podIP
|
|
||||||
- name: FLUXER_ERLANG_NODE_NAME
|
|
||||||
value: fluxer_gateway@$(POD_IP)
|
|
||||||
- name: FLUXER_ERLANG_DIST_PORT
|
|
||||||
value: "8081"
|
|
||||||
- name: FLUXER_GATEWAY_CLUSTER_ENABLED
|
|
||||||
value: "true"
|
|
||||||
- name: FLUXER_GATEWAY_CLUSTER_DISCOVERY_DNS_NAME
|
|
||||||
value: {{ printf "%s.%s.svc.%s" (include "gateway.headlessName" $root) $root.Release.Namespace $root.Values.clusterDomain | quote }}
|
|
||||||
- name: FLUXER_GATEWAY_CLUSTER_DISCOVERY_NODE_BASENAME
|
|
||||||
value: fluxer_gateway
|
|
||||||
{{- include "gateway.envList" . }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "gateway.pod" -}}
|
|
||||||
{{- $root := .root }}
|
|
||||||
{{- $w := .w -}}
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
{{- include "gateway.labels" . | nindent 4 }}
|
|
||||||
{{- with include "gateway.podAnnotations" . }}
|
|
||||||
annotations:
|
|
||||||
{{- . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
{{- with include "gateway.pick" (dict "root" $root "w" $w "key" "affinity") }}
|
|
||||||
affinity:
|
|
||||||
{{- . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "gateway.pick" (dict "root" $root "w" $w "key" "imagePullSecrets") }}
|
|
||||||
imagePullSecrets:
|
|
||||||
{{- . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "gateway.pick" (dict "root" $root "w" $w "key" "nodeSelector") }}
|
|
||||||
nodeSelector:
|
|
||||||
{{- . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "gateway.pick" (dict "root" $root "w" $w "key" "tolerations") }}
|
|
||||||
tolerations:
|
|
||||||
{{- . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "gateway.topologySpreadConstraints" . }}
|
|
||||||
topologySpreadConstraints:
|
|
||||||
{{- . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "gateway.pick" (dict "root" $root "w" $w "key" "podSecurityContext") }}
|
|
||||||
securityContext:
|
|
||||||
{{- . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if not (kindIs "invalid" $w.terminationGracePeriodSeconds) }}
|
|
||||||
terminationGracePeriodSeconds: {{ $w.terminationGracePeriodSeconds }}
|
|
||||||
{{- end }}
|
|
||||||
containers:
|
|
||||||
- name: gateway
|
|
||||||
image: {{ include "gateway.image" . }}
|
|
||||||
imagePullPolicy: {{ ($w.image | default dict).pullPolicy | default $root.Values.image.pullPolicy }}
|
|
||||||
env:
|
|
||||||
{{- include "gateway.env" . | trim | nindent 6 }}
|
|
||||||
{{- with include "gateway.envFrom" . }}
|
|
||||||
envFrom:
|
|
||||||
{{- . | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.lifecycle }}
|
|
||||||
lifecycle:
|
|
||||||
{{- toYaml . | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
containerPort: 8080
|
|
||||||
protocol: TCP
|
|
||||||
- name: epmd
|
|
||||||
containerPort: 4369
|
|
||||||
protocol: TCP
|
|
||||||
- name: erl-dist
|
|
||||||
containerPort: 8081
|
|
||||||
protocol: TCP
|
|
||||||
{{- with include "gateway.probes" . | trim }}
|
|
||||||
{{- . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.resources }}
|
|
||||||
resources:
|
|
||||||
{{- toYaml . | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "gateway.pick" (dict "root" $root "w" $w "key" "securityContext") }}
|
|
||||||
securityContext:
|
|
||||||
{{- . | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.extraVolumeMounts }}
|
|
||||||
volumeMounts:
|
|
||||||
{{- toYaml . | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.extraVolumes }}
|
|
||||||
volumes:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "gateway.pdb" -}}
|
|
||||||
{{- with .w.pdb }}
|
|
||||||
---
|
|
||||||
apiVersion: policy/v1
|
|
||||||
kind: PodDisruptionBudget
|
|
||||||
metadata:
|
|
||||||
name: {{ $.name }}-pdb
|
|
||||||
namespace: {{ $.root.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "gateway.labels" $ | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
{{- if not (kindIs "invalid" .minAvailable) }}
|
|
||||||
minAvailable: {{ .minAvailable }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if not (kindIs "invalid" .maxUnavailable) }}
|
|
||||||
maxUnavailable: {{ .maxUnavailable }}
|
|
||||||
{{- end }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "gateway.selectorLabels" $ | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "gateway.hpa" -}}
|
|
||||||
{{- with .w.hpa }}
|
|
||||||
---
|
|
||||||
apiVersion: autoscaling/v2
|
|
||||||
kind: HorizontalPodAutoscaler
|
|
||||||
metadata:
|
|
||||||
name: {{ $.name }}
|
|
||||||
namespace: {{ $.root.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "gateway.labels" $ | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
scaleTargetRef:
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
name: {{ $.name }}
|
|
||||||
minReplicas: {{ required (printf "%s.hpa.minReplicas is required" $.name) .minReplicas }}
|
|
||||||
maxReplicas: {{ required (printf "%s.hpa.maxReplicas is required" $.name) .maxReplicas }}
|
|
||||||
{{- if not (kindIs "invalid" .targetCPUUtilizationPercentage) }}
|
|
||||||
metrics:
|
|
||||||
- type: Resource
|
|
||||||
resource:
|
|
||||||
name: cpu
|
|
||||||
target:
|
|
||||||
type: Utilization
|
|
||||||
averageUtilization: {{ .targetCPUUtilizationPercentage }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .behavior }}
|
|
||||||
behavior:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
{{- range $name, $w := .Values.deployments }}
|
|
||||||
{{- if not (kindIs "invalid" $w) }}
|
|
||||||
{{- $ctx := dict "root" $ "name" $name "component" $w.role "w" $w }}
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: {{ $name }}
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "gateway.labels" $ctx | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
{{- if not $w.hpa }}
|
|
||||||
replicas: {{ include "gateway.replicas" $ctx }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if not (kindIs "invalid" $w.minReadySeconds) }}
|
|
||||||
minReadySeconds: {{ $w.minReadySeconds }}
|
|
||||||
{{- end }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "gateway.selectorLabels" $ctx | nindent 6 }}
|
|
||||||
{{- with include "gateway.pick" (dict "root" $ "w" $w "key" "strategy") }}
|
|
||||||
strategy:
|
|
||||||
{{- . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
template:
|
|
||||||
{{- include "gateway.pod" $ctx | nindent 4 }}
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: {{ $name }}
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "gateway.labels" $ctx | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
type: ClusterIP
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
port: 8080
|
|
||||||
protocol: TCP
|
|
||||||
targetPort: http
|
|
||||||
selector:
|
|
||||||
{{- include "gateway.selectorLabels" $ctx | nindent 4 }}
|
|
||||||
{{- include "gateway.hpa" $ctx }}
|
|
||||||
{{- include "gateway.pdb" $ctx }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: {{ include "gateway.headlessName" . }}
|
|
||||||
namespace: {{ .Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "gateway.labels" (dict "root" . "name" "gateway" "component" "discovery") | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
type: ClusterIP
|
|
||||||
clusterIP: None
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
port: 8080
|
|
||||||
protocol: TCP
|
|
||||||
targetPort: http
|
|
||||||
- name: epmd
|
|
||||||
port: 4369
|
|
||||||
protocol: TCP
|
|
||||||
targetPort: epmd
|
|
||||||
- name: erl-dist
|
|
||||||
port: 8081
|
|
||||||
protocol: TCP
|
|
||||||
targetPort: erl-dist
|
|
||||||
selector:
|
|
||||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
|
||||||
app.kubernetes.io/part-of: fluxer
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
{{- $np := .Values.networkPolicy | default dict }}
|
|
||||||
{{- if $np.enabled }}
|
|
||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
kind: NetworkPolicy
|
|
||||||
metadata:
|
|
||||||
name: gateway
|
|
||||||
namespace: {{ .Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "gateway.labels" (dict "root" . "name" "gateway") | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
podSelector:
|
|
||||||
matchLabels:
|
|
||||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
|
||||||
app.kubernetes.io/part-of: fluxer
|
|
||||||
policyTypes:
|
|
||||||
- Ingress
|
|
||||||
- Egress
|
|
||||||
egress:
|
|
||||||
- {}
|
|
||||||
ingress:
|
|
||||||
{{- with $np.ingressNamespace }}
|
|
||||||
- from:
|
|
||||||
- namespaceSelector:
|
|
||||||
matchLabels:
|
|
||||||
kubernetes.io/metadata.name: {{ . }}
|
|
||||||
ports:
|
|
||||||
- port: 8080
|
|
||||||
protocol: TCP
|
|
||||||
{{- end }}
|
|
||||||
{{- with $np.clients }}
|
|
||||||
- from:
|
|
||||||
{{- range . }}
|
|
||||||
- podSelector:
|
|
||||||
matchLabels:
|
|
||||||
{{- toYaml . | nindent 10 }}
|
|
||||||
{{- end }}
|
|
||||||
ports:
|
|
||||||
- port: 8080
|
|
||||||
protocol: TCP
|
|
||||||
{{- end }}
|
|
||||||
- from:
|
|
||||||
- podSelector:
|
|
||||||
matchLabels:
|
|
||||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
|
||||||
app.kubernetes.io/part-of: fluxer
|
|
||||||
ports:
|
|
||||||
- port: 8080
|
|
||||||
protocol: TCP
|
|
||||||
- port: 4369
|
|
||||||
protocol: TCP
|
|
||||||
- port: 8081
|
|
||||||
protocol: TCP
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
{{- range $name, $w := .Values.statefulsets }}
|
|
||||||
{{- if not (kindIs "invalid" $w) }}
|
|
||||||
{{- $ctx := dict "root" $ "name" $name "component" $w.role "w" $w }}
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: StatefulSet
|
|
||||||
metadata:
|
|
||||||
name: {{ $name }}
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "gateway.labels" $ctx | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
replicas: {{ include "gateway.replicas" $ctx }}
|
|
||||||
{{- if not (kindIs "invalid" $w.minReadySeconds) }}
|
|
||||||
minReadySeconds: {{ $w.minReadySeconds }}
|
|
||||||
{{- end }}
|
|
||||||
serviceName: {{ include "gateway.headlessName" $ }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "gateway.selectorLabels" $ctx | nindent 6 }}
|
|
||||||
{{- with include "gateway.pick" (dict "root" $ "w" $w "key" "updateStrategy") }}
|
|
||||||
updateStrategy:
|
|
||||||
{{- . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
template:
|
|
||||||
{{- include "gateway.pod" $ctx | nindent 4 }}
|
|
||||||
{{- include "gateway.pdb" $ctx }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
image:
|
|
||||||
registry: ghcr.io/fluxerapp
|
|
||||||
tag: v1
|
|
||||||
pullPolicy: IfNotPresent
|
|
||||||
|
|
||||||
imagePullSecrets: []
|
|
||||||
|
|
||||||
clusterDomain: cluster.local
|
|
||||||
|
|
||||||
env:
|
|
||||||
FLUXER_ENV: production
|
|
||||||
FLUXER_GATEWAY_PORT: "8080"
|
|
||||||
FLUXER_GATEWAY_MEDIA_PROXY_ENDPOINT: https://media.example.com
|
|
||||||
FLUXER_INTERNAL_API_ENDPOINT: http://api:8080
|
|
||||||
|
|
||||||
extraEnv: []
|
|
||||||
|
|
||||||
envFrom:
|
|
||||||
- secretRef:
|
|
||||||
name: fluxer-env
|
|
||||||
|
|
||||||
podAnnotations: {}
|
|
||||||
|
|
||||||
podSecurityContext:
|
|
||||||
runAsNonRoot: true
|
|
||||||
seccompProfile:
|
|
||||||
type: RuntimeDefault
|
|
||||||
|
|
||||||
securityContext:
|
|
||||||
allowPrivilegeEscalation: false
|
|
||||||
|
|
||||||
probes:
|
|
||||||
startup:
|
|
||||||
httpGet:
|
|
||||||
path: /_health
|
|
||||||
port: http
|
|
||||||
failureThreshold: 30
|
|
||||||
liveness:
|
|
||||||
httpGet:
|
|
||||||
path: /_health
|
|
||||||
port: http
|
|
||||||
readiness:
|
|
||||||
exec:
|
|
||||||
command:
|
|
||||||
- curl
|
|
||||||
- -fsS
|
|
||||||
- -o
|
|
||||||
- /dev/null
|
|
||||||
- --max-time
|
|
||||||
- "2"
|
|
||||||
- http://127.0.0.1:8080/_health/ready
|
|
||||||
timeoutSeconds: 3
|
|
||||||
|
|
||||||
strategy: {}
|
|
||||||
updateStrategy: {}
|
|
||||||
|
|
||||||
topologySpreadConstraints: []
|
|
||||||
nodeSelector: {}
|
|
||||||
tolerations: []
|
|
||||||
affinity: {}
|
|
||||||
|
|
||||||
networkPolicy:
|
|
||||||
enabled: false
|
|
||||||
ingressNamespace: ingress-nginx
|
|
||||||
clients:
|
|
||||||
- app.kubernetes.io/part-of: fluxer
|
|
||||||
|
|
||||||
deployments:
|
|
||||||
gateway:
|
|
||||||
role: all
|
|
||||||
replicas: 1
|
|
||||||
lifecycle:
|
|
||||||
preStop:
|
|
||||||
exec:
|
|
||||||
command:
|
|
||||||
- /bin/sh
|
|
||||||
- -c
|
|
||||||
- curl -fsS -o /dev/null --max-time 2 http://127.0.0.1:8080/_health/drain; sleep 5
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
cpu: 100m
|
|
||||||
memory: 384Mi
|
|
||||||
limits:
|
|
||||||
memory: 1Gi
|
|
||||||
|
|
||||||
statefulsets: {}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
apiVersion: v2
|
|
||||||
name: fluxer-infra
|
|
||||||
description: NATS and Valkey for a Fluxer installation.
|
|
||||||
type: application
|
|
||||||
version: 0.1.0
|
|
||||||
appVersion: "v1"
|
|
||||||
@@ -1,282 +0,0 @@
|
|||||||
{{- define "fluxer-infra.chart" -}}
|
|
||||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-infra.selectorLabels" -}}
|
|
||||||
app.kubernetes.io/name: {{ .name }}
|
|
||||||
app.kubernetes.io/instance: {{ .root.Release.Name }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-infra.labels" -}}
|
|
||||||
{{ include "fluxer-infra.selectorLabels" . }}
|
|
||||||
app.kubernetes.io/component: {{ .component }}
|
|
||||||
app.kubernetes.io/part-of: fluxer
|
|
||||||
app.kubernetes.io/managed-by: {{ .root.Release.Service }}
|
|
||||||
helm.sh/chart: {{ include "fluxer-infra.chart" .root }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-infra.pick" -}}
|
|
||||||
{{- $v := get .root.Values .key }}
|
|
||||||
{{- if hasKey .w .key }}
|
|
||||||
{{- $v = get .w .key }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $v }}
|
|
||||||
{{- toYaml . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-infra.string" -}}
|
|
||||||
{{- if and (kindIs "float64" .) (eq . (float64 (int64 .))) }}
|
|
||||||
{{- int64 . | toString }}
|
|
||||||
{{- else }}
|
|
||||||
{{- toString . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-infra.envList" -}}
|
|
||||||
{{- $env := deepCopy (.root.Values.env | default dict) }}
|
|
||||||
{{- range $k, $v := .w.env | default dict }}
|
|
||||||
{{- if kindIs "invalid" $v }}
|
|
||||||
{{- $_ := unset $env $k }}
|
|
||||||
{{- else }}
|
|
||||||
{{- $_ := set $env $k $v }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range $k, $v := $env }}
|
|
||||||
{{- if not (kindIs "invalid" $v) }}
|
|
||||||
- name: {{ $k }}
|
|
||||||
value: {{ include "fluxer-infra.string" $v | quote }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with concat (.root.Values.extraEnv | default list) (.w.extraEnv | default list) }}
|
|
||||||
{{ toYaml . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-infra.envFrom" -}}
|
|
||||||
{{- with concat (.root.Values.envFrom | default list) (.w.envFrom | default list) }}
|
|
||||||
{{- toYaml . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-infra.probes" -}}
|
|
||||||
{{- $global := .root.Values.probes | default dict }}
|
|
||||||
{{- $own := .w.probes | default dict }}
|
|
||||||
{{- range $probe := list "startup" "liveness" "readiness" }}
|
|
||||||
{{- $p := get $global $probe }}
|
|
||||||
{{- if hasKey $own $probe }}
|
|
||||||
{{- $p = get $own $probe }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $p }}
|
|
||||||
{{ $probe }}Probe:
|
|
||||||
{{- toYaml . | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-infra.topologySpreadConstraints" -}}
|
|
||||||
{{- $out := list }}
|
|
||||||
{{- range include "fluxer-infra.pick" (dict "root" .root "w" .w "key" "topologySpreadConstraints") | fromYamlArray }}
|
|
||||||
{{- $c := deepCopy . }}
|
|
||||||
{{- if not (hasKey $c "labelSelector") }}
|
|
||||||
{{- $_ := set $c "labelSelector" (dict "matchLabels" (include "fluxer-infra.selectorLabels" $ | fromYaml)) }}
|
|
||||||
{{- end }}
|
|
||||||
{{- $out = append $out $c }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $out }}
|
|
||||||
{{- toYaml . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-infra.replicas" -}}
|
|
||||||
{{- if kindIs "invalid" .w.replicas }}1{{ else }}{{ .w.replicas }}{{ end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-infra.image" -}}
|
|
||||||
{{- $ref := printf "%s:%s" .repository .tag }}
|
|
||||||
{{- with .digest }}
|
|
||||||
{{- $ref = printf "%s@%s" $ref . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- $ref | quote }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-infra.podAnnotations" -}}
|
|
||||||
{{- with merge (deepCopy (.extra | default dict)) (deepCopy (.w.podAnnotations | default dict)) (deepCopy (.root.Values.podAnnotations | default dict)) }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-infra.podSpec" -}}
|
|
||||||
{{- $root := .root }}
|
|
||||||
{{- $w := .w }}
|
|
||||||
{{- with include "fluxer-infra.pick" (dict "root" $root "w" $w "key" "affinity") }}
|
|
||||||
affinity:
|
|
||||||
{{- . | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-infra.pick" (dict "root" $root "w" $w "key" "imagePullSecrets") }}
|
|
||||||
imagePullSecrets:
|
|
||||||
{{- . | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-infra.pick" (dict "root" $root "w" $w "key" "nodeSelector") }}
|
|
||||||
nodeSelector:
|
|
||||||
{{- . | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-infra.pick" (dict "root" $root "w" $w "key" "tolerations") }}
|
|
||||||
tolerations:
|
|
||||||
{{- . | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-infra.topologySpreadConstraints" . }}
|
|
||||||
topologySpreadConstraints:
|
|
||||||
{{- . | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-infra.pick" (dict "root" $root "w" $w "key" "podSecurityContext") }}
|
|
||||||
securityContext:
|
|
||||||
{{- . | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if not (kindIs "invalid" $w.terminationGracePeriodSeconds) }}
|
|
||||||
terminationGracePeriodSeconds: {{ $w.terminationGracePeriodSeconds }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-infra.containerCommon" -}}
|
|
||||||
{{- $root := .root }}
|
|
||||||
{{- $w := .w }}
|
|
||||||
{{- $img := $w.image | default dict }}
|
|
||||||
image: {{ include "fluxer-infra.image" $img }}
|
|
||||||
imagePullPolicy: {{ $img.pullPolicy }}
|
|
||||||
{{- $env := include "fluxer-infra.envList" . | trim }}
|
|
||||||
{{- if or .env $env }}
|
|
||||||
env:
|
|
||||||
{{- with .env }}
|
|
||||||
{{- toYaml . | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $env }}
|
|
||||||
{{- . | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-infra.envFrom" . }}
|
|
||||||
envFrom:
|
|
||||||
{{- . | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.lifecycle }}
|
|
||||||
lifecycle:
|
|
||||||
{{- toYaml . | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- include "fluxer-infra.probes" . }}
|
|
||||||
{{- with $w.resources }}
|
|
||||||
resources:
|
|
||||||
{{- toYaml . | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-infra.pick" (dict "root" $root "w" $w "key" "securityContext") }}
|
|
||||||
securityContext:
|
|
||||||
{{- . | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with concat .mounts ($w.extraVolumeMounts | default list) }}
|
|
||||||
volumeMounts:
|
|
||||||
{{- toYaml . | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-infra.statefulSetSpec" -}}
|
|
||||||
{{- $w := .w }}
|
|
||||||
{{- with include "fluxer-infra.pick" (dict "root" .root "w" $w "key" "updateStrategy") }}
|
|
||||||
updateStrategy:
|
|
||||||
{{- . | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if not (kindIs "invalid" $w.minReadySeconds) }}
|
|
||||||
minReadySeconds: {{ $w.minReadySeconds }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-infra.volumeClaim" -}}
|
|
||||||
- metadata:
|
|
||||||
name: data
|
|
||||||
spec:
|
|
||||||
accessModes:
|
|
||||||
- ReadWriteOnce
|
|
||||||
{{- with .storageClassName }}
|
|
||||||
storageClassName: {{ . | quote }}
|
|
||||||
{{- end }}
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
storage: {{ .size }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-infra.pdb" -}}
|
|
||||||
{{- with .w.pdb }}
|
|
||||||
---
|
|
||||||
apiVersion: policy/v1
|
|
||||||
kind: PodDisruptionBudget
|
|
||||||
metadata:
|
|
||||||
name: {{ $.name }}-pdb
|
|
||||||
namespace: {{ $.root.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-infra.labels" $ | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
{{- if not (kindIs "invalid" .minAvailable) }}
|
|
||||||
minAvailable: {{ .minAvailable }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if not (kindIs "invalid" .maxUnavailable) }}
|
|
||||||
maxUnavailable: {{ .maxUnavailable }}
|
|
||||||
{{- end }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "fluxer-infra.selectorLabels" $ | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-infra.service" }}
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: {{ .svcName }}
|
|
||||||
namespace: {{ .root.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-infra.labels" . | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
{{- if .headless }}
|
|
||||||
clusterIP: None
|
|
||||||
{{- end }}
|
|
||||||
{{- if .publishNotReady }}
|
|
||||||
publishNotReadyAddresses: true
|
|
||||||
{{- end }}
|
|
||||||
selector:
|
|
||||||
{{- include "fluxer-infra.selectorLabels" . | nindent 4 }}
|
|
||||||
ports:
|
|
||||||
{{- range .ports }}
|
|
||||||
- name: {{ index . 0 }}
|
|
||||||
port: {{ index . 1 }}
|
|
||||||
targetPort: {{ index . 0 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-infra.natsConf" -}}
|
|
||||||
{{- $w := .Values.nats -}}
|
|
||||||
{{- with $w.config -}}
|
|
||||||
listen: 0.0.0.0:4222
|
|
||||||
http: 0.0.0.0:8222
|
|
||||||
max_payload: {{ .maxPayload }}
|
|
||||||
max_pending: {{ .maxPending }}
|
|
||||||
max_connections: {{ .maxConnections }}
|
|
||||||
{{- if $w.jetstream.enabled }}
|
|
||||||
server_name: $POD_NAME
|
|
||||||
|
|
||||||
jetstream {
|
|
||||||
store_dir: /data
|
|
||||||
}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
cluster {
|
|
||||||
name: {{ .clusterName }}
|
|
||||||
listen: 0.0.0.0:6222
|
|
||||||
|
|
||||||
routes = [
|
|
||||||
{{- range $i := until (int (include "fluxer-infra.replicas" (dict "w" $w))) }}
|
|
||||||
nats-route://nats-{{ $i }}.nats-headless.{{ $.Release.Namespace }}.svc.{{ $.Values.clusterDomain }}:6222
|
|
||||||
{{- end }}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
{{ end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
{{- with .Values.nats }}
|
|
||||||
{{- $ctx := dict "root" $ "w" . "name" "nats" "component" "messaging" }}
|
|
||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: nats-config
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-infra.labels" $ctx | nindent 4 }}
|
|
||||||
data:
|
|
||||||
nats.conf: {{ include "fluxer-infra.natsConf" $ | toJson }}
|
|
||||||
{{- include "fluxer-infra.pdb" $ctx }}
|
|
||||||
{{- include "fluxer-infra.service" (merge (dict "svcName" "nats" "ports" (list (list "client" 4222))) $ctx) }}
|
|
||||||
{{- include "fluxer-infra.service" (merge (dict "svcName" "nats-headless" "headless" true "ports" (list (list "client" 4222) (list "cluster" 6222) (list "monitor" 8222))) $ctx) }}
|
|
||||||
{{- $mounts := list (dict "name" "config" "mountPath" "/etc/nats") }}
|
|
||||||
{{- $env := list }}
|
|
||||||
{{- if .jetstream.enabled }}
|
|
||||||
{{- $mounts = append $mounts (dict "name" "data" "mountPath" "/data") }}
|
|
||||||
{{- $env = append $env (dict "name" "POD_NAME" "valueFrom" (dict "fieldRef" (dict "fieldPath" "metadata.name"))) }}
|
|
||||||
{{- end }}
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: StatefulSet
|
|
||||||
metadata:
|
|
||||||
name: nats
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-infra.labels" $ctx | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
replicas: {{ include "fluxer-infra.replicas" $ctx }}
|
|
||||||
serviceName: nats-headless
|
|
||||||
{{- with include "fluxer-infra.statefulSetSpec" $ctx | trim }}
|
|
||||||
{{- . | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "fluxer-infra.selectorLabels" $ctx | nindent 6 }}
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-infra.labels" $ctx | nindent 8 }}
|
|
||||||
{{- with include "fluxer-infra.podAnnotations" (merge (dict "extra" (dict "checksum/config" (include "fluxer-infra.natsConf" $ | sha256sum))) $ctx) | trim }}
|
|
||||||
{{- . | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
{{- include "fluxer-infra.podSpec" $ctx | trim | nindent 6 }}
|
|
||||||
containers:
|
|
||||||
- name: nats
|
|
||||||
{{- include "fluxer-infra.containerCommon" (merge (dict "env" $env "mounts" $mounts) $ctx) | trim | nindent 10 }}
|
|
||||||
args:
|
|
||||||
- -c
|
|
||||||
- /etc/nats/nats.conf
|
|
||||||
ports:
|
|
||||||
- name: client
|
|
||||||
containerPort: 4222
|
|
||||||
- name: cluster
|
|
||||||
containerPort: 6222
|
|
||||||
- name: monitor
|
|
||||||
containerPort: 8222
|
|
||||||
volumes:
|
|
||||||
- name: config
|
|
||||||
configMap:
|
|
||||||
name: nats-config
|
|
||||||
{{- with .extraVolumes }}
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if .jetstream.enabled }}
|
|
||||||
volumeClaimTemplates:
|
|
||||||
{{- include "fluxer-infra.volumeClaim" .jetstream.storage | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
{{- with .Values.valkey }}
|
|
||||||
{{- $ctx := dict "root" $ "w" . "name" "valkey" "component" "cache" }}
|
|
||||||
{{- include "fluxer-infra.pdb" $ctx }}
|
|
||||||
{{- include "fluxer-infra.service" (merge (dict "svcName" "valkey" "ports" (list (list "valkey" 6379))) $ctx) }}
|
|
||||||
{{- include "fluxer-infra.service" (merge (dict "svcName" "valkey-headless" "headless" true "publishNotReady" true "ports" (list (list "valkey" 6379))) $ctx) }}
|
|
||||||
{{- $mounts := list }}
|
|
||||||
{{- if .persistence.enabled }}
|
|
||||||
{{- $mounts = append $mounts (dict "name" "data" "mountPath" "/data") }}
|
|
||||||
{{- end }}
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: StatefulSet
|
|
||||||
metadata:
|
|
||||||
name: valkey
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-infra.labels" $ctx | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
serviceName: valkey-headless
|
|
||||||
{{- with include "fluxer-infra.statefulSetSpec" $ctx | trim }}
|
|
||||||
{{- . | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "fluxer-infra.selectorLabels" $ctx | nindent 6 }}
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-infra.labels" $ctx | nindent 8 }}
|
|
||||||
{{- with include "fluxer-infra.podAnnotations" $ctx | trim }}
|
|
||||||
{{- . | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
{{- include "fluxer-infra.podSpec" $ctx | trim | nindent 6 }}
|
|
||||||
containers:
|
|
||||||
- name: valkey
|
|
||||||
{{- include "fluxer-infra.containerCommon" (merge (dict "env" list "mounts" $mounts) $ctx) | trim | nindent 10 }}
|
|
||||||
command:
|
|
||||||
- valkey-server
|
|
||||||
{{- if .persistence.enabled }}
|
|
||||||
- --appendonly
|
|
||||||
- "yes"
|
|
||||||
- --dir
|
|
||||||
- /data
|
|
||||||
{{- else }}
|
|
||||||
- --save
|
|
||||||
- ""
|
|
||||||
- --appendonly
|
|
||||||
- "no"
|
|
||||||
{{- end }}
|
|
||||||
- --maxmemory
|
|
||||||
- {{ .maxmemory | quote }}
|
|
||||||
- --maxmemory-policy
|
|
||||||
- {{ .maxmemoryPolicy | quote }}
|
|
||||||
ports:
|
|
||||||
- name: valkey
|
|
||||||
containerPort: 6379
|
|
||||||
{{- with .extraVolumes }}
|
|
||||||
volumes:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if .persistence.enabled }}
|
|
||||||
volumeClaimTemplates:
|
|
||||||
{{- include "fluxer-infra.volumeClaim" .persistence | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,108 +0,0 @@
|
|||||||
imagePullSecrets: []
|
|
||||||
|
|
||||||
clusterDomain: cluster.local
|
|
||||||
|
|
||||||
env: {}
|
|
||||||
|
|
||||||
extraEnv: []
|
|
||||||
|
|
||||||
envFrom: []
|
|
||||||
|
|
||||||
podAnnotations: {}
|
|
||||||
|
|
||||||
podSecurityContext:
|
|
||||||
runAsNonRoot: true
|
|
||||||
seccompProfile:
|
|
||||||
type: RuntimeDefault
|
|
||||||
|
|
||||||
securityContext:
|
|
||||||
allowPrivilegeEscalation: false
|
|
||||||
|
|
||||||
probes: {}
|
|
||||||
|
|
||||||
updateStrategy: {}
|
|
||||||
|
|
||||||
topologySpreadConstraints: []
|
|
||||||
|
|
||||||
nodeSelector: {}
|
|
||||||
|
|
||||||
tolerations: []
|
|
||||||
|
|
||||||
affinity: {}
|
|
||||||
|
|
||||||
nats:
|
|
||||||
image:
|
|
||||||
repository: nats
|
|
||||||
tag: 2.14-alpine
|
|
||||||
pullPolicy: IfNotPresent
|
|
||||||
replicas: 3
|
|
||||||
config:
|
|
||||||
clusterName: nats
|
|
||||||
maxPayload: 1MB
|
|
||||||
maxPending: 64MB
|
|
||||||
maxConnections: 65536
|
|
||||||
jetstream:
|
|
||||||
enabled: true
|
|
||||||
storage:
|
|
||||||
size: 10Gi
|
|
||||||
storageClassName: ""
|
|
||||||
podSecurityContext:
|
|
||||||
fsGroup: 65534
|
|
||||||
runAsGroup: 65534
|
|
||||||
runAsNonRoot: true
|
|
||||||
runAsUser: 65534
|
|
||||||
seccompProfile:
|
|
||||||
type: RuntimeDefault
|
|
||||||
probes:
|
|
||||||
liveness:
|
|
||||||
httpGet:
|
|
||||||
path: /healthz
|
|
||||||
port: monitor
|
|
||||||
initialDelaySeconds: 10
|
|
||||||
readiness:
|
|
||||||
httpGet:
|
|
||||||
path: /healthz?js-enabled-only=true
|
|
||||||
port: monitor
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
cpu: 50m
|
|
||||||
memory: 128Mi
|
|
||||||
limits:
|
|
||||||
memory: 512Mi
|
|
||||||
|
|
||||||
valkey:
|
|
||||||
image:
|
|
||||||
repository: valkey/valkey
|
|
||||||
tag: 9.1-alpine
|
|
||||||
pullPolicy: IfNotPresent
|
|
||||||
maxmemory: 192mb
|
|
||||||
maxmemoryPolicy: noeviction
|
|
||||||
persistence:
|
|
||||||
enabled: true
|
|
||||||
size: 1Gi
|
|
||||||
storageClassName: ""
|
|
||||||
podSecurityContext:
|
|
||||||
fsGroup: 999
|
|
||||||
runAsGroup: 999
|
|
||||||
runAsNonRoot: true
|
|
||||||
runAsUser: 999
|
|
||||||
seccompProfile:
|
|
||||||
type: RuntimeDefault
|
|
||||||
probes:
|
|
||||||
liveness:
|
|
||||||
exec:
|
|
||||||
command:
|
|
||||||
- valkey-cli
|
|
||||||
- ping
|
|
||||||
initialDelaySeconds: 10
|
|
||||||
readiness:
|
|
||||||
exec:
|
|
||||||
command:
|
|
||||||
- valkey-cli
|
|
||||||
- ping
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
cpu: 50m
|
|
||||||
memory: 64Mi
|
|
||||||
limits:
|
|
||||||
memory: 256Mi
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
apiVersion: v2
|
|
||||||
name: fluxer-ingress
|
|
||||||
description: Ingress routing for the public Fluxer endpoints.
|
|
||||||
type: application
|
|
||||||
version: 0.1.0
|
|
||||||
appVersion: "v1"
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
{{- define "fluxer-ingress.chart" -}}
|
|
||||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-ingress.labels" -}}
|
|
||||||
app.kubernetes.io/name: {{ .Chart.Name }}
|
|
||||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
|
||||||
app.kubernetes.io/part-of: fluxer
|
|
||||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
|
||||||
helm.sh/chart: {{ include "fluxer-ingress.chart" . }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-ingress.annotationKey" -}}
|
|
||||||
{{- if or (contains "/" .key) (not .prefix) -}}
|
|
||||||
{{- .key -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- printf "%s/%s" .prefix .key -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-ingress.string" -}}
|
|
||||||
{{- if and (kindIs "float64" .) (eq . (floor .)) -}}
|
|
||||||
{{- . | int64 | toString -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- . | toString -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
{{- with .Values.clusterIssuer }}
|
|
||||||
{{- if .enabled }}
|
|
||||||
apiVersion: cert-manager.io/v1
|
|
||||||
kind: ClusterIssuer
|
|
||||||
metadata:
|
|
||||||
name: {{ required "clusterIssuer.name is required" .name }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-ingress.labels" $ | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
acme:
|
|
||||||
email: {{ required "clusterIssuer.email is required" .email | quote }}
|
|
||||||
privateKeySecretRef:
|
|
||||||
name: {{ required "clusterIssuer.privateKeySecretName is required" .privateKeySecretName }}
|
|
||||||
server: {{ required "clusterIssuer.server is required" .server }}
|
|
||||||
solvers:
|
|
||||||
- http01:
|
|
||||||
ingress:
|
|
||||||
class: {{ required "clusterIssuer.solverIngressClass is required" .solverIngressClass }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
{{- $v := .Values }}
|
|
||||||
{{- $presets := $v.annotationPresets | default dict }}
|
|
||||||
{{- $issuer := $v.clusterIssuer | default dict }}
|
|
||||||
{{- range $name, $spec := ($v.ingresses | default dict) }}
|
|
||||||
{{- if not (kindIs "invalid" $spec) }}
|
|
||||||
{{- $ann := deepCopy ($v.commonAnnotations | default dict) }}
|
|
||||||
{{- range ($spec.presets | default list) }}
|
|
||||||
{{- $ann = mergeOverwrite $ann (deepCopy (required (printf "unknown annotation preset %s" .) (index $presets .))) }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if and $spec.tls $issuer.enabled }}
|
|
||||||
{{- $_ := set $ann "cert-manager.io/cluster-issuer" (required "clusterIssuer.name is required" $issuer.name) }}
|
|
||||||
{{- end }}
|
|
||||||
{{- $ann = mergeOverwrite $ann (deepCopy ($spec.annotations | default dict)) }}
|
|
||||||
{{- range $k, $val := $ann }}
|
|
||||||
{{- if kindIs "invalid" $val }}
|
|
||||||
{{- $_ := unset $ann $k }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
---
|
|
||||||
apiVersion: networking.k8s.io/v1
|
|
||||||
kind: Ingress
|
|
||||||
metadata:
|
|
||||||
name: {{ $name }}
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-ingress.labels" $ | nindent 4 }}
|
|
||||||
{{- with $ann }}
|
|
||||||
annotations:
|
|
||||||
{{- range $k, $val := . }}
|
|
||||||
{{ include "fluxer-ingress.annotationKey" (dict "key" $k "prefix" $v.annotationPrefix) }}: {{ include "fluxer-ingress.string" $val | quote }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
{{- with $spec.ingressClassName | default $v.ingressClassName }}
|
|
||||||
ingressClassName: {{ . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $spec.tls }}
|
|
||||||
tls:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
rules:
|
|
||||||
{{- range $rule := required (printf "ingress %s needs rules" $name) $spec.rules }}
|
|
||||||
- host: {{ required (printf "ingress %s has a rule without a host" $name) $rule.host | quote }}
|
|
||||||
http:
|
|
||||||
paths:
|
|
||||||
{{- range $p := $rule.paths | default (list dict) }}
|
|
||||||
{{- $p = $p | default dict }}
|
|
||||||
- path: {{ $p.path | default "/" | quote }}
|
|
||||||
pathType: {{ $p.pathType | default "Prefix" }}
|
|
||||||
backend:
|
|
||||||
service:
|
|
||||||
name: {{ required (printf "ingress %s host %s needs a service" $name $rule.host) ($p.service | default $rule.service) }}
|
|
||||||
port:
|
|
||||||
number: {{ required (printf "ingress %s host %s needs a port or servicePort" $name $rule.host) ($p.port | default $rule.port | default $v.servicePort) | int64 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
ingressClassName: nginx
|
|
||||||
annotationPrefix: nginx.ingress.kubernetes.io
|
|
||||||
servicePort: 8080
|
|
||||||
|
|
||||||
commonAnnotations: {}
|
|
||||||
|
|
||||||
annotationPresets:
|
|
||||||
websocket:
|
|
||||||
proxy-read-timeout: "3600"
|
|
||||||
proxy-send-timeout: "3600"
|
|
||||||
stripPrefix:
|
|
||||||
use-regex: "true"
|
|
||||||
rewrite-target: /$2
|
|
||||||
|
|
||||||
ingresses:
|
|
||||||
fluxer:
|
|
||||||
rules:
|
|
||||||
- host: web.example.com
|
|
||||||
service: app-proxy
|
|
||||||
- host: api.example.com
|
|
||||||
service: api
|
|
||||||
- host: admin.example.com
|
|
||||||
service: admin
|
|
||||||
- host: media.example.com
|
|
||||||
service: media-proxy
|
|
||||||
fluxer-web-api:
|
|
||||||
presets: [stripPrefix]
|
|
||||||
rules:
|
|
||||||
- host: web.example.com
|
|
||||||
service: api
|
|
||||||
paths:
|
|
||||||
- path: /api(/(.*))?$
|
|
||||||
pathType: ImplementationSpecific
|
|
||||||
fluxer-gateway:
|
|
||||||
presets: [websocket]
|
|
||||||
rules:
|
|
||||||
- host: gateway.example.com
|
|
||||||
service: gateway
|
|
||||||
fluxer-uploads:
|
|
||||||
annotations:
|
|
||||||
proxy-body-size: 100m
|
|
||||||
proxy-request-buffering: "off"
|
|
||||||
rules:
|
|
||||||
- host: uploads.example.com
|
|
||||||
service: uploads
|
|
||||||
|
|
||||||
clusterIssuer:
|
|
||||||
enabled: false
|
|
||||||
name: letsencrypt
|
|
||||||
email: ""
|
|
||||||
server: https://acme-v02.api.letsencrypt.org/directory
|
|
||||||
privateKeySecretName: letsencrypt-account-key
|
|
||||||
solverIngressClass: nginx
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
apiVersion: v2
|
|
||||||
name: fluxer-media-proxy
|
|
||||||
description: Fluxer media proxy and upload relay workloads.
|
|
||||||
type: application
|
|
||||||
version: 0.1.0
|
|
||||||
appVersion: "v1"
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
{{- define "fluxer-media-proxy.chart" -}}
|
|
||||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-media-proxy.selectorLabels" -}}
|
|
||||||
app.kubernetes.io/name: {{ .name }}
|
|
||||||
app.kubernetes.io/instance: {{ .root.Release.Name }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-media-proxy.labels" -}}
|
|
||||||
{{ include "fluxer-media-proxy.selectorLabels" . }}
|
|
||||||
app.kubernetes.io/component: {{ include "fluxer-media-proxy.mode" . }}
|
|
||||||
app.kubernetes.io/part-of: fluxer
|
|
||||||
app.kubernetes.io/managed-by: {{ .root.Release.Service }}
|
|
||||||
helm.sh/chart: {{ include "fluxer-media-proxy.chart" .root }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-media-proxy.image" -}}
|
|
||||||
{{- $g := .root.Values.image -}}
|
|
||||||
{{- $i := .w.image | default dict -}}
|
|
||||||
{{- $repo := $i.repository | default (printf "%s/%s" $g.registry ($i.name | default "fluxer-media-proxy")) -}}
|
|
||||||
{{- $tag := $i.tag | default $g.tag -}}
|
|
||||||
{{- if $i.digest -}}
|
|
||||||
{{- printf "%s:%s@%s" $repo $tag $i.digest | quote -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- printf "%s:%s" $repo $tag | quote -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-media-proxy.pick" -}}
|
|
||||||
{{- $v := ternary (get .w .key) (get .root.Values .key) (hasKey .w .key) -}}
|
|
||||||
{{- if $v }}
|
|
||||||
{{- toYaml $v }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-media-proxy.mode" -}}
|
|
||||||
{{- $mode := required (printf "workloads.%s.mode is required" .name) .w.mode -}}
|
|
||||||
{{- if not (has $mode (list "mp" "static" "upload" "relay")) -}}
|
|
||||||
{{- fail (printf "workloads.%s.mode must be mp, static, upload or relay" .name) -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- $mode -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-media-proxy.envValue" -}}
|
|
||||||
{{- if and (kindIs "float64" .) (eq . (float64 (int64 .))) -}}
|
|
||||||
{{- int64 . | toString -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- toString . -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-media-proxy.mergeEnv" -}}
|
|
||||||
{{- $out := dict -}}
|
|
||||||
{{- range $layer := . -}}
|
|
||||||
{{- range $k, $v := ($layer | default dict) -}}
|
|
||||||
{{- if kindIs "invalid" $v -}}
|
|
||||||
{{- $_ := unset $out $k -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- $_ := set $out $k $v -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- toYaml $out -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-media-proxy.topologySpreadConstraints" -}}
|
|
||||||
{{- $out := list -}}
|
|
||||||
{{- range .constraints -}}
|
|
||||||
{{- if .labelSelector -}}
|
|
||||||
{{- $out = append $out . -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- $out = append $out (merge (dict "labelSelector" (dict "matchLabels" $.selector)) .) -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- toYaml $out -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-media-proxy.pdb" -}}
|
|
||||||
{{- $out := dict -}}
|
|
||||||
{{- range $k := list "minAvailable" "maxUnavailable" -}}
|
|
||||||
{{- if and (hasKey $ $k) (not (kindIs "invalid" (index $ $k))) -}}
|
|
||||||
{{- $_ := set $out $k (index $ $k) -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- toYaml $out -}}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,191 +0,0 @@
|
|||||||
{{- range $name, $w := .Values.workloads }}
|
|
||||||
{{- if not (kindIs "invalid" $w) }}
|
|
||||||
{{- $ctx := dict "root" $ "name" $name "w" $w }}
|
|
||||||
{{- $mode := include "fluxer-media-proxy.mode" $ctx }}
|
|
||||||
{{- $sel := include "fluxer-media-proxy.selectorLabels" $ctx | fromYaml }}
|
|
||||||
{{- $env := include "fluxer-media-proxy.mergeEnv" (list $.Values.env $w.env) | fromYaml }}
|
|
||||||
{{- $extraEnv := concat ($.Values.extraEnv | default list) ($w.extraEnv | default list) }}
|
|
||||||
{{- $envFrom := concat ($.Values.envFrom | default list) ($w.envFrom | default list) }}
|
|
||||||
{{- $podAnnotations := merge (dict) ($w.podAnnotations | default dict) ($.Values.podAnnotations | default dict) }}
|
|
||||||
{{- $probes := dict }}
|
|
||||||
{{- range $k, $v := ($.Values.probes | default dict) }}
|
|
||||||
{{- $_ := set $probes $k $v }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range $k, $v := ($w.probes | default dict) }}
|
|
||||||
{{- $_ := set $probes $k $v }}
|
|
||||||
{{- end }}
|
|
||||||
{{- $pick := dict "root" $ "w" $w }}
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: {{ $name }}
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-media-proxy.labels" $ctx | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
{{- if not $w.hpa }}
|
|
||||||
replicas: {{ ternary $w.replicas 1 (hasKey $w "replicas") | int64 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if not (kindIs "invalid" $w.minReadySeconds) }}
|
|
||||||
minReadySeconds: {{ $w.minReadySeconds | int64 }}
|
|
||||||
{{- end }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- toYaml $sel | nindent 6 }}
|
|
||||||
{{- with include "fluxer-media-proxy.pick" (set (deepCopy $pick) "key" "strategy") }}
|
|
||||||
strategy:
|
|
||||||
{{- . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
{{- with $podAnnotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-media-proxy.labels" $ctx | nindent 8 }}
|
|
||||||
spec:
|
|
||||||
{{- with include "fluxer-media-proxy.pick" (set (deepCopy $pick) "key" "imagePullSecrets") }}
|
|
||||||
imagePullSecrets:
|
|
||||||
{{- . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-media-proxy.pick" (set (deepCopy $pick) "key" "podSecurityContext") }}
|
|
||||||
securityContext:
|
|
||||||
{{- . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if not (kindIs "invalid" $w.terminationGracePeriodSeconds) }}
|
|
||||||
terminationGracePeriodSeconds: {{ $w.terminationGracePeriodSeconds | int64 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-media-proxy.pick" (set (deepCopy $pick) "key" "nodeSelector") }}
|
|
||||||
nodeSelector:
|
|
||||||
{{- . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-media-proxy.pick" (set (deepCopy $pick) "key" "tolerations") }}
|
|
||||||
tolerations:
|
|
||||||
{{- . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-media-proxy.pick" (set (deepCopy $pick) "key" "affinity") }}
|
|
||||||
affinity:
|
|
||||||
{{- . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-media-proxy.pick" (set (deepCopy $pick) "key" "topologySpreadConstraints") | fromYamlArray }}
|
|
||||||
topologySpreadConstraints:
|
|
||||||
{{- include "fluxer-media-proxy.topologySpreadConstraints" (dict "constraints" . "selector" $sel) | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
containers:
|
|
||||||
- name: {{ $name }}
|
|
||||||
image: {{ include "fluxer-media-proxy.image" $ctx }}
|
|
||||||
imagePullPolicy: {{ ($w.image | default dict).pullPolicy | default $.Values.image.pullPolicy }}
|
|
||||||
env:
|
|
||||||
{{- if not (kindIs "invalid" $w.buildVersion) }}
|
|
||||||
- name: BUILD_VERSION
|
|
||||||
value: {{ include "fluxer-media-proxy.envValue" $w.buildVersion | quote }}
|
|
||||||
{{- end }}
|
|
||||||
- name: FLUXER_MEDIA_PROXY_MODE
|
|
||||||
value: {{ $mode | quote }}
|
|
||||||
{{- range $k, $v := $env }}
|
|
||||||
- name: {{ $k }}
|
|
||||||
value: {{ include "fluxer-media-proxy.envValue" $v | quote }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $extraEnv }}
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $envFrom }}
|
|
||||||
envFrom:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
containerPort: 8080
|
|
||||||
protocol: TCP
|
|
||||||
{{- with $w.lifecycle }}
|
|
||||||
lifecycle:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range $k := list "startup" "liveness" "readiness" }}
|
|
||||||
{{- with get $probes $k }}
|
|
||||||
{{ $k }}Probe:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.resources }}
|
|
||||||
resources:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-media-proxy.pick" (set (deepCopy $pick) "key" "securityContext") }}
|
|
||||||
securityContext:
|
|
||||||
{{- . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.extraVolumeMounts }}
|
|
||||||
volumeMounts:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.extraVolumes }}
|
|
||||||
volumes:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: {{ $name }}
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-media-proxy.labels" $ctx | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
type: ClusterIP
|
|
||||||
selector:
|
|
||||||
{{- toYaml $sel | nindent 4 }}
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
port: 8080
|
|
||||||
targetPort: http
|
|
||||||
protocol: TCP
|
|
||||||
{{- with include "fluxer-media-proxy.pdb" ($w.pdb | default dict) | fromYaml }}
|
|
||||||
---
|
|
||||||
apiVersion: policy/v1
|
|
||||||
kind: PodDisruptionBudget
|
|
||||||
metadata:
|
|
||||||
name: {{ $name }}-pdb
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-media-proxy.labels" $ctx | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
{{- toYaml . | nindent 2 }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- toYaml $sel | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.hpa }}
|
|
||||||
---
|
|
||||||
apiVersion: autoscaling/v2
|
|
||||||
kind: HorizontalPodAutoscaler
|
|
||||||
metadata:
|
|
||||||
name: {{ $name }}
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-media-proxy.labels" $ctx | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
scaleTargetRef:
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
name: {{ $name }}
|
|
||||||
minReplicas: {{ required (printf "workloads.%s.hpa.minReplicas is required" $name) .minReplicas | int64 }}
|
|
||||||
maxReplicas: {{ required (printf "workloads.%s.hpa.maxReplicas is required" $name) .maxReplicas | int64 }}
|
|
||||||
{{- if not (kindIs "invalid" .targetCPUUtilizationPercentage) }}
|
|
||||||
metrics:
|
|
||||||
- type: Resource
|
|
||||||
resource:
|
|
||||||
name: cpu
|
|
||||||
target:
|
|
||||||
type: Utilization
|
|
||||||
averageUtilization: {{ .targetCPUUtilizationPercentage | int64 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .behavior }}
|
|
||||||
behavior:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
image:
|
|
||||||
registry: ghcr.io/fluxerapp
|
|
||||||
tag: v1
|
|
||||||
pullPolicy: IfNotPresent
|
|
||||||
|
|
||||||
imagePullSecrets: []
|
|
||||||
|
|
||||||
env: {}
|
|
||||||
|
|
||||||
extraEnv: []
|
|
||||||
|
|
||||||
envFrom:
|
|
||||||
- secretRef:
|
|
||||||
name: fluxer-env
|
|
||||||
|
|
||||||
podAnnotations: {}
|
|
||||||
|
|
||||||
podSecurityContext:
|
|
||||||
runAsNonRoot: true
|
|
||||||
seccompProfile:
|
|
||||||
type: RuntimeDefault
|
|
||||||
|
|
||||||
securityContext:
|
|
||||||
allowPrivilegeEscalation: false
|
|
||||||
capabilities:
|
|
||||||
drop:
|
|
||||||
- ALL
|
|
||||||
|
|
||||||
probes:
|
|
||||||
liveness:
|
|
||||||
httpGet:
|
|
||||||
path: /_health
|
|
||||||
port: http
|
|
||||||
readiness:
|
|
||||||
httpGet:
|
|
||||||
path: /_health
|
|
||||||
port: http
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
type: RollingUpdate
|
|
||||||
rollingUpdate:
|
|
||||||
maxSurge: 25%
|
|
||||||
maxUnavailable: 25%
|
|
||||||
|
|
||||||
topologySpreadConstraints: []
|
|
||||||
|
|
||||||
nodeSelector: {}
|
|
||||||
|
|
||||||
tolerations: []
|
|
||||||
|
|
||||||
affinity: {}
|
|
||||||
|
|
||||||
workloads:
|
|
||||||
media-proxy:
|
|
||||||
mode: mp
|
|
||||||
replicas: 1
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
cpu: 100m
|
|
||||||
memory: 256Mi
|
|
||||||
limits:
|
|
||||||
memory: 1Gi
|
|
||||||
|
|
||||||
uploads:
|
|
||||||
mode: relay
|
|
||||||
replicas: 1
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
cpu: 50m
|
|
||||||
memory: 64Mi
|
|
||||||
limits:
|
|
||||||
memory: 512Mi
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
apiVersion: v2
|
|
||||||
name: fluxer-push
|
|
||||||
description: Fluxer push notification delivery service
|
|
||||||
type: application
|
|
||||||
version: 0.1.0
|
|
||||||
appVersion: "v1"
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
{{- define "fluxer-push.selectorLabels" -}}
|
|
||||||
app.kubernetes.io/name: {{ .name }}
|
|
||||||
app.kubernetes.io/instance: {{ .root.Release.Name }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-push.labels" -}}
|
|
||||||
{{ include "fluxer-push.selectorLabels" . }}
|
|
||||||
app.kubernetes.io/component: {{ include "fluxer-push.mode" . }}
|
|
||||||
app.kubernetes.io/part-of: fluxer
|
|
||||||
app.kubernetes.io/managed-by: {{ .root.Release.Service }}
|
|
||||||
helm.sh/chart: {{ printf "%s-%s" .root.Chart.Name .root.Chart.Version | replace "+" "_" }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-push.mode" -}}
|
|
||||||
{{- $mode := .w.mode | default "delivery" -}}
|
|
||||||
{{- if not (has $mode (list "delivery" "relay")) -}}
|
|
||||||
{{- fail (printf "workloads.%s.mode must be delivery or relay" .name) -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- $mode -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-push.port" -}}
|
|
||||||
{{- .w.port | default (ternary 8127 8126 (eq (include "fluxer-push.mode" .) "relay")) -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-push.image" -}}
|
|
||||||
{{- $global := .root.Values.image | default dict -}}
|
|
||||||
{{- $img := .w.image | default dict -}}
|
|
||||||
{{- $repo := $img.repository -}}
|
|
||||||
{{- if not $repo -}}
|
|
||||||
{{- $repo = printf "%s/%s" (required "image.registry is required" $global.registry) ($img.name | default "fluxer-push") -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- $ref := printf "%s:%s" $repo (include "fluxer-push.string" (required "image.tag is required" ($img.tag | default $global.tag))) -}}
|
|
||||||
{{- with $img.digest }}{{ $ref = printf "%s@%s" $ref . }}{{ end -}}
|
|
||||||
{{- $ref -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-push.string" -}}
|
|
||||||
{{- if and (kindIs "float64" .) (eq . (floor .)) -}}
|
|
||||||
{{- . | int64 | toString -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- . | toString -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-push.env" -}}
|
|
||||||
{{- $env := deepCopy (.root.Values.env | default dict) -}}
|
|
||||||
{{- range $k, $v := (.w.env | default dict) -}}
|
|
||||||
{{- if kindIs "invalid" $v -}}
|
|
||||||
{{- $_ := unset $env $k -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- $_ := set $env $k $v -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if not (kindIs "invalid" .w.port) -}}
|
|
||||||
{{- $_ := set $env "FLUXER_PUSH_SERVICE_PORT" .w.port -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- if not (kindIs "invalid" .w.buildVersion) }}
|
|
||||||
- name: BUILD_VERSION
|
|
||||||
value: {{ include "fluxer-push.string" .w.buildVersion | quote }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range $k, $v := $env }}
|
|
||||||
{{- if not (kindIs "invalid" $v) }}
|
|
||||||
- name: {{ $k }}
|
|
||||||
value: {{ include "fluxer-push.string" $v | quote }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with concat (.root.Values.extraEnv | default list) (.w.extraEnv | default list) }}
|
|
||||||
{{ toYaml . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,205 +0,0 @@
|
|||||||
{{- range $name, $w := .Values.workloads }}
|
|
||||||
{{- if not (kindIs "invalid" $w) }}
|
|
||||||
{{- $ctx := dict "root" $ "name" $name "w" $w }}
|
|
||||||
{{- $mode := include "fluxer-push.mode" $ctx }}
|
|
||||||
{{- $port := include "fluxer-push.port" $ctx | int }}
|
|
||||||
{{- $globalProbes := $.Values.probes | default dict }}
|
|
||||||
{{- $workloadProbes := $w.probes | default dict }}
|
|
||||||
{{- $probes := dict }}
|
|
||||||
{{- range $probe := list "startup" "liveness" "readiness" }}
|
|
||||||
{{- $_ := set $probes $probe (ternary (index $workloadProbes $probe) (index $globalProbes $probe) (hasKey $workloadProbes $probe)) }}
|
|
||||||
{{- end }}
|
|
||||||
{{- $annotations := mergeOverwrite (deepCopy ($.Values.podAnnotations | default dict)) (deepCopy ($w.podAnnotations | default dict)) }}
|
|
||||||
{{- $pullSecrets := ternary $w.imagePullSecrets $.Values.imagePullSecrets (hasKey $w "imagePullSecrets") }}
|
|
||||||
{{- $podSecurityContext := ternary $w.podSecurityContext $.Values.podSecurityContext (hasKey $w "podSecurityContext") }}
|
|
||||||
{{- $securityContext := ternary $w.securityContext $.Values.securityContext (hasKey $w "securityContext") }}
|
|
||||||
{{- $strategy := ternary $w.strategy $.Values.strategy (hasKey $w "strategy") }}
|
|
||||||
{{- $tsc := ternary $w.topologySpreadConstraints $.Values.topologySpreadConstraints (hasKey $w "topologySpreadConstraints") }}
|
|
||||||
{{- $nodeSelector := ternary $w.nodeSelector $.Values.nodeSelector (hasKey $w "nodeSelector") }}
|
|
||||||
{{- $tolerations := ternary $w.tolerations $.Values.tolerations (hasKey $w "tolerations") }}
|
|
||||||
{{- $affinity := ternary $w.affinity $.Values.affinity (hasKey $w "affinity") }}
|
|
||||||
{{- $envFrom := concat ($.Values.envFrom | default list) ($w.envFrom | default list) }}
|
|
||||||
{{- $env := include "fluxer-push.env" $ctx }}
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: {{ $name }}
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-push.labels" $ctx | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
{{- if not $w.hpa }}
|
|
||||||
replicas: {{ ternary $w.replicas 1 (hasKey $w "replicas") | int }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if hasKey $w "minReadySeconds" }}
|
|
||||||
minReadySeconds: {{ $w.minReadySeconds | int }}
|
|
||||||
{{- end }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "fluxer-push.selectorLabels" $ctx | nindent 6 }}
|
|
||||||
{{- with $strategy }}
|
|
||||||
strategy:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
{{- with $annotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-push.labels" $ctx | nindent 8 }}
|
|
||||||
spec:
|
|
||||||
{{- with $pullSecrets }}
|
|
||||||
imagePullSecrets:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $podSecurityContext }}
|
|
||||||
securityContext:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if hasKey $w "terminationGracePeriodSeconds" }}
|
|
||||||
terminationGracePeriodSeconds: {{ $w.terminationGracePeriodSeconds | int }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $nodeSelector }}
|
|
||||||
nodeSelector:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $tolerations }}
|
|
||||||
tolerations:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $affinity }}
|
|
||||||
affinity:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $tsc }}
|
|
||||||
topologySpreadConstraints:
|
|
||||||
{{- range . }}
|
|
||||||
{{- $c := deepCopy . }}
|
|
||||||
{{- if not $c.labelSelector }}
|
|
||||||
{{- $_ := set $c "labelSelector" (dict "matchLabels" (include "fluxer-push.selectorLabels" $ctx | fromYaml)) }}
|
|
||||||
{{- end }}
|
|
||||||
{{- toYaml (list $c) | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
containers:
|
|
||||||
- name: {{ $name }}
|
|
||||||
image: {{ include "fluxer-push.image" $ctx | quote }}
|
|
||||||
imagePullPolicy: {{ ($w.image | default dict).pullPolicy | default ($.Values.image | default dict).pullPolicy | default "IfNotPresent" }}
|
|
||||||
command:
|
|
||||||
- /usr/local/bin/fluxer-push
|
|
||||||
{{- if eq $mode "relay" }}
|
|
||||||
args:
|
|
||||||
- --mode
|
|
||||||
- relay
|
|
||||||
{{- end }}
|
|
||||||
{{- with trim $env }}
|
|
||||||
env:
|
|
||||||
{{- . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $envFrom }}
|
|
||||||
envFrom:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
containerPort: {{ $port }}
|
|
||||||
protocol: TCP
|
|
||||||
{{- with $probes.startup }}
|
|
||||||
startupProbe:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $probes.liveness }}
|
|
||||||
livenessProbe:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $probes.readiness }}
|
|
||||||
readinessProbe:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.resources }}
|
|
||||||
resources:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $securityContext }}
|
|
||||||
securityContext:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.lifecycle }}
|
|
||||||
lifecycle:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.extraVolumeMounts }}
|
|
||||||
volumeMounts:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.extraVolumes }}
|
|
||||||
volumes:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: {{ $name }}
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-push.labels" $ctx | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
type: ClusterIP
|
|
||||||
selector:
|
|
||||||
{{- include "fluxer-push.selectorLabels" $ctx | nindent 4 }}
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
port: {{ $port }}
|
|
||||||
protocol: TCP
|
|
||||||
targetPort: http
|
|
||||||
{{- with $w.pdb }}
|
|
||||||
---
|
|
||||||
apiVersion: policy/v1
|
|
||||||
kind: PodDisruptionBudget
|
|
||||||
metadata:
|
|
||||||
name: {{ $name }}-pdb
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-push.labels" $ctx | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
{{- toYaml . | nindent 2 }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "fluxer-push.selectorLabels" $ctx | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.hpa }}
|
|
||||||
---
|
|
||||||
apiVersion: autoscaling/v2
|
|
||||||
kind: HorizontalPodAutoscaler
|
|
||||||
metadata:
|
|
||||||
name: {{ $name }}
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-push.labels" $ctx | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
scaleTargetRef:
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
name: {{ $name }}
|
|
||||||
minReplicas: {{ required (printf "workloads.%s.hpa.minReplicas is required" $name) .minReplicas | int }}
|
|
||||||
maxReplicas: {{ required (printf "workloads.%s.hpa.maxReplicas is required" $name) .maxReplicas | int }}
|
|
||||||
{{- if not (kindIs "invalid" .targetCPUUtilizationPercentage) }}
|
|
||||||
metrics:
|
|
||||||
- type: Resource
|
|
||||||
resource:
|
|
||||||
name: cpu
|
|
||||||
target:
|
|
||||||
type: Utilization
|
|
||||||
averageUtilization: {{ .targetCPUUtilizationPercentage | int }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .behavior }}
|
|
||||||
behavior:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
image:
|
|
||||||
registry: ghcr.io/fluxerapp
|
|
||||||
tag: v1
|
|
||||||
pullPolicy: IfNotPresent
|
|
||||||
|
|
||||||
imagePullSecrets: []
|
|
||||||
|
|
||||||
env: {}
|
|
||||||
|
|
||||||
extraEnv: []
|
|
||||||
|
|
||||||
envFrom:
|
|
||||||
- secretRef:
|
|
||||||
name: fluxer-env
|
|
||||||
|
|
||||||
podAnnotations: {}
|
|
||||||
|
|
||||||
podSecurityContext:
|
|
||||||
runAsNonRoot: true
|
|
||||||
seccompProfile:
|
|
||||||
type: RuntimeDefault
|
|
||||||
|
|
||||||
securityContext:
|
|
||||||
allowPrivilegeEscalation: false
|
|
||||||
capabilities:
|
|
||||||
drop:
|
|
||||||
- ALL
|
|
||||||
|
|
||||||
probes:
|
|
||||||
liveness:
|
|
||||||
httpGet:
|
|
||||||
path: /_healthz
|
|
||||||
port: http
|
|
||||||
readiness:
|
|
||||||
httpGet:
|
|
||||||
path: /_healthz
|
|
||||||
port: http
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
type: RollingUpdate
|
|
||||||
rollingUpdate:
|
|
||||||
maxSurge: 25%
|
|
||||||
maxUnavailable: 25%
|
|
||||||
|
|
||||||
topologySpreadConstraints: []
|
|
||||||
|
|
||||||
nodeSelector: {}
|
|
||||||
|
|
||||||
tolerations: []
|
|
||||||
|
|
||||||
affinity: {}
|
|
||||||
|
|
||||||
workloads:
|
|
||||||
push:
|
|
||||||
mode: delivery
|
|
||||||
replicas: 1
|
|
||||||
env:
|
|
||||||
FLUXER_INTERNAL_API_ENDPOINT: http://api:8080
|
|
||||||
FLUXER_SVC_NATS_URL: nats://nats:4222
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
cpu: 50m
|
|
||||||
memory: 64Mi
|
|
||||||
limits:
|
|
||||||
memory: 256Mi
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
apiVersion: v2
|
|
||||||
name: fluxer-svc
|
|
||||||
description: Fluxer internal services, each a router Deployment and a shard StatefulSet
|
|
||||||
type: application
|
|
||||||
version: 0.1.0
|
|
||||||
appVersion: v1
|
|
||||||
@@ -1,203 +0,0 @@
|
|||||||
{{- define "fluxer-svc.chart" -}}
|
|
||||||
{{ printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-svc.selectorLabels" -}}
|
|
||||||
app.kubernetes.io/name: {{ .name }}
|
|
||||||
app.kubernetes.io/instance: {{ .root.Release.Name }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-svc.labels" -}}
|
|
||||||
{{ include "fluxer-svc.selectorLabels" . }}
|
|
||||||
app.kubernetes.io/component: {{ .mode }}
|
|
||||||
app.kubernetes.io/part-of: fluxer
|
|
||||||
app.kubernetes.io/managed-by: {{ .root.Release.Service }}
|
|
||||||
helm.sh/chart: {{ include "fluxer-svc.chart" .root }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-svc.envValue" -}}
|
|
||||||
{{- if and (kindIs "float64" .) (eq . (float64 (int64 .))) -}}
|
|
||||||
{{- int64 . | toString -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- toString . -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-svc.mergeEnv" -}}
|
|
||||||
{{- $out := dict -}}
|
|
||||||
{{- range $layer := . -}}
|
|
||||||
{{- range $k, $v := ($layer | default dict) -}}
|
|
||||||
{{- if kindIs "invalid" $v -}}
|
|
||||||
{{- $_ := unset $out $k -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- $_ := set $out $k $v -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- toYaml $out -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-svc.topologySpreadConstraints" -}}
|
|
||||||
{{- $out := list -}}
|
|
||||||
{{- range .constraints -}}
|
|
||||||
{{- if .labelSelector -}}
|
|
||||||
{{- $out = append $out . -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- $out = append $out (merge (dict "labelSelector" (dict "matchLabels" $.selector)) .) -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- toYaml $out -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-svc.pdb" -}}
|
|
||||||
{{- $out := dict -}}
|
|
||||||
{{- range $k := list "minAvailable" "maxUnavailable" -}}
|
|
||||||
{{- if and (hasKey $ $k) (not (kindIs "invalid" (index $ $k))) -}}
|
|
||||||
{{- $_ := set $out $k (index $ $k) -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- toYaml $out -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-svc.config" -}}
|
|
||||||
{{- $v := .root.Values -}}
|
|
||||||
{{- $levels := list (index $v .mode) (index .svc .mode) -}}
|
|
||||||
{{- $c := dict "extraEnv" ($v.extraEnv | default list) "envFrom" ($v.envFrom | default list) "podAnnotations" (deepCopy ($v.podAnnotations | default dict)) "probes" (deepCopy ($v.probes | default dict)) "image" (deepCopy (.svc.image | default dict)) -}}
|
|
||||||
{{- range $k := list "imagePullSecrets" "podSecurityContext" "securityContext" "topologySpreadConstraints" "nodeSelector" "tolerations" "affinity" (ternary "updateStrategy" "strategy" (eq .mode "shard")) -}}
|
|
||||||
{{- $_ := set $c $k (index $v $k) -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- $envLayers := list $v.env -}}
|
|
||||||
{{- range $level := $levels -}}
|
|
||||||
{{- range $k, $x := ($level | default dict) -}}
|
|
||||||
{{- if eq $k "env" -}}
|
|
||||||
{{- $envLayers = append $envLayers $x -}}
|
|
||||||
{{- else if has $k (list "podAnnotations" "image") -}}
|
|
||||||
{{- $_ := set $c $k (mergeOverwrite (index $c $k) (deepCopy ($x | default dict))) -}}
|
|
||||||
{{- else if has $k (list "extraEnv" "envFrom") -}}
|
|
||||||
{{- $_ := set $c $k (concat (index $c $k) ($x | default list)) -}}
|
|
||||||
{{- else if eq $k "probes" -}}
|
|
||||||
{{- range $name, $p := ($x | default dict) -}}
|
|
||||||
{{- $_ := set $c.probes $name $p -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- $_ := set $c $k $x -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- $_ := set $c "env" (include "fluxer-svc.mergeEnv" $envLayers | fromYaml) -}}
|
|
||||||
{{- toYaml $c }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-svc.image" -}}
|
|
||||||
{{- $g := .root.Values.image -}}
|
|
||||||
{{- $i := .c.image -}}
|
|
||||||
{{- $repo := $i.repository | default (printf "%s/%s" $g.registry ($i.name | default (printf "fluxer-%s" .service))) -}}
|
|
||||||
{{- $ref := printf "%s:%s" $repo ($i.tag | default $g.tag) -}}
|
|
||||||
{{- with $i.digest }}{{ $ref = printf "%s@%s" $ref . }}{{ end -}}
|
|
||||||
{{- $ref -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-svc.pod" -}}
|
|
||||||
{{- $v := .root.Values -}}
|
|
||||||
{{- $c := .c -}}
|
|
||||||
metadata:
|
|
||||||
{{- with $c.podAnnotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-svc.labels" . | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
{{- with $c.imagePullSecrets }}
|
|
||||||
imagePullSecrets:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $c.podSecurityContext }}
|
|
||||||
securityContext:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if not (kindIs "invalid" $c.terminationGracePeriodSeconds) }}
|
|
||||||
terminationGracePeriodSeconds: {{ $c.terminationGracePeriodSeconds | int64 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $c.nodeSelector }}
|
|
||||||
nodeSelector:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $c.tolerations }}
|
|
||||||
tolerations:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $c.affinity }}
|
|
||||||
affinity:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $c.topologySpreadConstraints }}
|
|
||||||
topologySpreadConstraints:
|
|
||||||
{{- include "fluxer-svc.topologySpreadConstraints" (dict "constraints" . "selector" (include "fluxer-svc.selectorLabels" $ | fromYaml)) | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
containers:
|
|
||||||
- name: {{ .mode }}
|
|
||||||
image: {{ include "fluxer-svc.image" . | quote }}
|
|
||||||
imagePullPolicy: {{ $c.image.pullPolicy | default $v.image.pullPolicy }}
|
|
||||||
env:
|
|
||||||
- name: FLUXER_SVC_MODE
|
|
||||||
value: {{ .mode | quote }}
|
|
||||||
- name: FLUXER_SVC_NAME
|
|
||||||
value: {{ .service | quote }}
|
|
||||||
- name: FLUXER_SVC_SHARD_COUNT
|
|
||||||
value: {{ .shardCount | quote }}
|
|
||||||
- name: FLUXER_SVC_PORT
|
|
||||||
value: {{ include "fluxer-svc.envValue" $v.port | quote }}
|
|
||||||
{{- if not (kindIs "invalid" $c.buildVersion) }}
|
|
||||||
- name: BUILD_VERSION
|
|
||||||
value: {{ include "fluxer-svc.envValue" $c.buildVersion | quote }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if eq .mode "shard" }}
|
|
||||||
- name: POD_NAME
|
|
||||||
valueFrom:
|
|
||||||
fieldRef:
|
|
||||||
apiVersion: v1
|
|
||||||
fieldPath: metadata.name
|
|
||||||
{{- end }}
|
|
||||||
{{- range $name, $value := $c.env }}
|
|
||||||
- name: {{ $name }}
|
|
||||||
value: {{ include "fluxer-svc.envValue" $value | quote }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $c.extraEnv }}
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $c.envFrom }}
|
|
||||||
envFrom:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
containerPort: {{ $v.port }}
|
|
||||||
protocol: TCP
|
|
||||||
{{- with $c.lifecycle }}
|
|
||||||
lifecycle:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range $name := list "startup" "liveness" "readiness" }}
|
|
||||||
{{- with index $c.probes $name }}
|
|
||||||
{{ $name }}Probe:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $c.resources }}
|
|
||||||
resources:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $c.securityContext }}
|
|
||||||
securityContext:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $c.extraVolumeMounts }}
|
|
||||||
volumeMounts:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $c.extraVolumes }}
|
|
||||||
volumes:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,145 +0,0 @@
|
|||||||
{{- range $service, $svc := .Values.services }}
|
|
||||||
{{- if not (kindIs "invalid" $svc) }}
|
|
||||||
{{- $svc = $svc | default dict }}
|
|
||||||
{{- $rc := fromYaml (include "fluxer-svc.config" (dict "root" $ "svc" $svc "mode" "router")) }}
|
|
||||||
{{- $sc := fromYaml (include "fluxer-svc.config" (dict "root" $ "svc" $svc "mode" "shard")) }}
|
|
||||||
{{- $routerReplicas := ternary $rc.replicas 1 (hasKey $rc "replicas") | int64 }}
|
|
||||||
{{- $shardCount := ternary $sc.replicas 1 (hasKey $sc "replicas") | int64 }}
|
|
||||||
{{- if lt $shardCount 1 }}
|
|
||||||
{{- fail (printf "services.%s shard replicas must be at least 1" $service) }}
|
|
||||||
{{- end }}
|
|
||||||
{{- $router := dict "root" $ "service" $service "svc" $svc "mode" "router" "name" $service "c" $rc "shardCount" (toString $shardCount) }}
|
|
||||||
{{- $shard := dict "root" $ "service" $service "svc" $svc "mode" "shard" "name" (printf "%s-shard" $service) "c" $sc "shardCount" (toString $shardCount) }}
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: {{ $service }}
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-svc.labels" $router | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
{{- if not $rc.hpa }}
|
|
||||||
replicas: {{ $routerReplicas }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if not (kindIs "invalid" $rc.minReadySeconds) }}
|
|
||||||
minReadySeconds: {{ $rc.minReadySeconds | int64 }}
|
|
||||||
{{- end }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "fluxer-svc.selectorLabels" $router | nindent 6 }}
|
|
||||||
{{- with $rc.strategy }}
|
|
||||||
strategy:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
template:
|
|
||||||
{{- include "fluxer-svc.pod" $router | nindent 4 }}
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: StatefulSet
|
|
||||||
metadata:
|
|
||||||
name: {{ $service }}-shard
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-svc.labels" $shard | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
replicas: {{ $shardCount }}
|
|
||||||
{{- if not (kindIs "invalid" $sc.minReadySeconds) }}
|
|
||||||
minReadySeconds: {{ $sc.minReadySeconds | int64 }}
|
|
||||||
{{- end }}
|
|
||||||
podManagementPolicy: Parallel
|
|
||||||
serviceName: {{ $service }}-shard-headless
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "fluxer-svc.selectorLabels" $shard | nindent 6 }}
|
|
||||||
{{- with $sc.updateStrategy }}
|
|
||||||
updateStrategy:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
template:
|
|
||||||
{{- include "fluxer-svc.pod" $shard | nindent 4 }}
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: {{ $service }}
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-svc.labels" $router | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
type: ClusterIP
|
|
||||||
selector:
|
|
||||||
{{- include "fluxer-svc.selectorLabels" $router | nindent 4 }}
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
port: {{ $.Values.port }}
|
|
||||||
targetPort: {{ $.Values.port }}
|
|
||||||
protocol: TCP
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: {{ $service }}-shard-headless
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-svc.labels" $shard | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
type: ClusterIP
|
|
||||||
clusterIP: None
|
|
||||||
publishNotReadyAddresses: true
|
|
||||||
selector:
|
|
||||||
{{- include "fluxer-svc.selectorLabels" $shard | nindent 4 }}
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
port: {{ $.Values.port }}
|
|
||||||
targetPort: {{ $.Values.port }}
|
|
||||||
protocol: TCP
|
|
||||||
{{- with $rc.hpa }}
|
|
||||||
---
|
|
||||||
apiVersion: autoscaling/v2
|
|
||||||
kind: HorizontalPodAutoscaler
|
|
||||||
metadata:
|
|
||||||
name: {{ $service }}
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-svc.labels" $router | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
scaleTargetRef:
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
name: {{ $service }}
|
|
||||||
minReplicas: {{ required (printf "services.%s router hpa.minReplicas is required" $service) .minReplicas | int64 }}
|
|
||||||
maxReplicas: {{ required (printf "services.%s router hpa.maxReplicas is required" $service) .maxReplicas | int64 }}
|
|
||||||
{{- if not (kindIs "invalid" .targetCPUUtilizationPercentage) }}
|
|
||||||
metrics:
|
|
||||||
- type: Resource
|
|
||||||
resource:
|
|
||||||
name: cpu
|
|
||||||
target:
|
|
||||||
type: Utilization
|
|
||||||
averageUtilization: {{ .targetCPUUtilizationPercentage | int64 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .behavior }}
|
|
||||||
behavior:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range $ctx := list $router $shard }}
|
|
||||||
{{- with include "fluxer-svc.pdb" ($ctx.c.pdb | default dict) | fromYaml }}
|
|
||||||
---
|
|
||||||
apiVersion: policy/v1
|
|
||||||
kind: PodDisruptionBudget
|
|
||||||
metadata:
|
|
||||||
name: {{ $ctx.name }}-pdb
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-svc.labels" $ctx | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
{{- toYaml . | nindent 2 }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "fluxer-svc.selectorLabels" $ctx | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
image:
|
|
||||||
registry: ghcr.io/fluxerapp
|
|
||||||
tag: v1
|
|
||||||
pullPolicy: IfNotPresent
|
|
||||||
|
|
||||||
imagePullSecrets: []
|
|
||||||
|
|
||||||
env:
|
|
||||||
FLUXER_SVC_NATS_URL: nats://nats:4222
|
|
||||||
|
|
||||||
extraEnv: []
|
|
||||||
|
|
||||||
envFrom:
|
|
||||||
- secretRef:
|
|
||||||
name: fluxer-env
|
|
||||||
|
|
||||||
podAnnotations: {}
|
|
||||||
|
|
||||||
podSecurityContext:
|
|
||||||
runAsNonRoot: true
|
|
||||||
seccompProfile:
|
|
||||||
type: RuntimeDefault
|
|
||||||
|
|
||||||
securityContext:
|
|
||||||
allowPrivilegeEscalation: false
|
|
||||||
|
|
||||||
probes:
|
|
||||||
liveness:
|
|
||||||
httpGet:
|
|
||||||
path: /_healthz
|
|
||||||
port: http
|
|
||||||
readiness:
|
|
||||||
httpGet:
|
|
||||||
path: /_health
|
|
||||||
port: http
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
type: RollingUpdate
|
|
||||||
rollingUpdate:
|
|
||||||
maxSurge: 25%
|
|
||||||
maxUnavailable: 25%
|
|
||||||
|
|
||||||
updateStrategy:
|
|
||||||
type: RollingUpdate
|
|
||||||
|
|
||||||
topologySpreadConstraints: []
|
|
||||||
nodeSelector: {}
|
|
||||||
tolerations: []
|
|
||||||
affinity: {}
|
|
||||||
|
|
||||||
port: 8090
|
|
||||||
|
|
||||||
router:
|
|
||||||
replicas: 1
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
cpu: 50m
|
|
||||||
memory: 64Mi
|
|
||||||
limits:
|
|
||||||
memory: 192Mi
|
|
||||||
|
|
||||||
shard:
|
|
||||||
replicas: 2
|
|
||||||
probes:
|
|
||||||
startup:
|
|
||||||
httpGet:
|
|
||||||
path: /_healthz
|
|
||||||
port: http
|
|
||||||
periodSeconds: 10
|
|
||||||
failureThreshold: 30
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
cpu: 50m
|
|
||||||
memory: 96Mi
|
|
||||||
limits:
|
|
||||||
memory: 384Mi
|
|
||||||
|
|
||||||
services:
|
|
||||||
gifs:
|
|
||||||
shard:
|
|
||||||
env:
|
|
||||||
FLUXER_MEDIA_PROXY_PUBLIC_ENDPOINT: https://media.example.com
|
|
||||||
messages: {}
|
|
||||||
snowflakes: {}
|
|
||||||
unfurl:
|
|
||||||
shard:
|
|
||||||
env:
|
|
||||||
FLUXER_MEDIA_PROXY_ENDPOINT: http://media-proxy:8080
|
|
||||||
users: {}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
apiVersion: v2
|
|
||||||
name: fluxer-web
|
|
||||||
description: Fluxer web app proxy and admin dashboard.
|
|
||||||
type: application
|
|
||||||
version: 0.1.0
|
|
||||||
appVersion: "v1"
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
{{- define "fluxer-web.chart" -}}
|
|
||||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-web.selectorLabels" -}}
|
|
||||||
app.kubernetes.io/name: {{ .name }}
|
|
||||||
app.kubernetes.io/instance: {{ .root.Release.Name }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-web.labels" -}}
|
|
||||||
{{ include "fluxer-web.selectorLabels" . }}
|
|
||||||
app.kubernetes.io/component: web
|
|
||||||
app.kubernetes.io/part-of: fluxer
|
|
||||||
app.kubernetes.io/managed-by: {{ .root.Release.Service }}
|
|
||||||
helm.sh/chart: {{ include "fluxer-web.chart" .root }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-web.image" -}}
|
|
||||||
{{- $g := .root.Values.image | default dict -}}
|
|
||||||
{{- $i := .w.image | default dict -}}
|
|
||||||
{{- $repo := $i.repository -}}
|
|
||||||
{{- if not $repo -}}
|
|
||||||
{{- $repo = printf "%s/%s" (required "image.registry is required" $g.registry) ($i.name | default (printf "fluxer-%s" .name)) -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- $tag := required "image.tag is required" ($i.tag | default $g.tag) -}}
|
|
||||||
{{- if $i.digest -}}
|
|
||||||
{{- printf "%s:%s@%s" $repo $tag $i.digest | quote -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- printf "%s:%s" $repo $tag | quote -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-web.pick" -}}
|
|
||||||
{{- $v := ternary (get .w .key) (get .root.Values .key) (hasKey .w .key) -}}
|
|
||||||
{{- if $v }}
|
|
||||||
{{- toYaml $v }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-web.str" -}}
|
|
||||||
{{- if and (kindIs "float64" .) (eq . (floor .)) -}}
|
|
||||||
{{- int64 . | toString | quote -}}
|
|
||||||
{{- else -}}
|
|
||||||
{{- toString . | quote -}}
|
|
||||||
{{- end -}}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-web.env" -}}
|
|
||||||
{{- $env := dict -}}
|
|
||||||
{{- range $k, $val := .root.Values.env | default dict }}
|
|
||||||
{{- $_ := set $env $k $val }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range $k, $val := .w.env | default dict }}
|
|
||||||
{{- $_ := set $env $k $val }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range $k, $val := $env }}
|
|
||||||
{{- if not (kindIs "invalid" $val) }}
|
|
||||||
- name: {{ $k }}
|
|
||||||
value: {{ include "fluxer-web.str" $val }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .w.buildVersion }}
|
|
||||||
- name: BUILD_VERSION
|
|
||||||
value: {{ include "fluxer-web.str" . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with concat (.root.Values.extraEnv | default list) (.w.extraEnv | default list) }}
|
|
||||||
{{ toYaml . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
|
|
||||||
{{- define "fluxer-web.topologySpread" -}}
|
|
||||||
{{- $tscs := ternary .w.topologySpreadConstraints .root.Values.topologySpreadConstraints (hasKey .w "topologySpreadConstraints") -}}
|
|
||||||
{{- range $tscs }}
|
|
||||||
{{- $c := deepCopy . }}
|
|
||||||
{{- if not $c.labelSelector }}
|
|
||||||
{{- $_ := set $c "labelSelector" (dict "matchLabels" (include "fluxer-web.selectorLabels" $ | fromYaml)) }}
|
|
||||||
{{- end }}
|
|
||||||
- {{- toYaml $c | nindent 2 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
{{- $v := .Values }}
|
|
||||||
{{- range $name, $w := .Values.workloads }}
|
|
||||||
{{- if not (kindIs "invalid" $w) }}
|
|
||||||
{{- $ctx := dict "root" $ "name" $name "w" $w }}
|
|
||||||
{{- $envFrom := concat ($v.envFrom | default list) ($w.envFrom | default list) }}
|
|
||||||
{{- $podAnnotations := merge (dict) ($w.podAnnotations | default dict) ($v.podAnnotations | default dict) }}
|
|
||||||
{{- $wProbes := $w.probes | default dict }}
|
|
||||||
{{- $gProbes := $v.probes | default dict }}
|
|
||||||
---
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: {{ $name }}
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-web.labels" $ctx | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
{{- if not $w.hpa }}
|
|
||||||
replicas: {{ if kindIs "invalid" $w.replicas }}1{{ else }}{{ int $w.replicas }}{{ end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if not (kindIs "invalid" $w.minReadySeconds) }}
|
|
||||||
minReadySeconds: {{ int $w.minReadySeconds }}
|
|
||||||
{{- end }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "fluxer-web.selectorLabels" $ctx | nindent 6 }}
|
|
||||||
{{- with include "fluxer-web.pick" (dict "root" $ "w" $w "key" "strategy") }}
|
|
||||||
strategy:
|
|
||||||
{{- . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-web.labels" $ctx | nindent 8 }}
|
|
||||||
{{- with $podAnnotations }}
|
|
||||||
annotations:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
spec:
|
|
||||||
{{- with include "fluxer-web.pick" (dict "root" $ "w" $w "key" "imagePullSecrets") }}
|
|
||||||
imagePullSecrets:
|
|
||||||
{{- . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-web.pick" (dict "root" $ "w" $w "key" "podSecurityContext") }}
|
|
||||||
securityContext:
|
|
||||||
{{- . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if not (kindIs "invalid" $w.terminationGracePeriodSeconds) }}
|
|
||||||
terminationGracePeriodSeconds: {{ int $w.terminationGracePeriodSeconds }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-web.pick" (dict "root" $ "w" $w "key" "nodeSelector") }}
|
|
||||||
nodeSelector:
|
|
||||||
{{- . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-web.pick" (dict "root" $ "w" $w "key" "affinity") }}
|
|
||||||
affinity:
|
|
||||||
{{- . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-web.pick" (dict "root" $ "w" $w "key" "tolerations") }}
|
|
||||||
tolerations:
|
|
||||||
{{- . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-web.topologySpread" $ctx | trim }}
|
|
||||||
topologySpreadConstraints:
|
|
||||||
{{- . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
containers:
|
|
||||||
- name: {{ $name }}
|
|
||||||
image: {{ include "fluxer-web.image" $ctx }}
|
|
||||||
imagePullPolicy: {{ ($w.image | default dict).pullPolicy | default ($v.image | default dict).pullPolicy | default "IfNotPresent" }}
|
|
||||||
{{- with include "fluxer-web.env" $ctx | trim }}
|
|
||||||
env:
|
|
||||||
{{- . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $envFrom }}
|
|
||||||
envFrom:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
containerPort: 8080
|
|
||||||
protocol: TCP
|
|
||||||
{{- with $w.lifecycle }}
|
|
||||||
lifecycle:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- range $probe := list "startup" "liveness" "readiness" }}
|
|
||||||
{{- with hasKey $wProbes $probe | ternary (get $wProbes $probe) (get $gProbes $probe) }}
|
|
||||||
{{ $probe }}Probe:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.resources }}
|
|
||||||
resources:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with include "fluxer-web.pick" (dict "root" $ "w" $w "key" "securityContext") }}
|
|
||||||
securityContext:
|
|
||||||
{{- . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.extraVolumeMounts }}
|
|
||||||
volumeMounts:
|
|
||||||
{{- toYaml . | nindent 12 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.extraVolumes }}
|
|
||||||
volumes:
|
|
||||||
{{- toYaml . | nindent 8 }}
|
|
||||||
{{- end }}
|
|
||||||
---
|
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: {{ $name }}
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-web.labels" $ctx | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
type: ClusterIP
|
|
||||||
selector:
|
|
||||||
{{- include "fluxer-web.selectorLabels" $ctx | nindent 4 }}
|
|
||||||
ports:
|
|
||||||
- name: http
|
|
||||||
port: 8080
|
|
||||||
targetPort: http
|
|
||||||
protocol: TCP
|
|
||||||
{{- with $w.hpa }}
|
|
||||||
---
|
|
||||||
apiVersion: autoscaling/v2
|
|
||||||
kind: HorizontalPodAutoscaler
|
|
||||||
metadata:
|
|
||||||
name: {{ $name }}
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-web.labels" $ctx | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
scaleTargetRef:
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
name: {{ $name }}
|
|
||||||
minReplicas: {{ required (printf "%s.hpa.minReplicas is required" $name) .minReplicas }}
|
|
||||||
maxReplicas: {{ required (printf "%s.hpa.maxReplicas is required" $name) .maxReplicas }}
|
|
||||||
{{- with .targetCPUUtilizationPercentage }}
|
|
||||||
metrics:
|
|
||||||
- type: Resource
|
|
||||||
resource:
|
|
||||||
name: cpu
|
|
||||||
target:
|
|
||||||
type: Utilization
|
|
||||||
averageUtilization: {{ . }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with .behavior }}
|
|
||||||
behavior:
|
|
||||||
{{- toYaml . | nindent 4 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- with $w.pdb }}
|
|
||||||
---
|
|
||||||
apiVersion: policy/v1
|
|
||||||
kind: PodDisruptionBudget
|
|
||||||
metadata:
|
|
||||||
name: {{ $name }}-pdb
|
|
||||||
namespace: {{ $.Release.Namespace }}
|
|
||||||
labels:
|
|
||||||
{{- include "fluxer-web.labels" $ctx | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
{{- toYaml . | nindent 2 }}
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
{{- include "fluxer-web.selectorLabels" $ctx | nindent 6 }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
{{- end }}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
image:
|
|
||||||
registry: ghcr.io/fluxerapp
|
|
||||||
tag: v1
|
|
||||||
pullPolicy: IfNotPresent
|
|
||||||
|
|
||||||
imagePullSecrets: []
|
|
||||||
|
|
||||||
env: {}
|
|
||||||
|
|
||||||
extraEnv: []
|
|
||||||
|
|
||||||
envFrom:
|
|
||||||
- secretRef:
|
|
||||||
name: fluxer-env
|
|
||||||
|
|
||||||
podAnnotations: {}
|
|
||||||
|
|
||||||
podSecurityContext:
|
|
||||||
runAsNonRoot: true
|
|
||||||
seccompProfile:
|
|
||||||
type: RuntimeDefault
|
|
||||||
|
|
||||||
securityContext:
|
|
||||||
allowPrivilegeEscalation: false
|
|
||||||
|
|
||||||
probes:
|
|
||||||
startup:
|
|
||||||
httpGet:
|
|
||||||
path: /_health
|
|
||||||
port: http
|
|
||||||
periodSeconds: 10
|
|
||||||
failureThreshold: 30
|
|
||||||
liveness:
|
|
||||||
httpGet:
|
|
||||||
path: /_health
|
|
||||||
port: http
|
|
||||||
readiness:
|
|
||||||
httpGet:
|
|
||||||
path: /_health
|
|
||||||
port: http
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
type: RollingUpdate
|
|
||||||
|
|
||||||
topologySpreadConstraints: []
|
|
||||||
|
|
||||||
nodeSelector: {}
|
|
||||||
|
|
||||||
tolerations: []
|
|
||||||
|
|
||||||
affinity: {}
|
|
||||||
|
|
||||||
workloads:
|
|
||||||
admin:
|
|
||||||
image:
|
|
||||||
name: fluxer-admin
|
|
||||||
replicas: 1
|
|
||||||
env:
|
|
||||||
FLUXER_API_ENDPOINT: https://api.example.com
|
|
||||||
FLUXER_ADMIN_ENDPOINT: https://admin.example.com
|
|
||||||
FLUXER_MEDIA_ENDPOINT: https://media.example.com
|
|
||||||
FLUXER_APP_ENDPOINT: https://web.example.com
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
cpu: 50m
|
|
||||||
memory: 96Mi
|
|
||||||
limits:
|
|
||||||
memory: 384Mi
|
|
||||||
app-proxy:
|
|
||||||
image:
|
|
||||||
name: fluxer-app-proxy-self-hosted
|
|
||||||
replicas: 1
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
cpu: 50m
|
|
||||||
memory: 96Mi
|
|
||||||
limits:
|
|
||||||
memory: 384Mi
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
.DS_Store
|
||||||
|
.git/
|
||||||
|
.gitignore
|
||||||
|
*.swp
|
||||||
|
*.bak
|
||||||
|
*.tmp
|
||||||
|
*.orig
|
||||||
|
*~
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
ci/
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: v2
|
||||||
|
name: fluxer
|
||||||
|
description: A complete Fluxer instance on Kubernetes, at parity with the self-hosted Docker Compose stack.
|
||||||
|
type: application
|
||||||
|
version: 0.1.0
|
||||||
|
appVersion: "v1"
|
||||||
|
kubeVersion: ">=1.29.0-0"
|
||||||
|
home: https://docs.fluxer.app/operator/kubernetes/
|
||||||
|
sources:
|
||||||
|
- https://github.com/fluxerapp/fluxer/tree/main/deploy/helm/fluxer
|
||||||
|
keywords:
|
||||||
|
- fluxer
|
||||||
|
- chat
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
domain: chat.example.test
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
domain: chat.example.test
|
||||||
|
secrets:
|
||||||
|
existingSecret: fluxer-ci-secret
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
domain: chat.example.test
|
||||||
|
postgres:
|
||||||
|
enabled: false
|
||||||
|
external:
|
||||||
|
host: db.example.test
|
||||||
|
ssl: "true"
|
||||||
|
valkey:
|
||||||
|
enabled: false
|
||||||
|
nats:
|
||||||
|
enabled: false
|
||||||
|
external:
|
||||||
|
url: nats://mq.example.test:4222
|
||||||
|
meilisearch:
|
||||||
|
enabled: false
|
||||||
|
external:
|
||||||
|
url: https://search.example.test
|
||||||
|
seaweedfs:
|
||||||
|
enabled: false
|
||||||
|
s3:
|
||||||
|
endpoint: https://s3.example.test
|
||||||
|
publicEndpoint: https://cdn.example.test
|
||||||
|
region: eu-central-1
|
||||||
|
forcePathStyle: false
|
||||||
|
livekit:
|
||||||
|
enabled: false
|
||||||
|
external:
|
||||||
|
url: http://livekit.voice.svc:7880
|
||||||
|
publicUrl: wss://livekit.example.test
|
||||||
|
secrets:
|
||||||
|
values:
|
||||||
|
FLUXER_POSTGRES_PASSWORD: ci-postgres-password
|
||||||
|
FLUXER_SEARCH_API_KEY: ci-search-key
|
||||||
|
FLUXER_S3_SECRET_ACCESS_KEY: ci-s3-secret
|
||||||
|
FLUXER_NATS_AUTH_TOKEN: ci-nats-token
|
||||||
|
FLUXER_LIVEKIT_API_KEY: ci-livekit-key
|
||||||
|
FLUXER_LIVEKIT_API_SECRET: ci-livekit-secret-of-at-least-32-characters
|
||||||
|
extra:
|
||||||
|
FLUXER_KV_URL: redis://:[email protected]:6379/0
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
domain: chat.example.test
|
||||||
|
edge:
|
||||||
|
expose: gateway
|
||||||
|
gateway:
|
||||||
|
parentRefs:
|
||||||
|
- name: shared
|
||||||
|
namespace: gateway-system
|
||||||
|
timeouts:
|
||||||
|
request: 0s
|
||||||
|
livekit:
|
||||||
|
expose: nodePort
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
domain: chat.example.test
|
||||||
|
email: [email protected]
|
||||||
|
edge:
|
||||||
|
expose: loadBalancer
|
||||||
|
loadBalancer:
|
||||||
|
http3: true
|
||||||
|
livekit:
|
||||||
|
expose: loadBalancer
|
||||||
|
nodeIP: 203.0.113.10
|
||||||
|
loadBalancerIP: 203.0.113.10
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
domain: chat.example.test
|
||||||
|
networkPolicy:
|
||||||
|
enabled: false
|
||||||
|
livekit:
|
||||||
|
enabled: false
|
||||||
|
nats:
|
||||||
|
replicas: 3
|
||||||
|
initImage:
|
||||||
|
repository: registry.example.test/busybox
|
||||||
|
digest: sha256:0000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
postgres:
|
||||||
|
image:
|
||||||
|
repository: registry.example.test/postgres
|
||||||
|
tag: "16"
|
||||||
|
runAsUser: 999
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
domain: chat.example.test
|
||||||
|
networkPolicy:
|
||||||
|
ingressNamespaceSelector:
|
||||||
|
matchLabels:
|
||||||
|
kubernetes.io/metadata.name: ingress-nginx
|
||||||
|
edge:
|
||||||
|
ingress:
|
||||||
|
className: nginx
|
||||||
|
livekit:
|
||||||
|
nodeSelector:
|
||||||
|
kubernetes.io/hostname: voice-1
|
||||||
|
nodeCIDRs:
|
||||||
|
- 10.0.0.12/32
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
{
|
||||||
|
servers {
|
||||||
|
trusted_proxies static {$FLUXER_EDGE_TRUSTED_PROXIES:private_ranges}
|
||||||
|
trusted_proxies_strict
|
||||||
|
}
|
||||||
|
{$FLUXER_EDGE_GLOBAL_OPTIONS}
|
||||||
|
}
|
||||||
|
|
||||||
|
{$FLUXER_EDGE_SITE_ADDRESS} {
|
||||||
|
encode {$FLUXER_EDGE_ENCODE:zstd gzip}
|
||||||
|
|
||||||
|
handle /_health {
|
||||||
|
respond "OK" 200
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_path /api/* {
|
||||||
|
reverse_proxy api:8080
|
||||||
|
}
|
||||||
|
|
||||||
|
handle /gateway {
|
||||||
|
rewrite * /
|
||||||
|
reverse_proxy gateway:8080
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_path /gateway/* {
|
||||||
|
reverse_proxy gateway:8080
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_path /media/* {
|
||||||
|
reverse_proxy media-proxy:8080
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_path /livekit/* {
|
||||||
|
reverse_proxy livekit:7880
|
||||||
|
}
|
||||||
|
|
||||||
|
handle {$FLUXER_ADMIN_BASE_PATH:/admin} {
|
||||||
|
rewrite * /
|
||||||
|
reverse_proxy admin:8080
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_path {$FLUXER_ADMIN_BASE_PATH:/admin}/* {
|
||||||
|
reverse_proxy admin:8080
|
||||||
|
}
|
||||||
|
|
||||||
|
@staticAssets path /web/* /emoji/* /libs/* /avatars/* /badges/* /desktop/*
|
||||||
|
handle @staticAssets {
|
||||||
|
reverse_proxy static-proxy:8080
|
||||||
|
}
|
||||||
|
|
||||||
|
handle /.well-known/fluxer {
|
||||||
|
reverse_proxy api:8080
|
||||||
|
}
|
||||||
|
|
||||||
|
handle {
|
||||||
|
reverse_proxy app-proxy:8080
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:8088 {
|
||||||
|
handle /.well-known/fluxer {
|
||||||
|
reverse_proxy api:8080
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
trap 'exit 0' TERM INT
|
||||||
|
buckets="$FLUXER_S3_BUCKET_CDN $FLUXER_S3_BUCKET_UPLOADS $FLUXER_S3_BUCKET_REPORTS $FLUXER_S3_BUCKET_HARVESTS"
|
||||||
|
missing="$buckets"
|
||||||
|
for attempt in $(seq 1 "$FLUXER_SEAWEEDFS_INIT_ATTEMPTS"); do
|
||||||
|
if ! nc -z 127.0.0.1 9333 2>/dev/null; then
|
||||||
|
sleep 2
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
listed=$(echo "s3.bucket.list" | timeout 10 weed shell -master=127.0.0.1:9333 2>&1)
|
||||||
|
missing=""
|
||||||
|
for b in $buckets; do
|
||||||
|
echo "$listed" | grep -q "^[[:space:]]*$b[[:space:]]" || missing="${missing:+$missing }$b"
|
||||||
|
done
|
||||||
|
if [ -z "$missing" ]; then
|
||||||
|
if ! echo "s3.configure -user=fluxer -access_key=$FLUXER_S3_ACCESS_KEY -secret_key=$FLUXER_S3_SECRET_KEY -actions=Admin,Read,Write,List,Tagging -apply" | timeout 10 weed shell -master=127.0.0.1:9333 >/dev/null 2>&1; then
|
||||||
|
echo "seaweedfs-init could not configure the S3 identity" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "buckets ready"
|
||||||
|
touch /tmp/fluxer-buckets-ready
|
||||||
|
while :; do
|
||||||
|
sleep 86400 &
|
||||||
|
wait $!
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
for b in $missing; do
|
||||||
|
echo "s3.bucket.create -name $b" | timeout 10 weed shell -master=127.0.0.1:9333 >/dev/null 2>&1
|
||||||
|
done
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
echo "seaweedfs-init could not verify buckets: $missing" >&2
|
||||||
|
exit 1
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
{{- include "fluxer.validate" . }}
|
||||||
|
{{- $v := .Values }}
|
||||||
|
{{- $o := include "fluxer.origin" . }}
|
||||||
|
Fluxer is installing in namespace {{ .Release.Namespace }}. Run one release per namespace.
|
||||||
|
|
||||||
|
Open {{ $o }} once every pod is ready:
|
||||||
|
|
||||||
|
kubectl -n {{ .Release.Namespace }} get pods
|
||||||
|
|
||||||
|
The admin panel is at {{ $o }}{{ $v.adminBasePath }}.
|
||||||
|
|
||||||
|
Register the first account and finish the setup wizard in the same sitting.
|
||||||
|
Until the wizard is finished, any account that registers can change the
|
||||||
|
instance configuration.
|
||||||
|
{{- if eq $v.edge.expose "loadBalancer" }}
|
||||||
|
|
||||||
|
Point DNS for {{ $v.domain }} at the external address of the edge-public Service:
|
||||||
|
|
||||||
|
kubectl -n {{ .Release.Namespace }} get service edge-public
|
||||||
|
{{- else if eq $v.edge.expose "none" }}
|
||||||
|
|
||||||
|
Nothing exposes the instance yet. Send your proxy or tunnel to the Service edge
|
||||||
|
on port 8080, with the Host header {{ $v.domain }}.
|
||||||
|
{{- else }}
|
||||||
|
|
||||||
|
Point DNS for {{ $v.domain }} at your {{ ternary "ingress controller" "gateway" (eq $v.edge.expose "ingress") }}. Its Service needs
|
||||||
|
externalTrafficPolicy Local or the PROXY protocol, or every client shares one IP
|
||||||
|
and registration hits its per-IP limit.
|
||||||
|
{{- end }}
|
||||||
|
{{- if $v.livekit.external.url }}
|
||||||
|
|
||||||
|
Voice uses your LiveKit server at {{ $v.livekit.external.publicUrl }}. Point its webhook at
|
||||||
|
{{ $o }}/api/webhooks/livekit, signed with the key in FLUXER_LIVEKIT_API_KEY.
|
||||||
|
{{- end }}
|
||||||
|
{{- if $v.livekit.enabled }}
|
||||||
|
|
||||||
|
Voice media does not pass through the edge. Open these ports to the internet:
|
||||||
|
{{- if eq $v.livekit.expose "hostNetwork" }}
|
||||||
|
{{ $v.livekit.tcpPort }}/tcp and {{ $v.livekit.udpPort }}/udp on the node that runs the livekit pod.
|
||||||
|
hostNetwork needs a namespace that allows privileged pods. Keep 7880 closed.
|
||||||
|
{{- else if eq $v.livekit.expose "nodePort" }}
|
||||||
|
{{ $v.livekit.nodePorts.tcp }}/tcp and {{ $v.livekit.nodePorts.udp }}/udp on the node that runs the livekit pod.
|
||||||
|
{{- else }}
|
||||||
|
{{ $v.livekit.tcpPort }}/tcp and {{ $v.livekit.udpPort }}/udp on the load balancer of the Service livekit-rtc,
|
||||||
|
whose public IP must be {{ $v.livekit.nodeIP }}.
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
Back up the Secret {{ include "fluxer.secretName" . }}{{ if $v.postgres.enabled }}, the database in postgres-0{{ end }}{{ if $v.seaweedfs.enabled }} and the uploads on the volume data-seaweedfs-0{{ end }}.
|
||||||
|
{{- if $v.secrets.existingSecret }}
|
||||||
|
After editing the Secret {{ $v.secrets.existingSecret }}, restart the release:
|
||||||
|
|
||||||
|
kubectl -n {{ .Release.Namespace }} rollout restart deployment,statefulset -l app.kubernetes.io/instance={{ .Release.Name }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and $v.secrets.generate (not $v.secrets.existingSecret) }}
|
||||||
|
|
||||||
|
Argo CD and helm template cannot read the existing Secret and would generate
|
||||||
|
new secrets on every render. Under them, set secrets.generate=false and use
|
||||||
|
secrets.existingSecret or give every key in secrets.values.
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
To move to the latest v1 images, pull the repository and upgrade with your values file:
|
||||||
|
|
||||||
|
helm upgrade {{ .Release.Name }} <chart> -n {{ .Release.Namespace }} -f <your values file> --set-string image.revision=$(date +%s)
|
||||||
|
|
||||||
|
Leave out --reuse-values, which keeps the defaults of the old chart version.
|
||||||
|
|
||||||
|
Documentation: https://docs.fluxer.app/operator/kubernetes/
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
{{- define "fluxer.s3Endpoint" -}}
|
||||||
|
{{- .Values.s3.endpoint | default (ternary "http://seaweedfs:8333" "" .Values.seaweedfs.enabled) }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.configData" -}}
|
||||||
|
{{- $v := .Values }}
|
||||||
|
{{- $o := include "fluxer.origin" . }}
|
||||||
|
{{- $hostOrigin := include "fluxer.hostOrigin" . }}
|
||||||
|
{{- $media := printf "%s/media" $o }}
|
||||||
|
{{- $s3 := include "fluxer.s3Endpoint" . }}
|
||||||
|
{{- $c := dict }}
|
||||||
|
{{- $_ := set $c "FLUXER_ENV" "production" }}
|
||||||
|
{{- $_ := set $c "FLUXER_SELF_HOSTED" "true" }}
|
||||||
|
{{- $_ := set $c "FLUXER_DATABASE_BACKEND" "postgres" }}
|
||||||
|
{{- $_ := set $c "FLUXER_TRUST_CLIENT_IP_HEADER" "true" }}
|
||||||
|
{{- $_ := set $c "FLUXER_BASE_DOMAIN" $v.domain }}
|
||||||
|
{{- $_ := set $c "FLUXER_PUBLIC_SCHEME" $v.scheme }}
|
||||||
|
{{- $_ := set $c "FLUXER_PUBLIC_PORT" (include "fluxer.string" $v.port) }}
|
||||||
|
{{- $_ := set $c "FLUXER_PUBLIC_ORIGIN" (trimSuffix "/" ($v.publicOrigin | default "")) }}
|
||||||
|
{{- $_ := set $c "FLUXER_APP_ENDPOINT" $o }}
|
||||||
|
{{- $_ := set $c "FLUXER_MARKETING_ENDPOINT" $o }}
|
||||||
|
{{- $_ := set $c "FLUXER_MEDIA_ENDPOINT" $media }}
|
||||||
|
{{- $_ := set $c "FLUXER_MEDIA_PROXY_PUBLIC_ENDPOINT" $media }}
|
||||||
|
{{- $_ := set $c "FLUXER_MEDIA_PROXY_UPLOAD_RELAY_ENDPOINT" $media }}
|
||||||
|
{{- $_ := set $c "FLUXER_GATEWAY_MEDIA_PROXY_ENDPOINT" $media }}
|
||||||
|
{{- $_ := set $c "FLUXER_ADMIN_ENDPOINT" (printf "%s%s" $o $v.adminBasePath) }}
|
||||||
|
{{- $_ := set $c "FLUXER_GATEWAY_STATIC_CDN_ENDPOINT" $o }}
|
||||||
|
{{- $_ := set $c "FLUXER_MEDIA_PROXY_CORS_ALLOWED_ORIGINS" $hostOrigin }}
|
||||||
|
{{- $_ := set $c "FLUXER_PASSKEY_RP_ID" $v.domain }}
|
||||||
|
{{- $_ := set $c "FLUXER_PASSKEY_ADDITIONAL_ALLOWED_ORIGINS" $o }}
|
||||||
|
{{- if $v.postgres.enabled }}
|
||||||
|
{{- $_ := set $c "FLUXER_POSTGRES_HOST" "postgres" }}
|
||||||
|
{{- $_ := set $c "FLUXER_POSTGRES_PORT" "5432" }}
|
||||||
|
{{- $_ := set $c "FLUXER_POSTGRES_DATABASE" $v.postgres.database }}
|
||||||
|
{{- $_ := set $c "FLUXER_POSTGRES_USERNAME" $v.postgres.username }}
|
||||||
|
{{- else }}
|
||||||
|
{{- with $v.postgres.external }}
|
||||||
|
{{- $_ := set $c "FLUXER_POSTGRES_HOST" (.host | default "") }}
|
||||||
|
{{- $_ := set $c "FLUXER_POSTGRES_PORT" (include "fluxer.string" (.port | default "")) }}
|
||||||
|
{{- $_ := set $c "FLUXER_POSTGRES_DATABASE" (.database | default "") }}
|
||||||
|
{{- $_ := set $c "FLUXER_POSTGRES_USERNAME" (.username | default "") }}
|
||||||
|
{{- $_ := set $c "FLUXER_POSTGRES_SSL" (include "fluxer.string" (.ssl | default "")) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if not $v.valkey.enabled }}
|
||||||
|
{{- $_ := set $c "FLUXER_KV_URL" ($v.valkey.external.url | default "") }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $nats := ternary "nats://nats:4222" ($v.nats.external.url | default "") $v.nats.enabled }}
|
||||||
|
{{- $_ := set $c "FLUXER_NATS_URL" $nats }}
|
||||||
|
{{- $_ := set $c "FLUXER_NATS_JETSTREAM_URL" $nats }}
|
||||||
|
{{- $_ := set $c "FLUXER_SVC_NATS_URL" $nats }}
|
||||||
|
{{- $_ := set $c "FLUXER_SEARCH_ENGINE" "meilisearch" }}
|
||||||
|
{{- $_ := set $c "FLUXER_SEARCH_URL" (ternary "http://meilisearch:7700" ($v.meilisearch.external.url | default "") $v.meilisearch.enabled) }}
|
||||||
|
{{- $_ := set $c "FLUXER_S3_ENDPOINT" $s3 }}
|
||||||
|
{{- $_ := set $c "FLUXER_S3_PUBLIC_ENDPOINT" ($v.s3.publicEndpoint | default $s3) }}
|
||||||
|
{{- $_ := set $c "FLUXER_S3_REGION" $v.s3.region }}
|
||||||
|
{{- $_ := set $c "FLUXER_S3_FORCE_PATH_STYLE" (toString $v.s3.forcePathStyle) }}
|
||||||
|
{{- $_ := set $c "FLUXER_S3_BUCKET_CDN" $v.s3.buckets.cdn }}
|
||||||
|
{{- $_ := set $c "FLUXER_S3_BUCKET_UPLOADS" $v.s3.buckets.uploads }}
|
||||||
|
{{- $_ := set $c "FLUXER_S3_BUCKET_REPORTS" $v.s3.buckets.reports }}
|
||||||
|
{{- $_ := set $c "FLUXER_S3_BUCKET_HARVESTS" $v.s3.buckets.harvests }}
|
||||||
|
{{- $livekit := include "fluxer.livekitMode" . }}
|
||||||
|
{{- $_ := set $c "FLUXER_LIVEKIT_ENABLED" (toString (ne $livekit "off")) }}
|
||||||
|
{{- if eq $livekit "bundled" }}
|
||||||
|
{{- $_ := set $c "FLUXER_LIVEKIT_INTERNAL_URL" "http://livekit:7880" }}
|
||||||
|
{{- $_ := set $c "FLUXER_LIVEKIT_DEFAULT_REGION" $v.livekit.defaultRegion }}
|
||||||
|
{{- $_ := set $c "FLUXER_LIVEKIT_URL" (printf "%s/livekit" $hostOrigin) }}
|
||||||
|
{{- else if eq $livekit "external" }}
|
||||||
|
{{- $_ := set $c "FLUXER_LIVEKIT_INTERNAL_URL" $v.livekit.external.url }}
|
||||||
|
{{- $_ := set $c "FLUXER_LIVEKIT_DEFAULT_REGION" $v.livekit.defaultRegion }}
|
||||||
|
{{- $_ := set $c "FLUXER_LIVEKIT_URL" $v.livekit.external.publicUrl }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $_ := set $c "FLUXER_API_PRESIGNED_HARVEST_DOWNLOADS_ENABLED" "false" }}
|
||||||
|
{{- $_ := set $c "FLUXER_EMAIL_FROM_EMAIL" "noreply@localhost" }}
|
||||||
|
{{- $_ := set $c "FLUXER_VAPID_EMAIL" ($v.email | default (printf "admin@%s" $v.domain)) }}
|
||||||
|
{{- $_ := set $c "FLUXER_INTERNAL_API_ENDPOINT" "http://api:8080" }}
|
||||||
|
{{- $_ := set $c "FLUXER_INTERNAL_MEDIA_PROXY_ENDPOINT" "http://media-proxy:8080" }}
|
||||||
|
{{- range $k, $val := $v.env | default dict }}
|
||||||
|
{{- $_ := set $c $k (include "fluxer.string" ($val | default "")) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $out := dict }}
|
||||||
|
{{- range $k, $val := $c }}
|
||||||
|
{{- if $val }}
|
||||||
|
{{- $_ := set $out $k $val }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- toYaml $out }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.appProxyConfigData" -}}
|
||||||
|
{{- $v := .Values }}
|
||||||
|
{{- $s3 := include "fluxer.s3Endpoint" . }}
|
||||||
|
{{- $c := dict }}
|
||||||
|
{{- $_ := set $c "FLUXER_APP_PROXY_PORT" "8080" }}
|
||||||
|
{{- $_ := set $c "DISCOVERY_UPSTREAM_URL" "http://api:8080/.well-known/fluxer" }}
|
||||||
|
{{- $_ := set $c "FLUXER_S3_PUBLIC_ENDPOINT" ($v.s3.publicEndpoint | default $s3) }}
|
||||||
|
{{- $_ := set $c "FLUXER_S3_BUCKET_UPLOADS" $v.s3.buckets.uploads }}
|
||||||
|
{{- $_ := set $c "FLUXER_MEDIA_ENDPOINT" (printf "%s/media" (include "fluxer.origin" .)) }}
|
||||||
|
{{- range $k, $val := $v.appProxy.config | default dict }}
|
||||||
|
{{- $_ := set $c $k (include "fluxer.string" ($val | default "")) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $out := dict }}
|
||||||
|
{{- range $k, $val := $c }}
|
||||||
|
{{- if $val }}
|
||||||
|
{{- $_ := set $out $k $val }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- toYaml $out }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,374 @@
|
|||||||
|
{{- define "fluxer.chart" -}}
|
||||||
|
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.selectorLabels" -}}
|
||||||
|
app.kubernetes.io/name: {{ .name }}
|
||||||
|
app.kubernetes.io/instance: {{ .root.Release.Name }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.podLabels" -}}
|
||||||
|
{{ include "fluxer.selectorLabels" . }}
|
||||||
|
{{- with .component }}
|
||||||
|
app.kubernetes.io/component: {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
app.kubernetes.io/part-of: fluxer
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.labels" -}}
|
||||||
|
{{ include "fluxer.podLabels" . }}
|
||||||
|
app.kubernetes.io/managed-by: {{ .root.Release.Service }}
|
||||||
|
app.kubernetes.io/version: {{ .root.Chart.AppVersion | quote }}
|
||||||
|
helm.sh/chart: {{ include "fluxer.chart" .root }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.string" -}}
|
||||||
|
{{- if and (kindIs "float64" .) (eq . (float64 (int64 .))) }}
|
||||||
|
{{- int64 . | toString }}
|
||||||
|
{{- else }}
|
||||||
|
{{- toString . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.origin" -}}
|
||||||
|
{{- $v := .Values }}
|
||||||
|
{{- if $v.publicOrigin }}
|
||||||
|
{{- trimSuffix "/" $v.publicOrigin }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $default := ternary 443 80 (eq $v.scheme "https") }}
|
||||||
|
{{- if eq (int $v.port) $default }}
|
||||||
|
{{- printf "%s://%s" $v.scheme $v.domain }}
|
||||||
|
{{- else }}
|
||||||
|
{{- printf "%s://%s:%d" $v.scheme $v.domain (int $v.port) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.hostOrigin" -}}
|
||||||
|
{{- $v := .Values }}
|
||||||
|
{{- if $v.publicOrigin }}
|
||||||
|
{{- trimSuffix "/" $v.publicOrigin }}
|
||||||
|
{{- else }}
|
||||||
|
{{- printf "%s://%s:%d" $v.scheme $v.domain (int $v.port) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.secretName" -}}
|
||||||
|
{{- .Values.secrets.existingSecret | default "fluxer-env" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.thirdPartyImage" -}}
|
||||||
|
{{- $ref := printf "%s:%s" .repository (include "fluxer.string" .tag) }}
|
||||||
|
{{- with .digest }}
|
||||||
|
{{- $ref = printf "%s@%s" $ref . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $ref | quote }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.image" -}}
|
||||||
|
{{- $v := .root.Values.image }}
|
||||||
|
{{- $img := (.w | default dict).image | default dict }}
|
||||||
|
{{- $registry := $img.registry | default $v.registry }}
|
||||||
|
{{- $tag := $img.tag | default (get ($v.tags | default dict) .image) | default $v.tag }}
|
||||||
|
{{- $ref := printf "%s/%s:%s" $registry .image (include "fluxer.string" $tag) }}
|
||||||
|
{{- with $img.digest | default (get ($v.digests | default dict) .image) }}
|
||||||
|
{{- $ref = printf "%s@%s" $ref . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $ref | quote }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.pullPolicy" -}}
|
||||||
|
{{- (((.w | default dict).image | default dict).pullPolicy) | default .root.Values.image.pullPolicy }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.pullSecrets" -}}
|
||||||
|
{{- with .Values.image.pullSecrets }}
|
||||||
|
imagePullSecrets:
|
||||||
|
{{- toYaml . | nindent 2 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.podSecurityContext" -}}
|
||||||
|
runAsNonRoot: true
|
||||||
|
{{- with .uid }}
|
||||||
|
runAsUser: {{ . }}
|
||||||
|
runAsGroup: {{ $.gid | default . }}
|
||||||
|
fsGroup: {{ $.gid | default . }}
|
||||||
|
fsGroupChangePolicy: OnRootMismatch
|
||||||
|
{{- end }}
|
||||||
|
seccompProfile:
|
||||||
|
type: RuntimeDefault
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.containerSecurityContext" -}}
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.scheduling" -}}
|
||||||
|
{{- $w := .w | default dict }}
|
||||||
|
{{- with $w.nodeSelector }}
|
||||||
|
nodeSelector:
|
||||||
|
{{- toYaml . | nindent 2 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with $w.tolerations }}
|
||||||
|
tolerations:
|
||||||
|
{{- toYaml . | nindent 2 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with $w.affinity }}
|
||||||
|
affinity:
|
||||||
|
{{- toYaml . | nindent 2 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $spread := list }}
|
||||||
|
{{- range $w.topologySpreadConstraints }}
|
||||||
|
{{- $c := deepCopy . }}
|
||||||
|
{{- if not (hasKey $c "labelSelector") }}
|
||||||
|
{{- $_ := set $c "labelSelector" (dict "matchLabels" (include "fluxer.selectorLabels" $ | fromYaml)) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $spread = append $spread $c }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with $spread }}
|
||||||
|
topologySpreadConstraints:
|
||||||
|
{{- toYaml . | nindent 2 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.pvc" -}}
|
||||||
|
- metadata:
|
||||||
|
name: data
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
{{- with .storageClassName }}
|
||||||
|
storageClassName: {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ .size }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.vapidPair" -}}
|
||||||
|
{{- $der := genPrivateKey "ecdsa" | replace "-----BEGIN EC PRIVATE KEY-----" "" | replace "-----END EC PRIVATE KEY-----" "" | nospace | b64dec -}}
|
||||||
|
private: {{ substr 7 39 $der | b64enc | replace "+" "-" | replace "/" "_" | trimAll "=" }}
|
||||||
|
public: {{ substr 56 121 $der | b64enc | replace "+" "-" | replace "/" "_" | trimAll "=" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.livekitMode" -}}
|
||||||
|
{{- if .Values.livekit.enabled }}bundled{{ else if .Values.livekit.external.url }}external{{ else }}off{{ end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.noGenerateKeys" -}}
|
||||||
|
{{- $keys := list }}
|
||||||
|
{{- $extra := .Values.secrets.extra | default dict }}
|
||||||
|
{{- if and (not .Values.postgres.enabled) (not (get $extra "FLUXER_POSTGRES_URL")) }}
|
||||||
|
{{- $keys = append $keys "FLUXER_POSTGRES_PASSWORD" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if not .Values.meilisearch.enabled }}
|
||||||
|
{{- $keys = append $keys "FLUXER_SEARCH_API_KEY" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if not .Values.seaweedfs.enabled }}
|
||||||
|
{{- $keys = append $keys "FLUXER_S3_SECRET_ACCESS_KEY" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if eq (include "fluxer.livekitMode" .) "external" }}
|
||||||
|
{{- $keys = append $keys "FLUXER_LIVEKIT_API_SECRET" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- toJson $keys }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.requiredSecretKeys" -}}
|
||||||
|
{{- $keys := list }}
|
||||||
|
{{- $extra := .Values.secrets.extra | default dict }}
|
||||||
|
{{- range $k, $_ := .Values.secrets.values }}
|
||||||
|
{{- if and (eq $k "FLUXER_POSTGRES_PASSWORD") (get $extra "FLUXER_POSTGRES_URL") }}
|
||||||
|
{{- else if and (hasPrefix "FLUXER_LIVEKIT_" $k) (eq (include "fluxer.livekitMode" $) "off") }}
|
||||||
|
{{- else if and (eq $k "FLUXER_VALKEY_PASSWORD") (not $.Values.valkey.enabled) }}
|
||||||
|
{{- else if and (eq $k "FLUXER_NATS_AUTH_TOKEN") (not $.Values.nats.enabled) }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $keys = append $keys $k }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- toJson $keys }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.resolveSecrets" -}}
|
||||||
|
{{- $v := .Values }}
|
||||||
|
{{- $existing := dict }}
|
||||||
|
{{- $found := lookup "v1" "Secret" .Release.Namespace (include "fluxer.secretName" .) }}
|
||||||
|
{{- range $k, $val := ($found.data | default dict) }}
|
||||||
|
{{- $_ := set $existing $k (b64dec $val) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $out := dict }}
|
||||||
|
{{- if $v.secrets.existingSecret }}
|
||||||
|
{{- $out = $existing }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $noGenerate := include "fluxer.noGenerateKeys" . | fromJsonArray }}
|
||||||
|
{{- $explicit := $v.secrets.values | default dict }}
|
||||||
|
{{- $vapidPublic := include "fluxer.string" (get $explicit "FLUXER_VAPID_PUBLIC_KEY" | default "") }}
|
||||||
|
{{- $vapidPrivate := include "fluxer.string" (get $explicit "FLUXER_VAPID_PRIVATE_KEY" | default "") }}
|
||||||
|
{{- if and $vapidPublic $vapidPrivate }}
|
||||||
|
{{- else if or $vapidPublic $vapidPrivate }}
|
||||||
|
{{- fail "secrets.values.FLUXER_VAPID_PUBLIC_KEY and secrets.values.FLUXER_VAPID_PRIVATE_KEY must be set together, or both left empty to generate a pair" }}
|
||||||
|
{{- else if and (get $existing "FLUXER_VAPID_PUBLIC_KEY") (get $existing "FLUXER_VAPID_PRIVATE_KEY") }}
|
||||||
|
{{- $vapidPublic = get $existing "FLUXER_VAPID_PUBLIC_KEY" }}
|
||||||
|
{{- $vapidPrivate = get $existing "FLUXER_VAPID_PRIVATE_KEY" }}
|
||||||
|
{{- else if $v.secrets.generate }}
|
||||||
|
{{- $pair := include "fluxer.vapidPair" . | fromYaml }}
|
||||||
|
{{- $vapidPublic = $pair.public }}
|
||||||
|
{{- $vapidPrivate = $pair.private }}
|
||||||
|
{{- else }}
|
||||||
|
{{- fail "secrets.values.FLUXER_VAPID_PUBLIC_KEY and secrets.values.FLUXER_VAPID_PRIVATE_KEY are empty and secrets.generate is false" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $_ := set $out "FLUXER_VAPID_PUBLIC_KEY" $vapidPublic }}
|
||||||
|
{{- $_ := set $out "FLUXER_VAPID_PRIVATE_KEY" $vapidPrivate }}
|
||||||
|
{{- $required := include "fluxer.requiredSecretKeys" . | fromJsonArray }}
|
||||||
|
{{- $outsideToken := include "fluxer.string" (get $explicit "FLUXER_NATS_AUTH_TOKEN" | default "") }}
|
||||||
|
{{- if and $outsideToken (not $v.nats.enabled) }}
|
||||||
|
{{- $_ := set $out "FLUXER_NATS_AUTH_TOKEN" $outsideToken }}
|
||||||
|
{{- end }}
|
||||||
|
{{- range $k := $required }}
|
||||||
|
{{- if not (hasPrefix "FLUXER_VAPID_" $k) }}
|
||||||
|
{{- $given := include "fluxer.string" (get $explicit $k | default "") }}
|
||||||
|
{{- if $given }}
|
||||||
|
{{- $_ := set $out $k $given }}
|
||||||
|
{{- else if has $k $noGenerate }}
|
||||||
|
{{- fail (printf "secrets.values.%s is required when the matching service is not bundled" $k) }}
|
||||||
|
{{- else if get $existing $k }}
|
||||||
|
{{- $_ := set $out $k (get $existing $k) }}
|
||||||
|
{{- else if $v.secrets.generate }}
|
||||||
|
{{- if eq $k "FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64" }}
|
||||||
|
{{- $_ := set $out $k (randBytes 32) }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $_ := set $out $k (randAlphaNum 64) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else }}
|
||||||
|
{{- fail (printf "secrets.values.%s is empty and secrets.generate is false" $k) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- range $k, $val := $v.secrets.extra | default dict }}
|
||||||
|
{{- $s := include "fluxer.string" ($val | default "") }}
|
||||||
|
{{- if $s }}
|
||||||
|
{{- $_ := set $out $k $s }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- toJson $out }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.secretData" -}}
|
||||||
|
{{- if not (hasKey .Values "fluxerResolvedSecrets") }}
|
||||||
|
{{- $_ := set .Values "fluxerResolvedSecrets" (include "fluxer.resolveSecrets" . | fromJson) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- toJson (get .Values "fluxerResolvedSecrets") }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.secretEnv" -}}
|
||||||
|
- name: {{ .name }}
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: {{ include "fluxer.secretName" .root }}
|
||||||
|
key: {{ .key }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.instanceChecksum" -}}
|
||||||
|
{{- $parts := list (include "fluxer.configData" .) (include "fluxer.appProxyConfigData" .) (toJson .Values.secrets.values) (toJson (.Values.secrets.extra | default dict)) (include "fluxer.string" .Values.image.revision) (include "fluxer.secretData" .) }}
|
||||||
|
{{- join "\n" $parts | sha256sum }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.envList" -}}
|
||||||
|
{{- $w := .w | default dict }}
|
||||||
|
{{- $own := $w.env | default dict }}
|
||||||
|
{{- $base := .env | default list }}
|
||||||
|
{{- $names := list }}
|
||||||
|
{{- range $base }}
|
||||||
|
{{- $names = append $names .name }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $out := list }}
|
||||||
|
{{- range $base }}
|
||||||
|
{{- if hasKey $own .name }}
|
||||||
|
{{- $val := get $own .name }}
|
||||||
|
{{- if not (kindIs "invalid" $val) }}
|
||||||
|
{{- $out = append $out (dict "name" .name "value" (include "fluxer.string" $val)) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- else }}
|
||||||
|
{{- $out = append $out . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- range $k := keys $own | sortAlpha }}
|
||||||
|
{{- $val := get $own $k }}
|
||||||
|
{{- if and (not (has $k $names)) (not (kindIs "invalid" $val)) }}
|
||||||
|
{{- $out = append $out (dict "name" $k "value" (include "fluxer.string" $val)) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $out = concat $out ($w.extraEnv | default list) }}
|
||||||
|
{{- with $out }}
|
||||||
|
{{- toYaml . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.probes" -}}
|
||||||
|
{{- $own := (.w | default dict).probes | default dict }}
|
||||||
|
{{- range $probe := list "startup" "liveness" "readiness" }}
|
||||||
|
{{- $p := get ($.probes | default dict) $probe }}
|
||||||
|
{{- if hasKey $own $probe }}
|
||||||
|
{{- $p = get $own $probe }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with $p }}
|
||||||
|
{{ $probe }}Probe:
|
||||||
|
{{- toYaml . | nindent 2 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.waitFor" -}}
|
||||||
|
{{- with .waitFor }}
|
||||||
|
initContainers:
|
||||||
|
- name: wait-for-dependencies
|
||||||
|
image: {{ include "fluxer.thirdPartyImage" $.root.Values.initImage }}
|
||||||
|
imagePullPolicy: {{ $.root.Values.initImage.pullPolicy }}
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- {{ printf "for t in %s; do until nc -z -w 2 ${t%%:*} ${t##*:}; do echo waiting for $t; sleep 2; done; done" (join " " .) | quote }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 16Mi
|
||||||
|
limits:
|
||||||
|
memory: 32Mi
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 65532
|
||||||
|
runAsGroup: 65532
|
||||||
|
{{- include "fluxer.containerSecurityContext" . | nindent 6 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.appWaitFor" -}}
|
||||||
|
{{- $out := list }}
|
||||||
|
{{- if and .usesNats .root.Values.nats.enabled }}
|
||||||
|
{{- $out = append $out "nats:4222" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and .usesPostgres .root.Values.postgres.enabled }}
|
||||||
|
{{- $out = append $out "postgres:5432" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and .usesS3 .root.Values.seaweedfs.enabled }}
|
||||||
|
{{- $out = append $out "seaweedfs:8333" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and .usesKv .root.Values.valkey.enabled }}
|
||||||
|
{{- $out = append $out "valkey:6379" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if .usesSvc }}
|
||||||
|
{{- range $name := list "gifs" "messages" "snowflakes" "unfurl" "users" }}
|
||||||
|
{{- $svc := get $.root.Values.svc $name | default dict }}
|
||||||
|
{{- if gt (int (include "fluxer.replicas" (dict "w" ($svc.router | default dict)))) 0 }}
|
||||||
|
{{- $out = append $out (printf "%s:8090" $name) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if gt (int (include "fluxer.replicas" (dict "w" ($svc.shard | default dict)))) 0 }}
|
||||||
|
{{- $out = append $out (printf "%s-shard:8090" $name) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- toJson $out }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,245 @@
|
|||||||
|
{{- define "fluxer.validate" -}}
|
||||||
|
{{- if not (hasKey .Values "fluxerValidated") }}
|
||||||
|
{{- $_ := set .Values "fluxerValidated" true }}
|
||||||
|
{{- $v := .Values }}
|
||||||
|
{{- if not (regexMatch "^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)+$" ($v.domain | default "")) }}
|
||||||
|
{{- fail "domain must be set to the lowercase public hostname of the instance, for example --set domain=chat.example.com" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if not (has $v.scheme (list "http" "https")) }}
|
||||||
|
{{- fail "scheme must be http or https" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and $v.publicOrigin (not (regexMatch "^https?://[^/]+$" (trimSuffix "/" $v.publicOrigin))) }}
|
||||||
|
{{- fail "publicOrigin must be a scheme, host and optional port, for example https://chat.example.com" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if not (regexMatch "^/[^/].*[^/]$|^/[^/]$" $v.adminBasePath) }}
|
||||||
|
{{- fail "adminBasePath must start with a slash and must not end with one, for example /admin" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $extra := $v.secrets.extra | default dict }}
|
||||||
|
{{- if and (not $v.postgres.enabled) (not $v.postgres.external.host) (not (get $extra "FLUXER_POSTGRES_URL")) (not $v.secrets.existingSecret) }}
|
||||||
|
{{- fail "postgres.enabled is false, so set postgres.external.host or secrets.extra.FLUXER_POSTGRES_URL" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and (not $v.valkey.enabled) (not $v.valkey.external.url) (not (get $extra "FLUXER_KV_URL")) (not $v.secrets.existingSecret) }}
|
||||||
|
{{- fail "valkey.enabled is false, so set valkey.external.url or secrets.extra.FLUXER_KV_URL" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and (not $v.nats.enabled) (not $v.nats.external.url) }}
|
||||||
|
{{- fail "nats.enabled is false, so set nats.external.url" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and (not $v.meilisearch.enabled) (not $v.meilisearch.external.url) }}
|
||||||
|
{{- fail "meilisearch.enabled is false, so set meilisearch.external.url" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and (not $v.seaweedfs.enabled) (not $v.s3.endpoint) }}
|
||||||
|
{{- fail "seaweedfs.enabled is false, so set s3.endpoint to your S3 store" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if gt (int $v.nats.replicas) 1 }}
|
||||||
|
{{- if lt (int $v.nats.replicas) 3 }}
|
||||||
|
{{- fail "nats.replicas must be 1, or 3 or more for a JetStream cluster" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if gt (int (include "fluxer.replicas" (dict "w" $v.worker))) 1 }}
|
||||||
|
{{- fail "worker.replicas must be 1, because the worker runs the cron scheduler" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if not (has $v.livekit.expose (list "hostNetwork" "loadBalancer" "nodePort")) }}
|
||||||
|
{{- fail "livekit.expose must be hostNetwork, loadBalancer or nodePort" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and $v.livekit.enabled $v.livekit.external.url }}
|
||||||
|
{{- fail "livekit.external.url names a LiveKit server of your own, so set livekit.enabled to false" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and $v.livekit.external.url (not (regexMatch "^(wss?|https?)://[^/]+" ($v.livekit.external.publicUrl | default ""))) }}
|
||||||
|
{{- fail "livekit.external.url is set, so set livekit.external.publicUrl to the address browsers use to reach that LiveKit server, for example wss://livekit.example.com" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and $v.livekit.enabled (eq $v.livekit.expose "loadBalancer") (not $v.livekit.nodeIP) }}
|
||||||
|
{{- fail "livekit.expose is loadBalancer, so reserve a public address before installing, set livekit.nodeIP to it, and pin the Service livekit-rtc to it with livekit.loadBalancerIP or livekit.serviceAnnotations. Use hostNetwork or nodePort where a load balancer cannot serve TCP and UDP on one address" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if not (has $v.edge.expose (list "ingress" "gateway" "loadBalancer" "none")) }}
|
||||||
|
{{- fail "edge.expose must be ingress, gateway, loadBalancer or none" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if not (has $v.edge.ingress.tls.mode (list "certManager" "existingSecret" "none")) }}
|
||||||
|
{{- fail "edge.ingress.tls.mode must be certManager, existingSecret or none" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and (eq $v.edge.expose "gateway") (not $v.edge.gateway.parentRefs) }}
|
||||||
|
{{- fail "edge.expose is gateway, so set edge.gateway.parentRefs to the Gateway the route attaches to" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and (eq $v.edge.expose "loadBalancer") (ne $v.scheme "https") }}
|
||||||
|
{{- fail "edge.expose loadBalancer serves HTTPS itself, so scheme must be https" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and $v.networkPolicy.enabled $v.networkPolicy.ingressNamespaceSelector $v.livekit.enabled (eq $v.livekit.expose "hostNetwork") (not $v.livekit.nodeCIDRs) }}
|
||||||
|
{{- fail "networkPolicy.ingressNamespaceSelector limits who reaches the edge, and LiveKit on the host network sends its webhook to the edge from a node address. Set livekit.nodeCIDRs to the address of the LiveKit node, for example 10.0.0.12/32" }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- $placeholder := "(?i)change[_-]?me" }}
|
||||||
|
{{- $secretName := "_(PASSWORD|SECRET|TOKEN|COOKIE|KEY|KEYS|KEY_BASE|SECRETS?_BASE64)$" }}
|
||||||
|
{{- $credentialUrl := "://[^/@ ]*:[^/@ ]*@" }}
|
||||||
|
{{- $plain := dict "env" ($v.env | default dict) "appProxy.config" ($v.appProxy.config | default dict) "edge.env" ($v.edge.env | default dict) }}
|
||||||
|
{{- range $name := list "api" "worker" "gateway" "mediaProxy" "push" "admin" "appProxy" "staticProxy" }}
|
||||||
|
{{- $_ := set $plain (printf "%s.env" $name) ((get $v $name).env | default dict) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- range $name, $svc := $v.svc }}
|
||||||
|
{{- range $part := list "router" "shard" }}
|
||||||
|
{{- $_ := set $plain (printf "svc.%s.%s.env" $name $part) ((get ($svc | default dict) $part | default dict).env | default dict) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- range $where, $map := $plain }}
|
||||||
|
{{- range $k, $val := $map }}
|
||||||
|
{{- $s := include "fluxer.string" ($val | default "") }}
|
||||||
|
{{- if regexMatch $placeholder $s }}
|
||||||
|
{{- fail (printf "%s.%s is a placeholder. Remove it or set a real value" $where $k) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if or (hasKey $v.secrets.values $k) (regexMatch $secretName $k) }}
|
||||||
|
{{- fail (printf "%s.%s is a secret and would be stored in plain text. Set it in secrets.extra instead, or reference a Secret of your own from extraEnv" $where $k) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if regexMatch $credentialUrl $s }}
|
||||||
|
{{- fail (printf "%s.%s is a URL that holds a password and would be stored in plain text. Set it in secrets.extra instead" $where $k) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- range $k, $val := $v.secrets.values }}
|
||||||
|
{{- if regexMatch $placeholder (include "fluxer.string" ($val | default "")) }}
|
||||||
|
{{- fail (printf "secrets.values.%s is a placeholder. Leave it empty to generate a value, or set a real one" $k) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- range $k, $val := $extra }}
|
||||||
|
{{- if regexMatch $placeholder (include "fluxer.string" ($val | default "")) }}
|
||||||
|
{{- fail (printf "secrets.extra.%s is a placeholder. Remove it or set a real value" $k) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- $connected := false }}
|
||||||
|
{{- if $v.clusterChecks }}
|
||||||
|
{{- $connected = or (lookup "v1" "Namespace" "" .Release.Namespace) (lookup "v1" "Namespace" "" "kube-system") | not | not }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $data := include "fluxer.secretData" . | fromJson }}
|
||||||
|
{{- $secret := include "fluxer.secretName" . }}
|
||||||
|
{{- if $v.secrets.existingSecret }}
|
||||||
|
{{- if and $connected (not $data) }}
|
||||||
|
{{- fail (printf "secrets.existingSecret names the Secret %s, which does not exist in namespace %s. Create it first with every key listed under secrets.values" $secret .Release.Namespace) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $data }}
|
||||||
|
{{- $missing := list }}
|
||||||
|
{{- range $k := include "fluxer.requiredSecretKeys" . | fromJsonArray }}
|
||||||
|
{{- if not (get $data $k) }}
|
||||||
|
{{- $missing = append $missing $k }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with $missing }}
|
||||||
|
{{- fail (printf "Secret %s is missing these keys: %s" $secret (join ", " .)) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $config := include "fluxer.configData" . | fromYaml }}
|
||||||
|
{{- if $v.valkey.enabled }}
|
||||||
|
{{- $_ := set $config "FLUXER_KV_URL" "the bundled Valkey" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $shadowed := list }}
|
||||||
|
{{- range $k := keys $config | sortAlpha }}
|
||||||
|
{{- if and (hasKey $data $k) (ne (get $data $k) (get $config $k)) }}
|
||||||
|
{{- $shadowed = append $shadowed $k }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with $shadowed }}
|
||||||
|
{{- fail (printf "Secret %s holds settings the chart sets itself, and the two disagree: %s. Remove them from the Secret. To keep an outside service, turn the bundled one off, as the External services section of the Kubernetes page describes" $secret (join ", " .)) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $data }}
|
||||||
|
{{- range $k, $val := $data }}
|
||||||
|
{{- if regexMatch $placeholder $val }}
|
||||||
|
{{- fail (printf "%s in the Secret %s is a placeholder. Set a real value" $k $secret) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with get $data "FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64" }}
|
||||||
|
{{- if or (not (regexMatch "^[A-Za-z0-9+/]+={0,2}$" .)) (lt (len (b64dec .)) 32) }}
|
||||||
|
{{- fail "FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64 must be standard base64 of at least 32 bytes, for example the output of openssl rand -base64 32" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $long := list "FLUXER_SUDO_MODE_SECRET" "FLUXER_CONNECTION_INITIATION_SECRET" "FLUXER_PROFILE_PSEUDONYM_SECRET" "FLUXER_GATEWAY_RPC_AUTH_TOKEN" "FLUXER_ERLANG_COOKIE" "FLUXER_MEDIA_PROXY_SECRET_KEY" "FLUXER_ADMIN_SECRET_KEY_BASE" "FLUXER_ADMIN_OAUTH_CLIENT_SECRET" }}
|
||||||
|
{{- if ne (include "fluxer.livekitMode" .) "off" }}
|
||||||
|
{{- $long = append $long "FLUXER_LIVEKIT_API_SECRET" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $v.valkey.enabled }}
|
||||||
|
{{- $long = append $long "FLUXER_VALKEY_PASSWORD" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $v.nats.enabled }}
|
||||||
|
{{- $long = append $long "FLUXER_NATS_AUTH_TOKEN" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- range $k := $long }}
|
||||||
|
{{- if and (hasKey $data $k) (lt (len (get $data $k)) 32) }}
|
||||||
|
{{- fail (printf "%s must be at least 32 characters, for example the output of openssl rand -hex 32" $k) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and $v.meilisearch.enabled (hasKey $data "FLUXER_SEARCH_API_KEY") (lt (len (get $data "FLUXER_SEARCH_API_KEY")) 16) }}
|
||||||
|
{{- fail "FLUXER_SEARCH_API_KEY must be at least 16 characters, or the bundled Meilisearch refuses to start" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if eq (get $data "FLUXER_POSTGRES_PASSWORD" | default "") "fluxer" }}
|
||||||
|
{{- fail "FLUXER_POSTGRES_PASSWORD must not be fluxer, which the services refuse in production" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $plainOnly := list }}
|
||||||
|
{{- if $v.seaweedfs.enabled }}
|
||||||
|
{{- $plainOnly = concat $plainOnly (list "FLUXER_S3_ACCESS_KEY_ID" "FLUXER_S3_SECRET_ACCESS_KEY") }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $v.valkey.enabled }}
|
||||||
|
{{- $plainOnly = append $plainOnly "FLUXER_VALKEY_PASSWORD" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $v.nats.enabled }}
|
||||||
|
{{- $plainOnly = append $plainOnly "FLUXER_NATS_AUTH_TOKEN" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- range $k := $plainOnly }}
|
||||||
|
{{- if and (hasKey $data $k) (not (regexMatch "^[A-Za-z0-9]+$" (get $data $k))) }}
|
||||||
|
{{- fail (printf "%s must contain letters and digits only, because the bundled service takes it on a command line or in a URL" $k) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $pub := get $data "FLUXER_VAPID_PUBLIC_KEY" | default "" }}
|
||||||
|
{{- $priv := get $data "FLUXER_VAPID_PRIVATE_KEY" | default "" }}
|
||||||
|
{{- if or $pub $priv }}
|
||||||
|
{{- if or (not (regexMatch "^[A-Za-z0-9_-]{87}$" $pub)) (not (regexMatch "^[A-Za-z0-9_-]{43}$" $priv)) }}
|
||||||
|
{{- fail "FLUXER_VAPID_PUBLIC_KEY and FLUXER_VAPID_PRIVATE_KEY must be an unpadded base64url P-256 pair of 87 and 43 characters" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- if $connected }}
|
||||||
|
{{- if and (eq $v.edge.expose "ingress") (eq $v.edge.ingress.tls.mode "certManager") (not (.Capabilities.APIVersions.Has "cert-manager.io/v1")) }}
|
||||||
|
{{- fail "edge.ingress.tls.mode is certManager, but cert-manager is not installed. Install cert-manager, or set edge.ingress.tls.mode to existingSecret or none, or set edge.expose to loadBalancer so the edge obtains its own certificate" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and (eq $v.edge.expose "gateway") (not (.Capabilities.APIVersions.Has "gateway.networking.k8s.io/v1")) }}
|
||||||
|
{{- fail "edge.expose is gateway, but the Gateway API is not installed in the cluster" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $emptyClass := and (eq $v.edge.expose "loadBalancer") (not $v.edge.loadBalancer.persistence.storageClassName) }}
|
||||||
|
{{- range $c := list $v.postgres $v.valkey $v.nats $v.meilisearch $v.seaweedfs }}
|
||||||
|
{{- if and $c.enabled (not $c.persistence.storageClassName) }}
|
||||||
|
{{- $emptyClass = true }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if $emptyClass }}
|
||||||
|
{{- $default := false }}
|
||||||
|
{{- range (lookup "storage.k8s.io/v1" "StorageClass" "" "").items | default list }}
|
||||||
|
{{- if eq (get (.metadata.annotations | default dict) "storageclass.kubernetes.io/is-default-class") "true" }}
|
||||||
|
{{- $default = true }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if not $default }}
|
||||||
|
{{- fail "The cluster has no default StorageClass, so the volumes would never bind. Install a storage provisioner and mark its class as default, or set persistence.storageClassName on postgres, valkey, nats, meilisearch and seaweedfs" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if and (eq $v.edge.expose "ingress") (not $v.edge.ingress.className) }}
|
||||||
|
{{- $classes := (lookup "networking.k8s.io/v1" "IngressClass" "" "").items | default list }}
|
||||||
|
{{- if not $classes }}
|
||||||
|
{{- fail "The cluster has no IngressClass, so nothing would serve the Ingress. Install an ingress controller, or set edge.expose to loadBalancer, gateway or none. Set clusterChecks to false if your controller serves an Ingress without a class" }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $defaults := list }}
|
||||||
|
{{- range $classes }}
|
||||||
|
{{- if eq (get (.metadata.annotations | default dict) "ingressclass.kubernetes.io/is-default-class") "true" }}
|
||||||
|
{{- $defaults = append $defaults .metadata.name }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if not $defaults }}
|
||||||
|
{{- $names := list }}
|
||||||
|
{{- range $classes }}
|
||||||
|
{{- $names = append $names .metadata.name }}
|
||||||
|
{{- end }}
|
||||||
|
{{- fail (printf "The cluster has no default IngressClass. Set edge.ingress.className to one of: %s" (join ", " $names)) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if gt (len $defaults) 1 }}
|
||||||
|
{{- fail (printf "The cluster marks more than one IngressClass as default (%s), so the Ingress may land on the wrong controller. Set edge.ingress.className" (join ", " $defaults)) }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,188 @@
|
|||||||
|
{{- define "fluxer.replicas" -}}
|
||||||
|
{{- $w := .w | default dict }}
|
||||||
|
{{- if kindIs "invalid" $w.replicas }}1{{ else }}{{ $w.replicas | int }}{{ end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.appPod" -}}
|
||||||
|
{{- $root := .root }}
|
||||||
|
{{- $w := .w | default dict }}
|
||||||
|
{{- $readsSecret := and (not .noEnvFrom) (not .configMapOnly) }}
|
||||||
|
{{- $env := .env | default list }}
|
||||||
|
{{- if and $readsSecret $root.Values.valkey.enabled }}
|
||||||
|
{{- $env = prepend $env (dict "name" "FLUXER_KV_URL" "value" "redis://:$(FLUXER_VALKEY_PASSWORD)@valkey:6379/0") }}
|
||||||
|
{{- end }}
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.podLabels" . | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
checksum/instance: {{ include "fluxer.instanceChecksum" $root }}
|
||||||
|
{{- with $w.podAnnotations }}
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
automountServiceAccountToken: false
|
||||||
|
enableServiceLinks: false
|
||||||
|
{{- include "fluxer.pullSecrets" $root | nindent 2 }}
|
||||||
|
securityContext:
|
||||||
|
{{- include "fluxer.podSecurityContext" (dict) | nindent 4 }}
|
||||||
|
{{- include "fluxer.scheduling" . | nindent 2 }}
|
||||||
|
{{- with $w.terminationGracePeriodSeconds }}
|
||||||
|
terminationGracePeriodSeconds: {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- include "fluxer.waitFor" . | nindent 2 }}
|
||||||
|
containers:
|
||||||
|
- name: {{ .containerName | default .name }}
|
||||||
|
image: {{ include "fluxer.image" . }}
|
||||||
|
imagePullPolicy: {{ include "fluxer.pullPolicy" . }}
|
||||||
|
{{- with .command }}
|
||||||
|
command:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with include "fluxer.envList" (dict "w" $w "env" $env) }}
|
||||||
|
env:
|
||||||
|
{{- . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if not .noEnvFrom }}
|
||||||
|
envFrom:
|
||||||
|
{{- if .configMapOnly }}
|
||||||
|
- configMapRef:
|
||||||
|
name: {{ .configMapOnly }}
|
||||||
|
{{- else }}
|
||||||
|
- configMapRef:
|
||||||
|
name: fluxer-config
|
||||||
|
- secretRef:
|
||||||
|
name: {{ include "fluxer.secretName" $root }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: {{ .port }}
|
||||||
|
protocol: TCP
|
||||||
|
{{- range .extraPorts }}
|
||||||
|
- name: {{ .name }}
|
||||||
|
containerPort: {{ .port }}
|
||||||
|
protocol: TCP
|
||||||
|
{{- end }}
|
||||||
|
{{- with include "fluxer.probes" . | trim }}
|
||||||
|
{{- . | nindent 6 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with .lifecycle }}
|
||||||
|
lifecycle:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with $w.resources }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
securityContext:
|
||||||
|
{{- include "fluxer.containerSecurityContext" . | nindent 8 }}
|
||||||
|
{{- with concat (.volumeMounts | default list) ($w.extraVolumeMounts | default list) }}
|
||||||
|
volumeMounts:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with concat (.volumes | default list) ($w.extraVolumes | default list) }}
|
||||||
|
volumes:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.app" -}}
|
||||||
|
{{- $root := .root }}
|
||||||
|
{{- $w := .w | default dict }}
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: {{ .kind | default "Deployment" }}
|
||||||
|
metadata:
|
||||||
|
name: {{ .name }}
|
||||||
|
namespace: {{ $root.Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
{{- if not (and $w.hpa $w.hpa.maxReplicas) }}
|
||||||
|
replicas: {{ include "fluxer.replicas" . }}
|
||||||
|
{{- end }}
|
||||||
|
revisionHistoryLimit: 3
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "fluxer.selectorLabels" . | nindent 6 }}
|
||||||
|
{{- if eq (.kind | default "Deployment") "StatefulSet" }}
|
||||||
|
serviceName: {{ .serviceName }}
|
||||||
|
podManagementPolicy: Parallel
|
||||||
|
{{- else if .strategy }}
|
||||||
|
strategy:
|
||||||
|
{{- toYaml .strategy | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
template:
|
||||||
|
{{- include "fluxer.appPod" . | nindent 4 }}
|
||||||
|
{{- if not .noService }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: {{ .name }}
|
||||||
|
namespace: {{ $root.Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" . | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
{{- if .headless }}
|
||||||
|
clusterIP: None
|
||||||
|
publishNotReadyAddresses: true
|
||||||
|
{{- end }}
|
||||||
|
selector:
|
||||||
|
{{- include "fluxer.selectorLabels" . | nindent 4 }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: {{ .servicePort | default .port }}
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
{{- end }}
|
||||||
|
{{- with $w.pdb }}
|
||||||
|
{{- if or (not (kindIs "invalid" .minAvailable)) (not (kindIs "invalid" .maxUnavailable)) }}
|
||||||
|
---
|
||||||
|
apiVersion: policy/v1
|
||||||
|
kind: PodDisruptionBudget
|
||||||
|
metadata:
|
||||||
|
name: {{ $.name }}
|
||||||
|
namespace: {{ $root.Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
{{- if not (kindIs "invalid" .minAvailable) }}
|
||||||
|
minAvailable: {{ .minAvailable }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if not (kindIs "invalid" .maxUnavailable) }}
|
||||||
|
maxUnavailable: {{ .maxUnavailable }}
|
||||||
|
{{- end }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "fluxer.selectorLabels" $ | nindent 6 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- with $w.hpa }}
|
||||||
|
{{- if .maxReplicas }}
|
||||||
|
---
|
||||||
|
apiVersion: autoscaling/v2
|
||||||
|
kind: HorizontalPodAutoscaler
|
||||||
|
metadata:
|
||||||
|
name: {{ $.name }}
|
||||||
|
namespace: {{ $root.Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
scaleTargetRef:
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: {{ $.kind | default "Deployment" }}
|
||||||
|
name: {{ $.name }}
|
||||||
|
minReplicas: {{ .minReplicas | default 1 }}
|
||||||
|
maxReplicas: {{ .maxReplicas }}
|
||||||
|
metrics:
|
||||||
|
- type: Resource
|
||||||
|
resource:
|
||||||
|
name: cpu
|
||||||
|
target:
|
||||||
|
type: Utilization
|
||||||
|
averageUtilization: {{ .targetCPUUtilizationPercentage | default 80 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
{{- include "fluxer.validate" . }}
|
||||||
|
{{- $v := .Values }}
|
||||||
|
{{- $o := include "fluxer.origin" . }}
|
||||||
|
{{- $http := dict "port" "http" }}
|
||||||
|
{{- $start := dict "periodSeconds" 10 "timeoutSeconds" 5 "failureThreshold" 30 }}
|
||||||
|
{{- $check := dict "periodSeconds" 10 "timeoutSeconds" 5 "failureThreshold" 3 }}
|
||||||
|
{{- $health := merge (dict "path" "/_health") $http }}
|
||||||
|
{{- $healthProbes := dict "startup" (merge (dict "httpGet" $health) $start) "liveness" (merge (dict "httpGet" $health) $check) "readiness" (merge (dict "httpGet" $health) $check) }}
|
||||||
|
{{- $nodeEnv := list (dict "name" "NODE_ENV" "value" "production") (dict "name" "NODE_OPTIONS" "value" "--enable-source-maps") (dict "name" "NODE_EXTRA_CA_CERTS" "value" "/etc/ssl/certs/ca-certificates.crt") (dict "name" "FLUXER_POSTGRES_MAX_CONNECTIONS" "value" "25") }}
|
||||||
|
|
||||||
|
{{- include "fluxer.app" (dict "root" . "name" "api" "component" "api" "w" $v.api "image" "fluxer-api" "port" 8080
|
||||||
|
"env" (concat (list (dict "name" "FLUXER_API_PORT" "value" "8080") (dict "name" "FLUXER_API_PRESIGNED_ATTACHMENT_UPLOADS_ENABLED" "value" "true")) $nodeEnv)
|
||||||
|
"probes" $healthProbes
|
||||||
|
"waitFor" (include "fluxer.appWaitFor" (dict "root" . "usesNats" true "usesPostgres" true "usesS3" true "usesKv" true "usesSvc" true) | fromJsonArray)) }}
|
||||||
|
|
||||||
|
{{- $heartbeat := dict "exec" (dict "command" (list "node" "-e" "const age=Date.now()-require('node:fs').statSync('/tmp/fluxer-worker-heartbeat').mtimeMs;if(age>30000){console.error('worker heartbeat is '+Math.round(age)+'ms old');process.exit(1)}")) "initialDelaySeconds" 90 "periodSeconds" 10 "timeoutSeconds" 5 "failureThreshold" 3 }}
|
||||||
|
{{- include "fluxer.app" (dict "root" . "name" "worker" "component" "worker" "w" $v.worker "image" "fluxer-api" "port" 8080 "noService" true
|
||||||
|
"command" (list "node" "dist/WorkerEntrypoint.js")
|
||||||
|
"env" (concat (list (dict "name" "FLUXER_API_WORKER_MODE" "value" "all_lanes") (dict "name" "FLUXER_API_WORKER_ENABLE_CRON_SCHEDULER" "value" "true")) $nodeEnv)
|
||||||
|
"probes" (dict "liveness" $heartbeat)
|
||||||
|
"strategy" (dict "type" "Recreate")
|
||||||
|
"waitFor" (include "fluxer.appWaitFor" (dict "root" . "usesNats" true "usesPostgres" true "usesS3" true "usesKv" true "usesSvc" true) | fromJsonArray)) }}
|
||||||
|
|
||||||
|
{{- $gatewayEnv := list
|
||||||
|
(dict "name" "FLUXER_GATEWAY_PORT" "value" "8080")
|
||||||
|
(dict "name" "FLUXER_GATEWAY_ROLE" "value" "all")
|
||||||
|
(dict "name" "POD_IP" "valueFrom" (dict "fieldRef" (dict "apiVersion" "v1" "fieldPath" "status.podIP")))
|
||||||
|
(dict "name" "FLUXER_ERLANG_NODE_NAME" "value" "fluxer_gateway@$(POD_IP)")
|
||||||
|
(dict "name" "FLUXER_ERLANG_DIST_PORT" "value" "8081")
|
||||||
|
(dict "name" "FLUXER_GATEWAY_CLUSTER_ENABLED" "value" "true")
|
||||||
|
(dict "name" "FLUXER_GATEWAY_CLUSTER_DISCOVERY_DNS_NAME" "value" (printf "gateway-headless.%s.svc.%s" .Release.Namespace $v.clusterDomain))
|
||||||
|
(dict "name" "FLUXER_GATEWAY_CLUSTER_DISCOVERY_NODE_BASENAME" "value" "fluxer_gateway") }}
|
||||||
|
{{- $gatewayReady := dict "exec" (dict "command" (list "curl" "-fsS" "-o" "/dev/null" "--max-time" "4" "http://127.0.0.1:8080/_health/ready")) "periodSeconds" 10 "timeoutSeconds" 5 "failureThreshold" 3 }}
|
||||||
|
{{- $gatewayCtx := dict "root" . "name" "gateway" "component" "gateway" "w" $v.gateway "image" "fluxer-gateway" "port" 8080
|
||||||
|
"extraPorts" (list (dict "name" "epmd" "port" 4369) (dict "name" "erl-dist" "port" 8081))
|
||||||
|
"env" $gatewayEnv
|
||||||
|
"probes" (dict "startup" (merge (dict "httpGet" $health) $start) "liveness" (merge (dict "httpGet" $health) $check) "readiness" $gatewayReady)
|
||||||
|
"waitFor" (include "fluxer.appWaitFor" (dict "root" . "usesNats" true) | fromJsonArray)
|
||||||
|
"lifecycle" (dict "preStop" (dict "exec" (dict "command" (list "/bin/sh" "-c" "curl -fsS -o /dev/null --max-time 2 http://127.0.0.1:8080/_health/drain; sleep 5")))) }}
|
||||||
|
{{- include "fluxer.app" $gatewayCtx }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: gateway-headless
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $gatewayCtx | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
clusterIP: None
|
||||||
|
publishNotReadyAddresses: true
|
||||||
|
selector:
|
||||||
|
{{- include "fluxer.selectorLabels" $gatewayCtx | nindent 4 }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 8080
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
- name: epmd
|
||||||
|
port: 4369
|
||||||
|
targetPort: epmd
|
||||||
|
protocol: TCP
|
||||||
|
- name: erl-dist
|
||||||
|
port: 8081
|
||||||
|
targetPort: erl-dist
|
||||||
|
protocol: TCP
|
||||||
|
|
||||||
|
{{- include "fluxer.app" (dict "root" . "name" "media-proxy" "component" "media" "w" $v.mediaProxy "image" "fluxer-media-proxy" "port" 8080
|
||||||
|
"env" (list (dict "name" "FLUXER_MEDIA_PROXY_PORT" "value" "8080") (dict "name" "FLUXER_MEDIA_PROXY_MODE" "value" "upload") (dict "name" "FLUXER_MEDIA_PROXY_STORAGE_BACKEND" "value" "s3") (dict "name" "FLUXER_S3_READ_SIGNED" "value" "true"))
|
||||||
|
"probes" $healthProbes
|
||||||
|
"waitFor" (include "fluxer.appWaitFor" (dict "root" . "usesNats" true "usesS3" true) | fromJsonArray)) }}
|
||||||
|
|
||||||
|
{{- $pushCheck := dict "exec" (dict "command" (list "/usr/local/bin/fluxer-push" "healthcheck")) }}
|
||||||
|
{{- include "fluxer.app" (dict "root" . "name" "push" "component" "push" "w" $v.push "image" "fluxer-push" "port" 8126
|
||||||
|
"env" (list (dict "name" "FLUXER_PUSH_SERVICE_PORT" "value" "8126"))
|
||||||
|
"waitFor" (include "fluxer.appWaitFor" (dict "root" . "usesNats" true) | fromJsonArray)
|
||||||
|
"probes" (dict "startup" (merge (deepCopy $pushCheck) (dict "periodSeconds" 10 "timeoutSeconds" 5 "failureThreshold" 12)) "liveness" (merge (deepCopy $pushCheck) $check) "readiness" (merge (deepCopy $pushCheck) $check))) }}
|
||||||
|
|
||||||
|
{{- include "fluxer.app" (dict "root" . "name" "admin" "component" "admin" "w" $v.admin "image" "fluxer-admin" "port" 8080
|
||||||
|
"env" (list (dict "name" "FLUXER_ADMIN_PORT" "value" "8080") (dict "name" "FLUXER_ADMIN_BASE_PATH" "value" $v.adminBasePath) (dict "name" "FLUXER_API_ENDPOINT" "value" "http://api:8080") (dict "name" "FLUXER_STATIC_CDN_ENDPOINT" "value" $o))
|
||||||
|
"probes" $healthProbes) }}
|
||||||
|
|
||||||
|
{{- $ready := merge (dict "path" "/_ready") $http }}
|
||||||
|
{{- include "fluxer.app" (dict "root" . "name" "app-proxy" "component" "web" "w" $v.appProxy "image" "fluxer-app-proxy-self-hosted" "port" 8080 "configMapOnly" "fluxer-app-proxy"
|
||||||
|
"probes" (dict "startup" (merge (dict "httpGet" $health) $start) "liveness" (merge (dict "httpGet" $health) $check) "readiness" (merge (dict "httpGet" $ready) $check))) }}
|
||||||
|
|
||||||
|
{{- $avatar := merge (dict "path" "/avatars/0.png") $http }}
|
||||||
|
{{- include "fluxer.app" (dict "root" . "name" "static-proxy" "component" "web" "w" $v.staticProxy "image" "fluxer-static" "port" 8080 "noEnvFrom" true
|
||||||
|
"probes" (dict "startup" (merge (dict "httpGet" $avatar) $start) "liveness" (merge (dict "httpGet" $avatar) $check) "readiness" (merge (dict "httpGet" $avatar) $check))) }}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{{- include "fluxer.validate" . }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: fluxer-config
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" (dict "root" . "name" "fluxer-config" "component" "config") | nindent 4 }}
|
||||||
|
data:
|
||||||
|
{{- include "fluxer.configData" . | nindent 2 }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: fluxer-app-proxy
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" (dict "root" . "name" "fluxer-app-proxy" "component" "config") | nindent 4 }}
|
||||||
|
data:
|
||||||
|
{{- include "fluxer.appProxyConfigData" . | nindent 2 }}
|
||||||
@@ -0,0 +1,296 @@
|
|||||||
|
{{- include "fluxer.validate" . }}
|
||||||
|
{{- $v := .Values }}
|
||||||
|
{{- $e := $v.edge }}
|
||||||
|
{{- $ctx := dict "root" . "name" "edge" "component" "edge" "w" $e }}
|
||||||
|
{{- $lb := eq $e.expose "loadBalancer" }}
|
||||||
|
{{- $caddyfile := .Files.Get "files/Caddyfile" }}
|
||||||
|
{{- $globalOptions := ternary (printf "email %s" $v.email) "" (and $lb (ne $v.email "")) }}
|
||||||
|
{{- $siteAddress := ternary (printf "https://%s, :8080" $v.domain) ":8080" $lb }}
|
||||||
|
{{- $trusted := ternary "127.0.0.1/32" "private_ranges" $lb }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: edge-caddyfile
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
data:
|
||||||
|
Caddyfile: {{ $caddyfile | quote }}
|
||||||
|
{{- if $lb }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: PersistentVolumeClaim
|
||||||
|
metadata:
|
||||||
|
name: edge-data
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
helm.sh/resource-policy: keep
|
||||||
|
spec:
|
||||||
|
accessModes:
|
||||||
|
- ReadWriteOnce
|
||||||
|
{{- with $e.loadBalancer.persistence.storageClassName }}
|
||||||
|
storageClassName: {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: {{ $e.loadBalancer.persistence.size }}
|
||||||
|
{{- end }}
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: edge
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ ternary 1 ($e.replicas | int) $lb }}
|
||||||
|
revisionHistoryLimit: 3
|
||||||
|
{{- if $lb }}
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
{{- end }}
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "fluxer.selectorLabels" $ctx | nindent 6 }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.podLabels" $ctx | nindent 8 }}
|
||||||
|
annotations:
|
||||||
|
checksum/config: {{ printf "%s\n%s\n%s\n%s" $caddyfile $siteAddress $globalOptions (toJson (list $e.env $e.extraEnv)) | sha256sum }}
|
||||||
|
{{- with $e.podAnnotations }}
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
automountServiceAccountToken: false
|
||||||
|
enableServiceLinks: false
|
||||||
|
{{- include "fluxer.pullSecrets" . | nindent 6 }}
|
||||||
|
securityContext:
|
||||||
|
{{- include "fluxer.podSecurityContext" (dict "uid" 65532) | nindent 8 }}
|
||||||
|
{{- if $lb }}
|
||||||
|
sysctls:
|
||||||
|
- name: net.ipv4.ip_unprivileged_port_start
|
||||||
|
value: "0"
|
||||||
|
{{- end }}
|
||||||
|
{{- include "fluxer.scheduling" $ctx | nindent 6 }}
|
||||||
|
containers:
|
||||||
|
- name: edge
|
||||||
|
image: {{ include "fluxer.thirdPartyImage" $e.image }}
|
||||||
|
imagePullPolicy: {{ $e.image.pullPolicy }}
|
||||||
|
{{- $edgeEnv := list (dict "name" "FLUXER_EDGE_SITE_ADDRESS" "value" $siteAddress) (dict "name" "FLUXER_EDGE_TRUSTED_PROXIES" "value" $trusted) (dict "name" "FLUXER_EDGE_GLOBAL_OPTIONS" "value" $globalOptions) (dict "name" "FLUXER_ADMIN_BASE_PATH" "value" $v.adminBasePath) }}
|
||||||
|
env:
|
||||||
|
{{- include "fluxer.envList" (dict "w" $e "env" $edgeEnv) | nindent 12 }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 8080
|
||||||
|
protocol: TCP
|
||||||
|
{{- if $lb }}
|
||||||
|
- name: public-http
|
||||||
|
containerPort: 80
|
||||||
|
protocol: TCP
|
||||||
|
- name: public-https
|
||||||
|
containerPort: 443
|
||||||
|
protocol: TCP
|
||||||
|
- name: public-quic
|
||||||
|
containerPort: 443
|
||||||
|
protocol: UDP
|
||||||
|
{{- end }}
|
||||||
|
startupProbe:
|
||||||
|
exec:
|
||||||
|
command: ["wget", "-q", "-O", "/dev/null", "http://127.0.0.1:2019/config/"]
|
||||||
|
periodSeconds: 5
|
||||||
|
failureThreshold: 24
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["wget", "-q", "-O", "/dev/null", "http://127.0.0.1:2019/config/"]
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 6
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["wget", "-q", "-O", "/dev/null", "http://127.0.0.1:2019/config/"]
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
{{- with $e.resources }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
securityContext:
|
||||||
|
allowPrivilegeEscalation: false
|
||||||
|
readOnlyRootFilesystem: true
|
||||||
|
capabilities:
|
||||||
|
drop:
|
||||||
|
- ALL
|
||||||
|
add:
|
||||||
|
- NET_BIND_SERVICE
|
||||||
|
volumeMounts:
|
||||||
|
- name: caddyfile
|
||||||
|
mountPath: /etc/caddy
|
||||||
|
readOnly: true
|
||||||
|
- name: config
|
||||||
|
mountPath: /config
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
volumes:
|
||||||
|
- name: caddyfile
|
||||||
|
configMap:
|
||||||
|
name: edge-caddyfile
|
||||||
|
- name: config
|
||||||
|
emptyDir: {}
|
||||||
|
- name: data
|
||||||
|
{{- if $lb }}
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: edge-data
|
||||||
|
{{- else }}
|
||||||
|
emptyDir: {}
|
||||||
|
{{- end }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: edge
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
{{- include "fluxer.selectorLabels" $ctx | nindent 4 }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 8080
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
{{- if $lb }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: edge-public
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
{{- with $e.loadBalancer.annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
type: LoadBalancer
|
||||||
|
externalTrafficPolicy: Local
|
||||||
|
selector:
|
||||||
|
{{- include "fluxer.selectorLabels" $ctx | nindent 4 }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 80
|
||||||
|
targetPort: public-http
|
||||||
|
protocol: TCP
|
||||||
|
- name: https
|
||||||
|
port: 443
|
||||||
|
targetPort: public-https
|
||||||
|
protocol: TCP
|
||||||
|
{{- if $e.loadBalancer.http3 }}
|
||||||
|
- name: quic
|
||||||
|
port: 443
|
||||||
|
targetPort: public-quic
|
||||||
|
protocol: UDP
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if eq $e.expose "ingress" }}
|
||||||
|
{{- $tls := $e.ingress.tls }}
|
||||||
|
{{- $annotations := dict
|
||||||
|
"nginx.ingress.kubernetes.io/proxy-body-size" "512m"
|
||||||
|
"nginx.ingress.kubernetes.io/proxy-read-timeout" "3600"
|
||||||
|
"nginx.ingress.kubernetes.io/proxy-send-timeout" "3600" }}
|
||||||
|
{{- if eq $tls.mode "certManager" }}
|
||||||
|
{{- $_ := set $annotations "cert-manager.io/issuer" "fluxer-acme" }}
|
||||||
|
---
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: Issuer
|
||||||
|
metadata:
|
||||||
|
name: fluxer-acme
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
acme:
|
||||||
|
server: {{ $tls.acmeServer }}
|
||||||
|
{{- with $v.email }}
|
||||||
|
email: {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
privateKeySecretRef:
|
||||||
|
name: fluxer-acme-account
|
||||||
|
solvers:
|
||||||
|
- http01:
|
||||||
|
{{- with $e.ingress.className }}
|
||||||
|
ingress:
|
||||||
|
ingressClassName: {{ . }}
|
||||||
|
{{- else }}
|
||||||
|
ingress: {}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $annotations = merge (deepCopy ($e.ingress.annotations | default dict)) $annotations }}
|
||||||
|
---
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: fluxer
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
{{- with $annotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
{{- with $e.ingress.className }}
|
||||||
|
ingressClassName: {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if ne $tls.mode "none" }}
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- {{ $v.domain }}
|
||||||
|
secretName: {{ $tls.secretName }}
|
||||||
|
{{- end }}
|
||||||
|
rules:
|
||||||
|
- host: {{ $v.domain }}
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: edge
|
||||||
|
port:
|
||||||
|
name: http
|
||||||
|
{{- end }}
|
||||||
|
{{- if eq $e.expose "gateway" }}
|
||||||
|
---
|
||||||
|
apiVersion: gateway.networking.k8s.io/v1
|
||||||
|
kind: HTTPRoute
|
||||||
|
metadata:
|
||||||
|
name: fluxer
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
parentRefs:
|
||||||
|
{{- toYaml $e.gateway.parentRefs | nindent 4 }}
|
||||||
|
hostnames:
|
||||||
|
- {{ $v.domain }}
|
||||||
|
rules:
|
||||||
|
- matches:
|
||||||
|
- path:
|
||||||
|
type: PathPrefix
|
||||||
|
value: /
|
||||||
|
backendRefs:
|
||||||
|
- name: edge
|
||||||
|
port: 8080
|
||||||
|
{{- with $e.gateway.timeouts }}
|
||||||
|
timeouts:
|
||||||
|
{{- toYaml . | nindent 8 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
{{- include "fluxer.validate" . }}
|
||||||
|
{{- with .Values.livekit }}
|
||||||
|
{{- if .enabled }}
|
||||||
|
{{- $ctx := dict "root" $ "name" "livekit" "component" "voice" "w" . }}
|
||||||
|
{{- $tcp := .tcpPort | int }}
|
||||||
|
{{- $udp := .udpPort | int }}
|
||||||
|
{{- if eq .expose "nodePort" }}
|
||||||
|
{{- $tcp = .nodePorts.tcp | int }}
|
||||||
|
{{- $udp = .nodePorts.udp | int }}
|
||||||
|
{{- end }}
|
||||||
|
{{- $useExternal := and .useExternalIP (ne .expose "loadBalancer") }}
|
||||||
|
{{- $secrets := include "fluxer.secretData" $ | fromJson }}
|
||||||
|
{{- $config := dict
|
||||||
|
"port" 7880
|
||||||
|
"log_level" .logLevel
|
||||||
|
"rtc" (dict "tcp_port" $tcp "udp_port" $udp "use_external_ip" $useExternal "node_ip" (.nodeIP | default "") "stun_servers" .stunServers) }}
|
||||||
|
{{- $config = mergeOverwrite $config (deepCopy (.extraConfig | default dict)) }}
|
||||||
|
{{- $configYaml := toYaml $config }}
|
||||||
|
{{- $root := dict "path" "/" "port" "http" }}
|
||||||
|
{{- $webhook := ternary "http://edge:8080/api/webhooks/livekit" "http://api:8080/webhooks/livekit" (eq .expose "hostNetwork") }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: livekit
|
||||||
|
namespace: {{ $.Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
{{- include "fluxer.selectorLabels" $ctx | nindent 4 }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 7880
|
||||||
|
targetPort: 7880
|
||||||
|
protocol: TCP
|
||||||
|
{{- if ne .expose "hostNetwork" }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: livekit-rtc
|
||||||
|
namespace: {{ $.Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
{{- with .serviceAnnotations }}
|
||||||
|
annotations:
|
||||||
|
{{- toYaml . | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
spec:
|
||||||
|
type: {{ ternary "LoadBalancer" "NodePort" (eq .expose "loadBalancer") }}
|
||||||
|
externalTrafficPolicy: Local
|
||||||
|
{{- if and (eq .expose "loadBalancer") .loadBalancerIP }}
|
||||||
|
loadBalancerIP: {{ .loadBalancerIP }}
|
||||||
|
{{- end }}
|
||||||
|
selector:
|
||||||
|
{{- include "fluxer.selectorLabels" $ctx | nindent 4 }}
|
||||||
|
ports:
|
||||||
|
- name: rtc-tcp
|
||||||
|
port: {{ $tcp }}
|
||||||
|
targetPort: rtc-tcp
|
||||||
|
protocol: TCP
|
||||||
|
{{- if eq .expose "nodePort" }}
|
||||||
|
nodePort: {{ $tcp }}
|
||||||
|
{{- end }}
|
||||||
|
- name: rtc-udp
|
||||||
|
port: {{ $udp }}
|
||||||
|
targetPort: rtc-udp
|
||||||
|
protocol: UDP
|
||||||
|
{{- if eq .expose "nodePort" }}
|
||||||
|
nodePort: {{ $udp }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: livekit
|
||||||
|
namespace: {{ $.Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
revisionHistoryLimit: 3
|
||||||
|
strategy:
|
||||||
|
type: Recreate
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "fluxer.selectorLabels" $ctx | nindent 6 }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.podLabels" $ctx | nindent 8 }}
|
||||||
|
annotations:
|
||||||
|
checksum/config: {{ list $configYaml $webhook (get $secrets "FLUXER_LIVEKIT_API_KEY" | default "") (get $secrets "FLUXER_LIVEKIT_API_SECRET" | default "") | toJson | sha256sum }}
|
||||||
|
spec:
|
||||||
|
automountServiceAccountToken: false
|
||||||
|
enableServiceLinks: false
|
||||||
|
{{- if eq .expose "hostNetwork" }}
|
||||||
|
hostNetwork: true
|
||||||
|
dnsPolicy: ClusterFirstWithHostNet
|
||||||
|
{{- end }}
|
||||||
|
{{- include "fluxer.pullSecrets" $ | nindent 6 }}
|
||||||
|
securityContext:
|
||||||
|
{{- include "fluxer.podSecurityContext" (dict "uid" 65532) | nindent 8 }}
|
||||||
|
{{- include "fluxer.scheduling" $ctx | nindent 6 }}
|
||||||
|
containers:
|
||||||
|
- name: livekit
|
||||||
|
image: {{ include "fluxer.thirdPartyImage" .image }}
|
||||||
|
imagePullPolicy: {{ .image.pullPolicy }}
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
export LIVEKIT_KEYS="${LIVEKIT_API_KEY}: ${LIVEKIT_API_SECRET}"
|
||||||
|
export LIVEKIT_CONFIG="$(printf '%s\nwebhook:\n api_key: %s\n urls:\n - %s\n' "$LIVEKIT_CONFIG" "$LIVEKIT_API_KEY" "$LIVEKIT_WEBHOOK_URL")"
|
||||||
|
exec /livekit-server
|
||||||
|
env:
|
||||||
|
- name: LIVEKIT_CONFIG
|
||||||
|
value: {{ $configYaml | quote }}
|
||||||
|
- name: LIVEKIT_WEBHOOK_URL
|
||||||
|
value: {{ $webhook }}
|
||||||
|
{{- include "fluxer.secretEnv" (dict "root" $ "name" "LIVEKIT_API_KEY" "key" "FLUXER_LIVEKIT_API_KEY") | nindent 12 }}
|
||||||
|
{{- include "fluxer.secretEnv" (dict "root" $ "name" "LIVEKIT_API_SECRET" "key" "FLUXER_LIVEKIT_API_SECRET") | nindent 12 }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 7880
|
||||||
|
protocol: TCP
|
||||||
|
- name: rtc-tcp
|
||||||
|
containerPort: {{ $tcp }}
|
||||||
|
protocol: TCP
|
||||||
|
- name: rtc-udp
|
||||||
|
containerPort: {{ $udp }}
|
||||||
|
protocol: UDP
|
||||||
|
startupProbe:
|
||||||
|
httpGet: {{ toJson $root }}
|
||||||
|
periodSeconds: 5
|
||||||
|
failureThreshold: 60
|
||||||
|
livenessProbe:
|
||||||
|
httpGet: {{ toJson $root }}
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 6
|
||||||
|
readinessProbe:
|
||||||
|
httpGet: {{ toJson $root }}
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
{{- with .resources }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
securityContext:
|
||||||
|
{{- include "fluxer.containerSecurityContext" . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
{{- include "fluxer.validate" . }}
|
||||||
|
{{- with .Values.meilisearch }}
|
||||||
|
{{- if .enabled }}
|
||||||
|
{{- $ctx := dict "root" $ "name" "meilisearch" "component" "search" "w" . }}
|
||||||
|
{{- $health := dict "path" "/health" "port" "http" }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: meilisearch
|
||||||
|
namespace: {{ $.Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
{{- include "fluxer.selectorLabels" $ctx | nindent 4 }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
port: 7700
|
||||||
|
targetPort: http
|
||||||
|
protocol: TCP
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: meilisearch
|
||||||
|
namespace: {{ $.Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
serviceName: meilisearch
|
||||||
|
podManagementPolicy: Parallel
|
||||||
|
persistentVolumeClaimRetentionPolicy:
|
||||||
|
whenDeleted: Retain
|
||||||
|
whenScaled: Retain
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "fluxer.selectorLabels" $ctx | nindent 6 }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.podLabels" $ctx | nindent 8 }}
|
||||||
|
spec:
|
||||||
|
automountServiceAccountToken: false
|
||||||
|
enableServiceLinks: false
|
||||||
|
{{- include "fluxer.pullSecrets" $ | nindent 6 }}
|
||||||
|
securityContext:
|
||||||
|
{{- include "fluxer.podSecurityContext" (dict "uid" 65532) | nindent 8 }}
|
||||||
|
{{- include "fluxer.scheduling" $ctx | nindent 6 }}
|
||||||
|
containers:
|
||||||
|
- name: meilisearch
|
||||||
|
image: {{ include "fluxer.thirdPartyImage" .image }}
|
||||||
|
imagePullPolicy: {{ .image.pullPolicy }}
|
||||||
|
env:
|
||||||
|
- name: MEILI_ENV
|
||||||
|
value: production
|
||||||
|
- name: MEILI_NO_ANALYTICS
|
||||||
|
value: "true"
|
||||||
|
- name: MEILI_UPGRADE_DB
|
||||||
|
value: "true"
|
||||||
|
- name: MEILI_MAX_INDEXING_MEMORY
|
||||||
|
value: {{ .maxIndexingMemory | quote }}
|
||||||
|
- name: MEILI_MAX_INDEXING_THREADS
|
||||||
|
value: {{ include "fluxer.string" .maxIndexingThreads | quote }}
|
||||||
|
{{- include "fluxer.secretEnv" (dict "root" $ "name" "MEILI_MASTER_KEY" "key" "FLUXER_SEARCH_API_KEY") | nindent 12 }}
|
||||||
|
ports:
|
||||||
|
- name: http
|
||||||
|
containerPort: 7700
|
||||||
|
protocol: TCP
|
||||||
|
startupProbe:
|
||||||
|
httpGet: {{ toJson $health }}
|
||||||
|
periodSeconds: 5
|
||||||
|
failureThreshold: 120
|
||||||
|
livenessProbe:
|
||||||
|
httpGet: {{ toJson $health }}
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 6
|
||||||
|
readinessProbe:
|
||||||
|
httpGet: {{ toJson $health }}
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
{{- with .resources }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
securityContext:
|
||||||
|
{{- include "fluxer.containerSecurityContext" . | nindent 12 }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /meili_data
|
||||||
|
volumeClaimTemplates:
|
||||||
|
{{- include "fluxer.pvc" .persistence | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
{{- include "fluxer.validate" . }}
|
||||||
|
{{- with .Values.nats }}
|
||||||
|
{{- if .enabled }}
|
||||||
|
{{- $ctx := dict "root" $ "name" "nats" "component" "messaging" "w" . }}
|
||||||
|
{{- $replicas := .replicas | int }}
|
||||||
|
{{- $conf := include "fluxer.natsConf" (dict "root" $ "replicas" $replicas) }}
|
||||||
|
{{- $secrets := include "fluxer.secretData" $ | fromJson }}
|
||||||
|
{{- $healthz := dict "exec" (dict "command" (list "wget" "-q" "-O" "/dev/null" "http://127.0.0.1:8222/healthz")) }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: nats-config
|
||||||
|
namespace: {{ $.Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
data:
|
||||||
|
nats.conf: {{ $conf | quote }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: nats
|
||||||
|
namespace: {{ $.Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
{{- include "fluxer.selectorLabels" $ctx | nindent 4 }}
|
||||||
|
ports:
|
||||||
|
- name: client
|
||||||
|
port: 4222
|
||||||
|
targetPort: client
|
||||||
|
protocol: TCP
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: nats-headless
|
||||||
|
namespace: {{ $.Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
clusterIP: None
|
||||||
|
publishNotReadyAddresses: true
|
||||||
|
selector:
|
||||||
|
{{- include "fluxer.selectorLabels" $ctx | nindent 4 }}
|
||||||
|
ports:
|
||||||
|
- name: client
|
||||||
|
port: 4222
|
||||||
|
targetPort: client
|
||||||
|
protocol: TCP
|
||||||
|
- name: cluster
|
||||||
|
port: 6222
|
||||||
|
targetPort: cluster
|
||||||
|
protocol: TCP
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: nats
|
||||||
|
namespace: {{ $.Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
replicas: {{ $replicas }}
|
||||||
|
serviceName: nats-headless
|
||||||
|
podManagementPolicy: Parallel
|
||||||
|
persistentVolumeClaimRetentionPolicy:
|
||||||
|
whenDeleted: Retain
|
||||||
|
whenScaled: Retain
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "fluxer.selectorLabels" $ctx | nindent 6 }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.podLabels" $ctx | nindent 8 }}
|
||||||
|
annotations:
|
||||||
|
checksum/config: {{ printf "%s\n%s" $conf (get $secrets "FLUXER_NATS_AUTH_TOKEN" | default "") | sha256sum }}
|
||||||
|
spec:
|
||||||
|
automountServiceAccountToken: false
|
||||||
|
enableServiceLinks: false
|
||||||
|
{{- include "fluxer.pullSecrets" $ | nindent 6 }}
|
||||||
|
securityContext:
|
||||||
|
{{- include "fluxer.podSecurityContext" (dict "uid" 65534) | nindent 8 }}
|
||||||
|
{{- include "fluxer.scheduling" $ctx | nindent 6 }}
|
||||||
|
containers:
|
||||||
|
- name: nats
|
||||||
|
image: {{ include "fluxer.thirdPartyImage" .image }}
|
||||||
|
imagePullPolicy: {{ .image.pullPolicy }}
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- sed "s/__FLUXER_NATS_AUTH_TOKEN__/$FLUXER_NATS_AUTH_TOKEN/g" /etc/nats/nats.conf > /run/nats/nats.conf && exec nats-server --config /run/nats/nats.conf
|
||||||
|
env:
|
||||||
|
- name: POD_NAME
|
||||||
|
valueFrom:
|
||||||
|
fieldRef:
|
||||||
|
apiVersion: v1
|
||||||
|
fieldPath: metadata.name
|
||||||
|
{{- include "fluxer.secretEnv" (dict "root" $ "name" "FLUXER_NATS_AUTH_TOKEN" "key" "FLUXER_NATS_AUTH_TOKEN") | nindent 12 }}
|
||||||
|
ports:
|
||||||
|
- name: client
|
||||||
|
containerPort: 4222
|
||||||
|
protocol: TCP
|
||||||
|
- name: cluster
|
||||||
|
containerPort: 6222
|
||||||
|
protocol: TCP
|
||||||
|
startupProbe:
|
||||||
|
{{- toYaml (merge (dict "periodSeconds" 5 "timeoutSeconds" 5 "failureThreshold" 60) $healthz) | nindent 12 }}
|
||||||
|
livenessProbe:
|
||||||
|
{{- toYaml (merge (dict "periodSeconds" 10 "timeoutSeconds" 5 "failureThreshold" 6) $healthz) | nindent 12 }}
|
||||||
|
readinessProbe:
|
||||||
|
{{- toYaml (merge (dict "periodSeconds" 10 "timeoutSeconds" 5) $healthz) | nindent 12 }}
|
||||||
|
{{- with .resources }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
securityContext:
|
||||||
|
{{- include "fluxer.containerSecurityContext" . | nindent 12 }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: config
|
||||||
|
mountPath: /etc/nats
|
||||||
|
readOnly: true
|
||||||
|
- name: rendered
|
||||||
|
mountPath: /run/nats
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
volumes:
|
||||||
|
- name: config
|
||||||
|
configMap:
|
||||||
|
name: nats-config
|
||||||
|
- name: rendered
|
||||||
|
emptyDir:
|
||||||
|
medium: Memory
|
||||||
|
volumeClaimTemplates:
|
||||||
|
{{- include "fluxer.pvc" .persistence | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{- define "fluxer.natsConf" -}}
|
||||||
|
server_name: $POD_NAME
|
||||||
|
listen: 0.0.0.0:4222
|
||||||
|
http: 127.0.0.1:8222
|
||||||
|
authorization {
|
||||||
|
token: "__FLUXER_NATS_AUTH_TOKEN__"
|
||||||
|
}
|
||||||
|
jetstream {
|
||||||
|
store_dir: /data
|
||||||
|
}
|
||||||
|
{{- if gt .replicas 1 }}
|
||||||
|
cluster {
|
||||||
|
name: fluxer
|
||||||
|
listen: 0.0.0.0:6222
|
||||||
|
authorization {
|
||||||
|
user: fluxer
|
||||||
|
password: "__FLUXER_NATS_AUTH_TOKEN__"
|
||||||
|
}
|
||||||
|
routes: [
|
||||||
|
{{- range $i := until .replicas }}
|
||||||
|
nats://fluxer:__FLUXER_NATS_AUTH_TOKEN__@nats-{{ $i }}.nats-headless.{{ $.root.Release.Namespace }}.svc.{{ $.root.Values.clusterDomain }}:6222
|
||||||
|
{{- end }}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
{{- include "fluxer.validate" . }}
|
||||||
|
{{- if .Values.networkPolicy.enabled }}
|
||||||
|
{{- $v := .Values }}
|
||||||
|
{{- $release := dict "app.kubernetes.io/instance" .Release.Name }}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: fluxer
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" (dict "root" . "name" "fluxer" "component" "network") | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
{{- toYaml $release | nindent 6 }}
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
ingress:
|
||||||
|
- from:
|
||||||
|
- podSelector:
|
||||||
|
matchLabels:
|
||||||
|
{{- toYaml $release | nindent 14 }}
|
||||||
|
---
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: fluxer-edge
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" (dict "root" . "name" "fluxer-edge" "component" "network") | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "fluxer.selectorLabels" (dict "root" . "name" "edge") | nindent 6 }}
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
ingress:
|
||||||
|
- ports:
|
||||||
|
- port: 8080
|
||||||
|
protocol: TCP
|
||||||
|
{{- with $v.networkPolicy.ingressNamespaceSelector }}
|
||||||
|
from:
|
||||||
|
- namespaceSelector:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- if and $v.livekit.enabled (eq $v.livekit.expose "hostNetwork") }}
|
||||||
|
{{- range $v.livekit.nodeCIDRs }}
|
||||||
|
- ipBlock:
|
||||||
|
cidr: {{ . }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if eq $v.edge.expose "loadBalancer" }}
|
||||||
|
- ports:
|
||||||
|
- port: 80
|
||||||
|
protocol: TCP
|
||||||
|
- port: 443
|
||||||
|
protocol: TCP
|
||||||
|
- port: 443
|
||||||
|
protocol: UDP
|
||||||
|
{{- end }}
|
||||||
|
{{- if and $v.livekit.enabled (ne $v.livekit.expose "hostNetwork") }}
|
||||||
|
---
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: NetworkPolicy
|
||||||
|
metadata:
|
||||||
|
name: fluxer-livekit
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" (dict "root" . "name" "fluxer-livekit" "component" "network") | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
podSelector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "fluxer.selectorLabels" (dict "root" . "name" "livekit") | nindent 6 }}
|
||||||
|
policyTypes:
|
||||||
|
- Ingress
|
||||||
|
ingress:
|
||||||
|
- ports:
|
||||||
|
- port: {{ ternary $v.livekit.nodePorts.tcp $v.livekit.tcpPort (eq $v.livekit.expose "nodePort") }}
|
||||||
|
protocol: TCP
|
||||||
|
- port: {{ ternary $v.livekit.nodePorts.udp $v.livekit.udpPort (eq $v.livekit.expose "nodePort") }}
|
||||||
|
protocol: UDP
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
{{- include "fluxer.validate" . }}
|
||||||
|
{{- with .Values.postgres }}
|
||||||
|
{{- if .enabled }}
|
||||||
|
{{- $ctx := dict "root" $ "name" "postgres" "component" "database" "w" . }}
|
||||||
|
{{- $args := list }}
|
||||||
|
{{- range $k := keys .parameters | sortAlpha }}
|
||||||
|
{{- $args = concat $args (list "-c" (printf "%s=%s" $k (include "fluxer.string" (get $.Values.postgres.parameters $k)))) }}
|
||||||
|
{{- end }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: postgres
|
||||||
|
namespace: {{ $.Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
{{- include "fluxer.selectorLabels" $ctx | nindent 4 }}
|
||||||
|
ports:
|
||||||
|
- name: postgres
|
||||||
|
port: 5432
|
||||||
|
targetPort: postgres
|
||||||
|
protocol: TCP
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: postgres
|
||||||
|
namespace: {{ $.Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
serviceName: postgres
|
||||||
|
podManagementPolicy: Parallel
|
||||||
|
persistentVolumeClaimRetentionPolicy:
|
||||||
|
whenDeleted: Retain
|
||||||
|
whenScaled: Retain
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "fluxer.selectorLabels" $ctx | nindent 6 }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.podLabels" $ctx | nindent 8 }}
|
||||||
|
annotations:
|
||||||
|
checksum/config: {{ toJson $args | sha256sum }}
|
||||||
|
spec:
|
||||||
|
automountServiceAccountToken: false
|
||||||
|
enableServiceLinks: false
|
||||||
|
terminationGracePeriodSeconds: 60
|
||||||
|
{{- include "fluxer.pullSecrets" $ | nindent 6 }}
|
||||||
|
securityContext:
|
||||||
|
{{- include "fluxer.podSecurityContext" (dict "uid" (.runAsUser | int)) | nindent 8 }}
|
||||||
|
{{- include "fluxer.scheduling" $ctx | nindent 6 }}
|
||||||
|
initContainers:
|
||||||
|
- name: version-guard
|
||||||
|
image: {{ include "fluxer.thirdPartyImage" .image }}
|
||||||
|
imagePullPolicy: {{ .image.pullPolicy }}
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
want=$(postgres --version | sed -E 's/[^0-9]*([0-9]+).*/\1/')
|
||||||
|
if [ -s "$PGDATA/PG_VERSION" ]; then
|
||||||
|
have=$(cat "$PGDATA/PG_VERSION")
|
||||||
|
if [ "$have" != "$want" ]; then
|
||||||
|
echo "The data directory was created by Postgres $have and this image runs Postgres $want. Set postgres.image.tag back to the $have image, or dump the database and restore it into a fresh volume. See the Kubernetes page of the operator docs." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
env:
|
||||||
|
- name: PGDATA
|
||||||
|
value: /var/lib/postgresql/data/pgdata
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 16Mi
|
||||||
|
limits:
|
||||||
|
memory: 64Mi
|
||||||
|
securityContext:
|
||||||
|
{{- include "fluxer.containerSecurityContext" . | nindent 12 }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /var/lib/postgresql/data
|
||||||
|
containers:
|
||||||
|
- name: postgres
|
||||||
|
image: {{ include "fluxer.thirdPartyImage" .image }}
|
||||||
|
imagePullPolicy: {{ .image.pullPolicy }}
|
||||||
|
args:
|
||||||
|
{{- toYaml $args | nindent 12 }}
|
||||||
|
env:
|
||||||
|
- name: PGDATA
|
||||||
|
value: /var/lib/postgresql/data/pgdata
|
||||||
|
- name: POSTGRES_DB
|
||||||
|
value: {{ .database | quote }}
|
||||||
|
- name: POSTGRES_USER
|
||||||
|
value: {{ .username | quote }}
|
||||||
|
{{- include "fluxer.secretEnv" (dict "root" $ "name" "POSTGRES_PASSWORD" "key" "FLUXER_POSTGRES_PASSWORD") | nindent 12 }}
|
||||||
|
ports:
|
||||||
|
- name: postgres
|
||||||
|
containerPort: 5432
|
||||||
|
protocol: TCP
|
||||||
|
startupProbe:
|
||||||
|
exec:
|
||||||
|
command: ["sh", "-c", "pg_isready -U \"$POSTGRES_USER\" -d \"$POSTGRES_DB\""]
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 30
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["sh", "-c", "pg_isready -U \"$POSTGRES_USER\" -d \"$POSTGRES_DB\""]
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 6
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["sh", "-c", "pg_isready -U \"$POSTGRES_USER\" -d \"$POSTGRES_DB\""]
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
{{- with .resources }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
securityContext:
|
||||||
|
{{- include "fluxer.containerSecurityContext" . | nindent 12 }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /var/lib/postgresql/data
|
||||||
|
- name: shm
|
||||||
|
mountPath: /dev/shm
|
||||||
|
- name: run
|
||||||
|
mountPath: /var/run/postgresql
|
||||||
|
volumes:
|
||||||
|
- name: shm
|
||||||
|
emptyDir:
|
||||||
|
medium: Memory
|
||||||
|
sizeLimit: {{ .shmSize }}
|
||||||
|
- name: run
|
||||||
|
emptyDir: {}
|
||||||
|
volumeClaimTemplates:
|
||||||
|
{{- include "fluxer.pvc" .persistence | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
{{- include "fluxer.validate" . }}
|
||||||
|
{{- with .Values.seaweedfs }}
|
||||||
|
{{- if .enabled }}
|
||||||
|
{{- $ctx := dict "root" $ "name" "seaweedfs" "component" "storage" "w" . }}
|
||||||
|
{{- $healthz := dict "path" "/healthz" "port" "s3" }}
|
||||||
|
{{- $secrets := include "fluxer.secretData" $ | fromJson }}
|
||||||
|
{{- $init := $.Files.Get "files/seaweedfs-init.sh" }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: seaweedfs
|
||||||
|
namespace: {{ $.Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
{{- include "fluxer.selectorLabels" $ctx | nindent 4 }}
|
||||||
|
ports:
|
||||||
|
- name: s3
|
||||||
|
port: 8333
|
||||||
|
targetPort: s3
|
||||||
|
protocol: TCP
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: seaweedfs
|
||||||
|
namespace: {{ $.Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
serviceName: seaweedfs
|
||||||
|
podManagementPolicy: Parallel
|
||||||
|
persistentVolumeClaimRetentionPolicy:
|
||||||
|
whenDeleted: Retain
|
||||||
|
whenScaled: Retain
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "fluxer.selectorLabels" $ctx | nindent 6 }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.podLabels" $ctx | nindent 8 }}
|
||||||
|
annotations:
|
||||||
|
checksum/init: {{ list $init (get $secrets "FLUXER_S3_ACCESS_KEY_ID" | default "") (get $secrets "FLUXER_S3_SECRET_ACCESS_KEY" | default "") $.Values.s3.buckets | toJson | sha256sum }}
|
||||||
|
spec:
|
||||||
|
automountServiceAccountToken: false
|
||||||
|
enableServiceLinks: false
|
||||||
|
{{- include "fluxer.pullSecrets" $ | nindent 6 }}
|
||||||
|
securityContext:
|
||||||
|
{{- include "fluxer.podSecurityContext" (dict "uid" 1000) | nindent 8 }}
|
||||||
|
{{- include "fluxer.scheduling" $ctx | nindent 6 }}
|
||||||
|
containers:
|
||||||
|
- name: seaweedfs
|
||||||
|
image: {{ include "fluxer.thirdPartyImage" .image }}
|
||||||
|
imagePullPolicy: {{ .image.pullPolicy }}
|
||||||
|
args:
|
||||||
|
- server
|
||||||
|
- -s3
|
||||||
|
- -dir=/data
|
||||||
|
- -master.telemetry=false
|
||||||
|
- -ip=127.0.0.1
|
||||||
|
- -ip.bind=127.0.0.1
|
||||||
|
- -s3.ip.bind=0.0.0.0
|
||||||
|
env:
|
||||||
|
- name: GOMEMLIMIT
|
||||||
|
value: {{ .gomemlimit | quote }}
|
||||||
|
- name: WEED_MASTER_VOLUME_GROWTH_COPY_1
|
||||||
|
value: {{ include "fluxer.string" .volumeGrowth | quote }}
|
||||||
|
ports:
|
||||||
|
- name: s3
|
||||||
|
containerPort: 8333
|
||||||
|
protocol: TCP
|
||||||
|
startupProbe:
|
||||||
|
httpGet: {{ toJson $healthz }}
|
||||||
|
periodSeconds: 5
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 24
|
||||||
|
livenessProbe:
|
||||||
|
httpGet: {{ toJson $healthz }}
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 6
|
||||||
|
readinessProbe:
|
||||||
|
httpGet: {{ toJson $healthz }}
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
{{- with .resources }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
securityContext:
|
||||||
|
{{- include "fluxer.containerSecurityContext" . | nindent 12 }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
- name: seaweedfs-init
|
||||||
|
image: {{ include "fluxer.thirdPartyImage" .image }}
|
||||||
|
imagePullPolicy: {{ .image.pullPolicy }}
|
||||||
|
command:
|
||||||
|
- /bin/sh
|
||||||
|
- -c
|
||||||
|
- {{ $init | quote }}
|
||||||
|
env:
|
||||||
|
{{- include "fluxer.secretEnv" (dict "root" $ "name" "FLUXER_S3_ACCESS_KEY" "key" "FLUXER_S3_ACCESS_KEY_ID") | nindent 12 }}
|
||||||
|
{{- include "fluxer.secretEnv" (dict "root" $ "name" "FLUXER_S3_SECRET_KEY" "key" "FLUXER_S3_SECRET_ACCESS_KEY") | nindent 12 }}
|
||||||
|
- name: FLUXER_S3_BUCKET_CDN
|
||||||
|
value: {{ $.Values.s3.buckets.cdn | quote }}
|
||||||
|
- name: FLUXER_S3_BUCKET_UPLOADS
|
||||||
|
value: {{ $.Values.s3.buckets.uploads | quote }}
|
||||||
|
- name: FLUXER_S3_BUCKET_REPORTS
|
||||||
|
value: {{ $.Values.s3.buckets.reports | quote }}
|
||||||
|
- name: FLUXER_S3_BUCKET_HARVESTS
|
||||||
|
value: {{ $.Values.s3.buckets.harvests | quote }}
|
||||||
|
- name: FLUXER_SEAWEEDFS_INIT_ATTEMPTS
|
||||||
|
value: {{ include "fluxer.string" .initAttempts | quote }}
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command: ["test", "-f", "/tmp/fluxer-buckets-ready"]
|
||||||
|
periodSeconds: 5
|
||||||
|
timeoutSeconds: 5
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
memory: 128Mi
|
||||||
|
securityContext:
|
||||||
|
{{- include "fluxer.containerSecurityContext" . | nindent 12 }}
|
||||||
|
volumeClaimTemplates:
|
||||||
|
{{- include "fluxer.pvc" .persistence | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{{- include "fluxer.validate" . }}
|
||||||
|
{{- if not .Values.secrets.existingSecret }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: fluxer-env
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" (dict "root" . "name" "fluxer-env" "component" "config") | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
helm.sh/resource-policy: keep
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
{{- range $k, $val := include "fluxer.secretData" . | fromJson }}
|
||||||
|
{{ $k }}: {{ $val | b64enc | quote }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
{{- include "fluxer.validate" . }}
|
||||||
|
{{- $healthz := dict "path" "/_healthz" "port" "http" }}
|
||||||
|
{{- $health := dict "path" "/_health" "port" "http" }}
|
||||||
|
{{- $probes := dict
|
||||||
|
"startup" (dict "httpGet" $healthz "periodSeconds" 10 "timeoutSeconds" 5 "failureThreshold" 12)
|
||||||
|
"liveness" (dict "httpGet" $healthz "periodSeconds" 10 "timeoutSeconds" 5 "failureThreshold" 3)
|
||||||
|
"readiness" (dict "httpGet" $health "periodSeconds" 10 "timeoutSeconds" 5 "failureThreshold" 3) }}
|
||||||
|
{{- range $name := list "gifs" "messages" "snowflakes" "unfurl" "users" }}
|
||||||
|
{{- $svc := get $.Values.svc $name | default dict }}
|
||||||
|
{{- $router := $svc.router | default dict }}
|
||||||
|
{{- $shard := $svc.shard | default dict }}
|
||||||
|
{{- $count := include "fluxer.replicas" (dict "w" $shard) }}
|
||||||
|
{{- $common := list (dict "name" "FLUXER_SVC_NAME" "value" $name) (dict "name" "FLUXER_SVC_PORT" "value" "8090") (dict "name" "FLUXER_SVC_SHARD_COUNT" "value" $count) }}
|
||||||
|
{{- $shardEnv := concat $common (list (dict "name" "FLUXER_SVC_MODE" "value" "shard") (dict "name" "FLUXER_SVC_SHARD_ID" "valueFrom" (dict "fieldRef" (dict "apiVersion" "v1" "fieldPath" "metadata.labels['apps.kubernetes.io/pod-index']"))) (dict "name" "POD_NAME" "valueFrom" (dict "fieldRef" (dict "apiVersion" "v1" "fieldPath" "metadata.name")))) }}
|
||||||
|
{{- $usesPostgres := has $name (list "users" "messages") }}
|
||||||
|
{{- if $usesPostgres }}
|
||||||
|
{{- $shardEnv = append $shardEnv (dict "name" "FLUXER_POSTGRES_MAX_CONNECTIONS" "value" "20") }}
|
||||||
|
{{- end }}
|
||||||
|
{{- if eq $name "unfurl" }}
|
||||||
|
{{- $shardEnv = append $shardEnv (dict "name" "FLUXER_MEDIA_PROXY_ENDPOINT" "value" "http://media-proxy:8080") }}
|
||||||
|
{{- end }}
|
||||||
|
{{- include "fluxer.app" (dict "root" $ "name" $name "component" "svc" "w" $router "image" (printf "fluxer-%s" $name) "port" 8090 "containerName" "router"
|
||||||
|
"env" (append $common (dict "name" "FLUXER_SVC_MODE" "value" "router"))
|
||||||
|
"probes" $probes
|
||||||
|
"waitFor" (include "fluxer.appWaitFor" (dict "root" $ "usesNats" true) | fromJsonArray)) }}
|
||||||
|
{{- include "fluxer.app" (dict "root" $ "name" (printf "%s-shard" $name) "component" "svc" "w" $shard "image" (printf "fluxer-%s" $name) "port" 8090 "containerName" "shard"
|
||||||
|
"kind" "StatefulSet" "serviceName" (printf "%s-shard" $name) "headless" true
|
||||||
|
"env" $shardEnv
|
||||||
|
"probes" $probes
|
||||||
|
"waitFor" (include "fluxer.appWaitFor" (dict "root" $ "usesNats" true "usesPostgres" $usesPostgres) | fromJsonArray)) }}
|
||||||
|
{{- end }}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
{{- include "fluxer.validate" . }}
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: fluxer-test-edge
|
||||||
|
namespace: {{ .Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" (dict "root" . "name" "fluxer-test" "component" "test") | nindent 4 }}
|
||||||
|
annotations:
|
||||||
|
helm.sh/hook: test
|
||||||
|
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
|
||||||
|
spec:
|
||||||
|
restartPolicy: Never
|
||||||
|
automountServiceAccountToken: false
|
||||||
|
enableServiceLinks: false
|
||||||
|
{{- include "fluxer.pullSecrets" . | nindent 2 }}
|
||||||
|
securityContext:
|
||||||
|
{{- include "fluxer.podSecurityContext" (dict "uid" 65532) | nindent 4 }}
|
||||||
|
containers:
|
||||||
|
- name: check
|
||||||
|
image: {{ include "fluxer.thirdPartyImage" .Values.edge.image }}
|
||||||
|
imagePullPolicy: {{ .Values.edge.image.pullPolicy }}
|
||||||
|
command:
|
||||||
|
- sh
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
for i in $(seq 1 30); do
|
||||||
|
if wget -q -O /dev/null http://edge:8080/_health && wget -q -O - --header "Host: $DOMAIN" http://edge:8080/.well-known/fluxer > /tmp/discovery && grep -q "$DOMAIN" /tmp/discovery; then
|
||||||
|
echo "edge and discovery answer for $DOMAIN"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
sleep 2
|
||||||
|
done
|
||||||
|
echo "edge or discovery did not answer for $DOMAIN within 60 seconds" >&2
|
||||||
|
exit 1
|
||||||
|
env:
|
||||||
|
- name: DOMAIN
|
||||||
|
value: {{ .Values.domain | quote }}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 16Mi
|
||||||
|
limits:
|
||||||
|
memory: 64Mi
|
||||||
|
securityContext:
|
||||||
|
{{- include "fluxer.containerSecurityContext" . | nindent 8 }}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
{{- include "fluxer.validate" . }}
|
||||||
|
{{- with .Values.valkey }}
|
||||||
|
{{- if .enabled }}
|
||||||
|
{{- $ctx := dict "root" $ "name" "valkey" "component" "cache" "w" . }}
|
||||||
|
{{- $args := list "valkey-server" "--appendonly" "yes" "--appendfsync" .appendfsync "--dir" "/data" "--maxmemory" .maxmemory "--maxmemory-policy" .maxmemoryPolicy "--requirepass" "$(REDISCLI_AUTH)" }}
|
||||||
|
{{- $ping := dict "exec" (dict "command" (list "sh" "-c" "valkey-cli ping | grep -q PONG")) "periodSeconds" 10 "timeoutSeconds" 5 }}
|
||||||
|
{{- $secrets := include "fluxer.secretData" $ | fromJson }}
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: valkey
|
||||||
|
namespace: {{ $.Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
type: ClusterIP
|
||||||
|
selector:
|
||||||
|
{{- include "fluxer.selectorLabels" $ctx | nindent 4 }}
|
||||||
|
ports:
|
||||||
|
- name: redis
|
||||||
|
port: 6379
|
||||||
|
targetPort: redis
|
||||||
|
protocol: TCP
|
||||||
|
---
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: valkey
|
||||||
|
namespace: {{ $.Release.Namespace }}
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.labels" $ctx | nindent 4 }}
|
||||||
|
spec:
|
||||||
|
replicas: 1
|
||||||
|
serviceName: valkey
|
||||||
|
podManagementPolicy: Parallel
|
||||||
|
persistentVolumeClaimRetentionPolicy:
|
||||||
|
whenDeleted: Retain
|
||||||
|
whenScaled: Retain
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
{{- include "fluxer.selectorLabels" $ctx | nindent 6 }}
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
{{- include "fluxer.podLabels" $ctx | nindent 8 }}
|
||||||
|
annotations:
|
||||||
|
checksum/config: {{ printf "%s\n%s" (toJson $args) (get $secrets "FLUXER_VALKEY_PASSWORD" | default "") | sha256sum }}
|
||||||
|
spec:
|
||||||
|
automountServiceAccountToken: false
|
||||||
|
enableServiceLinks: false
|
||||||
|
{{- include "fluxer.pullSecrets" $ | nindent 6 }}
|
||||||
|
securityContext:
|
||||||
|
{{- include "fluxer.podSecurityContext" (dict "uid" 999 "gid" 1000) | nindent 8 }}
|
||||||
|
{{- include "fluxer.scheduling" $ctx | nindent 6 }}
|
||||||
|
containers:
|
||||||
|
- name: valkey
|
||||||
|
image: {{ include "fluxer.thirdPartyImage" .image }}
|
||||||
|
imagePullPolicy: {{ .image.pullPolicy }}
|
||||||
|
command:
|
||||||
|
{{- toYaml $args | nindent 12 }}
|
||||||
|
env:
|
||||||
|
{{- include "fluxer.secretEnv" (dict "root" $ "name" "REDISCLI_AUTH" "key" "FLUXER_VALKEY_PASSWORD") | nindent 12 }}
|
||||||
|
ports:
|
||||||
|
- name: redis
|
||||||
|
containerPort: 6379
|
||||||
|
protocol: TCP
|
||||||
|
livenessProbe:
|
||||||
|
{{- toYaml (merge (dict "failureThreshold" 6 "initialDelaySeconds" 10) $ping) | nindent 12 }}
|
||||||
|
readinessProbe:
|
||||||
|
{{- toYaml (merge (dict "failureThreshold" 3) $ping) | nindent 12 }}
|
||||||
|
{{- with .resources }}
|
||||||
|
resources:
|
||||||
|
{{- toYaml . | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
securityContext:
|
||||||
|
{{- include "fluxer.containerSecurityContext" . | nindent 12 }}
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
volumeClaimTemplates:
|
||||||
|
{{- include "fluxer.pvc" .persistence | nindent 4 }}
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,706 @@
|
|||||||
|
# The public hostname of the instance, lowercase, for example chat.example.com.
|
||||||
|
# Required. Point DNS for it at your ingress controller or at the edge load balancer.
|
||||||
|
domain: ""
|
||||||
|
|
||||||
|
# The scheme browsers use to reach the instance.
|
||||||
|
scheme: https
|
||||||
|
|
||||||
|
# The port browsers use to reach the instance.
|
||||||
|
port: 443
|
||||||
|
|
||||||
|
# The origin browsers see, with no trailing slash. Set it only when browsers
|
||||||
|
# reach the instance on an origin that domain, scheme and port do not describe.
|
||||||
|
# It wins over those three in every derived URL.
|
||||||
|
publicOrigin: ""
|
||||||
|
|
||||||
|
# The path the admin panel is served under, with a leading slash and no
|
||||||
|
# trailing slash.
|
||||||
|
adminBasePath: /admin
|
||||||
|
|
||||||
|
# A contact address. It becomes FLUXER_VAPID_EMAIL for web push and the ACME
|
||||||
|
# account email. Empty uses admin@<domain> for web push and no ACME email.
|
||||||
|
email: ""
|
||||||
|
|
||||||
|
# The cluster DNS suffix, used in the gateway discovery name.
|
||||||
|
clusterDomain: cluster.local
|
||||||
|
|
||||||
|
# Look up namespaces, StorageClasses, IngressClasses and installed APIs before
|
||||||
|
# installing, to fail early on a cluster that cannot run the release. Set false
|
||||||
|
# when your account cannot read those cluster-scoped objects.
|
||||||
|
clusterChecks: true
|
||||||
|
|
||||||
|
image:
|
||||||
|
# The registry and owner the Fluxer images come from.
|
||||||
|
registry: ghcr.io/fluxerapp
|
||||||
|
# The tag for every Fluxer image. v1 moves with each release.
|
||||||
|
tag: v1
|
||||||
|
# Always pulls the moving tag whenever a pod starts, including a pod that
|
||||||
|
# restarts by itself. Pin with digests for rollouts you control.
|
||||||
|
pullPolicy: Always
|
||||||
|
# Per-image tag overrides, keyed by image name, for example fluxer-api: 2026.1012.120000.
|
||||||
|
tags: {}
|
||||||
|
# Per-image digests, keyed by image name, for example fluxer-api: sha256:0123.
|
||||||
|
# A digest pins the image whatever the tag.
|
||||||
|
digests: {}
|
||||||
|
# Image pull secrets for every pod, as a list of {name: <secret>}.
|
||||||
|
pullSecrets: []
|
||||||
|
# Any new value restarts every Fluxer pod, which pulls the moving tag again.
|
||||||
|
# Add --set-string image.revision=$(date +%s) to a helm upgrade that passes
|
||||||
|
# your values file to move to the latest v1.
|
||||||
|
revision: ""
|
||||||
|
|
||||||
|
# The image of the init container that waits for the backing services.
|
||||||
|
initImage:
|
||||||
|
repository: busybox
|
||||||
|
tag: "1.37"
|
||||||
|
# A digest pins the image whatever the tag.
|
||||||
|
digest: ""
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
|
||||||
|
secrets:
|
||||||
|
# The name of a Secret you manage yourself. The chart then renders no Secret
|
||||||
|
# and never changes this one. It needs every key listed under values below.
|
||||||
|
# After editing it, run kubectl rollout restart for the deployments and
|
||||||
|
# statefulsets of the release.
|
||||||
|
existingSecret: ""
|
||||||
|
# Generate every empty key below on first install and keep it on upgrade.
|
||||||
|
# Set false under Argo CD or helm template, which cannot read the existing
|
||||||
|
# Secret, and give every key here or use existingSecret.
|
||||||
|
generate: true
|
||||||
|
# Keys of the fluxer-env Secret. Empty means generate once, then keep.
|
||||||
|
# Generated values are never rotated by an upgrade. Back up the Secret.
|
||||||
|
values:
|
||||||
|
# Password of the bundled Postgres role. Changing it after the first install
|
||||||
|
# does not change the stored role password.
|
||||||
|
FLUXER_POSTGRES_PASSWORD: ""
|
||||||
|
# Meilisearch master key.
|
||||||
|
FLUXER_SEARCH_API_KEY: ""
|
||||||
|
# S3 access key id. The bundled store installs it on every upgrade.
|
||||||
|
FLUXER_S3_ACCESS_KEY_ID: fluxer
|
||||||
|
# S3 secret key. Letters and digits only for the bundled store.
|
||||||
|
FLUXER_S3_SECRET_ACCESS_KEY: ""
|
||||||
|
# Signs sudo mode tokens.
|
||||||
|
FLUXER_SUDO_MODE_SECRET: ""
|
||||||
|
# Signs connection initiation tokens.
|
||||||
|
FLUXER_CONNECTION_INITIATION_SECRET: ""
|
||||||
|
# Derives hidden profile names. Changing it renames every hidden profile.
|
||||||
|
FLUXER_PROFILE_PSEUDONYM_SECRET: ""
|
||||||
|
# Authenticates RPC between the gateway, push and the api.
|
||||||
|
FLUXER_GATEWAY_RPC_AUTH_TOKEN: ""
|
||||||
|
# Password of the bundled Valkey. Letters and digits only.
|
||||||
|
FLUXER_VALKEY_PASSWORD: ""
|
||||||
|
# Token of the bundled NATS, letters and digits only. With an outside NATS,
|
||||||
|
# its token if it has one.
|
||||||
|
FLUXER_NATS_AUTH_TOKEN: ""
|
||||||
|
# Erlang distribution cookie of the gateway.
|
||||||
|
FLUXER_ERLANG_COOKIE: ""
|
||||||
|
# Signs media proxy URLs.
|
||||||
|
FLUXER_MEDIA_PROXY_SECRET_KEY: ""
|
||||||
|
# Standard base64 of at least 32 random bytes. Signs upload relay tokens.
|
||||||
|
FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64: ""
|
||||||
|
# Signs admin panel sessions.
|
||||||
|
FLUXER_ADMIN_SECRET_KEY_BASE: ""
|
||||||
|
# Client secret of the built-in admin OAuth application.
|
||||||
|
FLUXER_ADMIN_OAUTH_CLIENT_SECRET: ""
|
||||||
|
# LiveKit API key.
|
||||||
|
FLUXER_LIVEKIT_API_KEY: fluxer
|
||||||
|
# LiveKit API secret, at least 32 characters.
|
||||||
|
FLUXER_LIVEKIT_API_SECRET: ""
|
||||||
|
# Web push key pair, base64url. Set both or neither.
|
||||||
|
FLUXER_VAPID_PUBLIC_KEY: ""
|
||||||
|
FLUXER_VAPID_PRIVATE_KEY: ""
|
||||||
|
# Optional secret-bearing settings, added to the Secret as given. The keys are
|
||||||
|
# the variable names on the configuration page of the operator docs.
|
||||||
|
extra: {}
|
||||||
|
# A full Postgres URL. Wins over the host, port, database and password.
|
||||||
|
# FLUXER_POSTGRES_URL: postgres://fluxer:[email protected]:5432/fluxer
|
||||||
|
# PEM text of the CA that signed the Postgres server certificate.
|
||||||
|
# FLUXER_POSTGRES_SSL_CA: ""
|
||||||
|
# The URL of an outside key-value store that holds a password.
|
||||||
|
# FLUXER_KV_URL: redis://:[email protected]:6379/0
|
||||||
|
# The password of an outside search server.
|
||||||
|
# FLUXER_SEARCH_PASSWORD: ""
|
||||||
|
# A temporary S3 session token.
|
||||||
|
# FLUXER_S3_SESSION_TOKEN: ""
|
||||||
|
# Comma-separated base64 secrets that sign attachment URLs.
|
||||||
|
# FLUXER_MEDIA_PROXY_ATTACHMENT_URL_SECRETS_BASE64: ""
|
||||||
|
# SMTP password for outgoing email.
|
||||||
|
# FLUXER_EMAIL_SMTP_PASSWORD: ""
|
||||||
|
# Secret that authenticates email provider webhooks.
|
||||||
|
# FLUXER_EMAIL_WEBHOOK_SECRET: ""
|
||||||
|
# Stripe secret key.
|
||||||
|
# FLUXER_STRIPE_SECRET_KEY: ""
|
||||||
|
# Stripe webhook signing secret.
|
||||||
|
# FLUXER_STRIPE_WEBHOOK_SECRET: ""
|
||||||
|
# Key of the donation proxy.
|
||||||
|
# FLUXER_API_DONATION_PROXY_KEY: ""
|
||||||
|
# Bearer token of the HTTP cache purge endpoint.
|
||||||
|
# FLUXER_CACHE_PURGE_HTTP_TOKEN: ""
|
||||||
|
# Klipy GIF API key.
|
||||||
|
# FLUXER_KLIPY_API_KEY: ""
|
||||||
|
# YouTube Data API key.
|
||||||
|
# FLUXER_YOUTUBE_API_KEY: ""
|
||||||
|
# Bluesky OAuth signing keys.
|
||||||
|
# FLUXER_AUTH_BLUESKY_KEYS: ""
|
||||||
|
# APNs private key for iOS push.
|
||||||
|
# FLUXER_PUSH_APNS_PRIVATE_KEY: ""
|
||||||
|
# FCM private key for Android push.
|
||||||
|
# FLUXER_PUSH_FCM_PRIVATE_KEY: ""
|
||||||
|
|
||||||
|
# Extra non-secret settings for every Fluxer service, as NAME: value. The names
|
||||||
|
# and meanings are on the configuration page of the operator docs. An empty
|
||||||
|
# value is left out. The chart refuses a secret here. Secrets belong in
|
||||||
|
# secrets.extra.
|
||||||
|
env: {}
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
# Run Postgres in the release. Set false to use your own server.
|
||||||
|
enabled: true
|
||||||
|
image:
|
||||||
|
repository: postgres
|
||||||
|
# A new major needs a dump and restore. The pod refuses a data directory
|
||||||
|
# from another major.
|
||||||
|
tag: 16-alpine
|
||||||
|
digest: ""
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
# The user and group id of the postgres user in the image. 70 in the Alpine
|
||||||
|
# images, 999 in the Debian ones.
|
||||||
|
runAsUser: 70
|
||||||
|
# Your own server, used when enabled is false. Its password goes in
|
||||||
|
# secrets.values.FLUXER_POSTGRES_PASSWORD, or a URL in secrets.extra.FLUXER_POSTGRES_URL.
|
||||||
|
# The database and the role have to exist already.
|
||||||
|
external:
|
||||||
|
host: ""
|
||||||
|
port: 5432
|
||||||
|
database: fluxer
|
||||||
|
username: fluxer
|
||||||
|
# true or false. Empty keeps the service default.
|
||||||
|
ssl: ""
|
||||||
|
# The database and role the bundled server creates.
|
||||||
|
database: fluxer
|
||||||
|
username: fluxer
|
||||||
|
# Server settings, passed as -c name=value.
|
||||||
|
parameters:
|
||||||
|
max_connections: "150"
|
||||||
|
shared_buffers: 512MB
|
||||||
|
effective_cache_size: 2GB
|
||||||
|
work_mem: 8MB
|
||||||
|
maintenance_work_mem: 256MB
|
||||||
|
autovacuum_work_mem: 128MB
|
||||||
|
random_page_cost: "1.1"
|
||||||
|
effective_io_concurrency: "200"
|
||||||
|
default_statistics_target: "200"
|
||||||
|
jit: "off"
|
||||||
|
min_wal_size: 512MB
|
||||||
|
max_wal_size: 2GB
|
||||||
|
checkpoint_completion_target: "0.9"
|
||||||
|
wal_buffers: 16MB
|
||||||
|
wal_compression: zstd
|
||||||
|
bgwriter_delay: 50ms
|
||||||
|
bgwriter_lru_maxpages: "1000"
|
||||||
|
autovacuum_vacuum_scale_factor: "0.05"
|
||||||
|
autovacuum_analyze_scale_factor: "0.02"
|
||||||
|
autovacuum_vacuum_cost_limit: "2000"
|
||||||
|
track_io_timing: "on"
|
||||||
|
shared_preload_libraries: pg_stat_statements
|
||||||
|
# Size of the in-memory /dev/shm. Parallel vacuum needs it.
|
||||||
|
shmSize: 1Gi
|
||||||
|
# The size and the class are fixed once the volume exists. To grow a volume
|
||||||
|
# later, edit the PersistentVolumeClaim, not this value.
|
||||||
|
persistence:
|
||||||
|
size: 20Gi
|
||||||
|
# Empty uses the cluster default StorageClass.
|
||||||
|
storageClassName: ""
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 1Gi
|
||||||
|
limits:
|
||||||
|
memory: 5Gi
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
|
|
||||||
|
valkey:
|
||||||
|
# Run Valkey in the release. Set false and give external.url to use your own.
|
||||||
|
enabled: true
|
||||||
|
image:
|
||||||
|
repository: valkey/valkey
|
||||||
|
tag: 9.1-alpine
|
||||||
|
digest: ""
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
external:
|
||||||
|
# A URL without a password. One with a password goes in secrets.extra.FLUXER_KV_URL.
|
||||||
|
url: ""
|
||||||
|
maxmemory: 192mb
|
||||||
|
maxmemoryPolicy: noeviction
|
||||||
|
appendfsync: everysec
|
||||||
|
persistence:
|
||||||
|
size: 1Gi
|
||||||
|
storageClassName: ""
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 20m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
|
|
||||||
|
nats:
|
||||||
|
# Run NATS with JetStream in the release. Set false and give external.url to use your own.
|
||||||
|
enabled: true
|
||||||
|
image:
|
||||||
|
repository: nats
|
||||||
|
tag: 2.14-alpine
|
||||||
|
digest: ""
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
external:
|
||||||
|
# Its token, if any, goes in secrets.values.FLUXER_NATS_AUTH_TOKEN.
|
||||||
|
url: ""
|
||||||
|
# 1, or 3 or more for a JetStream cluster.
|
||||||
|
replicas: 1
|
||||||
|
persistence:
|
||||||
|
size: 10Gi
|
||||||
|
storageClassName: ""
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 20m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
|
|
||||||
|
meilisearch:
|
||||||
|
# Run Meilisearch in the release. Set false and give external.url to use your own.
|
||||||
|
enabled: true
|
||||||
|
image:
|
||||||
|
repository: getmeili/meilisearch
|
||||||
|
tag: v1.53
|
||||||
|
digest: ""
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
external:
|
||||||
|
# Its key goes in secrets.values.FLUXER_SEARCH_API_KEY.
|
||||||
|
url: ""
|
||||||
|
maxIndexingMemory: 256mb
|
||||||
|
maxIndexingThreads: 2
|
||||||
|
persistence:
|
||||||
|
size: 10Gi
|
||||||
|
storageClassName: ""
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
memory: 1536Mi
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
|
|
||||||
|
seaweedfs:
|
||||||
|
# Run SeaweedFS as the S3 store and create the buckets. Only its S3 port
|
||||||
|
# listens outside the pod. Set false and give s3.endpoint to use your own
|
||||||
|
# store, with the buckets already created.
|
||||||
|
enabled: true
|
||||||
|
image:
|
||||||
|
repository: chrislusf/seaweedfs
|
||||||
|
tag: "4.47"
|
||||||
|
digest: ""
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
# Volumes grown per bucket. 1 keeps the store usable on small disks.
|
||||||
|
volumeGrowth: 1
|
||||||
|
gomemlimit: 1536MiB
|
||||||
|
# Tries, 2 seconds apart, the bucket setup makes before it starts over.
|
||||||
|
initAttempts: 60
|
||||||
|
persistence:
|
||||||
|
size: 20Gi
|
||||||
|
storageClassName: ""
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
memory: 2Gi
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
|
|
||||||
|
s3:
|
||||||
|
# The S3 endpoint the services use. Empty uses the bundled SeaweedFS.
|
||||||
|
endpoint: ""
|
||||||
|
# The S3 endpoint browsers use for direct uploads. Empty uses endpoint.
|
||||||
|
publicEndpoint: ""
|
||||||
|
region: us-east-1
|
||||||
|
forcePathStyle: true
|
||||||
|
buckets:
|
||||||
|
cdn: fluxer
|
||||||
|
uploads: fluxer-uploads
|
||||||
|
reports: fluxer-reports
|
||||||
|
harvests: fluxer-harvests
|
||||||
|
|
||||||
|
livekit:
|
||||||
|
# Run LiveKit for voice and video. false with no external.url turns voice off.
|
||||||
|
enabled: true
|
||||||
|
# A LiveKit server of your own, used when enabled is false. Its key and
|
||||||
|
# secret go in secrets.values.FLUXER_LIVEKIT_API_KEY and FLUXER_LIVEKIT_API_SECRET.
|
||||||
|
# Point its webhook at <origin>/api/webhooks/livekit, signed with the same key.
|
||||||
|
external:
|
||||||
|
# The address the api uses to reach it, for example http://livekit.voice.svc:7880.
|
||||||
|
url: ""
|
||||||
|
# The address browsers use to reach it, for example wss://livekit.example.com.
|
||||||
|
publicUrl: ""
|
||||||
|
image:
|
||||||
|
repository: livekit/livekit-server
|
||||||
|
tag: v1.12.0
|
||||||
|
digest: ""
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
# How clients reach the media ports. hostNetwork binds them on the node and
|
||||||
|
# needs a privileged namespace. loadBalancer and nodePort use the Service
|
||||||
|
# livekit-rtc, which serves TCP and UDP on one address.
|
||||||
|
expose: hostNetwork
|
||||||
|
# The public IP LiveKit advertises. Required for loadBalancer, where it is the
|
||||||
|
# address of the load balancer. Empty finds it over STUN.
|
||||||
|
nodeIP: ""
|
||||||
|
# The address the loadBalancer Service asks for. Reserve it with your
|
||||||
|
# provider first. Some providers take it from an annotation instead.
|
||||||
|
loadBalancerIP: ""
|
||||||
|
# Find the public IP over STUN.
|
||||||
|
useExternalIP: true
|
||||||
|
tcpPort: 7881
|
||||||
|
udpPort: 7882
|
||||||
|
# The node ports in nodePort mode. LiveKit advertises these too.
|
||||||
|
nodePorts:
|
||||||
|
tcp: 30881
|
||||||
|
udp: 30882
|
||||||
|
stunServers:
|
||||||
|
- stun.l.google.com:19302
|
||||||
|
- stun1.l.google.com:19302
|
||||||
|
logLevel: info
|
||||||
|
# More LiveKit configuration, merged over the chart's, for example
|
||||||
|
# {rtc: {ips: {includes: [10.0.0.0/8]}}} to advertise only the node network.
|
||||||
|
extraConfig: {}
|
||||||
|
# The voice region seeded on every api start, as JSON.
|
||||||
|
defaultRegion: '{"id":"default","name":"Default","emoji":"🌍","latitude":0,"longitude":0}'
|
||||||
|
# Node addresses allowed to reach the edge in hostNetwork mode, for the
|
||||||
|
# LiveKit webhook. Needed only with networkPolicy.ingressNamespaceSelector.
|
||||||
|
# Keep it as narrow as the LiveKit node, for example 10.0.0.12/32 together
|
||||||
|
# with nodeSelector.
|
||||||
|
nodeCIDRs: []
|
||||||
|
# Annotations for the Service livekit-rtc.
|
||||||
|
serviceAnnotations: {}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
memory: 512Mi
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
|
|
||||||
|
# Every Fluxer workload below takes the same keys:
|
||||||
|
# replicas, image (registry, tag, digest, pullPolicy), resources, env (NAME: value),
|
||||||
|
# extraEnv (a list of Kubernetes env entries), probes (startup, liveness or
|
||||||
|
# readiness, each replacing the default probe whole), podAnnotations,
|
||||||
|
# nodeSelector, tolerations, affinity, topologySpreadConstraints, pdb
|
||||||
|
# (minAvailable or maxUnavailable), hpa (minReplicas, maxReplicas,
|
||||||
|
# targetCPUUtilizationPercentage), extraVolumes and extraVolumeMounts.
|
||||||
|
|
||||||
|
api:
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 768Mi
|
||||||
|
limits:
|
||||||
|
memory: 2560Mi
|
||||||
|
env: {}
|
||||||
|
extraEnv: []
|
||||||
|
probes: {}
|
||||||
|
podAnnotations: {}
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
|
topologySpreadConstraints: []
|
||||||
|
pdb: {}
|
||||||
|
hpa: {}
|
||||||
|
extraVolumes: []
|
||||||
|
extraVolumeMounts: []
|
||||||
|
|
||||||
|
worker:
|
||||||
|
# Must stay 1. The worker runs the cron scheduler.
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 768Mi
|
||||||
|
limits:
|
||||||
|
memory: 2560Mi
|
||||||
|
env: {}
|
||||||
|
extraEnv: []
|
||||||
|
probes: {}
|
||||||
|
podAnnotations: {}
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
|
topologySpreadConstraints: []
|
||||||
|
pdb: {}
|
||||||
|
hpa: {}
|
||||||
|
extraVolumes: []
|
||||||
|
extraVolumeMounts: []
|
||||||
|
|
||||||
|
gateway:
|
||||||
|
replicas: 1
|
||||||
|
terminationGracePeriodSeconds: 30
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 256Mi
|
||||||
|
limits:
|
||||||
|
memory: 1Gi
|
||||||
|
env: {}
|
||||||
|
extraEnv: []
|
||||||
|
probes: {}
|
||||||
|
podAnnotations: {}
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
|
topologySpreadConstraints: []
|
||||||
|
pdb: {}
|
||||||
|
hpa: {}
|
||||||
|
extraVolumes: []
|
||||||
|
extraVolumeMounts: []
|
||||||
|
|
||||||
|
mediaProxy:
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 50m
|
||||||
|
memory: 128Mi
|
||||||
|
limits:
|
||||||
|
memory: 512Mi
|
||||||
|
env: {}
|
||||||
|
extraEnv: []
|
||||||
|
probes: {}
|
||||||
|
podAnnotations: {}
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
|
topologySpreadConstraints: []
|
||||||
|
pdb: {}
|
||||||
|
hpa: {}
|
||||||
|
extraVolumes: []
|
||||||
|
extraVolumeMounts: []
|
||||||
|
|
||||||
|
push:
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
env: {}
|
||||||
|
extraEnv: []
|
||||||
|
probes: {}
|
||||||
|
podAnnotations: {}
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
|
topologySpreadConstraints: []
|
||||||
|
pdb: {}
|
||||||
|
hpa: {}
|
||||||
|
extraVolumes: []
|
||||||
|
extraVolumeMounts: []
|
||||||
|
|
||||||
|
admin:
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
env: {}
|
||||||
|
extraEnv: []
|
||||||
|
probes: {}
|
||||||
|
podAnnotations: {}
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
|
topologySpreadConstraints: []
|
||||||
|
pdb: {}
|
||||||
|
hpa: {}
|
||||||
|
extraVolumes: []
|
||||||
|
extraVolumeMounts: []
|
||||||
|
|
||||||
|
appProxy:
|
||||||
|
replicas: 1
|
||||||
|
# Settings for app-proxy only: branding, CSP extras, the index upstream,
|
||||||
|
# same-origin hosts and manifest scope, as NAME: value. For example
|
||||||
|
# FLUXER_APP_PRODUCT_NAME, FLUXER_CSP_EXTRA_CONNECT_SRC or RUST_LOG.
|
||||||
|
config: {}
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 20m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
env: {}
|
||||||
|
extraEnv: []
|
||||||
|
probes: {}
|
||||||
|
podAnnotations: {}
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
|
topologySpreadConstraints: []
|
||||||
|
pdb: {}
|
||||||
|
hpa: {}
|
||||||
|
extraVolumes: []
|
||||||
|
extraVolumeMounts: []
|
||||||
|
|
||||||
|
staticProxy:
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 10m
|
||||||
|
memory: 32Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
env: {}
|
||||||
|
extraEnv: []
|
||||||
|
probes: {}
|
||||||
|
podAnnotations: {}
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
|
topologySpreadConstraints: []
|
||||||
|
pdb: {}
|
||||||
|
hpa: {}
|
||||||
|
extraVolumes: []
|
||||||
|
extraVolumeMounts: []
|
||||||
|
|
||||||
|
# The internal services. Each runs a router Deployment and a shard StatefulSet.
|
||||||
|
# router and shard take the workload keys above. shard.replicas sets the shard count.
|
||||||
|
svc:
|
||||||
|
gifs:
|
||||||
|
router:
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
requests: {cpu: 10m, memory: 32Mi}
|
||||||
|
limits: {memory: 128Mi}
|
||||||
|
shard:
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
requests: {cpu: 20m, memory: 64Mi}
|
||||||
|
limits: {memory: 256Mi}
|
||||||
|
messages:
|
||||||
|
router:
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
requests: {cpu: 10m, memory: 32Mi}
|
||||||
|
limits: {memory: 128Mi}
|
||||||
|
shard:
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
requests: {cpu: 20m, memory: 64Mi}
|
||||||
|
limits: {memory: 256Mi}
|
||||||
|
snowflakes:
|
||||||
|
router:
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
requests: {cpu: 10m, memory: 32Mi}
|
||||||
|
limits: {memory: 128Mi}
|
||||||
|
shard:
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
requests: {cpu: 20m, memory: 64Mi}
|
||||||
|
limits: {memory: 256Mi}
|
||||||
|
unfurl:
|
||||||
|
router:
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
requests: {cpu: 10m, memory: 32Mi}
|
||||||
|
limits: {memory: 128Mi}
|
||||||
|
shard:
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
requests: {cpu: 20m, memory: 64Mi}
|
||||||
|
limits: {memory: 256Mi}
|
||||||
|
users:
|
||||||
|
router:
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
requests: {cpu: 10m, memory: 32Mi}
|
||||||
|
limits: {memory: 128Mi}
|
||||||
|
shard:
|
||||||
|
replicas: 1
|
||||||
|
resources:
|
||||||
|
requests: {cpu: 20m, memory: 64Mi}
|
||||||
|
limits: {memory: 256Mi}
|
||||||
|
|
||||||
|
edge:
|
||||||
|
image:
|
||||||
|
repository: caddy
|
||||||
|
tag: 2.11-alpine
|
||||||
|
digest: ""
|
||||||
|
pullPolicy: IfNotPresent
|
||||||
|
# How traffic reaches the edge. ingress puts an Ingress in front of it,
|
||||||
|
# gateway an HTTPRoute, loadBalancer a LoadBalancer Service with its own TLS,
|
||||||
|
# and none leaves only the ClusterIP Service edge on port 8080.
|
||||||
|
expose: ingress
|
||||||
|
ingress:
|
||||||
|
# The IngressClass. Empty uses the cluster default.
|
||||||
|
className: ""
|
||||||
|
# Extra annotations. The chart always adds the ingress-nginx body size and
|
||||||
|
# timeout annotations, which other controllers ignore.
|
||||||
|
annotations: {}
|
||||||
|
tls:
|
||||||
|
# certManager issues a certificate through a namespaced ACME Issuer.
|
||||||
|
# existingSecret uses secretName. none serves plain HTTP behind the controller.
|
||||||
|
mode: certManager
|
||||||
|
secretName: fluxer-tls
|
||||||
|
acmeServer: https://acme-v02.api.letsencrypt.org/directory
|
||||||
|
gateway:
|
||||||
|
# The Gateway the HTTPRoute attaches to, as Gateway API parentRefs.
|
||||||
|
parentRefs: []
|
||||||
|
# HTTPRoute timeouts, for example {request: 0s}. Envoy-based gateways cut
|
||||||
|
# requests at 15 seconds without it.
|
||||||
|
timeouts: {}
|
||||||
|
loadBalancer:
|
||||||
|
# Also publish UDP 443 for HTTP/3. Some clouds cannot mix TCP and UDP on one Service.
|
||||||
|
http3: false
|
||||||
|
annotations: {}
|
||||||
|
# Size of the volume that keeps the certificates.
|
||||||
|
persistence:
|
||||||
|
size: 1Gi
|
||||||
|
storageClassName: ""
|
||||||
|
replicas: 1
|
||||||
|
# Edge settings as NAME: value, overriding the chart's, for example
|
||||||
|
# FLUXER_EDGE_GLOBAL_OPTIONS or FLUXER_EDGE_ENCODE.
|
||||||
|
env: {}
|
||||||
|
extraEnv: []
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 20m
|
||||||
|
memory: 64Mi
|
||||||
|
limits:
|
||||||
|
memory: 256Mi
|
||||||
|
podAnnotations: {}
|
||||||
|
nodeSelector: {}
|
||||||
|
tolerations: []
|
||||||
|
affinity: {}
|
||||||
|
|
||||||
|
networkPolicy:
|
||||||
|
# Admit traffic to the release pods only from the release itself, to the edge
|
||||||
|
# from anywhere, and to the LiveKit media ports. Network plugins without
|
||||||
|
# NetworkPolicy support ignore it. Add a NetworkPolicy of your own to let
|
||||||
|
# another namespace in, for example a metrics scraper.
|
||||||
|
enabled: true
|
||||||
|
# Namespaces allowed to reach the edge on port 8080, as a namespaceSelector,
|
||||||
|
# for example {matchLabels: {kubernetes.io/metadata.name: ingress-nginx}}.
|
||||||
|
# Empty allows any source.
|
||||||
|
ingressNamespaceSelector: {}
|
||||||
@@ -404,6 +404,10 @@ FLUXER_DISCOVERY_ENABLED=true
|
|||||||
# The compression the edge offers, as Caddy encode arguments.
|
# The compression the edge offers, as Caddy encode arguments.
|
||||||
#FLUXER_EDGE_ENCODE=zstd gzip
|
#FLUXER_EDGE_ENCODE=zstd gzip
|
||||||
|
|
||||||
|
# Extra Caddy global options, one line, added to the global block of the edge
|
||||||
|
# Caddyfile. Empty adds nothing. Example: email [email protected]
|
||||||
|
#FLUXER_EDGE_GLOBAL_OPTIONS=
|
||||||
|
|
||||||
# Images of the bundled services, for a mirror or another tag. A new Postgres
|
# Images of the bundled services, for a mirror or another tag. A new Postgres
|
||||||
# major needs a dump and restore, as the upgrade guide describes.
|
# major needs a dump and restore, as the upgrade guide describes.
|
||||||
#FLUXER_CADDY_IMAGE=caddy:2.11-alpine
|
#FLUXER_CADDY_IMAGE=caddy:2.11-alpine
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
trusted_proxies static {$FLUXER_EDGE_TRUSTED_PROXIES:private_ranges}
|
trusted_proxies static {$FLUXER_EDGE_TRUSTED_PROXIES:private_ranges}
|
||||||
trusted_proxies_strict
|
trusted_proxies_strict
|
||||||
}
|
}
|
||||||
|
{$FLUXER_EDGE_GLOBAL_OPTIONS}
|
||||||
}
|
}
|
||||||
|
|
||||||
{$FLUXER_EDGE_SITE_ADDRESS} {
|
{$FLUXER_EDGE_SITE_ADDRESS} {
|
||||||
|
|||||||
@@ -231,6 +231,7 @@ services:
|
|||||||
FLUXER_EDGE_SITE_ADDRESS: ${FLUXER_EDGE_SITE_ADDRESS:-${FLUXER_CADDY_SITE_ADDRESS:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN:?set FLUXER_DOMAIN in .env}}}
|
FLUXER_EDGE_SITE_ADDRESS: ${FLUXER_EDGE_SITE_ADDRESS:-${FLUXER_CADDY_SITE_ADDRESS:-${FLUXER_PUBLIC_SCHEME:-https}://${FLUXER_DOMAIN:?set FLUXER_DOMAIN in .env}}}
|
||||||
FLUXER_EDGE_TRUSTED_PROXIES: ${FLUXER_EDGE_TRUSTED_PROXIES:-private_ranges}
|
FLUXER_EDGE_TRUSTED_PROXIES: ${FLUXER_EDGE_TRUSTED_PROXIES:-private_ranges}
|
||||||
FLUXER_EDGE_ENCODE: ${FLUXER_EDGE_ENCODE:-zstd gzip}
|
FLUXER_EDGE_ENCODE: ${FLUXER_EDGE_ENCODE:-zstd gzip}
|
||||||
|
FLUXER_EDGE_GLOBAL_OPTIONS: ${FLUXER_EDGE_GLOBAL_OPTIONS:-}
|
||||||
FLUXER_ADMIN_BASE_PATH: ${FLUXER_ADMIN_BASE_PATH:-/admin}
|
FLUXER_ADMIN_BASE_PATH: ${FLUXER_ADMIN_BASE_PATH:-/admin}
|
||||||
volumes:
|
volumes:
|
||||||
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
- ./Caddyfile:/etc/caddy/Caddyfile:ro
|
||||||
|
|||||||
@@ -167,6 +167,7 @@ export default defineConfig({
|
|||||||
'operator/configuration',
|
'operator/configuration',
|
||||||
'operator/reverse-proxy',
|
'operator/reverse-proxy',
|
||||||
'operator/upgrading',
|
'operator/upgrading',
|
||||||
|
'operator/kubernetes',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1755,6 +1755,64 @@ console.log('self-hosting guide against deploy/self-hosting');
|
|||||||
failures += section('self-hosting guide disagreements', problems);
|
failures += section('self-hosting guide disagreements', problems);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('Kubernetes page against deploy/helm/fluxer');
|
||||||
|
{
|
||||||
|
const chartValues = await readFile(path.join(REPO_ROOT, 'deploy/helm/fluxer/values.yaml'), 'utf8');
|
||||||
|
const page = await readFile(path.join(DOCS_ROOT, 'operator/kubernetes.mdx'), 'utf8');
|
||||||
|
const problems: Array<string> = [];
|
||||||
|
|
||||||
|
const chartKeys: Array<string> = [];
|
||||||
|
let inSecrets = false;
|
||||||
|
let inValues = false;
|
||||||
|
for (const line of chartValues.split('\n')) {
|
||||||
|
if (/^\S/u.test(line)) {
|
||||||
|
inSecrets = line.startsWith('secrets:');
|
||||||
|
inValues = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (inSecrets && /^ {2}\S/u.test(line)) {
|
||||||
|
inValues = line.startsWith(' values:');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const key = inValues ? line.match(/^ {4}([A-Z][A-Z0-9_]*):/u) : null;
|
||||||
|
if (key != null) {
|
||||||
|
chartKeys.push(key[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (chartKeys.length === 0) {
|
||||||
|
problems.push('found no keys under secrets.values in deploy/helm/fluxer/values.yaml');
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableKeys = new Set<string>();
|
||||||
|
const header = '| Key | Chart default |';
|
||||||
|
const lines = page.split('\n');
|
||||||
|
const start = lines.indexOf(header);
|
||||||
|
if (start === -1) {
|
||||||
|
problems.push(`operator/kubernetes.mdx has no table headed \`${header}\``);
|
||||||
|
} else {
|
||||||
|
for (const row of lines.slice(start + 2)) {
|
||||||
|
const cell = row.match(/^\| `([A-Z][A-Z0-9_]*)` \|/u);
|
||||||
|
if (cell == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tableKeys.add(cell[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const key of chartKeys) {
|
||||||
|
if (!tableKeys.has(key)) {
|
||||||
|
problems.push(`secrets.values.${key} is missing from the secret table on operator/kubernetes.mdx`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const key of tableKeys) {
|
||||||
|
if (!chartKeys.includes(key)) {
|
||||||
|
problems.push(`operator/kubernetes.mdx lists ${key}, which secrets.values does not declare`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(` chart secret keys: ${chartKeys.length.toString()}`);
|
||||||
|
console.log(` documented in the secret table: ${tableKeys.size.toString()}`);
|
||||||
|
failures += section('Kubernetes page disagreements', problems);
|
||||||
|
}
|
||||||
|
|
||||||
console.log('unthrottled routes and global bucket claims');
|
console.log('unthrottled routes and global bucket claims');
|
||||||
{
|
{
|
||||||
const unthrottled = controllerRoutes
|
const unthrottled = controllerRoutes
|
||||||
|
|||||||
@@ -320,6 +320,7 @@ const ACCEPTED_TABLE_FINDINGS = new Map<string, Readonly<Partial<Record<TableRul
|
|||||||
['http-api/webhooks.mdx', {'table-identifier': 1, 'table-parallel': 1}],
|
['http-api/webhooks.mdx', {'table-identifier': 1, 'table-parallel': 1}],
|
||||||
['media-proxy/responses-and-limits.md', {'table-cell': 2}],
|
['media-proxy/responses-and-limits.md', {'table-cell': 2}],
|
||||||
['media-proxy/routes.mdx', {'table-cell': 1}],
|
['media-proxy/routes.mdx', {'table-cell': 1}],
|
||||||
|
['operator/kubernetes.mdx', {'table-identifier': 1}],
|
||||||
['voice/index.md', {'table-parallel': 1}],
|
['voice/index.md', {'table-parallel': 1}],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -312,6 +312,10 @@ Default `private_ranges`. The peer addresses whose `X-Forwarded-For` header the
|
|||||||
|
|
||||||
Default `zstd gzip`. The response compression the edge offers, written as the arguments of the Caddy `encode` directive. `gzip` alone stops the edge offering zstd. Read by the edge container only, and it takes effect on `docker compose up -d edge`.
|
Default `zstd gzip`. The response compression the edge offers, written as the arguments of the Caddy `encode` directive. `gzip` alone stops the edge offering zstd. Read by the edge container only, and it takes effect on `docker compose up -d edge`.
|
||||||
|
|
||||||
|
#### `FLUXER_EDGE_GLOBAL_OPTIONS`
|
||||||
|
|
||||||
|
No default. Extra Caddy global options on one line, added to the global block of the edge Caddyfile, such as `email [email protected]` for the ACME account. Compose forwards it from `.env` to `edge`, and an empty value adds nothing.
|
||||||
|
|
||||||
#### `FLUXER_EDGE_BIND`
|
#### `FLUXER_EDGE_BIND`
|
||||||
|
|
||||||
Default `127.0.0.1:8080`. Where the plain-HTTP port binds. Read only under the overlay. `0.0.0.0:8080` must be firewalled to the proxy host, because the edge takes the client address from the `X-Forwarded-For` header of any peer in `FLUXER_EDGE_TRUSTED_PROXIES`.
|
Default `127.0.0.1:8080`. Where the plain-HTTP port binds. Read only under the overlay. `0.0.0.0:8080` must be firewalled to the proxy host, because the edge takes the client address from the `X-Forwarded-For` header of any peer in `FLUXER_EDGE_TRUSTED_PROXIES`.
|
||||||
@@ -1648,7 +1652,7 @@ A front proxy must not add a [Content-Security-Policy of its own](/operator/reve
|
|||||||
|
|
||||||
## Keys in .env.example that no service reads
|
## Keys in .env.example that no service reads
|
||||||
|
|
||||||
Docker Compose or the edge container consumes most of the names below, and each of those reaches a service under a different name. Setting one outside Compose, in Kubernetes or a systemd unit, does nothing.
|
Docker Compose or the edge container consumes most of the names below, and each of those reaches a service under a different name. Setting one outside Compose, in Kubernetes or a systemd unit, does nothing. The [Kubernetes](/operator/kubernetes/) chart sets the names they stand for itself.
|
||||||
|
|
||||||
#### `FLUXER_DOMAIN`
|
#### `FLUXER_DOMAIN`
|
||||||
|
|
||||||
@@ -1666,7 +1670,7 @@ Read by the edge container only, and only in the bundled layout. Both overlays o
|
|||||||
|
|
||||||
Read by Docker Compose as the default for `FLUXER_EDGE_SITE_ADDRESS` when that name is unset.
|
Read by Docker Compose as the default for `FLUXER_EDGE_SITE_ADDRESS` when that name is unset.
|
||||||
|
|
||||||
#### `FLUXER_EDGE_TRUSTED_PROXIES` and `FLUXER_EDGE_ENCODE`
|
#### `FLUXER_EDGE_TRUSTED_PROXIES`, `FLUXER_EDGE_ENCODE` and `FLUXER_EDGE_GLOBAL_OPTIONS`
|
||||||
|
|
||||||
Read by the edge container only. They take effect on `docker compose up -d edge`.
|
Read by the edge container only. They take effect on `docker compose up -d edge`.
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ We are grateful to everyone supporting the project through [Fluxer Plutonium](ht
|
|||||||
|
|
||||||
By the end you have a Fluxer instance on a hostname you own, running the web app, HTTP API, Gateway, admin dashboard, uploads, search and voice signalling in Docker containers on one machine. Allow about 30 minutes, most of it spent downloading images.
|
By the end you have a Fluxer instance on a hostname you own, running the web app, HTTP API, Gateway, admin dashboard, uploads, search and voice signalling in Docker containers on one machine. Allow about 30 minutes, most of it spent downloading images.
|
||||||
|
|
||||||
|
To run the same instance on a Kubernetes cluster, follow [Kubernetes](/operator/kubernetes/) instead.
|
||||||
|
|
||||||
## What you need
|
## What you need
|
||||||
|
|
||||||
| Requirement | Value |
|
| Requirement | Value |
|
||||||
|
|||||||
@@ -0,0 +1,398 @@
|
|||||||
|
---
|
||||||
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
title: Kubernetes
|
||||||
|
description: Run a complete Fluxer instance on Kubernetes with one Helm chart.
|
||||||
|
---
|
||||||
|
|
||||||
|
:::tip[The Operator Pass is coming]
|
||||||
|
The [Operator Pass](https://fluxer.app/pass) gives you a direct line to the Fluxer team. It goes on sale in early November 2026 for $199 or €199, paid once. The price goes up on 1 January 2027. Pass holders get these perks for life.
|
||||||
|
|
||||||
|
- A private channel in Fluxer Labs where the team answers questions about your instance
|
||||||
|
- The Operator role in Fluxer Labs
|
||||||
|
- An Operator Pass profile badge
|
||||||
|
- Invitations to test new features on your instance
|
||||||
|
- Your avatar and name on the Fluxer website, if you want
|
||||||
|
|
||||||
|
The pass unlocks nothing in the software, and self-hosting stays free. If you have Visionary, you already have the pass.
|
||||||
|
|
||||||
|
We are grateful to everyone supporting the project through [Fluxer Plutonium](https://fluxer.app/plutonium) or [donations](https://fluxer.app/donate). All of our code is free and open source on [GitHub](https://github.com/fluxerapp/fluxer).
|
||||||
|
:::
|
||||||
|
|
||||||
|
The Helm chart in `deploy/helm/fluxer` runs the same services as the Docker Compose stack in [Get started](/operator/get-started/): the Fluxer services, Postgres, Valkey, NATS, Meilisearch, SeaweedFS, LiveKit and the Caddy edge that routes every path. It generates its own secrets, so a hostname is the only value an install needs.
|
||||||
|
|
||||||
|
Run one release per namespace. Every object has a fixed name, such as `api` or `postgres`, so the services find each other the same way they do under Compose.
|
||||||
|
|
||||||
|
## What you need
|
||||||
|
|
||||||
|
| Requirement | Value |
|
||||||
|
| --- | --- |
|
||||||
|
| Kubernetes | 1.29 or newer |
|
||||||
|
| Helm | Helm 3 or Helm 4. CI checks 3.19 and 4.2 |
|
||||||
|
| Nodes | 2 vCPU and 8 GB RAM free for the release. The defaults request 0.8 vCPU and 4.4 GiB |
|
||||||
|
| Storage | A default StorageClass with `ReadWriteOnce` volumes. The defaults request 61 GiB |
|
||||||
|
| Traffic | An ingress controller and cert-manager with the default values. See [Exposure](#exposure) for the other ways in |
|
||||||
|
| Client IP | The controller sees the real client address. See [Client IP](#client-ip) |
|
||||||
|
| DNS | An `A` record for the hostname pointing at the controller or the load balancer |
|
||||||
|
| Voice | 7881/tcp and 7882/udp reachable on a node, and outbound STUN |
|
||||||
|
| Processor | `amd64` or `arm64`. Every image ships for both |
|
||||||
|
|
||||||
|
The chart installs nothing outside its namespace. A cluster with no ingress controller needs one first, such as [Traefik](https://doc.traefik.io/traefik/getting-started/install-traefik/), and [cert-manager](https://cert-manager.io/docs/installation/helm/) for the certificate. `edge.expose: loadBalancer` needs neither, because the edge then takes the traffic and obtains the certificate itself.
|
||||||
|
|
||||||
|
The install stops with a message when the cluster has no default StorageClass, no IngressClass, more than one default IngressClass, or no cert-manager while the values ask for it. `clusterChecks: false` turns those checks off for an account that cannot read namespaces, StorageClasses and IngressClasses.
|
||||||
|
|
||||||
|
The volume sizes are upper bounds for most provisioners. Lower the `persistence.size` of each bundled service for a small instance. SeaweedFS keeps working on a small volume because the chart sets `seaweedfs.volumeGrowth` to `1`.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
Get the chart from the repository and write a values file with the hostname:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone --depth 1 https://github.com/fluxerapp/fluxer.git
|
||||||
|
cat > fluxer-values.yaml <<'EOF'
|
||||||
|
domain: chat.example.com
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
Install it into its own namespace:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm install fluxer ./fluxer/deploy/helm/fluxer \
|
||||||
|
--namespace fluxer --create-namespace \
|
||||||
|
-f fluxer-values.yaml --wait --timeout 15m
|
||||||
|
```
|
||||||
|
|
||||||
|
The first install pulls every image, creates the volumes and the buckets, and takes a few minutes. `helm test fluxer -n fluxer` then checks that the edge answers and serves the discovery document for the hostname. Keep `fluxer-values.yaml`, because every later upgrade passes it again.
|
||||||
|
|
||||||
|
:::caution[Finish setup before anyone else reaches the hostname]
|
||||||
|
An unconfigured instance lets any account that registers read and change the instance configuration. Register the first account and finish the wizard in the same sitting that brings the release up, as [Create the first admin](/operator/get-started/#first-run) describes.
|
||||||
|
:::
|
||||||
|
|
||||||
|
## Exposure
|
||||||
|
|
||||||
|
`edge.expose` decides how traffic reaches the edge. The edge routes every path to the right service, so whatever sits in front of it needs one rule that sends the whole hostname to the Service `edge` on port `8080`.
|
||||||
|
|
||||||
|
| `edge.expose` | What the chart renders |
|
||||||
|
| --- | --- |
|
||||||
|
| `ingress` | An Ingress named `fluxer` for the hostname. The default |
|
||||||
|
| `gateway` | An HTTPRoute named `fluxer` attached to `edge.gateway.parentRefs` |
|
||||||
|
| `loadBalancer` | A `LoadBalancer` Service named `edge-public`, with Caddy obtaining its own certificate |
|
||||||
|
| `none` | Only the `ClusterIP` Service `edge`, for a tunnel or a proxy of your own |
|
||||||
|
|
||||||
|
Whatever is in front has to forward WebSocket upgrades, allow request bodies of at least 512 MB, and keep idle connections open for an hour. [Behind your own reverse proxy](/operator/reverse-proxy/) explains each requirement.
|
||||||
|
|
||||||
|
### Ingress
|
||||||
|
|
||||||
|
The Ingress uses the cluster default IngressClass unless `edge.ingress.className` names one. The chart always adds the ingress-nginx annotations for the body size and the timeouts, which other controllers ignore. Other controllers need their equivalents in `edge.ingress.annotations`, or in their own configuration.
|
||||||
|
|
||||||
|
`edge.ingress.tls.mode` picks the certificate:
|
||||||
|
|
||||||
|
| Mode | Certificate |
|
||||||
|
| --- | --- |
|
||||||
|
| `certManager` | A namespaced ACME `Issuer` named `fluxer-acme` issues one into the Secret `fluxer-tls`. The default |
|
||||||
|
| `existingSecret` | The TLS Secret named in `edge.ingress.tls.secretName` |
|
||||||
|
| `none` | No TLS on the Ingress, for a controller that terminates TLS elsewhere |
|
||||||
|
|
||||||
|
`certManager` needs cert-manager in the cluster and the hostname reachable on port 80 for the HTTP challenge. `email` becomes the ACME account address when set.
|
||||||
|
|
||||||
|
### Gateway API
|
||||||
|
|
||||||
|
Set `edge.expose` to `gateway` and point `edge.gateway.parentRefs` at a Gateway that terminates TLS for the hostname. Gateways built on Envoy end requests after 15 seconds by default, which breaks large uploads. Set `edge.gateway.timeouts` to `{request: 0s}` on those, when the implementation supports route timeouts.
|
||||||
|
|
||||||
|
### Load balancer
|
||||||
|
|
||||||
|
Set `edge.expose` to `loadBalancer` on a cluster with no ingress controller. Caddy then obtains and renews the certificate itself, keeps it on a 1 GiB volume, and binds ports 80 and 443 through the namespaced `net.ipv4.ip_unprivileged_port_start` sysctl. `edge.loadBalancer.http3` adds UDP 443 for HTTP/3 on clouds that allow TCP and UDP on one Service. The Service uses `externalTrafficPolicy: Local`, so Caddy sees the client address.
|
||||||
|
|
||||||
|
### Client IP
|
||||||
|
|
||||||
|
Fluxer limits registrations and logins per client address, which it reads from `X-Forwarded-For`. The controller in front must see the real client address. Give its Service `externalTrafficPolicy: Local`, or turn on the PROXY protocol between the load balancer and the controller. Otherwise every client shares the address of a node, and three registrations an hour fill the limit for everyone.
|
||||||
|
|
||||||
|
## Voice
|
||||||
|
|
||||||
|
Voice and video media reach LiveKit on its own ports, never through the edge. Signalling goes through the edge under `/livekit`. `livekit.expose` decides how clients reach the media ports:
|
||||||
|
|
||||||
|
| `livekit.expose` | Ports | Notes |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `hostNetwork` | 7881/tcp and 7882/udp on the node running LiveKit | The default. Needs a namespace that allows privileged pods |
|
||||||
|
| `loadBalancer` | 7881/tcp and 7882/udp on the Service `livekit-rtc` | Needs an address reserved before the install |
|
||||||
|
| `nodePort` | `livekit.nodePorts`, 30881/tcp and 30882/udp by default | LiveKit advertises the node ports |
|
||||||
|
|
||||||
|
With `hostNetwork`, LiveKit also listens on 7880 on the node. Open only the two media ports in the firewall. LiveKit finds its public address over STUN. Set `livekit.nodeIP` when the node cannot reach a STUN server or has several addresses, and pin the pod with `livekit.nodeSelector` so the address stays right. `livekit.extraConfig` merges more [LiveKit configuration](https://docs.livekit.io/home/self-hosting/deployment/) over the chart's.
|
||||||
|
|
||||||
|
With `loadBalancer`, LiveKit advertises one address for both ports, so the chart renders one Service that serves TCP and UDP. Reserve a static public address with your provider first, set `livekit.nodeIP` to it, and ask for it with `livekit.loadBalancerIP` or with your provider's annotation in `livekit.serviceAnnotations`, such as `metallb.io/loadBalancerIPs` on MetalLB. Use `hostNetwork` or `nodePort` where the load balancer cannot serve TCP and UDP on one address.
|
||||||
|
|
||||||
|
### A LiveKit server of your own
|
||||||
|
|
||||||
|
Set `livekit.enabled` to `false` and name your server. `url` is the address the api calls, and `publicUrl` is the one browsers connect to:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
livekit:
|
||||||
|
enabled: false
|
||||||
|
external:
|
||||||
|
url: http://livekit.voice.svc:7880
|
||||||
|
publicUrl: wss://livekit.example.com
|
||||||
|
secrets:
|
||||||
|
values:
|
||||||
|
FLUXER_LIVEKIT_API_KEY: the-livekit-key
|
||||||
|
FLUXER_LIVEKIT_API_SECRET: the-livekit-secret
|
||||||
|
```
|
||||||
|
|
||||||
|
Point the webhook of that server at `https://chat.example.com/api/webhooks/livekit`, signed with the same key. Fluxer tracks who is in a call from those webhooks. `livekit.enabled: false` with no `external.url` turns voice off.
|
||||||
|
|
||||||
|
## Secrets
|
||||||
|
|
||||||
|
The chart keeps every secret in one Secret named `fluxer-env`. Each key below takes its value from `secrets.values`. An empty value is generated on the first install and kept on every upgrade, because the chart reads the existing Secret back. `helm uninstall` leaves the Secret in place, so a reinstall under the same release name and namespace finds the old values and the existing volumes still open.
|
||||||
|
|
||||||
|
| Key | Chart default |
|
||||||
|
| --- | --- |
|
||||||
|
| `FLUXER_POSTGRES_PASSWORD` | Generated, 64 letters and digits |
|
||||||
|
| `FLUXER_SEARCH_API_KEY` | Generated, 64 letters and digits |
|
||||||
|
| `FLUXER_S3_ACCESS_KEY_ID` | The fixed value `fluxer` |
|
||||||
|
| `FLUXER_S3_SECRET_ACCESS_KEY` | Generated, 64 letters and digits |
|
||||||
|
| `FLUXER_SUDO_MODE_SECRET` | Generated, 64 letters and digits |
|
||||||
|
| `FLUXER_CONNECTION_INITIATION_SECRET` | Generated, 64 letters and digits |
|
||||||
|
| `FLUXER_PROFILE_PSEUDONYM_SECRET` | Generated, 64 letters and digits |
|
||||||
|
| `FLUXER_GATEWAY_RPC_AUTH_TOKEN` | Generated, 64 letters and digits |
|
||||||
|
| `FLUXER_VALKEY_PASSWORD` | Generated, 64 letters and digits |
|
||||||
|
| `FLUXER_NATS_AUTH_TOKEN` | Generated, 64 letters and digits |
|
||||||
|
| `FLUXER_ERLANG_COOKIE` | Generated, 64 letters and digits |
|
||||||
|
| `FLUXER_MEDIA_PROXY_SECRET_KEY` | Generated, 64 letters and digits |
|
||||||
|
| `FLUXER_MEDIA_PROXY_UPLOAD_RELAY_SECRET_BASE64` | Generated, 32 random bytes in base64 |
|
||||||
|
| `FLUXER_ADMIN_SECRET_KEY_BASE` | Generated, 64 letters and digits |
|
||||||
|
| `FLUXER_ADMIN_OAUTH_CLIENT_SECRET` | Generated, 64 letters and digits |
|
||||||
|
| `FLUXER_LIVEKIT_API_KEY` | The fixed value `fluxer` |
|
||||||
|
| `FLUXER_LIVEKIT_API_SECRET` | Generated, 64 letters and digits |
|
||||||
|
| `FLUXER_VAPID_PUBLIC_KEY` | Generated P-256 pair |
|
||||||
|
| `FLUXER_VAPID_PRIVATE_KEY` | Generated P-256 pair |
|
||||||
|
|
||||||
|
[Secrets you must generate](/operator/configuration/#secrets-you-must-generate) explains what each one protects and what changing it does. `FLUXER_VALKEY_PASSWORD` and `FLUXER_NATS_AUTH_TOKEN` exist only in the chart, which gives the bundled Valkey and NATS a login. Every Fluxer service reads the whole Secret, as every service does under Compose.
|
||||||
|
|
||||||
|
The chart refuses any value that contains `CHANGE_ME`, a signing secret, token or cookie under 32 characters, a relay secret that does not decode to 32 bytes, the Postgres password `fluxer`, half a VAPID pair, and anything but letters and digits in the credentials of the bundled SeaweedFS, Valkey and NATS. A value set in `secrets.values` after the first install replaces the stored one, except that the Postgres role keeps its old password until you change it inside the database:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n fluxer exec postgres-0 -- psql -U fluxer -c "ALTER ROLE fluxer PASSWORD 'the-new-password'"
|
||||||
|
```
|
||||||
|
|
||||||
|
`secrets.extra` adds optional secret-bearing settings to the same Secret, such as `FLUXER_EMAIL_SMTP_PASSWORD`, `FLUXER_STRIPE_SECRET_KEY` or `FLUXER_POSTGRES_URL`. The chart's `values.yaml` lists each one with a line on what it does.
|
||||||
|
|
||||||
|
### A Secret you manage
|
||||||
|
|
||||||
|
Set `secrets.existingSecret` to the name of a Secret you create, holding every key in the table above. The chart then renders no Secret and never changes yours. The install stops when the Secret does not exist, lacks a key, or holds a setting that disagrees with one the chart sets itself, and it names the Secret and the keys. After editing it, restart the release so the pods read the new values:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n fluxer rollout restart deployment,statefulset -l app.kubernetes.io/instance=fluxer
|
||||||
|
```
|
||||||
|
|
||||||
|
### GitOps
|
||||||
|
|
||||||
|
Argo CD renders the chart with `helm template`, which cannot read the existing Secret, so generated values would change on every sync. Under Argo CD, set `secrets.generate: false` and either use `secrets.existingSecret` or give every key in `secrets.values`. Flux and Helmfile run a real `helm upgrade` and keep generated values. A render without a cluster skips the checks that read the cluster and the existing Secret.
|
||||||
|
|
||||||
|
## Settings
|
||||||
|
|
||||||
|
`env` passes settings to every Fluxer service as `NAME: value`. The names and their meanings are on [Configuration](/operator/configuration/), and an empty value is left out. For example:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
env:
|
||||||
|
FLUXER_EMAIL_ENABLED: "true"
|
||||||
|
FLUXER_EMAIL_PROVIDER: smtp
|
||||||
|
FLUXER_EMAIL_FROM_EMAIL: [email protected]
|
||||||
|
FLUXER_EMAIL_SMTP_HOST: smtp.example.com
|
||||||
|
FLUXER_EMAIL_SMTP_PORT: "587"
|
||||||
|
FLUXER_EMAIL_SMTP_USERNAME: fluxer
|
||||||
|
secrets:
|
||||||
|
extra:
|
||||||
|
FLUXER_EMAIL_SMTP_PASSWORD: the-smtp-password
|
||||||
|
```
|
||||||
|
|
||||||
|
`env` lands in a ConfigMap, so the chart refuses a secret there, by name or as a URL that holds a password, and points at `secrets.extra`.
|
||||||
|
|
||||||
|
Each workload also takes its own `env`, which wins over the shared one for that workload alone. `appProxy.config` holds the branding and Content Security Policy names that only `app-proxy` reads. The chart derives every public URL from `domain`, `scheme`, `port` and `publicOrigin` the way Compose does, and sets the [fixed wiring](/operator/configuration/#fixed-wiring) itself.
|
||||||
|
|
||||||
|
Every workload takes `replicas`, `resources`, `nodeSelector`, `tolerations`, `affinity`, `topologySpreadConstraints`, `pdb` and `hpa`. `worker` stays at one replica, because it runs the scheduled jobs. `svc.<name>.shard.replicas` sets the shard count of each internal service.
|
||||||
|
|
||||||
|
Every image can come from a mirror. `image.registry` moves the Fluxer images, and each bundled service and `initImage` takes a `repository`, a `tag` and a `digest`.
|
||||||
|
|
||||||
|
## External services
|
||||||
|
|
||||||
|
Each bundled backing service can be swapped for your own. Turn the bundled one off and say where yours is:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
postgres:
|
||||||
|
enabled: false
|
||||||
|
external:
|
||||||
|
host: db.example.com
|
||||||
|
ssl: "true"
|
||||||
|
valkey:
|
||||||
|
enabled: false
|
||||||
|
external:
|
||||||
|
url: redis://cache.example.com:6379/0
|
||||||
|
nats:
|
||||||
|
enabled: false
|
||||||
|
external:
|
||||||
|
url: nats://mq.example.com:4222
|
||||||
|
meilisearch:
|
||||||
|
enabled: false
|
||||||
|
external:
|
||||||
|
url: https://search.example.com
|
||||||
|
seaweedfs:
|
||||||
|
enabled: false
|
||||||
|
s3:
|
||||||
|
endpoint: https://s3.eu-central-1.amazonaws.com
|
||||||
|
publicEndpoint: https://cdn.example.com
|
||||||
|
region: eu-central-1
|
||||||
|
forcePathStyle: false
|
||||||
|
secrets:
|
||||||
|
values:
|
||||||
|
FLUXER_POSTGRES_PASSWORD: the-database-password
|
||||||
|
FLUXER_SEARCH_API_KEY: the-search-key
|
||||||
|
FLUXER_S3_ACCESS_KEY_ID: the-access-key
|
||||||
|
FLUXER_S3_SECRET_ACCESS_KEY: the-secret-key
|
||||||
|
FLUXER_NATS_AUTH_TOKEN: the-nats-token
|
||||||
|
```
|
||||||
|
|
||||||
|
The chart generates no password, search key or S3 secret for a service it does not run, so those three are required. `FLUXER_NATS_AUTH_TOKEN` is for a NATS server that asks for a token. An outside Postgres needs the database and the role to exist, and an outside S3 store needs the four buckets in `s3.buckets`. A URL that holds a password goes in `secrets.extra` as `FLUXER_KV_URL` or `FLUXER_POSTGRES_URL` instead. [A LiveKit server of your own](#a-livekit-server-of-your-own) covers voice.
|
||||||
|
|
||||||
|
## Network policy
|
||||||
|
|
||||||
|
The chart renders NetworkPolicies by default. They admit traffic to the release pods only from the release itself, to the edge on port 8080 from anywhere, and to the LiveKit media ports. No other namespace reaches Postgres, Valkey, NATS, Meilisearch, SeaweedFS or a Fluxer service directly. Network plugins without NetworkPolicy support ignore them, and `networkPolicy.enabled: false` leaves them out.
|
||||||
|
|
||||||
|
The bundled services also check a login of their own, which holds on any network plugin. Postgres, Valkey, NATS, Meilisearch and the S3 port of SeaweedFS each ask for the credential in the Secret, and the other SeaweedFS ports listen only inside its pod.
|
||||||
|
|
||||||
|
`networkPolicy.ingressNamespaceSelector` narrows the edge to the namespace of your ingress controller. LiveKit on the host network sends its webhook to the edge from a node address, so that selector also needs the address of the LiveKit node in `livekit.nodeCIDRs`, and the install stops without it. To let something else in, such as a metrics scraper or a backup job in another namespace, add a NetworkPolicy of your own beside the chart's.
|
||||||
|
|
||||||
|
## Upgrade
|
||||||
|
|
||||||
|
Pull the repository so the chart matches the images, then upgrade with the same values file. A new `image.revision` restarts every Fluxer pod, which pulls the current `v1` images:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git -C fluxer pull
|
||||||
|
helm upgrade fluxer ./fluxer/deploy/helm/fluxer -n fluxer -f fluxer-values.yaml \
|
||||||
|
--set-string image.revision=$(date +%s) --wait --timeout 15m
|
||||||
|
```
|
||||||
|
|
||||||
|
Pass the values file every time and leave out `--reuse-values`, which keeps the defaults of the chart version you installed and fails once a newer chart adds a setting. Generated secrets survive either way, because the chart reads them back from the Secret.
|
||||||
|
|
||||||
|
An upgrade restarts only the pods whose settings changed. A new chart version alone restarts nothing, a changed setting in `env` restarts the Fluxer pods, and each backing service restarts only when its own settings or image change. `helm rollback` returns to the previous values, and never undoes a schema change.
|
||||||
|
|
||||||
|
### Pin the images
|
||||||
|
|
||||||
|
`v1` is a moving tag and the chart pulls it whenever a pod starts. A pod that restarts by itself, after a node drain or a crash, therefore runs the newest `v1` build beside older ones, and a rollback cannot return to an earlier build. Pin the builds that are running once an upgrade has settled:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
{
|
||||||
|
echo "image:"
|
||||||
|
echo " digests:"
|
||||||
|
kubectl -n fluxer get pods -l app.kubernetes.io/part-of=fluxer \
|
||||||
|
-o jsonpath='{range .items[*].status.containerStatuses[*]}{.imageID}{"\n"}{end}' \
|
||||||
|
| sed -n 's|.*/\(fluxer-[a-z-]*\)@\(sha256:[0-9a-f]*\)$| \1: \2|p' | sort -u
|
||||||
|
} > fluxer-images.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
Pass `-f fluxer-images.yaml` after the values file on the next upgrade. Every pod then stays on those builds until you upgrade without the file and write a new one. `image.tags` pins one image to a release tag instead, keyed by image name such as `fluxer-api`.
|
||||||
|
|
||||||
|
### Grow a volume
|
||||||
|
|
||||||
|
`persistence.size` and `storageClassName` take effect only when a volume is first created, and Kubernetes refuses an upgrade that changes them afterwards. To grow a volume, edit the claim on a StorageClass that allows expansion, then let the chart catch up:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n fluxer patch pvc data-postgres-0 -p '{"spec":{"resources":{"requests":{"storage":"50Gi"}}}}'
|
||||||
|
kubectl -n fluxer delete statefulset postgres --cascade=orphan
|
||||||
|
```
|
||||||
|
|
||||||
|
Set `postgres.persistence.size` to the same size in the values file and upgrade. The upgrade creates the StatefulSet again around the running pod and its claim, and the pod may restart once.
|
||||||
|
|
||||||
|
### A new Postgres major
|
||||||
|
|
||||||
|
A new Postgres major does not read the old data directory, and the `postgres` pod stops with a message naming both majors. Setting `postgres.image.tag` back to the old major replaces the stopped pod by itself. Dump the database first, then move to the new major as [Move to a new Postgres major version](/operator/upgrading/#move-to-a-new-postgres-major-version) describes, with `kubectl exec postgres-0` in place of `docker compose exec postgres`. `postgres.runAsUser` is `70` for the Alpine images and `999` for the Debian ones.
|
||||||
|
|
||||||
|
## Backups
|
||||||
|
|
||||||
|
Back up the Secret, the database and the uploads. [Volumes and buckets](/operator/configuration/#volumes-and-buckets) says what each of the other volumes holds. The claims are named `data-<service>-0`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n fluxer get secret fluxer-env -o yaml > fluxer-env.yaml
|
||||||
|
kubectl -n fluxer exec postgres-0 -- sh -c 'pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" --format=custom' > fluxer.dump
|
||||||
|
```
|
||||||
|
|
||||||
|
Keep `fluxer-env.yaml` as safe as the database. Without it a restored database has no matching Postgres password, and every signed session and token stops working.
|
||||||
|
|
||||||
|
Uploads live on the volume `data-seaweedfs-0`. Snapshot it with your storage provider's VolumeSnapshot class. Without one, stop the store and copy the volume out through a helper pod:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n fluxer scale statefulset seaweedfs --replicas=0
|
||||||
|
kubectl -n fluxer wait pod/seaweedfs-0 --for=delete --timeout=2m
|
||||||
|
kubectl -n fluxer apply -f - <<'EOF'
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Pod
|
||||||
|
metadata:
|
||||||
|
name: uploads-copy
|
||||||
|
spec:
|
||||||
|
securityContext:
|
||||||
|
runAsUser: 1000
|
||||||
|
runAsGroup: 1000
|
||||||
|
fsGroup: 1000
|
||||||
|
containers:
|
||||||
|
- name: copy
|
||||||
|
image: busybox:1.37
|
||||||
|
command: ["sleep", "86400"]
|
||||||
|
volumeMounts:
|
||||||
|
- name: data
|
||||||
|
mountPath: /data
|
||||||
|
volumes:
|
||||||
|
- name: data
|
||||||
|
persistentVolumeClaim:
|
||||||
|
claimName: data-seaweedfs-0
|
||||||
|
EOF
|
||||||
|
kubectl -n fluxer wait pod/uploads-copy --for=condition=Ready --timeout=2m
|
||||||
|
kubectl -n fluxer exec uploads-copy -- tar czf - -C /data . > seaweedfs-data.tgz
|
||||||
|
kubectl -n fluxer delete pod uploads-copy
|
||||||
|
kubectl -n fluxer scale statefulset seaweedfs --replicas=1
|
||||||
|
```
|
||||||
|
|
||||||
|
Uploads and downloads fail while the store is stopped.
|
||||||
|
|
||||||
|
### Restore
|
||||||
|
|
||||||
|
Restore into a fresh install. Put the Secret back first, so the chart adopts it and the new database takes the old password:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl create namespace fluxer
|
||||||
|
kubectl apply -f fluxer-env.yaml
|
||||||
|
helm install fluxer ./fluxer/deploy/helm/fluxer -n fluxer -f fluxer-values.yaml --wait --timeout 15m
|
||||||
|
```
|
||||||
|
|
||||||
|
Stop everything but Postgres, so nothing writes while the data is replaced, and restore the dump:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n fluxer scale deployment,statefulset --replicas=0 \
|
||||||
|
-l 'app.kubernetes.io/part-of=fluxer,app.kubernetes.io/name notin (postgres)'
|
||||||
|
kubectl -n fluxer exec -i postgres-0 -- sh -c 'pg_restore -U "$POSTGRES_USER" -d "$POSTGRES_DB" --clean --if-exists' < fluxer.dump
|
||||||
|
```
|
||||||
|
|
||||||
|
Start the `uploads-copy` pod from [Backups](#backups) again and unpack the uploads over the volume:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n fluxer exec -i uploads-copy -- sh -c 'find /data -mindepth 1 -delete && tar xzf - -C /data' < seaweedfs-data.tgz
|
||||||
|
kubectl -n fluxer delete pod uploads-copy
|
||||||
|
```
|
||||||
|
|
||||||
|
An upgrade with the same values then puts every replica count back:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm upgrade fluxer ./fluxer/deploy/helm/fluxer -n fluxer -f fluxer-values.yaml --wait --timeout 15m
|
||||||
|
```
|
||||||
|
|
||||||
|
A workload with an `hpa` has no replica count in the chart, so scale it back with `kubectl scale`. [Restore a backup](/operator/upgrading/#restore-a-backup) has the reasoning behind each step, and [Volumes and buckets](/operator/configuration/#volumes-and-buckets) covers rebuilding the search index.
|
||||||
|
|
||||||
|
## Uninstall
|
||||||
|
|
||||||
|
```bash
|
||||||
|
helm uninstall fluxer -n fluxer
|
||||||
|
```
|
||||||
|
|
||||||
|
The Secret `fluxer-env` and the volumes stay, so a later install under the same release name and namespace picks up the same data. A release with another name cannot adopt the kept Secret. Pass `secrets.existingSecret: fluxer-env` to that release to reuse it. To remove everything, delete them too:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl -n fluxer delete secret fluxer-env
|
||||||
|
kubectl -n fluxer delete pvc -l app.kubernetes.io/instance=fluxer
|
||||||
|
kubectl delete namespace fluxer
|
||||||
|
```
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
import {readdirSync, readFileSync} from 'node:fs';
|
||||||
|
import path from 'node:path';
|
||||||
|
import {fileURLToPath} from 'node:url';
|
||||||
|
import {describe, expect, test} from 'vitest';
|
||||||
|
|
||||||
|
const REPO_ROOT = fileURLToPath(new URL('../../../../', import.meta.url));
|
||||||
|
const CHART = path.join(REPO_ROOT, 'deploy/helm/fluxer');
|
||||||
|
const CONFIGURATION_PAGE = path.join(REPO_ROOT, 'fluxer_docs/src/content/docs/operator/configuration.mdx');
|
||||||
|
|
||||||
|
const fixedWiringNames = (): Array<string> => {
|
||||||
|
const page = readFileSync(CONFIGURATION_PAGE, 'utf8');
|
||||||
|
const start = page.indexOf('#### Fixed wiring');
|
||||||
|
const end = page.indexOf('\n#### ', start + 1);
|
||||||
|
const section = page.slice(start, end);
|
||||||
|
return [...new Set([...section.matchAll(/`([A-Z][A-Z0-9_]*)`/g)].map(([, name]) => name))].sort();
|
||||||
|
};
|
||||||
|
|
||||||
|
const chartTemplates = (): string => {
|
||||||
|
const directory = path.join(CHART, 'templates');
|
||||||
|
return readdirSync(directory)
|
||||||
|
.filter((name) => name.endsWith('.yaml') || name.endsWith('.tpl'))
|
||||||
|
.map((name) => readFileSync(path.join(directory, name), 'utf8'))
|
||||||
|
.join('\n');
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('the Helm chart matches the Compose stack', () => {
|
||||||
|
test('the chart ships the same Caddyfile as Compose', () => {
|
||||||
|
const compose = readFileSync(path.join(REPO_ROOT, 'deploy/self-hosting/Caddyfile'));
|
||||||
|
const chart = readFileSync(path.join(CHART, 'files/Caddyfile'));
|
||||||
|
expect(chart.equals(compose)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('the chart sets every name Compose pins as fixed wiring', () => {
|
||||||
|
const names = fixedWiringNames();
|
||||||
|
expect(names.length).toBeGreaterThan(10);
|
||||||
|
const templates = chartTemplates();
|
||||||
|
const missing = names.filter((name) => !templates.includes(`"${name}"`));
|
||||||
|
expect(missing).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in new issue
Block a user