Volumes & Networking
Containers are isolated environments. By default, files created inside a container disappear when the container stops. Your host machine cannot see files inside the container, and the container cannot see files on your host. Volumes solve this problem by creating a bridge between the two.
Why volumes matter
Section titled “Why volumes matter”Imagine you run a DESeq2 analysis inside a container. The script reads count data, produces a results table, and exits. Without a volume, those results vanish the moment the container stops. You would have no way to retrieve them.
Volumes let you mount directories from your host machine into the container. The container can read input files you provide. It can also write output files directly to your host. This is what makes containers practical for real analysis work.
Bind mounts
Section titled “Bind mounts”A bind mount maps a directory on your host to a directory inside the container. You create one with the -v flag.
The syntax is:
-v /host/path:/container/pathEverything on the left side of the colon is the path on your machine. Everything on the right side is where it appears inside the container.
A basic example
Section titled “A basic example”Suppose you have a project with this structure:
my_project/├── data/│ └── counts.csv├── results/└── scripts/ └── analysis.RYou can mount both the data and results directories into a container:
$ podman run --rm \ -v ./data:/data:ro \ -v ./results:/results \ -v ./scripts:/scripts:ro \ my-image Rscript /scripts/analysis.RThis command does several things. It mounts your local data/ directory to /data inside the container. It mounts results/ to /results. It mounts scripts/ to /scripts. Then it runs the R script.
Read-only mounts with :ro
Section titled “Read-only mounts with :ro”Notice the :ro suffix on the data and scripts mounts. This makes them read-only. The container can read files from these directories but cannot modify or delete them.
Use :ro for input data and scripts. This protects your raw data from accidental modification. It is a simple safeguard that costs nothing.
# The container can read counts.csv but cannot change it$ podman run --rm \ -v ./data:/data:ro \ my-image cat /data/counts.csvThe results directory is mounted without :ro because the container needs to write output files there.
Working with bioinformatics data
Section titled “Working with bioinformatics data”Here is a concrete workflow. You have RNA-seq count data and want to run differential expression analysis inside a container.
Your project directory:
rnaseq_project/├── data/│ ├── counts_matrix.csv│ └── sample_info.csv├── results/└── scripts/ └── deseq2_analysis.RRun the analysis:
$ podman run --rm \ -v ./data:/data:ro \ -v ./results:/results \ -v ./scripts:/scripts:ro \ bioconductor/bioconductor:3.20 \ Rscript /scripts/deseq2_analysis.RWhen the container finishes, check your results directory:
$ ls results/deseq2_results.csvvolcano_plot.pngma_plot.pngThe output files are on your host machine. The container is gone, but your results persist. This is the key benefit of bind mounts.
Mounting single files
Section titled “Mounting single files”You can also mount individual files instead of entire directories. This is useful for configuration files.
$ podman run --rm \ -v ./config.yml:/app/config.yml:ro \ -v ./results:/results \ my-image python /app/run_pipeline.pyNamed volumes
Section titled “Named volumes”Bind mounts tie a container to a specific path on your host. Named volumes are different. Podman manages them, and they are not tied to any particular directory on your machine.
Creating a named volume
Section titled “Creating a named volume”$ podman volume create refgenomesThis creates a volume called refgenomes that Podman stores internally.
Using a named volume
Section titled “Using a named volume”$ podman run --rm \ -v refgenomes:/references \ my-image ls /referencesThe volume name goes on the left side of the colon instead of a host path. Podman recognizes it as a named volume because it is not a file path.
When to use named volumes
Section titled “When to use named volumes”Named volumes are useful when multiple containers need to share the same data. For example, you might download reference genomes once and share them across several analysis containers.
# Download reference genome into the named volume$ podman run --rm \ -v refgenomes:/references \ my-image wget -O /references/hg38.fa.gz \ https://example.com/hg38.fa.gz
# Use the same volume in a different container$ podman run --rm \ -v refgenomes:/references:ro \ -v ./data:/data:ro \ -v ./results:/results \ alignment-image bwa mem /references/hg38.fa /data/sample.fastq > results/aligned.samManaging named volumes
Section titled “Managing named volumes”# List all volumes$ podman volume ls
# Inspect a volume$ podman volume inspect refgenomes
# Remove a volume$ podman volume rm refgenomes
# Remove all unused volumes$ podman volume prunePort mapping
Section titled “Port mapping”Containers are isolated from the network by default. If a container runs a web server, you cannot reach it from your browser. Port mapping fixes this by forwarding traffic from a port on your host to a port inside the container.
The syntax is:
-p host_port:container_portRunning RStudio Server
Section titled “Running RStudio Server”RStudio Server is a popular way to use R in a browser. It listens on port 8787 by default.
$ podman run --rm \ -p 8787:8787 \ -v ./project:/home/rstudio/project \ -e PASSWORD=yourpassword \ rocker/rstudio:4.4Open your browser and go to http://localhost:8787. You will see the RStudio login page. Log in with username rstudio and the password you set.
Your project directory is available inside RStudio because of the volume mount. Any files you create or modify in /home/rstudio/project will appear on your host machine.
Running a Jupyter notebook server
Section titled “Running a Jupyter notebook server”Jupyter listens on port 8888 by default.
$ podman run --rm \ -p 8888:8888 \ -v ./notebooks:/home/jovyan/work \ jupyter/scipy-notebook:latestThe container prints a URL with a token to the terminal. Copy that URL and paste it into your browser.
Choosing a different host port
Section titled “Choosing a different host port”Sometimes port 8787 is already in use on your machine. You can map to a different host port.
$ podman run --rm \ -p 9999:8787 \ -v ./project:/home/rstudio/project \ -e PASSWORD=yourpassword \ rocker/rstudio:4.4Now RStudio is available at http://localhost:9999 instead. The container still listens on 8787 internally, but your machine forwards port 9999 to it.
Multiple ports
Section titled “Multiple ports”You can map more than one port by using the -p flag multiple times.
RStudio with a Shiny app
Section titled “RStudio with a Shiny app”RStudio Server uses port 8787. Shiny Server uses port 3838. You can expose both.
$ podman run --rm \ -p 8787:8787 \ -p 3838:3838 \ -v ./project:/home/rstudio/project \ -e PASSWORD=yourpassword \ rocker/shiny-verse:4.4Now you can access RStudio at http://localhost:8787 and your Shiny apps at http://localhost:3838.
A multi-service example
Section titled “A multi-service example”Suppose you have a container that runs both a Flask API and a monitoring dashboard.
$ podman run --rm \ -p 5000:5000 \ -p 8050:8050 \ -v ./data:/data:ro \ my-bioinfo-appPort 5000 serves the API. Port 8050 serves the dashboard. Both are accessible from your browser.
Quick reference
Section titled “Quick reference”| Task | Command |
|---|---|
| Bind mount a directory | -v ./data:/data |
| Bind mount as read-only | -v ./data:/data:ro |
| Create a named volume | podman volume create myvolume |
| Use a named volume | -v myvolume:/path |
| List volumes | podman volume ls |
| Remove a volume | podman volume rm myvolume |
| Map a single port | -p 8787:8787 |
| Map to a different host port | -p 9999:8787 |
| Map multiple ports | -p 8787:8787 -p 3838:3838 |
Next steps
Section titled “Next steps”You now know how to share files and expose services between containers and your host machine. In the next section, you will learn how to run multi-container setups with Podman Compose.