Merge pull request #3743 from bluewave-labs/feat/helm
feat: Update helm charts
This commit is contained in:
29 files changed
+487
-187
No files matched your search
@@ -2,5 +2,5 @@ apiVersion: v2
|
||||
name: checkmate-chart
|
||||
description: A Helm chart for Checkmate App
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "2.3"
|
||||
version: 0.2.0
|
||||
appVersion: "v3.8.1" # "v" prefix: published image tags are v-prefixed (ghcr.io/.../checkmate-*:v3.8.1)
|
||||
@@ -19,12 +19,11 @@ cd checkmate/charts/helm/checkmate
|
||||
|
||||
### 2. Customize values.yaml
|
||||
Edit `values.yaml` to update:
|
||||
- `client.ingress.host` and `server.ingress.host` with your domain names
|
||||
- `server.protocol` (usually http or https)
|
||||
- `client.ingress.host` and `api.ingress.host` with your domain names
|
||||
- `api.protocol` (usually http or https)
|
||||
- **If upgrading**: Migrate persistence settings from flat structure to nested:
|
||||
- Old: `persistence.mongodbSize` → New: `persistence.mongo.size`
|
||||
- Old: `persistence.redisSize` → New: `persistence.redis.size`
|
||||
- Add: `persistence.mongo.storageClass` and `persistence.redis.storageClass` (leave empty for default)
|
||||
- Add: `persistence.mongo.storageClass` (leave empty for default)
|
||||
- Secrets under the `secrets` section (`JWT_SECRET`, email credentials, API keys, etc.) — replace all change_me values
|
||||
- **For TLS/HTTPS**: Configure ingress TLS settings (see section below)
|
||||
|
||||
@@ -32,7 +31,7 @@ Edit `values.yaml` to update:
|
||||
```bash
|
||||
helm install checkmate ./charts/helm/checkmate
|
||||
```
|
||||
This will deploy the client, server, MongoDB, and Redis components.
|
||||
This will deploy the client, api, and MongoDB components.
|
||||
|
||||
### 4. Verify the deployment
|
||||
Check pods and services:
|
||||
@@ -43,6 +42,137 @@ kubectl get svc
|
||||
|
||||
Once all pods are `Running` and `Ready`, you can access Checkmate via the configured ingress hosts.
|
||||
|
||||
## Upgrading from a previous release
|
||||
|
||||
This release renames the `server.*` value block to `api.*` and drops the (unused) bundled Redis.
|
||||
Read this before running `helm upgrade` on an existing install.
|
||||
|
||||
### `server.*` → `api.*` (values rename)
|
||||
|
||||
The value block formerly named `server` is now `api` (`server.image` → `api.image`,
|
||||
`server.ingress.host` → `api.ingress.host`, `server.protocol` → `api.protocol`, `server.resources`,
|
||||
`server.affinity`, `server.tolerations`, `server.ingress.*`, etc.).
|
||||
|
||||
**Your existing `server.*` overrides keep working** — the chart merges any legacy `server.*` values on
|
||||
top of the `api.*` defaults (legacy wins where set), so an unchanged values file upgrades cleanly. The
|
||||
shim is transitional; migrate your overrides to `api.*` at your convenience and drop the `server:`
|
||||
block. If you set **both** `server.*` and `api.*` for the same field, the legacy `server.*` value wins —
|
||||
don't mix them.
|
||||
|
||||
### Resource renames cause a replace, not a rename
|
||||
|
||||
The Kubernetes objects are renamed alongside the values:
|
||||
|
||||
| Old object | New object |
|
||||
| --- | --- |
|
||||
| Deployment/Service `checkmate-server` | `checkmate-api` |
|
||||
| Ingress `checkmate-server-ingress` | `checkmate-api-ingress` |
|
||||
| ConfigMap `checkmate-server-nginx-cm` | `checkmate-client-nginx-cm` |
|
||||
|
||||
Helm deletes the old objects and creates the new ones on upgrade. Expect a brief API restart and a
|
||||
**new ClusterIP** for the API Service — update anything outside the chart that referenced the
|
||||
`checkmate-server` Service by name. MongoDB data (its PVC) is untouched.
|
||||
|
||||
### Redis removed
|
||||
|
||||
The bundled Redis StatefulSet/Service and the `redis.*` / `persistence.redis.*` values are gone — the
|
||||
scheduler runs in-process and never used them. Default installs (`redis.enabled: false`) are
|
||||
unaffected. If you had explicitly set `redis.enabled: true`, **the Redis StatefulSet and its PVC are
|
||||
deleted on upgrade** — back up anything you stored there first. Leftover `redis:` / `persistence.redis:`
|
||||
keys in your values file are harmless (ignored).
|
||||
|
||||
### New secret defaults
|
||||
|
||||
`NODE_ENV: production`, `LOG_LEVEL: info`, and `TOKEN_TTL: 99d` are now part of the default `secrets`
|
||||
block and merge into your install unless you override them. Set them explicitly if you relied on
|
||||
different values (e.g. a non-production `NODE_ENV`).
|
||||
|
||||
### Image tags follow the chart's `appVersion`
|
||||
|
||||
Each tier's `image` value is now the repository **without a tag**; the tag defaults to the chart's
|
||||
`appVersion`, so the client, api, worker, and mongodb images all move together when you upgrade the
|
||||
chart. You can still pin per tier:
|
||||
|
||||
```yaml
|
||||
api:
|
||||
image: ghcr.io/bluewave-labs/checkmate-backend # repo only
|
||||
tag: "" # empty → Chart.appVersion; set e.g. "v3.1.0" to pin, or "latest" for a dev tag
|
||||
```
|
||||
|
||||
- `<tier>.tag` overrides the version for that tier. The `worker` tier inherits `api.tag` (and
|
||||
`api.image`) unless you set `worker.tag` / `worker.image`.
|
||||
- If you put a **full `repo:tag`** in `image` (e.g. a legacy `server.image: …:v3.2.0` override), it is
|
||||
used verbatim and the `tag` field is ignored — so existing pinned values keep working unchanged.
|
||||
|
||||
**Prefer a pinned tag over `latest`.** With the default `imagePullPolicy: IfNotPresent`, `latest` is
|
||||
cached per node and never refreshed, and `helm rollback` can't move a floating tag — pin a version (or
|
||||
let it default to `appVersion`) for reproducible, rollback-able deploys.
|
||||
|
||||
## Scaling: the worker tier & autoscaling
|
||||
|
||||
By default the chart runs a single all-in-one API pod that both schedules **and** processes monitoring
|
||||
jobs (`worker.enabled: false`). For larger deployments you can split processing onto a dedicated,
|
||||
horizontally-scalable worker tier.
|
||||
|
||||
### Topology
|
||||
|
||||
| `worker.enabled` | API (`checkmate-api`) | Worker (`checkmate-worker`) |
|
||||
| --- | --- | --- |
|
||||
| `false` (default) | schedules **and** processes jobs (`QUEUE_PRIMARY_PROCESSES=true`) | not deployed |
|
||||
| `true` | schedules + serves the API only (`QUEUE_PRIMARY_PROCESSES=false`, derived) | processes all jobs |
|
||||
|
||||
`QUEUE_PRIMARY_PROCESSES` is **derived** from `worker.enabled` — you never set it directly, so the API
|
||||
and worker tier can never both process (or both ignore) the queue.
|
||||
|
||||
### Enabling the worker tier
|
||||
|
||||
```yaml
|
||||
worker:
|
||||
enabled: true
|
||||
replicas: 2 # used only when autoscaling.enabled = false
|
||||
```
|
||||
|
||||
The worker takes **no inbound traffic** (no Service): the kubelet probes pod IPs directly on
|
||||
`HEALTH_PORT` (`/livez`, `/readyz`), and graceful shutdown drains in-flight jobs before exit.
|
||||
|
||||
> **Invariant:** `worker.terminationGracePeriodSeconds` (default `30`) **must stay greater than the
|
||||
> server drain timeout (25s)**. Lower it and Kubernetes SIGKILLs workers mid-drain, losing in-flight
|
||||
> checks.
|
||||
|
||||
> **Caveat:** with the worker tier enabled the API no longer processes jobs, so if **all** workers are
|
||||
> down nothing processes. The `autoscaling.minReplicaCount: 1` floor plus liveness restarts mitigate
|
||||
> this; full failover to the API would need leader election (not supported).
|
||||
|
||||
### Autoscaling with KEDA
|
||||
|
||||
Backlog-driven autoscaling is **off by default** and requires the
|
||||
[KEDA operator](https://keda.sh/) installed in-cluster. Enable it with:
|
||||
|
||||
```yaml
|
||||
worker:
|
||||
enabled: true
|
||||
autoscaling:
|
||||
enabled: true
|
||||
minReplicaCount: 1 # processing floor — never 0, or checks silently stall
|
||||
maxReplicaCount: 10
|
||||
backlogPerReplica: 50 # target due-job backlog per worker
|
||||
mongo:
|
||||
dbName: uptime_db # MUST match the database in DB_CONNECTION_STRING
|
||||
```
|
||||
|
||||
A KEDA `ScaledObject` queries MongoDB directly for the due-check backlog and scales the worker
|
||||
Deployment between `minReplicaCount` and `maxReplicaCount`. When autoscaling is on, the Deployment
|
||||
omits `replicas` so it doesn't fight the HPA KEDA creates. Make sure `autoscaling.mongo.dbName`
|
||||
matches the database name in your `DB_CONNECTION_STRING`, or the scaler counts the wrong DB (always 0
|
||||
backlog → never scales up).
|
||||
|
||||
#### Fallback: Prometheus-adapter HPA (not shipped)
|
||||
|
||||
If your KEDA/Mongo versions reject the `$$NOW`/`$toLong` query, or you already run Prometheus, scrape
|
||||
the worker's `/metrics` (`checkmate_worker_due_backlog`), expose it via prometheus-adapter, and target
|
||||
it with a standard `HorizontalPodAutoscaler`. The manifest is left to the operator; the app computes
|
||||
`now` in code on this path, so the query coercion is unnecessary.
|
||||
|
||||
## Enabling TLS/HTTPS with cert-manager
|
||||
|
||||
If you have [cert-manager](https://cert-manager.io/) installed in your cluster, you can enable automatic TLS certificate provisioning using Let's Encrypt or other certificate issuers.
|
||||
@@ -68,7 +198,7 @@ client:
|
||||
enabled: true
|
||||
secretName: checkmate-client-tls
|
||||
|
||||
server:
|
||||
api:
|
||||
protocol: https
|
||||
ingress:
|
||||
enabled: true
|
||||
@@ -78,7 +208,7 @@ server:
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
tls:
|
||||
enabled: true
|
||||
secretName: checkmate-server-tls
|
||||
secretName: checkmate-api-tls
|
||||
```
|
||||
|
||||
### Alternative: Using --set flags
|
||||
@@ -88,13 +218,13 @@ You can also enable TLS during installation using Helm's `--set` flags:
|
||||
```bash
|
||||
helm install checkmate ./charts/helm/checkmate \
|
||||
--set client.protocol=https \
|
||||
--set server.protocol=https \
|
||||
--set api.protocol=https \
|
||||
--set client.ingress.annotations."cert-manager\.io/cluster-issuer"="letsencrypt-prod" \
|
||||
--set client.ingress.tls.enabled=true \
|
||||
--set client.ingress.tls.secretName=checkmate-client-tls \
|
||||
--set server.ingress.annotations."cert-manager\.io/cluster-issuer"="letsencrypt-prod" \
|
||||
--set server.ingress.tls.enabled=true \
|
||||
--set server.ingress.tls.secretName=checkmate-server-tls
|
||||
--set api.ingress.annotations."cert-manager\.io/cluster-issuer"="letsencrypt-prod" \
|
||||
--set api.ingress.tls.enabled=true \
|
||||
--set api.ingress.tls.secretName=checkmate-api-tls
|
||||
```
|
||||
|
||||
### Verification
|
||||
@@ -107,7 +237,7 @@ kubectl get certificates
|
||||
|
||||
# Check certificate details
|
||||
kubectl describe certificate checkmate-client-tls
|
||||
kubectl describe certificate checkmate-server-tls
|
||||
kubectl describe certificate checkmate-api-tls
|
||||
|
||||
# Verify the secrets were created
|
||||
kubectl get secrets | grep checkmate-tls
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
{{- /*
|
||||
Back-compat shim: the `server.*` value block was renamed to `api.*`. Existing installs that
|
||||
still pass a legacy `server:` block keep working — this returns the effective API values with any
|
||||
legacy `server.*` overrides merged on top of the `api.*` defaults (legacy wins where set).
|
||||
|
||||
New installs have no `server:` key, so this is a no-op deepCopy of `.Values.api`. Consume it as:
|
||||
{{- $api := include "checkmate.api" . | fromYaml -}}
|
||||
then reference `$api.*` instead of `.Values.api.*`.
|
||||
*/}}
|
||||
{{- define "checkmate.api" -}}
|
||||
{{- $api := deepCopy .Values.api -}}
|
||||
{{- with .Values.server -}}
|
||||
{{- $api = mergeOverwrite $api (deepCopy .) -}}
|
||||
{{- end -}}
|
||||
{{- $api | toYaml -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- /*
|
||||
Resolve a full image reference from a repo + optional tag. `appVersion` is the single source of
|
||||
truth for tags: bumping Chart.appVersion moves every tier at once. Call as:
|
||||
{{ include "checkmate.image" (dict "image" $repo "tag" $tag "root" $) }}
|
||||
|
||||
If `image` already carries a tag (a ":" in its final path segment) it is used verbatim — this keeps
|
||||
legacy `server.image: repo:tag` overrides working and lets anyone pin a full ref (e.g. tag "latest").
|
||||
A ":" only in the registry segment (a registry port like "reg:5000/x") is ignored, so a tag is still
|
||||
appended. Otherwise the tag is `tag` if set, else the chart's appVersion.
|
||||
*/}}
|
||||
{{- define "checkmate.image" -}}
|
||||
{{- $lastSegment := .image | splitList "/" | last -}}
|
||||
{{- if contains ":" $lastSegment -}}
|
||||
{{- .image -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s:%s" .image (.tag | default .root.Chart.AppVersion) -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
@@ -0,0 +1,65 @@
|
||||
{{- $api := include "checkmate.api" . | fromYaml -}}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: checkmate-api
|
||||
spec:
|
||||
replicas: 1 # single scheduler — seeds/reconciles the jobs collection
|
||||
selector:
|
||||
matchLabels:
|
||||
app: checkmate-api
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: checkmate-api
|
||||
spec:
|
||||
{{- with $api.affinity }}
|
||||
affinity:
|
||||
{{- tpl ( . | toYaml) $ | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with $api.tolerations }}
|
||||
tolerations:
|
||||
{{- tpl ( . | toYaml) $ | nindent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: api
|
||||
image: {{ include "checkmate.image" (dict "image" $api.image "tag" $api.tag "root" $) }}
|
||||
imagePullPolicy: {{ $api.imagePullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ $api.port }}
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: checkmate-secrets
|
||||
# Probes hit the Express /api/v1/health endpoint — proves the HTTP server is responsive.
|
||||
# NOTE: this does NOT detect a wedged job loop when queuePrimaryProcesses=true (the API is
|
||||
# also a worker). Worker-aware health for that mode is a follow-up — see worker-health-checks.md §7.5.
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /api/v1/health
|
||||
port: http
|
||||
initialDelaySeconds: {{ $api.probes.liveness.initialDelaySeconds }}
|
||||
periodSeconds: {{ $api.probes.liveness.periodSeconds }}
|
||||
timeoutSeconds: {{ $api.probes.liveness.timeoutSeconds }}
|
||||
failureThreshold: {{ $api.probes.liveness.failureThreshold }}
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /api/v1/health
|
||||
port: http
|
||||
initialDelaySeconds: {{ $api.probes.readiness.initialDelaySeconds }}
|
||||
periodSeconds: {{ $api.probes.readiness.periodSeconds }}
|
||||
timeoutSeconds: {{ $api.probes.readiness.timeoutSeconds }}
|
||||
failureThreshold: {{ $api.probes.readiness.failureThreshold }}
|
||||
{{- with $api.resources }}
|
||||
resources:
|
||||
{{- tpl ( . | toYaml) $ | nindent 12 }}
|
||||
{{- end }}
|
||||
env:
|
||||
- name: CLIENT_HOST
|
||||
value: "{{ .Values.client.protocol }}://{{ .Values.client.ingress.host }}"
|
||||
- name: QUEUE_MODE
|
||||
value: "primary"
|
||||
# Derived: when a worker tier is deployed the API only schedules (false); otherwise it is
|
||||
# all-in-one and processes jobs itself (true). Keeps the two from ever competing for jobs.
|
||||
- name: QUEUE_PRIMARY_PROCESSES
|
||||
value: {{ not .Values.worker.enabled | quote }}
|
||||
+12
-11
@@ -1,11 +1,12 @@
|
||||
{{- if .Values.server.ingress.enabled }}
|
||||
{{- $api := include "checkmate.api" . | fromYaml -}}
|
||||
{{- if $api.ingress.enabled }}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: checkmate-server-ingress
|
||||
{{- if .Values.server.ingress.annotations }}
|
||||
name: checkmate-api-ingress
|
||||
{{- if $api.ingress.annotations }}
|
||||
annotations:
|
||||
{{- range $key, $value := .Values.server.ingress.annotations }}
|
||||
{{- range $key, $value := $api.ingress.annotations }}
|
||||
{{ $key }}: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -17,22 +18,22 @@ metadata:
|
||||
#nginx.ingress.kubernetes.io/cors-allow-headers: "DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization"
|
||||
#nginx.ingress.kubernetes.io/cors-allow-credentials: "true"*/}}
|
||||
spec:
|
||||
ingressClassName: {{ .Values.server.ingress.className }}
|
||||
{{- if .Values.server.ingress.tls.enabled }}
|
||||
ingressClassName: {{ $api.ingress.className }}
|
||||
{{- if $api.ingress.tls.enabled }}
|
||||
tls:
|
||||
- hosts:
|
||||
- {{ .Values.server.ingress.host }}
|
||||
secretName: {{ default (printf "%s-server-tls" .Release.Name) .Values.server.ingress.tls.secretName }}
|
||||
- {{ $api.ingress.host }}
|
||||
secretName: {{ default (printf "%s-api-tls" .Release.Name) $api.ingress.tls.secretName }}
|
||||
{{- end }}
|
||||
rules:
|
||||
- host: {{ .Values.server.ingress.host }}
|
||||
- host: {{ $api.ingress.host }}
|
||||
http:
|
||||
paths:
|
||||
- path: /api/v1
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: checkmate-server
|
||||
name: checkmate-api
|
||||
port:
|
||||
number: {{ .Values.server.port }}
|
||||
number: {{ $api.port }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,10 @@
|
||||
{{- $api := include "checkmate.api" . | fromYaml -}}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: checkmate-api
|
||||
spec:
|
||||
selector:
|
||||
app: checkmate-api
|
||||
ports:
|
||||
- port: {{ $api.port }}
|
||||
+5
-3
@@ -1,3 +1,4 @@
|
||||
{{- $api := include "checkmate.api" . | fromYaml -}}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
@@ -22,12 +23,13 @@ spec:
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: client
|
||||
image: {{ .Values.client.image }}
|
||||
image: {{ include "checkmate.image" (dict "image" .Values.client.image "tag" .Values.client.tag "root" $) }}
|
||||
imagePullPolicy: {{ .Values.client.imagePullPolicy }}
|
||||
ports:
|
||||
- containerPort: {{ .Values.client.port }}
|
||||
env:
|
||||
- name: UPTIME_APP_API_BASE_URL
|
||||
value: "{{ .Values.server.protocol }}://{{ .Values.server.ingress.host }}/api/v1"
|
||||
value: "{{ $api.protocol }}://{{ $api.ingress.host }}/api/v1"
|
||||
- name: UPTIME_APP_CLIENT_HOST
|
||||
value: "{{ .Values.client.protocol }}://{{ .Values.client.ingress.host }}"
|
||||
volumeMounts:
|
||||
@@ -41,4 +43,4 @@ spec:
|
||||
volumes:
|
||||
- name: config-volume
|
||||
configMap:
|
||||
name: checkmate-server-nginx-cm
|
||||
name: checkmate-client-nginx-cm
|
||||
File renamed without changes.
+5
-4
@@ -1,7 +1,8 @@
|
||||
{{- $api := include "checkmate.api" . | fromYaml -}}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: checkmate-server-nginx-cm
|
||||
name: checkmate-client-nginx-cm
|
||||
data:
|
||||
default.conf: |
|
||||
server {
|
||||
@@ -22,7 +23,7 @@ data:
|
||||
}
|
||||
|
||||
# location /api/ {
|
||||
# proxy_pass http://{{ .Values.server.ingress.host }}:5000/api/;
|
||||
# proxy_pass http://{{ $api.ingress.host }}:5000/api/;
|
||||
# proxy_http_version 1.1;
|
||||
# proxy_set_header Host $host;
|
||||
# proxy_set_header X-Real-IP $remote_addr;
|
||||
@@ -31,7 +32,7 @@ data:
|
||||
# }
|
||||
|
||||
location /api-docs/ {
|
||||
proxy_pass http://{{ .Values.server.ingress.host }}:5000/api-docs/;
|
||||
proxy_pass http://{{ $api.ingress.host }}:5000/api-docs/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
File renamed without changes.
File renamed without changes.
+5
-2
@@ -22,7 +22,8 @@ spec:
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: mongodb
|
||||
image: {{ .Values.mongodb.image }}
|
||||
image: {{ include "checkmate.image" (dict "image" .Values.mongodb.image "tag" .Values.mongodb.tag "root" $) }}
|
||||
imagePullPolicy: {{ .Values.mongodb.imagePullPolicy }}
|
||||
ports:
|
||||
- containerPort: {{ .Values.mongodb.port }}
|
||||
command: ["mongod", "--quiet", "--bind_ip_all"]
|
||||
@@ -37,7 +38,9 @@ spec:
|
||||
- metadata:
|
||||
name: checkmate-mongo-persistent-storage
|
||||
spec:
|
||||
storageClassName: {{ .Values.persistence.mongo.storageClass | quote }}
|
||||
{{- with .Values.persistence.mongo.storageClass }}
|
||||
storageClassName: {{ . | quote }} {{/* omitted when empty so the cluster's default StorageClass applies */}}
|
||||
{{- end }}
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
@@ -1,14 +1,15 @@
|
||||
{{- $api := include "checkmate.api" . | fromYaml -}}
|
||||
{{- if eq .Values.client.ingress.host "change_me" }}
|
||||
{{- fail "client.ingress.host must be overridden and not set to 'change_me'" }}
|
||||
{{- end }}
|
||||
|
||||
{{- if eq .Values.server.ingress.host "change_me" }}
|
||||
{{- fail "server.ingress.host must be overridden and not set to 'change_me'" }}
|
||||
{{- if eq $api.ingress.host "change_me" }}
|
||||
{{- fail "api.ingress.host (or legacy server.ingress.host) must be overridden and not set to 'change_me'" }}
|
||||
{{- end }}
|
||||
|
||||
{{- $serverProtocol := .Values.server.protocol }}
|
||||
{{- if not (or (eq $serverProtocol "http") (eq $serverProtocol "https")) }}
|
||||
{{- fail "server.protocol must be either 'http' or 'https'" }}
|
||||
{{- $apiProtocol := $api.protocol }}
|
||||
{{- if not (or (eq $apiProtocol "http") (eq $apiProtocol "https")) }}
|
||||
{{- fail "api.protocol must be either 'http' or 'https'" }}
|
||||
{{- end }}
|
||||
|
||||
{{- $clientProtocol := .Values.client.protocol }}
|
||||
@@ -21,28 +22,33 @@
|
||||
{{- fail "client.ingress.tls.enabled is true but client.protocol is not 'https'. Set client.protocol: https to avoid mixed content." }}
|
||||
{{- end }}
|
||||
|
||||
{{- if and .Values.server.ingress.tls.enabled (ne $serverProtocol "https") }}
|
||||
{{- fail "server.ingress.tls.enabled is true but server.protocol is not 'https'. Set server.protocol: https to ensure correct API base URL." }}
|
||||
{{- if and $api.ingress.tls.enabled (ne $apiProtocol "https") }}
|
||||
{{- fail "api.ingress.tls.enabled is true but api.protocol is not 'https'. Set api.protocol: https to ensure correct API base URL." }}
|
||||
{{- end }}
|
||||
|
||||
{{/* If client runs on https, API must also be https to avoid mixed content */}}
|
||||
{{- if and (eq $clientProtocol "https") (ne $serverProtocol "https") }}
|
||||
{{- fail "client.protocol is 'https' but server.protocol is not. Set server.protocol: https to prevent browser mixed-content issues." }}
|
||||
{{- if and (eq $clientProtocol "https") (ne $apiProtocol "https") }}
|
||||
{{- fail "client.protocol is 'https' but api.protocol is not. Set api.protocol: https to prevent browser mixed-content issues." }}
|
||||
{{- end }}
|
||||
|
||||
{{/* Fail early if TLS enabled without cert-manager annotations (cluster-issuer or issuer) */}}
|
||||
{{- $cAnn := .Values.client.ingress.annotations | default dict }}
|
||||
{{- $sAnn := .Values.server.ingress.annotations | default dict }}
|
||||
{{- $aAnn := $api.ingress.annotations | default dict }}
|
||||
|
||||
{{- $clientHasIssuer := or (hasKey $cAnn "cert-manager.io/cluster-issuer") (hasKey $cAnn "cert-manager.io/issuer") }}
|
||||
{{- $serverHasIssuer := or (hasKey $sAnn "cert-manager.io/cluster-issuer") (hasKey $sAnn "cert-manager.io/issuer") }}
|
||||
{{- $apiHasIssuer := or (hasKey $aAnn "cert-manager.io/cluster-issuer") (hasKey $aAnn "cert-manager.io/issuer") }}
|
||||
|
||||
{{- if and .Values.client.ingress.tls.enabled (not $clientHasIssuer) }}
|
||||
{{- fail "client.ingress.tls.enabled is true but no cert-manager issuer annotation found. Add 'cert-manager.io/cluster-issuer' or 'cert-manager.io/issuer'." }}
|
||||
{{- end }}
|
||||
|
||||
{{- if and .Values.server.ingress.tls.enabled (not $serverHasIssuer) }}
|
||||
{{- fail "server.ingress.tls.enabled is true but no cert-manager issuer annotation found. Add 'cert-manager.io/cluster-issuer' or 'cert-manager.io/issuer'." }}
|
||||
{{- if and $api.ingress.tls.enabled (not $apiHasIssuer) }}
|
||||
{{- fail "api.ingress.tls.enabled is true but no cert-manager issuer annotation found. Add 'cert-manager.io/cluster-issuer' or 'cert-manager.io/issuer'." }}
|
||||
{{- end }}
|
||||
|
||||
{{/* Secret name can be omitted; we default to <release>-client|server-tls in templates */}}
|
||||
{{/* Worker grace period must exceed the server drain timeout (25s) or workers are SIGKILLed mid-drain */}}
|
||||
{{- if and .Values.worker.enabled (le (int .Values.worker.terminationGracePeriodSeconds) 25) }}
|
||||
{{- fail "worker.terminationGracePeriodSeconds must be greater than 25 (the server drain timeout) or workers are killed mid-drain" }}
|
||||
{{- end }}
|
||||
|
||||
{{/* Secret name can be omitted; we default to <release>-client|api-tls in templates */}}
|
||||
@@ -1,11 +0,0 @@
|
||||
{{- if .Values.redis.enabled }}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: checkmate-redis
|
||||
spec:
|
||||
selector:
|
||||
app: checkmate-redis
|
||||
ports:
|
||||
- port: {{ .Values.redis.port }}
|
||||
{{- end }}
|
||||
@@ -1,33 +0,0 @@
|
||||
{{- if .Values.redis.enabled }}
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: checkmate-redis
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: checkmate-redis
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: checkmate-redis
|
||||
spec:
|
||||
containers:
|
||||
- name: redis
|
||||
image: {{ .Values.redis.image }}
|
||||
ports:
|
||||
- containerPort: {{ .Values.redis.port }}
|
||||
volumeMounts:
|
||||
- name: redis-data
|
||||
mountPath: /data
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: checkmate-redis-persistent-storage
|
||||
spec:
|
||||
storageClassName: {{ .Values.persistence.redis.storageClass | quote }}
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.persistence.redis.size | default "1Gi" | quote }}
|
||||
{{- end }}
|
||||
@@ -4,6 +4,14 @@
|
||||
{{- fail "secrets.JWT_SECRET must be overridden and cannot be 'change_me'" }}
|
||||
{{- end }}
|
||||
|
||||
{{- /*
|
||||
The bundled Mongo service ("checkmate-mongodb") lives in .Release.Namespace. App pods reach it
|
||||
by bare name, but the KEDA operator runs in its own namespace and a bare name is NXDOMAIN there,
|
||||
so worker autoscaling fails to query the backlog. Qualify the in-cluster host to its FQDN here so
|
||||
the one connection string resolves from every namespace. External/already-qualified hosts are not
|
||||
matched (the char after the host name is "." for an FQDN, which the pattern excludes).
|
||||
*/}}
|
||||
{{- $mongoFqdn := printf "checkmate-mongodb.%s.svc.cluster.local" .Release.Namespace }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
@@ -11,5 +19,9 @@ metadata:
|
||||
type: Opaque
|
||||
stringData:
|
||||
{{- range $key, $value := $secrets }}
|
||||
{{- if eq $key "DB_CONNECTION_STRING" }}
|
||||
{{ $key }}: {{ regexReplaceAll "(//|@)checkmate-mongodb([:/,]|$)" $value (printf "${1}%s${2}" $mongoFqdn) | quote }}
|
||||
{{- else }}
|
||||
{{ $key }}: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,37 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: checkmate-server
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: checkmate-server
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: checkmate-server
|
||||
spec:
|
||||
{{- with .Values.server.affinity }}
|
||||
affinity:
|
||||
{{- tpl ( . | toYaml) $ | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.server.tolerations }}
|
||||
tolerations:
|
||||
{{- tpl ( . | toYaml) $ | nindent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: server
|
||||
image: {{ .Values.server.image }}
|
||||
ports:
|
||||
- containerPort: {{ .Values.server.port }}
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: checkmate-secrets
|
||||
{{- with .Values.server.resources }}
|
||||
resources:
|
||||
{{- tpl ( . | toYaml) $ | nindent 12 }}
|
||||
{{- end }}
|
||||
env:
|
||||
- name: CLIENT_HOST
|
||||
value: "{{ .Values.client.protocol }}://{{ .Values.client.ingress.host }}"
|
||||
@@ -1,9 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: checkmate-server
|
||||
spec:
|
||||
selector:
|
||||
app: checkmate-server
|
||||
ports:
|
||||
- port: {{ .Values.server.port }}
|
||||
@@ -0,0 +1,66 @@
|
||||
{{- $api := include "checkmate.api" . | fromYaml -}}
|
||||
{{- if .Values.worker.enabled }}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: checkmate-worker
|
||||
spec:
|
||||
{{- if not .Values.worker.autoscaling.enabled }}
|
||||
replicas: {{ .Values.worker.replicas }} # omitted when autoscaling owns the replica count
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
app: checkmate-worker
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: checkmate-worker
|
||||
spec:
|
||||
terminationGracePeriodSeconds: {{ .Values.worker.terminationGracePeriodSeconds }}
|
||||
{{- with .Values.worker.affinity }}
|
||||
affinity:
|
||||
{{- tpl ( . | toYaml) $ | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.worker.tolerations }}
|
||||
tolerations:
|
||||
{{- tpl ( . | toYaml) $ | nindent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: worker
|
||||
image: {{ include "checkmate.image" (dict "image" (.Values.worker.image | default $api.image) "tag" (.Values.worker.tag | default $api.tag) "root" $) }}
|
||||
imagePullPolicy: {{ .Values.worker.imagePullPolicy | default $api.imagePullPolicy }}
|
||||
ports:
|
||||
- name: health
|
||||
containerPort: {{ .Values.worker.healthPort }}
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: checkmate-secrets # DB_CONNECTION_STRING (+ JWT_SECRET/CLIENT_HOST for validateEnv)
|
||||
env:
|
||||
# Secret default CLIENT_HOST is the non-URL "change_me"; override like the API so validateEnv passes.
|
||||
- name: CLIENT_HOST
|
||||
value: "{{ .Values.client.protocol }}://{{ .Values.client.ingress.host }}"
|
||||
- name: QUEUE_MODE
|
||||
value: "worker"
|
||||
- name: HEALTH_PORT
|
||||
value: {{ .Values.worker.healthPort | quote }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /livez
|
||||
port: health
|
||||
initialDelaySeconds: {{ .Values.worker.probes.liveness.initialDelaySeconds }}
|
||||
periodSeconds: {{ .Values.worker.probes.liveness.periodSeconds }}
|
||||
timeoutSeconds: {{ .Values.worker.probes.liveness.timeoutSeconds }}
|
||||
failureThreshold: {{ .Values.worker.probes.liveness.failureThreshold }}
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: health
|
||||
initialDelaySeconds: {{ .Values.worker.probes.readiness.initialDelaySeconds }}
|
||||
periodSeconds: {{ .Values.worker.probes.readiness.periodSeconds }}
|
||||
timeoutSeconds: {{ .Values.worker.probes.readiness.timeoutSeconds }}
|
||||
failureThreshold: {{ .Values.worker.probes.readiness.failureThreshold }}
|
||||
{{- with .Values.worker.resources }}
|
||||
resources:
|
||||
{{- tpl ( . | toYaml) $ | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,30 @@
|
||||
{{- if and .Values.worker.enabled .Values.worker.autoscaling.enabled }}
|
||||
apiVersion: keda.sh/v1alpha1
|
||||
kind: ScaledObject
|
||||
metadata:
|
||||
name: checkmate-worker
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
name: checkmate-worker
|
||||
minReplicaCount: {{ .Values.worker.autoscaling.minReplicaCount }} # floor: never 0 — a cold gap stops checks
|
||||
maxReplicaCount: {{ .Values.worker.autoscaling.maxReplicaCount }}
|
||||
cooldownPeriod: {{ .Values.worker.autoscaling.cooldownPeriod }}
|
||||
advanced:
|
||||
horizontalPodAutoscalerConfig:
|
||||
behavior:
|
||||
scaleDown:
|
||||
stabilizationWindowSeconds: {{ .Values.worker.autoscaling.stabilizationWindowSeconds }}
|
||||
triggers:
|
||||
- type: mongodb
|
||||
metadata:
|
||||
dbName: {{ .Values.worker.autoscaling.mongo.dbName | quote }}
|
||||
collection: {{ .Values.worker.autoscaling.mongo.collection | quote }}
|
||||
# The Phase 2 countDueBacklog predicate, time-relativized with $$NOW (epoch-ms via $toLong):
|
||||
query: >-
|
||||
{ "type": "check", "isActive": true,
|
||||
"$expr": { "$lte": ["$nextScheduledAt", { "$toLong": "$$NOW" }] },
|
||||
"$or": [ { "lockedUntil": null },
|
||||
{ "$expr": { "$lt": ["$lockedUntil", { "$toLong": "$$NOW" }] } } ] }
|
||||
queryValue: {{ .Values.worker.autoscaling.backlogPerReplica | quote }}
|
||||
connectionStringFromEnv: DB_CONNECTION_STRING # resolved from the worker's checkmate-secrets
|
||||
{{- end }}
|
||||
@@ -1,5 +1,7 @@
|
||||
client:
|
||||
image: ghcr.io/bluewave-labs/checkmate-client:v3.2.0
|
||||
image: ghcr.io/bluewave-labs/checkmate-client
|
||||
tag: "" # defaults to Chart.appVersion; set a full repo:tag in `image` to pin (e.g. a :latest dev tag)
|
||||
imagePullPolicy: IfNotPresent # IfNotPresent so kind-loaded :latest images are used (not pulled)
|
||||
port: 80
|
||||
protocol: http
|
||||
ingress:
|
||||
@@ -17,10 +19,24 @@ client:
|
||||
# a cert-manager issuer annotation (e.g. cert-manager.io/cluster-issuer: "letsencrypt-prod").
|
||||
# The secret will be automatically created by cert-manager when using the cert-manager.io/cluster-issuer annotation
|
||||
|
||||
server:
|
||||
image: ghcr.io/bluewave-labs/checkmate-backend:v3.2.0
|
||||
api:
|
||||
image: ghcr.io/bluewave-labs/checkmate-backend
|
||||
tag: "" # defaults to Chart.appVersion; set a full repo:tag in `image` to pin (e.g. a :latest dev tag)
|
||||
imagePullPolicy: IfNotPresent # IfNotPresent so kind-loaded :latest images are used (not pulled)
|
||||
port: 52345
|
||||
protocol: http
|
||||
# Liveness/readiness probes hit GET /api/v1/health on the api port (proves the HTTP server is up).
|
||||
probes:
|
||||
liveness:
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
readiness:
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
ingress:
|
||||
enabled: true
|
||||
host: change_me
|
||||
@@ -31,40 +47,62 @@ server:
|
||||
# cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
tls:
|
||||
enabled: false
|
||||
# secretName: {{ .Release.Name }}-server-tls # Optional; defaults to <release>-server-tls if omitted
|
||||
# Note: when enabling TLS, also set server.protocol: https and add
|
||||
# secretName: {{ .Release.Name }}-api-tls # Optional; defaults to <release>-api-tls if omitted
|
||||
# Note: when enabling TLS, also set api.protocol: https and add
|
||||
# a cert-manager issuer annotation (e.g. cert-manager.io/cluster-issuer: "letsencrypt-prod").
|
||||
# The secret will be automatically created by cert-manager when using the cert-manager.io/cluster-issuer annotation
|
||||
|
||||
redis:
|
||||
enabled: false
|
||||
image: redis:7.2
|
||||
port: 6379
|
||||
|
||||
mongodb:
|
||||
image: ghcr.io/bluewave-labs/checkmate-mongo:v3.2.0
|
||||
image: ghcr.io/bluewave-labs/checkmate-mongo
|
||||
tag: "" # defaults to Chart.appVersion; set a full repo:tag in `image` to pin
|
||||
imagePullPolicy: IfNotPresent # IfNotPresent so kind-loaded :latest images are used (not pulled)
|
||||
port: 27017
|
||||
|
||||
worker:
|
||||
# Off by default; existing installs are unchanged. When true, a dedicated worker processes all
|
||||
# jobs and the API stops processing (QUEUE_PRIMARY_PROCESSES is derived as false). When false, the
|
||||
# API is all-in-one and processes jobs itself.
|
||||
enabled: false
|
||||
image: "" # defaults to api.image when empty, same as API image
|
||||
tag: "" # defaults to api.tag (-> Chart.appVersion) when empty
|
||||
imagePullPolicy: "" # defaults to api.imagePullPolicy when empty
|
||||
replicas: 1 # used only when autoscaling.enabled = false
|
||||
healthPort: 52346 # HEALTH_PORT; serves /livez /readyz /metrics
|
||||
terminationGracePeriodSeconds: 30 # MUST stay > the server drain timeout (25s) or workers are killed mid-drain
|
||||
resources: {}
|
||||
affinity: {}
|
||||
tolerations: {}
|
||||
probes:
|
||||
liveness: # /livez — failureThreshold>=3 so one slow tick never restarts mid-job
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
readiness: # /readyz — flips to 503 on drain
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
autoscaling:
|
||||
enabled: false # requires the KEDA operator installed in-cluster
|
||||
minReplicaCount: 1 # processing floor — never 0 (a cold gap silently stops checks)
|
||||
maxReplicaCount: 10
|
||||
backlogPerReplica: 50 # KEDA queryValue: target due-backlog per worker
|
||||
cooldownPeriod: 300 # seconds before scaling an idle target down
|
||||
stabilizationWindowSeconds: 300 # damp the interval-boundary herd
|
||||
mongo:
|
||||
dbName: uptime_db # must match DB_CONNECTION_STRING's database
|
||||
collection: jobs
|
||||
|
||||
secrets:
|
||||
JWT_SECRET: change_me
|
||||
# REFRESH_TOKEN_SECRET: change_me
|
||||
# SYSTEM_EMAIL_ADDRESS: test@example.com
|
||||
# SYSTEM_EMAIL_PASSWORD: change_me
|
||||
# SYSTEM_EMAIL_HOST: smtp.example.com
|
||||
# SYSTEM_EMAIL_PORT: "587"
|
||||
# PAGESPEED_API_KEY: change_me
|
||||
DB_CONNECTION_STRING: mongodb://checkmate-mongodb.namespace.svc:27017/uptime_db
|
||||
DB_CONNECTION_STRING: mongodb://checkmate-mongodb:27017/uptime_db
|
||||
CLIENT_HOST: change_me
|
||||
# REDIS_HOST: redis
|
||||
# REDIS_PORT: "6379"
|
||||
# DB_TYPE: MongoDB
|
||||
# TOKEN_TTL: 99d
|
||||
# REFRESH_TOKEN_TTL: 99d
|
||||
NODE_ENV: production
|
||||
LOG_LEVEL: info
|
||||
TOKEN_TTL: 99d
|
||||
|
||||
persistence:
|
||||
mongo:
|
||||
size: 5Gi
|
||||
storageClass: ""
|
||||
redis:
|
||||
size: 1Gi
|
||||
storageClass: ""
|
||||
@@ -2,14 +2,10 @@
|
||||
!quickstart.sh
|
||||
!build_images.sh
|
||||
dev/mongo/data/*
|
||||
dev/redis/data/*
|
||||
dist/mongo/data/*
|
||||
dist/redis/data/*
|
||||
prod/mongo/data/*
|
||||
prod/redis/data/*
|
||||
dist/docker-compose-test.yaml
|
||||
/dist-mono/mongo/data/*
|
||||
/dist-mono/redis/data/*
|
||||
/dist-arm/mongo/data/*
|
||||
*.env
|
||||
|
||||
|
||||
@@ -12,14 +12,11 @@ set dockerfiles[0]=.\docker\coolify\client.Dockerfile
|
||||
set services[1]=bluewaveuptime/uptime_database_mongo
|
||||
set dockerfiles[1]=.\docker\coolify\mongoDB.Dockerfile
|
||||
|
||||
set services[2]=bluewaveuptime/uptime_redis
|
||||
set dockerfiles[2]=.\docker\coolify\redis.Dockerfile
|
||||
|
||||
set services[3]=bluewaveuptime/uptime_server
|
||||
set dockerfiles[3]=.\docker\coolify\server.Dockerfile
|
||||
set services[2]=bluewaveuptime/uptime_server
|
||||
set dockerfiles[2]=.\docker\coolify\server.Dockerfile
|
||||
|
||||
REM Loop through each service and build the corresponding image
|
||||
for /L %%i in (0,1,2,3) do (
|
||||
for /L %%i in (0,1,2) do (
|
||||
set service=!services[%%i]!
|
||||
set dockerfile=!dockerfiles[%%i]!
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ cd ../../
|
||||
declare -A services=(
|
||||
["bluewaveuptime/uptime_client"]="./docker/coolify/client.Dockerfile"
|
||||
["bluewaveuptime/uptime_database_mongo"]="./docker/coolify/mongoDB.Dockerfile"
|
||||
["bluewaveuptime/uptime_redis"]="./docker/coolify/redis.Dockerfile"
|
||||
["bluewaveuptime/uptime_server"]="./docker/coolify/server.Dockerfile"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
FROM redis
|
||||
EXPOSE 6379
|
||||
@@ -19,7 +19,6 @@ services:
|
||||
# Mount the certs directory (read-only for security)
|
||||
- ./certs:/certs:ro
|
||||
depends_on:
|
||||
- redis
|
||||
- mongodb
|
||||
# Optional: Add healthcheck to ensure the server starts properly
|
||||
healthcheck:
|
||||
|
||||
@@ -9,7 +9,6 @@ services:
|
||||
- UPTIME_APP_API_BASE_URL=http://localhost:52345/api/v1
|
||||
- UPTIME_APP_CLIENT_HOST=http://localhost
|
||||
- DB_CONNECTION_STRING=mongodb://mongodb:27017/uptime_db
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- CLIENT_HOST=http://localhost
|
||||
- JWT_SECRET=my_secret
|
||||
depends_on:
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import rateLimit from "express-rate-limit";
|
||||
|
||||
export const generalApiLimiter = rateLimit({
|
||||
windowMs: 60 * 1000,
|
||||
limit: 600,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
ipv6Subnet: 64,
|
||||
});
|
||||
export const generalApiLimiter = (devMode: boolean) =>
|
||||
rateLimit({
|
||||
windowMs: 60 * 1000,
|
||||
limit: 600,
|
||||
standardHeaders: true,
|
||||
legacyHeaders: false,
|
||||
ipv6Subnet: 64,
|
||||
skip: () => devMode,
|
||||
});
|
||||
|
||||
export const authApiLimiter = rateLimit({
|
||||
windowMs: 60 * 1000,
|
||||
|
||||
+2
-1
@@ -39,7 +39,8 @@ export const createApp = ({
|
||||
};
|
||||
const publicStatusPageCorsOrigin = createStatusPageCorsOrigin(allowedOrigin, services.statusPagesRepository);
|
||||
|
||||
app.use(generalApiLimiter);
|
||||
const devMode = envSettings.nodeEnv === "development";
|
||||
app.use(generalApiLimiter(devMode));
|
||||
|
||||
app.use((req, res, next) => {
|
||||
const corsOptions = isPublicStatusPageApiPath(req.method, req.path)
|
||||
|
||||
Reference in new issue
Block a user