How Persistent Workspaces Actually Work (A Deep Dive)
How Persistent Workspaces Actually Work
GPU pods are ephemeral. When your pod restarts, everything outside of mounted volumes is gone. Your pip packages, your config files, your half-finished training script — all wiped. This is a deep dive into how our Persistent Workspace feature solves this, and why it works the way it does.
The Problem: Ephemeral Containers
Kubernetes pods run containers. Containers use layered filesystems (typically overlayfs) where the writable layer exists only for the container's lifetime. When the container stops, that layer is discarded.
This means:
pip install torch— gone after restart- Your
.bashrccustomizations — gone - That Jupyter notebook you forgot to download — gone
- SSH keys you generated — gone
For GPU workloads, this is brutal. A single pip install torch torchvision torchaudio takes several minutes and downloads gigabytes. Doing that every time your pod cycles is not acceptable.
The Solution: Volume Mounts + Init Scripts
The fix has two parts:
- Persistent volumes — Kubernetes PersistentVolumeClaims (PVCs) that survive pod restarts
- Init scripts — Bash scripts that wire the persistent storage into the right places on boot
When you launch a GPU on Packet with persistent storage enabled, we mount a PVC at /workspace. This directory persists across pod restarts. The question is: how do you make that useful?
The Init Script, Line by Line
Here's the actual script that runs when you select "Persistent Workspace":
#!/bin/bash
set -e
echo "=== Setting up Persistent Workspace ==="
# Check if /workspace exists (persistent storage mounted)
if [ ! -d "/workspace" ]; then
echo "Warning: /workspace not found."
exit 0
fi
# Create home backup location
mkdir -p /workspace/home
# Copy existing home contents if this is first run
if [ ! -f "/workspace/home/.packet-init" ]; then
echo "First run - copying home to persistent storage..."
cp -r $HOME/. /workspace/home/ 2>/dev/null || true
touch /workspace/home/.packet-init
fi
# Persist PATH additions
if ! grep -q "packet-persist" /workspace/home/.bashrc 2>/dev/null; then
echo '# packet-persist marker' >> /workspace/home/.bashrc
echo 'export PATH="/workspace/bin:$PATH"' >> /workspace/home/.bashrc
mkdir -p /workspace/bin
fi
Let's break this down.
Step 1: Guard Clause
if [ ! -d "/workspace" ]; then
echo "Warning: /workspace not found."
exit 0
fi
If there's no persistent volume mounted at /workspace, there's nothing to persist to. The script exits cleanly rather than failing. This is important because the script runs during pod boot — a hard failure here would prevent the pod from starting.
Note: exit 0 not exit 1. We don't want to block pod startup just because storage wasn't attached. The user will see the warning in the startup logs.
Step 2: The Init Marker Pattern
if [ ! -f "/workspace/home/.packet-init" ]; then
cp -r $HOME/. /workspace/home/ 2>/dev/null || true
touch /workspace/home/.packet-init
fi
This is the core trick. On the very first boot:
- Copy the entire home directory into
/workspace/home/ - Write a marker file (
.packet-init)
On subsequent boots, the marker file exists, so the copy is skipped. This means your persistent home directory keeps accumulating changes across restarts without being overwritten by the fresh container's defaults.
The 2>/dev/null || true is defensive. Some files in $HOME might have restrictive permissions or be special (sockets, etc). We don't want cp failures to abort the script.
The cp -r $HOME/. pattern (note the dot) copies the contents of $HOME including hidden files (like .bashrc, .ssh/, etc.) into /workspace/home/ without creating a nested directory.
Step 3: PATH Persistence
if ! grep -q "packet-persist" /workspace/home/.bashrc 2>/dev/null; then
echo '# packet-persist marker' >> /workspace/home/.bashrc
echo 'export PATH="/workspace/bin:$PATH"' >> /workspace/home/.bashrc
mkdir -p /workspace/bin
fi
This adds /workspace/bin to the PATH in the persisted .bashrc. The grep -q "packet-persist" check prevents duplicate entries across restarts (idempotency).
Why /workspace/bin? If you install binaries to this directory, they'll be available after restarts. For example:
# Install something to the persistent bin directory
cp my-tool /workspace/bin/
chmod +x /workspace/bin/my-tool
# Available after restart because /workspace/bin is in PATH
The Full Dev Environment Variant
When you select "Full Dev Environment", the persistence logic is embedded alongside VS Code and Jupyter setup:
# 1. Setup persistent workspace
if [ -d "/workspace" ]; then
mkdir -p /workspace/home
if [ ! -f "/workspace/home/.packet-init" ]; then
cp -r $HOME/. /workspace/home/ 2>/dev/null || true
touch /workspace/home/.packet-init
fi
fi
# 2. Install VS Code (code-server)
curl -fsSL https://code-server.dev/install.sh | sh
# 3. Install Jupyter Lab
pip install --quiet jupyterlab numpy pandas matplotlib
The workspace persistence runs first, then services are installed. Note that VS Code and Jupyter still get installed from scratch on each restart — only the workspace files persist, not the installed packages themselves.
What Persists (and What Doesn't)
Persists across restarts:
- Files in
/workspace/ - The home directory snapshot in
/workspace/home/ - Anything you put in
/workspace/bin/
Does NOT persist:
- System packages (
apt-get install ...) - pip packages (unless installed to
/workspace) - Systemd services / running processes
- Anything written to directories outside
/workspace/
Why Not Bind-Mount $HOME?
You might wonder: why not just mount the PVC directly at $HOME? Then everything would persist automatically.
There are a few reasons:
-
Container images expect a populated
$HOME— CUDA images have specific dotfiles, conda configs, and environment setups in the home directory. Mounting an empty volume there would break things. -
First-boot bootstrapping — The container needs to initialize
$HOMEwith defaults before we can persist it. You can't mount a PVC and populate it atomically during container creation. -
Clean escape hatch — If something goes wrong with the persisted home, you can simply delete
/workspace/home/.packet-initand the next restart will re-copy the fresh defaults.
Pro Tips
Persist pip packages
# Install to a persistent location
pip install --target=/workspace/pip-packages torch
# Add to your persistent bashrc
echo 'export PYTHONPATH="/workspace/pip-packages:$PYTHONPATH"' \
>> /workspace/home/.bashrc
Persist conda environments
# Create conda env in persistent storage
conda create --prefix /workspace/envs/myenv python=3.11
conda activate /workspace/envs/myenv
Custom startup script with persistence
Write a script that installs from a requirements file stored in /workspace:
#!/bin/bash
# Your custom startup script
if [ -f /workspace/requirements.txt ]; then
pip install -r /workspace/requirements.txt
fi
if [ -f /workspace/setup.sh ]; then
bash /workspace/setup.sh
fi
Store your requirements.txt and setup.sh in /workspace/ once, and they'll run on every boot automatically.
The Architecture
Here's the full picture:
┌──────────────────────────────────────┐
│ Kubernetes Pod │
│ │
│ ┌──────────────────────────────┐ │
│ │ Container (ephemeral) │ │
│ │ │ │
│ │ $HOME (/root or /home/x) │ │
│ │ └── .bashrc, .ssh/, etc. │ │
│ │ (reset every restart) │ │
│ │ │ │
│ │ /workspace (PVC mount) ────┼──┐ │
│ │ ├── home/ │ │ │
│ │ │ ├── .packet-init │ │ │
│ │ │ ├── .bashrc (persisted)│ │ │
│ │ │ └── your files... │ │ │
│ │ ├── bin/ │ │ │
│ │ └── your-project/ │ │ │
│ └──────────────────────────────┘ │ │
│ │ │
└────────────────────────────────────┘ │
│
┌────────────────────────────────────┘
│ PersistentVolumeClaim
│ (survives pod restarts)
└────────────────────────────────────
Summary
Persistent Workspaces are a simple mechanism:
- Mount a PVC at
/workspace - On first boot, copy
$HOMEinto/workspace/home/ - Mark it with
.packet-initso subsequent boots don't overwrite - Add
/workspace/binto PATH for persistent binaries
It's not magic. It's a well-placed cp -r, a marker file, and a volume that outlives the container. Simple, predictable, and easy to debug when things go wrong.
Next time you launch a GPU, enable persistent storage and select "Persistent Workspace" or "Full Dev Environment". Your files will be there when you come back.
