Content developed by Ben Rambo-Martin
Slides
Practical Exercises
These exercises walk you through installing Docker Desktop, configuring resources, running containers in different modes, and learning how volumes work.
All docker commands can be run from the terminal in VS Code.
Exercise 1 — Install and Configure Docker Desktop
1.1 Install Docker Desktop
- Download Docker Desktop from https://www.docker.com/products/docker-desktop/
- Run the installer.
- Windows: ensure Use WSL 2 instead of Hyper-V is checked.
- macOS: choose the correct chip (Apple Silicon or Intel).
- Linux: Docker Desktop is optional — you can install the Docker Engine directly instead (see docs.docker.com/engine/install).
- After installation, Docker Desktop will start automatically. On Windows you may need to log out and back in.
1.2 Verify the Backend
Click your operating system below for platform-specific instructions:
Windows
Open Docker Desktop → Settings → General and confirm:
- ✅ Use the WSL 2 based engine is enabled
Then open Settings → Resources → WSL integration and confirm:
- ✅ Your Ubuntu distribution is toggled on
macOS
Docker Desktop on macOS uses a built-in Linux VM automatically — no extra configuration is needed. Open Docker Desktop → Settings → General and confirm it is running.
Linux
If using Docker Engine (no Desktop), verify the daemon is running:
sudo systemctl status docker
If using Docker Desktop for Linux, open it and confirm it is running.
Verify from your terminal (all platforms):
docker info 2>/dev/null | grep -i "storage driver\|operating system\|server version"
You should see output referencing your Linux distribution (or the Docker VM) and overlay2 storage.
1.3 Allocate Resources
Click your operating system below for platform-specific instructions:
Windows (WSL2)
Docker Desktop on WSL2 shares memory and CPU with the WSL2 VM.
First, check how much RAM and how many CPUs your host machine has. Open PowerShell and run:
# Total physical memory (GB)
[math]::Round((Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory / 1GB)
# Total logical processors
(Get-CimInstance Win32_ComputerSystem).NumberOfLogicalProcessors
Use these numbers to calculate ~80% for each (e.g., 16 GB → 13 GB, 8 CPUs → 6).
Now edit (or create) the WSL config file from PowerShell or cmd:
notepad %USERPROFILE%\.wslconfig
Add the following (replace the values with your ~80% calculations):
[wsl2]
memory=13GB
processors=6
For example, on a machine with 16 GB RAM and 8 CPUs, the above allocates ~80% of each.
Save the file, then restart WSL from PowerShell:
wsl --shutdown
Reopen your WSL2 terminal and verify:
nproc # available CPUs
free -g # available memory in GB
macOS
Open Docker Desktop → Settings → Resources → Advanced.
Set CPUs and Memory to ~80% of your system (e.g., 6 CPUs and 13 GB on a 8-core / 16 GB machine).
Click Apply & Restart.
Verify from your terminal:
docker info 2>/dev/null | grep -i "cpus\|memory"
Linux
Docker Engine on Linux uses host resources directly — no VM layer, no resource limits by default. Your containers can access all available CPUs and memory.
Verify:
nproc # available CPUs
free -g # available memory in GB
Exercise 2 — Running Containers: Detached, Ephemeral, and Interactive
In this exercise you will run the same Ubuntu container three different ways and observe the differences.
2.1 Check Baseline Resource Usage
Before running anything, check that Docker is running and note your resource baseline:
docker info 2>/dev/null | grep -iE "cpus|memory"
2.2 Run a Container in Detached (Background) Mode
Start an Ubuntu container that allocates a large block of memory in the background:
docker run -d --name mem-test --shm-size=512m ubuntu:24.04 \
bash -c "dd if=/dev/zero of=/dev/shm/blob bs=1M count=500 && sleep 300"
FYI: What is dd and --shm-size?
dd (data duplicator) copies data block-by-block. Here it reads 500 one-megabyte blocks of zeros (if=/dev/zero) and writes them to /dev/shm/blob (of=), a RAM-backed filesystem inside the container — effectively allocating 500 MB of memory. The container then sleeps for 5 minutes so you can observe the usage.
--shm-size=512m increases the container’s shared memory (/dev/shm) from Docker’s default of 64 MB to 512 MB. You will rarely need this flag in practice — it is only required here because we are deliberately writing a large file to /dev/shm to simulate memory usage. Normal bioinformatics workflows do not use /dev/shm and do not need this flag.
Check that the container is running:
docker ps
Check host resource usage again with docker stats:
docker stats --no-stream
Compare the memory usage to your baseline.
2.3 Stop and Remove the Detached Container
docker stop mem-test && docker rm mem-test
Verify the container is gone:
docker ps -a | grep mem-test
Check that no containers are running:
docker ps
The list should be empty — only the header row is printed.
2.4 Run the Same Workload Ephemerally
The --rm flag tells Docker to automatically delete the container when it exits. This is the most common mode in bioinformatics — no leftover containers to clean up.
docker run --rm --name mem-test-ephemeral --shm-size=512m ubuntu:24.04 \
bash -c "dd if=/dev/zero of=/dev/shm/blob bs=1M count=500 && echo 'Done — container will self-destruct'"
After the command finishes, verify the container no longer exists:
docker ps -a | grep mem-test-ephemeral
Nothing is returned — the container was automatically removed.
2.5 Run the Same Container Interactively
The -it flags give you an interactive terminal inside the container:
docker run --rm -it --shm-size=512m ubuntu:24.04 bash
You are now inside the container.
Your prompt will look like:
root@ac1d39fb4bc6:/#
“ac1d39fb4bc6” is a randomly generated hostname docker assigned the container. You will have a different string of characters.
Try some commands:
# Check the OS
echo "os INFORMATION:"
cat /etc/os-release | head -3
echo "------------------------"
# Run the same memory workload manually
echo "dd COMMAND OUTPUT:"
dd if=/dev/zero of=/dev/shm/blob bs=1M count=500 && echo "Done"
echo "------------------------"
# See what's in the filesystem
echo "ls COMMAND OUTPUT:"
ls /
echo "------------------------"
# Exit the container (it will be removed because of --rm)
exit
After exiting, verify the container is gone:
docker ps -a
Although the container is removed, the image (ubuntu:24.04) is still stored on your host. Docker caches images so they don’t need to be downloaded again:
docker images
You should see ubuntu with tag 24.04 listed — it will be reused the next time you run a container from that image.
2.6 The Docker Daemon Uses Resources Even When Idle
Even with no containers running, the Docker daemon (and on macOS/Windows, its Linux VM) consumes CPU and memory on your host.
Check processes on your host with Docker Desktop running and no containers:
Windows (WSL2)
From PowerShell (not WSL):
# Check the WSL2 VM memory usage
Get-Process vmmem -ErrorAction SilentlyContinue | Select-Object Name, @{N='Memory (MB)';E={[math]::Round($_.WorkingSet64/1MB)}}
# Check Docker Desktop processes
Get-Process *docker* | Select-Object Name, @{N='Memory (MB)';E={[math]::Round($_.WorkingSet64/1MB)}}
The vmmem process is the WSL2 VM — it often holds several GB of memory even when idle.
macOS
# Check Docker VM memory usage (in MB)
ps aux | grep -i "com.docker" | grep -v grep | awk '{sum += $6} END {printf "Docker total: %d MB\n", sum/1024}'
Linux
# Check dockerd and containerd memory usage
ps -eo pid,rss,comm | grep -E "dockerd|containerd" | awk '{printf "%s\t%d MB\t%s\n", $1, $2/1024, $3}'
Recommendation: When you are not using containers, quit Docker Desktop (macOS/Windows) or stop the Docker service (Linux) to free those resources:
- macOS: Right-click the Docker icon in the menu bar → Quit Docker Desktop
- Windows: Right-click the Docker icon in the system tray → Quit Docker Desktop. Then also shut down WSL2 from PowerShell — the
vmmemprocess will continue holding memory even after Docker Desktop is closed:wsl --shutdown - Linux:
sudo systemctl stop docker
Restart it when you need containers again.
Exercise 3 — Understanding Volumes
Containers are ephemeral by default — any files created inside a container disappear when it is removed. Volumes (bind mounts) let you connect a host directory to a path inside the container so data persists.
3.1 Without a Volume — Data Does NOT Persist
Run a container that creates a file, then exits:
docker run --rm ubuntu:24.04 \
bash -c "echo 'hello from inside the container' > /tmp/output.txt && cat /tmp/output.txt"
You will see hello from inside the container printed. But the file is gone — it only existed inside the container:
ls /tmp/output.txt 2>/dev/null || echo "File does not exist on host"
3.2 With a Volume — Data Persists on the Host
Create a working directory and mount it into the container with -v:
mkdir -p ~/container-test
docker run --rm -v ~/container-test:/data ubuntu:24.04 \
bash -c "echo 'hello from inside the container' > /data/output.txt && cat /data/output.txt"
Now check the host — the file persists:
cat ~/container-test/output.txt
You should see hello from inside the container.
3.3 Writing Output to a Mounted Volume
A more realistic example — generate data inside the container and save it to the host:
docker run --rm -v ~/container-test:/data ubuntu:24.04 \
bash -c "date > /data/timestamp.txt && hostname >> /data/timestamp.txt && echo 'Wrote timestamp and hostname'"
Inspect the output on the host:
cat ~/container-test/timestamp.txt
Notice the hostname is the container ID, not your host — confirming the command ran inside the container, but the output file is on your host.
3.4 Interactive Exploration of Volumes
Enter a container interactively with the volume mounted:
docker run --rm -it -v ~/container-test:/data ubuntu:24.04 bash
Inside the container:
# See the mounted directory
echo "\`ls /data\` COMMAND OUTPUT:"
ls /data
echo "---------------"
# The files you created earlier are here
echo "\`cat /data/output.txt\` COMMAND OUTPUT:"
cat /data/output.txt
echo "---------------"
# Create another file
echo "\`echo "created interactively" > /data/interactive.txt\` COMMAND RUN"
echo "created interactively" > /data/interactive.txt
echo "---------------"
# Exit
exit
Verify on the host:
cat ~/container-test/interactive.txt
3.5 Clean Up
rm -r ~/container-test
Summary
| Mode | Flags | Container after exit | Use case |
|---|---|---|---|
| Detached | -d |
Remains (must docker rm) |
Long-running services |
| Ephemeral | --rm |
Automatically removed | Pipeline steps, one-off tasks |
| Interactive | --rm -it |
Automatically removed | Debugging, exploring tools |
| Volume | Flag | Data after exit |
|---|---|---|
| No mount | (none) | Lost |
| Bind mount | -v /host/path:/container/path |
Persists on host |