On this page
A Python script may work throughout a thesis project and then fail six months later. A library has changed, the original Python version is no longer installed, or a collaborator’s computer is missing a system package that nobody knew the script needed. The code is still present, but part of the analysis has disappeared: the environment in which it ran.
Docker provides a way to record that environment. You describe the operating-system layer, Python version, libraries, project directories, and run command in text files. Docker uses those files to build an image, then starts the analysis in a container created from that image.
In plain language, a Docker setup is a repeatable recipe for the computer environment around your analysis. It reduces dependence on one researcher’s laptop and makes “run this script” closer to a complete instruction.
This guide assumes no prior Docker experience. It explains what Docker is useful for, what it cannot reproduce, and how to create a small Python environment with read-only input data and a separate output directory.
The Missing Part of Many Research Projects
A research result depends on more than an analysis script:
result
├── input data
├── source code
├── parameters and method choices
├── Python and library versions
├── system libraries
└── exact run procedure
Git can record the source code and text files. It does not automatically record the software installed on a computer. A requirements.txt helps with Python packages, but it may still leave the Python version, operating-system packages, working directory, and run command implicit.
Docker makes those environment choices explicit. It is particularly useful when:
- More than one person must run the analysis
- The work will continue for months or years
- Several projects require conflicting package versions
- A clean machine or CI system must run the same command
- A thesis, paper, or report must identify the analysis environment
For a disposable script that uses only standard tools on one computer, Docker may be more setup than you need. The value increases with the lifetime, complexity, and number of users of the analysis.
Docker in Four Terms
You only need a few concepts to understand the example.
| Term | Plain-language meaning | Role in this guide |
|---|---|---|
| Dockerfile | The recipe for an image | Selects Python and installs declared libraries |
| Image | A packaged, read-only environment | Contains the runtime, libraries, and copied code |
| Container | A running process created from an image | Executes the analysis in the packaged environment |
| Compose file | A description of how to run one or more containers | Connects local code, data, and output directories and defines the command |
An image is not a running virtual computer. A container is an isolated process with the files it needs, while sharing the host’s kernel. Docker Desktop may itself use a lightweight virtual machine on macOS or Windows, but you do not need to manage that machine for this example.
What Docker Does Not Guarantee
Docker improves computational reproducibility, but it does not make a study correct or complete.
It does not automatically preserve:
- The exact input-data snapshot
- The reason a variable, threshold, or quality rule was chosen
- Random seeds and nondeterministic behavior
- External services that later return different results
- Identical floating-point results across all hardware
- Scientific validity of the calculation
Two people can run the same container with different data or parameters and obtain different results. A container records one layer of the analysis, not the entire provenance.
The Environment You Will Build
The project will have three clear boundaries:
research-project/
├── .dockerignore
├── Dockerfile
├── compose.yaml
├── requirements.txt
├── src/
│ └── check_environment.py
├── data/ # Input; mounted read-only
└── output/ # Generated files; writable
The container may read src/ and data/, but only output/ is writable. This separation reduces the chance that a script silently replaces raw input.
Create the directories and empty files:
mkdir -p research-project/src research-project/data research-project/output
cd research-project
touch Dockerfile compose.yaml requirements.txt .dockerignore
touch src/check_environment.py
The commands use a POSIX shell, such as a terminal on macOS, Linux, or Windows Subsystem for Linux.
Step 1: Install Docker and Check It
Install Docker using the current official instructions for your operating system. Docker Desktop is the common route on macOS and Windows; Linux installations vary by distribution and institutional policy.
Confirm that Docker and the current Compose command are available:
docker --version
docker compose version
This guide uses docker compose with a space. If only the older docker-compose command works, update the installation before building a shared workflow so the project does not need to document two command forms.
On a university workstation or cluster, ask the administrator whether Docker is permitted. Some shared systems provide Apptainer or another container runtime instead. Do not work around local security policy.
Step 2: Declare the Python Libraries
Add a small, reviewed set of versions to requirements.txt:
numpy==2.2.6
pandas==2.2.3
xarray==2025.6.1
These versions are an example environment, not a recommendation that every new study should use them. A real project should choose versions it has tested and use a generated lock file when the dependency tree becomes larger.
Pinning only direct packages does not fully lock their dependencies. The important beginner lesson is that dependency changes must be deliberate, reviewed, and recorded rather than introduced by an undocumented upgrade on one laptop.
Step 3: Describe the Image
Add this Dockerfile:
FROM python:3.12.10-slim
WORKDIR /workspace
COPY requirements.txt .
RUN python -m pip install --no-cache-dir -r requirements.txt
COPY src ./src
CMD ["python", "src/check_environment.py"]
Read it from top to bottom:
FROMselects the base Python environmentWORKDIRsets the same working directory for later commandsCOPY requirements.txtputs the dependency definition in the imageRUNinstalls those dependencies while the image is builtCOPY srcincludes the current analysis codeCMDstates the default command
The readable base-image tag is convenient for learning. For long-lived or high-assurance work, also record the reviewed image digest because a tag may later point to updated content.
Step 4: Connect Code, Data, and Output
Add compose.yaml:
services:
analysis:
build:
context: .
working_dir: /workspace
volumes:
- type: bind
source: ./src
target: /workspace/src
read_only: true
- type: bind
source: ./data
target: /workspace/data
read_only: true
- type: bind
source: ./output
target: /workspace/output
command: ["python", "src/check_environment.py"]
A bind mount makes a host directory available at a path inside the container. Docker bind mounts are writable by default, so read_only: true is stated for source and input data. Generated files go to the separate writable output mount.
This is a guardrail, not a universal security boundary. Review any Compose file that mounts paths outside the project, credentials, devices, or the Docker socket.
Step 5: Add an Environment Check
Put this code in src/check_environment.py:
from importlib.metadata import version
from pathlib import Path
import json
import platform
environment = {
"python": platform.python_version(),
"numpy": version("numpy"),
"pandas": version("pandas"),
"xarray": version("xarray"),
}
output_path = Path("/workspace/output/environment.json")
output_path.write_text(
json.dumps(environment, indent=2) + "\n",
encoding="utf-8",
)
print(json.dumps(environment, indent=2))
print(f"Wrote {output_path}")
This is not a scientific calculation. It checks four pieces of the workflow before scientific debugging begins:
- The image can start
- The declared packages are installed
- The output directory is writable
- The actual versions are captured in a generated file
Small environment checks separate “the container is broken” from “the analysis method is wrong.”
Step 6: Keep Data Out of the Image
Add .dockerignore:
.git
.env
.env.*
data
output
__pycache__
*.pyc
Docker sends a build context to the Docker engine. Excluding data/ and output/ prevents large inputs and generated results from being copied into that context or stored in image layers.
Never put passwords, tokens, cloud credentials, or restricted research data into an image. Removing a file in a later Dockerfile instruction may not remove it from an earlier layer.
Step 7: Build and Run
Build the image:
docker compose build
Run the check in a temporary container:
docker compose run --rm analysis
The terminal should display the Python and package versions. The same values should appear in output/environment.json.
--rm removes the stopped container after the command finishes. It does not delete the built image, source code, input data, or generated output.
Understand When to Rebuild
The example uses two ways of providing files:
- Libraries are installed into the image during
docker compose build - Local
src/is mounted into the container when it runs
After changing requirements.txt or the Dockerfile, rebuild:
docker compose build
After changing only a file under the mounted src/, run the analysis again without rebuilding. If you later remove the source mount and depend entirely on copied code, code changes will also require a rebuild.
This distinction explains a common beginner problem: editing a dependency file does not change an image that has already been built.
Replace the Check with a Real Analysis
Once the environment works, add analysis modules under src/ and change the Compose command:
command: ["python", "src/analyze_profiles.py"]
Keep the same boundary:
- Read unchanged input from
/workspace/data - Write tables, figures, logs, and derived files to
/workspace/output - Put parameters and method choices in tracked text files
- Stop with a clear error when an expected variable, unit, or input is missing
For an Argo study, the code must still state whether it uses raw or adjusted variables, which matching quality flags are accepted, how missing values are handled, and whether interpolation or derived calculations are applied. Docker records the software that executes those choices; it does not choose them.
Record the Rest of the Analysis
A repeatable environment must be connected to the rest of the provenance.
| Item | What to record |
|---|---|
| Input data | Provider, product, snapshot or retrieval date, subset, and checksum when available |
| Code | Git commit or release tag |
| Environment | Dockerfile, dependency lock, base image, and reviewed digest when needed |
| Parameters | Region, time range, variables, thresholds, and random seed |
| Procedure | Exact command and expected output files |
| Validation | Tests, reference comparisons, representative plots, and known limitations |
How to Keep Research Code Reproducible with Git and GitHub shows how to version the Docker definition, method files, and code without committing large datasets.
Common Problems
If Docker cannot connect to its daemon, start Docker Desktop or the Docker service and repeat the version checks. If Compose cannot find its configuration, return to the directory containing compose.yaml.
The local data/ and output/ directories must exist before they are mounted. On a shared Linux system, an output permission error can mean the container user and host directory owner do not match. Ask the administrator or project maintainer for a consistent user mapping instead of making the directory writable by everyone.
If a build succeeds on one CPU architecture but not another, check whether every base image and dependency provides compatible builds. A container reduces environment differences; it does not make hardware differences disappear.
Where OceanGraph Fits
Docker is most valuable once a question is ready for custom, repeated analysis. Before that stage, OceanGraph can help search and inspect Argo profiles, compare vertical structure, and identify cases worth carrying into a scripted workflow.
Visualizing Argo Float Data Without Python explains this screening stage. Exploration and reproducible analysis are complementary: first identify the observations and question, then record the environment used for the calculation.
A Practical Definition of Done
A first Docker environment is useful when a collaborator can:
- Clone the code repository
- Obtain the documented input data separately
- Run
docker compose build - Run one documented analysis command
- Find generated files only under
output/ - Identify the code, environment, data, and parameters behind those files
That result does not require a complex platform. It requires a clear boundary and a complete record.
If building and maintaining this environment inside your own team would be difficult, the inquiry link below can also be used to ask about setup and implementation support.
Contact
Implementation support and annotation services
Ask about setup, design, and implementation support, or annotation services.
Related Guides and Official References
Continue with:
- How to Keep Research Code Reproducible with Git and GitHub
- Codex and Claude Code for Research: Preventing Wrong Results
- Ocean Data Visualization: Methods, Examples, and Tools
References:
