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 Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ apiVersion: v2
name: pgdog-control
description: PgDog Control
type: application
version: 0.2.14
version: 0.2.15
appVersion: "29a6513b"
47 changes: 37 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ The three somewhat complex steps are:

## Chart summary

This chart installs two deployments: PgDog control plane and Redis.
This chart installs the PgDog control plane and, by default, a Redis instance.

The PgDog deployment contains the following components:

Expand All @@ -50,14 +50,33 @@ The PgDog deployment contains the following components:
| Service account, Cluster role, Cluster role bindings | Service account with RBAC to access select Kube APIs. See [RBAC](#rbac) for more details. |
| NetworkPolicy | Optional; restricts ingress/egress traffic. See [NetworkPolicy](#networkpolicy) for more details. |

In addition to installing the PgDog control plane, this chart will deploy a Redis deployment (with one replica). The control plane uses Redis for storing
metrics. The Redis deployment has the following components:
By default, the chart also deploys a single-replica Redis instance. The control plane uses Redis for storing metrics. Set `redis.enabled: false` and provide `redis.url` to use an external Redis instead. The chart-managed Redis has the following components:

| Components | Description |
|-|-|
| Deployment | Redis deployment with one replica. |
| Service | Redis service pointing to the deployment, with selector labels configured automatically. |

```yaml
redis:
enabled: true
url: "" # defaults to redis://<release>-redis.<namespace>.svc.cluster.local:6379
image:
repository: redis
tag: "7-alpine"
pullPolicy: IfNotPresent
pullSecrets: []
```

| Option | Description |
|-|-|
| `redis.enabled` | Deploy the chart-managed Redis resources (bool, default `true`). |
| `redis.url` | Redis connection string written to `[redis].url` in `control.toml`. When empty, defaults to the chart-managed Redis Service (string, default `""`). |
| `redis.image.repository` | Redis image repository (string, default `redis`). |
| `redis.image.tag` | Redis image tag (string, default `7-alpine`). |
| `redis.image.pullPolicy` | Redis image pull policy (string, default `IfNotPresent`). |
| `redis.image.pullSecrets` | Image pull secrets attached to the Redis pod (list, default `[]`). |

### Ingress

The PgDog control plane has a web dashboard. It can be accessed through the Ingress or HTTPRoute the chart creates. The chart supports 4 presets (called modes):
Expand Down Expand Up @@ -296,11 +315,11 @@ If your cluster manages RBAC out-of-band (a platform team's controller, GitOps,

## NetworkPolicy

When `networkPolicy.enabled` is `true`, the chart renders a `NetworkPolicy` for the control pod and one for Redis, restricting traffic to what the control plane actually needs:
When `networkPolicy.enabled` is `true`, the chart renders a `NetworkPolicy` for the control pod and, when `redis.enabled` is true, one for Redis, restricting traffic to what the control plane actually needs:

- Ingress on `control.port` from the `ingress-nginx` namespace only.
- Egress to Redis, to `kube-system` for DNS, and to the public internet on 5432 (Postgres) and 443 (HTTPS, e.g. the AWS/CloudWatch/RDS APIs), excluding RFC1918 private ranges.
- Redis accepts ingress only from the control pod and allows no egress.
- Egress to Redis on port 6379, to `kube-system` for DNS, and to the public internet on 5432 (Postgres) and 443 (HTTPS, e.g. the AWS/CloudWatch/RDS APIs), excluding RFC1918 private ranges. When chart-managed Redis is enabled, the Redis rule is restricted to its pods; otherwise it permits egress to any destination on port 6379 so the external Redis can be reached.
- Chart-managed Redis accepts ingress only from the control pod and allows no egress.

In clusters that deny pod-to-pod traffic by default, the built-in ingress-nginx rule alone often isn't enough — for example, PgDog pods calling the control plane's API need their own rule. Use `networkPolicy.extraIngress` to add any number of additional ingress rules to the control `NetworkPolicy`:

Expand All @@ -322,7 +341,7 @@ networkPolicy:

| Option | Description |
|-|-|
| `networkPolicy.enabled` | Render the control and Redis `NetworkPolicy` resources (bool, default `false`). |
| `networkPolicy.enabled` | Render the control and, when enabled, Redis `NetworkPolicy` resources (bool, default `false`). |
| `networkPolicy.extraIngress` | Additional ingress rules appended to the control `NetworkPolicy`, on top of the built-in ingress-nginx rule. Each entry follows the standard `NetworkPolicyIngressRule` schema (`from`/`ports`) and is passed through verbatim (list, default `[]`). |

## AWS access (EKS / IRSA)
Expand Down Expand Up @@ -712,21 +731,29 @@ control:

### Redis persistence

`control.config.redis` controls how the in-memory store is snapshotted to Redis between process restarts. The chart already provisions an in-cluster Redis (`<release>-redis`) and the control plane points at it by default, so most installs leave this section alone.
`control.config.redis` controls how often the in-memory store is snapshotted to Redis between process restarts. The chart provisions an in-cluster Redis (`<release>-redis`) by default and writes its connection string to `[redis].url` in `control.toml`.

```yaml
control:
config:
redis:
url: redis://my-redis.cache:6379
save_interval_secs: 60
```

| Option | Description |
|-|-|
| `url` | Redis connection string. Leave empty to use the in-cluster Redis the chart installs; set it only to point at an external Redis (string, optional). |
| `save_interval_secs` | How often the background task snapshots the store to Redis (int, default `60`). |

To use an external Redis, disable all chart-managed Redis resources and set its URL:

```yaml
redis:
enabled: false
url: redis://my-redis.cache:6379
```

For backwards compatibility, `control.config.redis.url` is still accepted, but `redis.url` is preferred.

## Examples

```sh
Expand Down
10 changes: 10 additions & 0 deletions templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ the same cluster don't collide.
{{- printf "%s-redis" .Release.Name | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Redis URL used by the control plane. redis.url is the public chart setting;
control.config.redis.url remains supported for backwards compatibility.
*/}}
{{- define "pgdog-control.redis.url" -}}
{{- $config := .Values.control.config | default dict -}}
{{- $redisConfig := $config.redis | default dict -}}
{{- .Values.redis.url | default $redisConfig.url | default (printf "redis://%s.%s.svc.cluster.local:6379" (include "pgdog-control.redis.fullname" .) .Release.Namespace) -}}
{{- end }}

{{/*
ServiceAccount name for the control component. Falls back to the
control fullname when not explicitly set in values.
Expand Down
3 changes: 1 addition & 2 deletions templates/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -229,10 +229,9 @@ data:
{{- end }}

{{- $redis := $config.redis | default dict }}
{{- $redisUrl := $redis.url | default (printf "redis://%s.%s.svc.cluster.local:6379" (include "pgdog-control.redis.fullname" .) .Release.Namespace) }}

[redis]
url = {{ $redisUrl | quote }}
url = {{ include "pgdog-control.redis.url" . | quote }}
{{- with $redis.save_interval_secs }}
save_interval_secs = {{ . }}
{{- end }}
8 changes: 8 additions & 0 deletions templates/networkpolicy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,19 @@ spec:
{{- toYaml . | nindent 2 }}
{{- end }}
egress:
{{- if .Values.redis.enabled }}
- to:
- podSelector:
matchLabels:
{{- include "pgdog-control.redis.selectorLabels" . | nindent 10 }}
ports:
- protocol: TCP
port: 6379
{{- else }}
- ports:
- protocol: TCP
port: 6379
{{- end }}
- to:
- ipBlock:
cidr: 0.0.0.0/0
Expand Down Expand Up @@ -60,6 +66,7 @@ spec:
port: 53
- protocol: TCP
port: 53
{{- if .Values.redis.enabled }}
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
Expand All @@ -84,3 +91,4 @@ spec:
port: 6379
egress: []
{{- end }}
{{- end }}
9 changes: 8 additions & 1 deletion templates/redis-deployment.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{{- if .Values.redis.enabled }}
apiVersion: apps/v1
kind: Deployment
metadata:
Expand All @@ -17,13 +18,18 @@ spec:
cluster-autoscaler.kubernetes.io/safe-to-evict: "false"
spec:
automountServiceAccountToken: false
{{- with .Values.redis.image.pullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.redis.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: redis
image: redis:7-alpine
image: "{{ .Values.redis.image.repository }}:{{ .Values.redis.image.tag }}"
imagePullPolicy: {{ .Values.redis.image.pullPolicy }}
{{- with .Values.redis.containerSecurityContext }}
securityContext:
{{- toYaml . | nindent 10 }}
Expand All @@ -38,3 +44,4 @@ spec:
limits:
memory: {{ .Values.redis.resources.limits.memory | quote }}
cpu: {{ .Values.redis.resources.limits.cpu | quote }}
{{- end }}
2 changes: 2 additions & 0 deletions templates/redis-pdb.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{{- if .Values.redis.enabled }}
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
Expand All @@ -9,3 +10,4 @@ spec:
selector:
matchLabels:
{{- include "pgdog-control.redis.selectorLabels" . | nindent 6 }}
{{- end }}
2 changes: 2 additions & 0 deletions templates/redis-service.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{{- if .Values.redis.enabled }}
apiVersion: v1
kind: Service
metadata:
Expand All @@ -13,3 +14,4 @@ spec:
name: redis
selector:
{{- include "pgdog-control.redis.selectorLabels" . | nindent 4 }}
{{- end }}
20 changes: 20 additions & 0 deletions test/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,25 @@ for values_file in "$TEST_DIR"/values-*.yaml; do
helm template test-release "$CHART_DIR" -f "$values_file" > /dev/null
done

echo ""
echo "==> Verifying external Redis rendering..."
external_render=$(helm template test-release "$CHART_DIR" -f "$TEST_DIR/values-redis-external.yaml")
if grep -q 'app.kubernetes.io/component: redis' <<< "$external_render"; then
echo "chart-managed Redis resources rendered while redis.enabled=false" >&2
exit 1
fi
if grep -q -- '- name: REDIS_URL' <<< "$external_render"; then
echo "REDIS_URL environment variable rendered, but the app only reads control.toml" >&2
exit 1
fi
grep -A1 '^ \[redis\]$' <<< "$external_render" | grep -q 'url = "redis://external-redis.example.com:6379"'

echo ""
echo "==> Verifying configurable Redis image..."
image_render=$(helm template test-release "$CHART_DIR" -f "$TEST_DIR/values-redis-image.yaml")
grep -q 'image: "registry.example.com/platform/redis:8-alpine"' <<< "$image_render"
grep -q 'imagePullPolicy: Always' <<< "$image_render"
grep -q 'name: registry-credentials' <<< "$image_render"

echo ""
echo "==> All chart tests passed!"
9 changes: 9 additions & 0 deletions test/values-redis-external.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
ingress:
enabled: false

networkPolicy:
enabled: true

redis:
enabled: false
url: redis://external-redis.example.com:6379
10 changes: 10 additions & 0 deletions test/values-redis-image.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
ingress:
enabled: false

redis:
image:
repository: registry.example.com/platform/redis
tag: "8-alpine"
pullPolicy: Always
pullSecrets:
- name: registry-credentials
13 changes: 12 additions & 1 deletion values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,21 @@ control:
# bot_token: "" # optional; defaults to SLACK_BOT_TOKEN env when absent
# channel: "" # optional; defaults to SLACK_CHANNEL env when absent
redis: {}
# url: "" # optional; defaults to in-cluster redis
# url: "" # deprecated; use redis.url instead
# save_interval_secs: 60

redis:
# Deploy the chart-managed Redis instance. Disable this when using an
# external Redis and set redis.url to its connection string.
enabled: true
# Connection string written to [redis].url in control.toml. When empty,
# it points to the chart-managed Redis service.
url: ""
image:
repository: redis
tag: "7-alpine"
pullPolicy: IfNotPresent
pullSecrets: []
resources:
requests:
memory: "128Mi"
Expand Down
Loading