Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
- **Security-first design**: Security contexts enabled by default (runAsNonRoot, drop ALL capabilities, seccomp RuntimeDefault profile).
- **Service accounts**: Dedicated service accounts for each component (app, engine, tables, analytics, nginx, postgres, redis) with configurable annotations for AWS IAM roles (IRSA), GCP Workload Identity, or Azure Managed Identity.
- **External Secrets Operator**: Built-in support for AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager, and Azure Key Vault integration.
- **PodDisruptionBudgets (PDBs)**: Configured for all stateless components to ensure minimum availability during voluntary disruptions (node drains, upgrades).
- **PodDisruptionBudgets (PDBs)**: Configured for `app`, `engine`, `nginx`, `analytics` and `tables` — note that `tables` is stateful (PVC, ReadWriteOnce), while the Postgres and Redis StatefulSets have no PDB. All default to `maxUnavailable: 1` so voluntary disruptions (node drains, upgrades) can always proceed. Each component also accepts `minAvailable` when `maxUnavailable` is unset, but avoid it where a component runs a single replica: `minAvailable: 1` then evaluates to `disruptionsAllowed: 0` and blocks every drain. `analytics` and `tables` default to one replica.
- **HorizontalPodAutoscalers (HPAs)**: Optional autoscaling for app, engine, analytics, and nginx based on CPU/memory metrics.
- **NetworkPolicy**: Optional network segmentation to restrict pod-to-pod communication and enforce least-privilege networking with explicit allow rules.
- **LimitRange**: Optional namespace-level resource defaults and constraints to prevent resource exhaustion.
Expand Down
52 changes: 39 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -829,26 +829,52 @@ global:
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule

