Rune: first writes to a freshly-provisioned gce-pd volume are lost — files keep metadata, lose contents
Severity: a service that writes state on first boot and reads it back later
comes up permanently broken. Silent — nothing in rune logs or status indicates
a problem, and the service reports Running 1/1 right up until it is restarted.
Versions: rune server + CLI v0.0.1-dev.146 (8c34e706), single edge node
(e2-standard-2, europe-west2-a), gce-pd CSI driver, StorageClass
pd-ssd-euw2a (diskType: pd-ssd, fsType: ext4, reclaimPolicy: retain).
Summary
On the first boot after a gce-pd volume is newly provisioned, files written
by the service end up on disk with correct name, owner and mode but zero
length. Two unrelated files in our case (SYSTEM, flo.pid) — directory
entries and inodes persisted, file contents did not.
The service keeps running and reports healthy. The damage only surfaces on the
next restart, when it tries to read what it thinks it wrote.
Once the directory is manually cleared and the service restarted, the same
volume works correctly and survives subsequent restarts, including the
detach/attach cycle a rune restart performs. So this is specific to the
initial-provisioning window, not to ongoing use of the volume.
Evidence
Same cast, same configmap, same image (ghcr.io/floruntime/flo:0.1.0-dev.9),
changing only storageClassName:
| storage |
SYSTEM after first boot |
outcome |
pd-ssd-euw2a (gce-pd), freshly provisioned |
0 bytes |
dies on next boot |
local, freshly provisioned |
90 bytes |
fine |
pd-ssd-euw2a, after manual wipe + sync |
90 bytes |
fine, survives restarts |
Control ruling out the workload: the same image with the same config file, run
directly under docker on the same host with a /tmp bind mount, writes 90
bytes and survives both docker stop (SIGTERM) and docker kill (SIGKILL) with
data intact. It is crash-consistent.
Reproduction
rune storageclass create -f storageclass-pd-ssd-euw2a.yaml # once
# any service with a claimTemplate on that class that writes a file on boot
rune cast flo.yaml -n shared # storageClassName: pd-ssd-euw2a
rune exec flo -n shared --no-tty -- stat -c '%s' /data/flo/SYSTEM
# -> 0 (expected 90)
rune restart flo -n shared
rune logs flo -n shared --tail=5
# Error starting runtime: error.UnexpectedEndOfInput (crash-loops)
Swap to storageClassName: local and the same step returns 90.
Recovery — note that rune volume delete is not sufficient (see below):
rune stop flo -n shared
# on the host:
sudo rm -rf /var/lib/rune/mounts/flo-data-flo-0/{00000,SYSTEM,flo.pid} && sync
rune scale flo 1 -n shared
# -> SYSTEM = 90 bytes, and restarts now work
On-disk state at failure
$ mount | grep flo-data
/dev/sdc on /var/lib/rune/mounts/flo-data-flo-0 type ext4 (rw,relatime)
$ sudo ls -la /var/lib/rune/mounts/flo-data-flo-0
drwxr-xr-x 4 ubuntu ubuntu 4096 Aug 29 00:00 00000
-rw-r--r-- 1 ubuntu ubuntu 0 Aug 29 00:00 SYSTEM <-- 0 bytes
-rw-r--r-- 1 ubuntu ubuntu 0 Aug 29 00:00 flo.pid <-- 0 bytes
drwx------ 2 ubuntu ubuntu 16384 Aug 29 00:00 lost+found
Mount options are unremarkable and identical to the MongoDB volume on the same
StorageClass. A disk snapshot of the failed state is preserved as
flo-corrupt-repro (source disk rune-shared-flo-data-flo-0) and can be shared.
What we have NOT established
Being explicit, because an earlier draft of this report guessed wrong: we first
suspected the volume detach was discarding unflushed page cache. That is
disproven — after the manual wipe, the same volume survives rune restart
(which detaches and reattaches) with contents intact.
The remaining suspicion is the provisioning path: format (mkfs.ext4),
mount, and hand-off to the container, where the earliest writes appear not to
reach the device. We have not instrumented that path and cannot say more from
outside. Worth checking whether the container is allowed to start before
mkfs/mount has fully settled, and whether there is a sync between format
and first use.
Secondary observations
-
rune volume delete does not give a clean slate under reclaimPolicy: retain. Deleting the volume row and letting the claimTemplate reprovision
re-binds the same underlying GCE disk with its old contents, so the obvious
recovery silently returns you to the broken state. This cost real debugging
time. A warning on the delete path, or docs, would help.
-
rune cast on a stateful service can lose the PD attach race. Cast
deletes and recreates the instance; the new one intermittently fails with
LaunchFailed: failed to resolve volume mount "flo-data": context canceled
while the old one is still detaching. The volume stays Available and bound
and rune restart clears it, so nothing is lost — but a retry/backoff on
attach would avoid an alarming failure mode. Roughly 1 in 3 casts.
-
rune volume delete has no --yes while rune release delete requires
one. Minor inconsistency.
Rune: first writes to a freshly-provisioned
gce-pdvolume are lost — files keep metadata, lose contentsSeverity: a service that writes state on first boot and reads it back later
comes up permanently broken. Silent — nothing in
runelogs or status indicatesa problem, and the service reports
Running 1/1right up until it is restarted.Versions: rune server + CLI
v0.0.1-dev.146(8c34e706), single edge node(
e2-standard-2,europe-west2-a),gce-pdCSI driver, StorageClasspd-ssd-euw2a(diskType: pd-ssd,fsType: ext4,reclaimPolicy: retain).Summary
On the first boot after a
gce-pdvolume is newly provisioned, files writtenby the service end up on disk with correct name, owner and mode but zero
length. Two unrelated files in our case (
SYSTEM,flo.pid) — directoryentries and inodes persisted, file contents did not.
The service keeps running and reports healthy. The damage only surfaces on the
next restart, when it tries to read what it thinks it wrote.
Once the directory is manually cleared and the service restarted, the same
volume works correctly and survives subsequent restarts, including the
detach/attach cycle a
rune restartperforms. So this is specific to theinitial-provisioning window, not to ongoing use of the volume.
Evidence
Same cast, same configmap, same image (
ghcr.io/floruntime/flo:0.1.0-dev.9),changing only
storageClassName:SYSTEMafter first bootpd-ssd-euw2a(gce-pd), freshly provisionedlocal, freshly provisionedpd-ssd-euw2a, after manual wipe +syncControl ruling out the workload: the same image with the same config file, run
directly under
dockeron the same host with a/tmpbind mount, writes 90bytes and survives both
docker stop(SIGTERM) anddocker kill(SIGKILL) withdata intact. It is crash-consistent.
Reproduction
Swap to
storageClassName: localand the same step returns 90.Recovery — note that
rune volume deleteis not sufficient (see below):On-disk state at failure
Mount options are unremarkable and identical to the MongoDB volume on the same
StorageClass. A disk snapshot of the failed state is preserved as
flo-corrupt-repro(source diskrune-shared-flo-data-flo-0) and can be shared.What we have NOT established
Being explicit, because an earlier draft of this report guessed wrong: we first
suspected the volume detach was discarding unflushed page cache. That is
disproven — after the manual wipe, the same volume survives
rune restart(which detaches and reattaches) with contents intact.
The remaining suspicion is the provisioning path: format (
mkfs.ext4),mount, and hand-off to the container, where the earliest writes appear not to
reach the device. We have not instrumented that path and cannot say more from
outside. Worth checking whether the container is allowed to start before
mkfs/mounthas fully settled, and whether there is asyncbetween formatand first use.
Secondary observations
rune volume deletedoes not give a clean slate underreclaimPolicy: retain. Deleting the volume row and letting the claimTemplate reprovisionre-binds the same underlying GCE disk with its old contents, so the obvious
recovery silently returns you to the broken state. This cost real debugging
time. A warning on the delete path, or docs, would help.
rune caston a stateful service can lose the PD attach race. Castdeletes and recreates the instance; the new one intermittently fails with
LaunchFailed: failed to resolve volume mount "flo-data": context canceledwhile the old one is still detaching. The volume stays
Availableand boundand
rune restartclears it, so nothing is lost — but a retry/backoff onattach would avoid an alarming failure mode. Roughly 1 in 3 casts.
rune volume deletehas no--yeswhilerune release deleterequiresone. Minor inconsistency.