Files
pad/deploy/k8s/deployment.yaml
T
xarmian 1fe9a15037 fix(deploy): Kubernetes keeps attachments on a PVC, and uploads get a writable /tmp (BUG-3714) (#2141)
* fix(deploy): the Kubernetes manifest keeps attachments on a PVC, and gives uploads a writable /tmp (BUG-3714)

/data holds every attachment's bytes in PostgreSQL mode too, but the
manifest mounted it as an emptyDir, so replacing the pod (an upgrade, a
drain, an eviction) lost them all while their rows stayed. It is now
a ReadWriteOnce PersistentVolumeClaim (deploy/k8s/pvc.yaml); the single
replica and Recreate strategy suit RWO.

On the way: with readOnlyRootFilesystem and no writable /tmp, every
upload failed with a 500 ("create upload temp: open /tmp/...:
read-only file system"). /tmp is now an emptyDir.

docs/deployment.md: pvc.yaml in the apply order, the StorageClass
prerequisite, back up the volume as well as the database, and a tar
block that carries attachments from an emptyDir install to the PVC.

Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS

* docs(deploy): the emptyDir-to-PVC migration block stops on a failed export and checks the restored count (BUG-3714, Codex r1)

Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS

* docs(deploy): the migration recovery line ends with the count check (BUG-3714, Codex r2)

Claude-Session: https://claude.ai/code/session_01Q9WssCjFuHjSfLABoW4tmS
2026-10-13 21:11:33 -04:00

98 lines
3.1 KiB
YAML

apiVersion: apps/v1
kind: Deployment
metadata:
name: pad
namespace: pad
labels:
app: pad
spec:
# ONE replica (BUG-3573). Real-time collaboration keeps each item's editing
# room in the process that serves it, with an in-process bus and serialized
# per-item op-log appends; two pods would each hold their own room for the
# same item, miss each other's edits, and leave gaps in the op-log. Running
# more than one needs a shared collab bus, which Pad does not have yet, so
# there is no HPA either.
replicas: 1
# Recreate, not RollingUpdate: a rolling update starts the new pod while the
# old one still serves, which is two writers for the length of the rollout.
# Recreate stops the old pod first (a brief outage per upgrade).
strategy:
type: Recreate
selector:
matchLabels:
app: pad
template:
metadata:
labels:
app: pad
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: pad
# PIN the release you run, and change it to upgrade (TASK-2034).
# Never `latest` here: a pod that restarts after a new release would
# pull it unannounced, running database migrations you did not plan.
# Tags are the bare version (no leading v):
# https://github.com/PerpetualSoftware/pad/releases
image: ghcr.io/perpetualsoftware/pad:0.17.2
ports:
- containerPort: 7777
name: http
envFrom:
- configMapRef:
name: pad-config
- secretRef:
name: pad-secret
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: "1"
memory: 512Mi
readinessProbe:
httpGet:
path: /api/v1/health
port: http
initialDelaySeconds: 5
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
livenessProbe:
httpGet:
path: /api/v1/health
port: http
initialDelaySeconds: 15
periodSeconds: 30
timeoutSeconds: 5
failureThreshold: 3
volumeMounts:
- name: data
mountPath: /data
# The root filesystem is read-only, and uploads stage in the
# temp dir before they land in /data/attachments: without a
# writable /tmp every attachment upload fails with a 500
# (BUG-3714).
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
# Attachments live in /data in every storage mode, PostgreSQL
# included, so it must outlive the pod (pvc.yaml, BUG-3714).
- name: data
persistentVolumeClaim:
claimName: pad-data