# Enable PodDisruptionBudgets
pdb:
enabled: true
app:
# PodDisruptionBudgets are enabled by default with maxUnavailable: 1
app:
podDisruptionBudget:
enabled: true
minAvailable: 2
engine:
maxUnavailable: 1
engine:
podDisruptionBudget:
enabled: true
minAvailable: 2
nginx:
maxUnavailable: 1
nginx:
podDisruptionBudget:
enabled: true
minAvailable: 1
analytics:
maxUnavailable: 1
analytics:
podDisruptionBudget:
enabled: true
minAvailable: 1
tables:
maxUnavailable: 1
tables:
podDisruptionBudget:
enabled: true
minAvailable: 1
maxUnavailable: 1
```

A PodDisruptionBudget resource carries only one of the two fields. The chart renders
`maxUnavailable` whenever that value is non-nil, and `minAvailable` otherwise;
`maxUnavailable: 0` counts as set and is rendered as `0`.

Prefer `maxUnavailable`. `minAvailable: 1` on a component running a single replica
evaluates to `disruptionsAllowed: 0`, which makes the pod impossible to evict and blocks
every node drain — cluster upgrades, node image upgrades and autoscaler scale-down all
fail while it is set. `analytics` and `tables` default to one replica, and `tables` uses
`ReadWriteOnce` storage so it cannot be scaled out of the problem.

To use `minAvailable` instead, set `maxUnavailable` to `null` explicitly:

```yaml
app:
podDisruptionBudget:
maxUnavailable: null
minAvailable: 2
```

Note that `maxUnavailable: 1` allows only one pod down at a time. At three or more
replicas that is stricter than `minAvailable: 1`, which permits all but one to go at
once — safer, but drains take longer.

### Monitoring and observability

**Prometheus metrics:**
Expand Down
6 changes: 5 additions & 1 deletion chart/templates/pdb-analytics.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ metadata:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
minAvailable: {{ .Values.analytics.podDisruptionBudget.minAvailable }}
{{- if not (kindIs "invalid" .Values.analytics.podDisruptionBudget.maxUnavailable) }}
maxUnavailable: {{ .Values.analytics.podDisruptionBudget.maxUnavailable }}
{{- else }}
minAvailable: {{ .Values.analytics.podDisruptionBudget.minAvailable | default 1 }}
{{- end }}
selector:
matchLabels:
{{- include "openops.componentSelectorLabels" (dict "root" . "component" "analytics") | nindent 6 }}
Expand Down
6 changes: 5 additions & 1 deletion chart/templates/pdb-app.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ metadata:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
minAvailable: {{ .Values.app.podDisruptionBudget.minAvailable }}
{{- if not (kindIs "invalid" .Values.app.podDisruptionBudget.maxUnavailable) }}
maxUnavailable: {{ .Values.app.podDisruptionBudget.maxUnavailable }}
{{- else }}
minAvailable: {{ .Values.app.podDisruptionBudget.minAvailable | default 1 }}
{{- end }}
selector:
matchLabels:
{{- include "openops.componentSelectorLabels" (dict "root" . "component" "app") | nindent 6 }}
Expand Down
6 changes: 5 additions & 1 deletion chart/templates/pdb-engine.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ metadata:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
minAvailable: {{ .Values.engine.podDisruptionBudget.minAvailable }}
{{- if not (kindIs "invalid" .Values.engine.podDisruptionBudget.maxUnavailable) }}
maxUnavailable: {{ .Values.engine.podDisruptionBudget.maxUnavailable }}
{{- else }}
minAvailable: {{ .Values.engine.podDisruptionBudget.minAvailable | default 1 }}
{{- end }}
selector:
matchLabels:
{{- include "openops.componentSelectorLabels" (dict "root" . "component" "engine") | nindent 6 }}
Expand Down
6 changes: 5 additions & 1 deletion chart/templates/pdb-nginx.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ metadata:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
minAvailable: {{ .Values.nginx.podDisruptionBudget.minAvailable }}
{{- if not (kindIs "invalid" .Values.nginx.podDisruptionBudget.maxUnavailable) }}
maxUnavailable: {{ .Values.nginx.podDisruptionBudget.maxUnavailable }}
{{- else }}
minAvailable: {{ .Values.nginx.podDisruptionBudget.minAvailable | default 1 }}
{{- end }}
selector:
matchLabels:
{{- include "openops.componentSelectorLabels" (dict "root" . "component" "nginx") | nindent 6 }}
Expand Down
6 changes: 5 additions & 1 deletion chart/templates/pdb-tables.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ metadata:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
minAvailable: {{ .Values.tables.podDisruptionBudget.minAvailable }}
{{- if not (kindIs "invalid" .Values.tables.podDisruptionBudget.maxUnavailable) }}
maxUnavailable: {{ .Values.tables.podDisruptionBudget.maxUnavailable }}
{{- else }}
minAvailable: {{ .Values.tables.podDisruptionBudget.minAvailable | default 1 }}
{{- end }}
selector:
matchLabels:
{{- include "openops.componentSelectorLabels" (dict "root" . "component" "tables") | nindent 6 }}
Expand Down
10 changes: 5 additions & 5 deletions chart/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ app:
# Pod Disruption Budget - ENABLED BY DEFAULT
podDisruptionBudget:
enabled: true
minAvailable: 1
maxUnavailable: 1
# Horizontal Pod Autoscaler
autoscaling:
enabled: false
Expand Down Expand Up @@ -229,7 +229,7 @@ engine:
# Pod Disruption Budget - ENABLED BY DEFAULT
podDisruptionBudget:
enabled: true
minAvailable: 1
maxUnavailable: 1
# Horizontal Pod Autoscaler
autoscaling:
enabled: false
Expand Down Expand Up @@ -269,7 +269,7 @@ tables:
# Pod Disruption Budget
podDisruptionBudget:
enabled: true
minAvailable: 1
maxUnavailable: 1
# Horizontal Pod Autoscaler
autoscaling:
enabled: false
Expand Down Expand Up @@ -332,7 +332,7 @@ analytics:
# Pod Disruption Budget
podDisruptionBudget:
enabled: true
minAvailable: 1
maxUnavailable: 1
# Horizontal Pod Autoscaler
autoscaling:
enabled: false
Expand Down Expand Up @@ -545,7 +545,7 @@ nginx:
# Pod Disruption Budget - ENABLED BY DEFAULT
podDisruptionBudget:
enabled: true
minAvailable: 1
maxUnavailable: 1
# Horizontal Pod Autoscaler
autoscaling:
enabled: false
Expand Down
27 changes: 15 additions & 12 deletions docs/DEPLOY_TO_AWS_EKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -751,23 +751,26 @@ nginx:
# service.beta.kubernetes.io/aws-load-balancer-internal: "true"

# Pod Disruption Budgets for HA
pdb:
enabled: true
app:
app:
podDisruptionBudget:
enabled: true
minAvailable: 2
engine:
maxUnavailable: 1
engine:
podDisruptionBudget:
enabled: true
minAvailable: 2
nginx:
maxUnavailable: 1
nginx:
podDisruptionBudget:
enabled: true
minAvailable: 1
analytics:
maxUnavailable: 1
analytics:
podDisruptionBudget:
enabled: true
minAvailable: 1
tables:
maxUnavailable: 1
tables:
podDisruptionBudget:
enabled: true
minAvailable: 1
maxUnavailable: 1

# Horizontal Pod Autoscaling
hpa:
Expand Down
Loading