Persistence model
The dev container uses a bind mount strategy to persist your work while keeping the container environment reproducible.What is a bind mount?
A bind mount creates a direct mapping between a directory on your host machine and a directory inside the container. Files written to either location appear in both.devcontainer.json:
source: Your project folder on the hosttarget: Mount point inside the containertype=bind: Direct filesystem mapping
Bind mounts ensure changes are immediately visible in both locations. No sync delay, no data copying.
Persisted data
Files in the workspace folder are automatically persisted to your host machine.Source code
All ROS2 packages in thesrc/ directory are persisted:
post-create.sh (first container creation)
Persisted: Yes, via bind mount
Safe to modify: Yes
Version controlled: Yes (each subdirectory is a git repository)
Configuration files
Dev container configuration files are persisted:Custom launch files and maps
Any files you create in the workspace are persisted:- Custom launch files in package directories
- Saved maps (typically in
~/maps/- see note below) - Configuration files
- Scripts and utilities
Project documentation
Readme files and documentation in the workspace:Ephemeral data
These files exist only while the container is running and are regenerated as needed.Build artifacts
Colcon build outputs are not persisted by default:- Can be regenerated from source with
colcon build - Often contain platform-specific binaries
- Large file sizes (hundreds of MB)
- May cause issues if host and container architectures differ
post-start.sh on every container start
The
.gitignore file explicitly excludes build/, install/, and log/ directories from version control.Container filesystem
Everything outside the workspace mount is ephemeral:- Installed apt packages (defined in Dockerfile)
- System configuration in
/etc/ - User home directory
~/(except workspace) - Temporary files in
/tmp/
Container state
Running processes and runtime state:- Running ROS2 nodes
- Gazebo simulation state
- Terminal sessions
- Environment variables set in current session (not in
.bashrc)
Special directories
Home directory (~/)
The container home directory is not persisted by default.
Location inside container: /home/<username>/
Persisted: No
Contains:
.bashrc(configured bypost-create.sh).bash_history- ROS2 logs
- Gazebo cache (
.gz/) - VNC configuration (
.vnc/)
~/my_data persists because it’s actually in the workspace.
Maps directory
By default,post-create.sh creates ~/maps/, which is not persisted.
Problem: Maps saved during SLAM will be lost when container is deleted.
Solution: Use a persisted location:
ROS2 logs
ROS2 runtime logs are stored in~/.ros/log/ and are not persisted.
Location: /home/<username>/.ros/log/
Persisted: No
Persistence workaround:
.bashrc in post-create.sh for permanence.
Container lifecycle
Container creation
First time opening the dev container:-
Image build: Dockerfile instructions execute
- Installs all packages
- Takes 10-15 minutes
- Image is cached for reuse
-
Container creation: Docker creates container from image
- Mounts workspace folder
- Forwards ports
- Applies runtime configuration
-
Post-create hook:
post-create.shruns- Clones TurtleBot3 repositories to
src/ - Configures
.bashrc - Installs dependencies
- Source code is now persisted
- Clones TurtleBot3 repositories to
-
Post-start hook:
post-start.shruns- Builds workspace with
colcon build - Build artifacts are ephemeral
- Builds workspace with
Container restart
When you reopen the project:-
Container start: Existing container resumes
- Workspace mount reconnects
- Persisted source code is available
- Build artifacts may or may not exist
-
Post-start hook:
post-start.shruns- Checks if workspace is built
- Rebuilds if necessary
- Ensures workspace is always ready
Container rebuild
When you explicitly rebuild (F1 → “Rebuild Container”):-
Container deletion: Old container is removed
- Ephemeral data lost
- Persisted workspace untouched
- Image rebuild: Dockerfile instructions re-execute (if needed)
- New container creation: Fresh container created
-
Post-create hook: Runs again
- Skips cloning if repositories already exist
- Re-configures
.bashrc
-
Post-start hook: Runs
- Rebuilds workspace from persisted source
The
post-create.sh script checks if TurtleBot3 repositories exist before cloning, so rebuilding doesn’t duplicate packages.Best practices
Keep source in workspace
Always create or clone packages inside the workspace:Use version control
The workspace is designed for git:Save important files to workspace
Move critical files to the workspace:Document persistent paths
If your package expects files in specific locations, document where to save them:~/maps/ as this is not persisted.
If TurtleBot3 repositories are missing
Run post-create script again:If container is unrecoverable
Rebuild from scratch:- Close VS Code
- Delete container:
docker rm -f <container-name> - Delete image:
docker rmi <image-name> - Open project in VS Code
- Reopen in container
- Wait for rebuild and post-create
src/ will still be there because it’s on the host.
Advanced persistence: Docker volumes
For advanced users, Docker volumes can persist additional directories.Adding a volume for home directory
Editdevcontainer.json:
Named volumes vs. bind mounts
Bind mount (current approach):- Direct host folder mapping
- Files accessible from both host and container
- Easy to backup, version control, and inspect
- Used for: Workspace source code
- Docker-managed storage
- Not directly accessible from host
- Better performance on non-Linux systems
- Potential use for: Home directory, cache directories
The default configuration uses bind mounts for simplicity and accessibility. Volumes are optional optimizations.