Skip to content

Commit 9ec09e2

Browse files
pimzandclaude
andcommitted
Persist /etc/frepple in the Kubernetes manifest so runtime config survives pod restarts
The manifest persisted only the log directories, so /etc/frepple reset to the image defaults on every pod restart — regenerating the secret key (logging users out) and dropping anything the app writes to djangosettings.py at runtime (installed apps, scenario count, display settings). Mount /etc/frepple on a PVC, seeded from the image on first start by an init container. The init container mounts the volume at /mnt/config (so the image's own copy stays visible) and runs as root, since the freshly provisioned volume root is root-owned and cp -a must preserve the image's ownership; the copy is skipped on later starts, preserving runtime changes. This matches how docker-compose already persists the directory on a named volume. Document it, including the seed-once / reconcile-on-upgrade caveat. Refs #747. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent fb551d7 commit 9ec09e2

2 files changed

Lines changed: 52 additions & 2 deletions

File tree

contrib/kubernetes/frepple-deployment.yaml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,18 @@ spec:
2323
storage: 50Mi
2424
status: {}
2525
---
26+
apiVersion: v1
27+
kind: PersistentVolumeClaim
28+
metadata:
29+
name: config-frepple
30+
spec:
31+
accessModes:
32+
- ReadWriteOnce
33+
resources:
34+
requests:
35+
storage: 50Mi
36+
status: {}
37+
---
2638
apiVersion: apps/v1
2739
kind: Deployment
2840
metadata:
@@ -42,6 +54,26 @@ spec:
4254
labels:
4355
app: frepple
4456
spec:
57+
initContainers:
58+
# Seed /etc/frepple from the image on the first start only. The volume is
59+
# mounted here at /mnt/config (not /etc/frepple) so the image's own copy
60+
# stays visible to copy from; on later starts the file already exists and
61+
# the copy is skipped, preserving runtime changes to djangosettings.py.
62+
# Runs as root: the freshly provisioned volume root is root-owned, so a
63+
# non-root user can't populate it, and cp -a can't preserve the image's
64+
# root-owned files unless it runs as root. This replicates the image's
65+
# ownership/modes (/etc/frepple is group-writable by the frepple group).
66+
- name: seed-config
67+
image: ghcr.io/frepple/frepple-community:latest
68+
securityContext:
69+
runAsUser: 0
70+
command:
71+
- sh
72+
- -c
73+
- test -f /mnt/config/djangosettings.py || cp -a /etc/frepple/. /mnt/config/
74+
volumeMounts:
75+
- mountPath: /mnt/config
76+
name: config-frepple
4577
containers:
4678
- env:
4779
- name: POSTGRES_HOST
@@ -66,12 +98,17 @@ spec:
6698
cpu: 250m
6799
memory: "4294967296"
68100
volumeMounts:
101+
- mountPath: /etc/frepple
102+
name: config-frepple
69103
- mountPath: /var/log/apache2
70104
name: log-apache
71105
- mountPath: /var/log/frepple
72106
name: log-frepple
73107
restartPolicy: Always
74108
volumes:
109+
- name: config-frepple
110+
persistentVolumeClaim:
111+
claimName: config-frepple
75112
- name: log-apache
76113
persistentVolumeClaim:
77114
claimName: log-apache

doc/installation-guide/advanced/kubernetes.rst

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,20 @@ The following resources are then defined in your cluster:
1919

2020
- A postgresql service to store the frepple data.
2121

22-
- Persistent volumes to store the web server logs (50MB), the application logs (100MB)
23-
and the postgresql data (1GB).
22+
- Persistent volumes to store the web server logs (50MB), the application logs (100MB),
23+
the frepple configuration in ``/etc/frepple`` (50MB) and the postgresql data (1GB).
2424

2525
- A network policy to keep the connection between frepple and its postgres database private.
26+
27+
frepple stores its runtime configuration in ``/etc/frepple/djangosettings.py``: the
28+
Django secret key, the list of installed apps, the number of scenarios and some display
29+
settings are all written to this file as you use the application. The deployment therefore
30+
mounts ``/etc/frepple`` on a persistent volume, seeded from the image on the first start by
31+
an init container, so that this configuration survives pod restarts - the same way the
32+
docker-compose deployment persists it on a named volume. Without it the directory resets to
33+
the image defaults on every restart: a new secret key is generated (invalidating sessions),
34+
and installed apps and scenario settings are lost.
35+
36+
The volume is seeded only once. After upgrading to a newer frepple image, any new default
37+
settings shipped in the image are not copied over an existing ``djangosettings.py``; review
38+
and apply such changes manually after an upgrade.

0 commit comments

Comments
 (0)