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.

TermPlain-language meaningRole in this guide
DockerfileThe recipe for an imageSelects Python and installs declared libraries
ImageA packaged, read-only environmentContains the runtime, libraries, and copied code
ContainerA running process created from an imageExecutes the analysis in the packaged environment
Compose fileA description of how to run one or more containersConnects 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:

  • FROM selects the base Python environment
  • WORKDIR sets the same working directory for later commands
  • COPY requirements.txt puts the dependency definition in the image
  • RUN installs those dependencies while the image is built
  • COPY src includes the current analysis code
  • CMD states 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.

ItemWhat to record
Input dataProvider, product, snapshot or retrieval date, subset, and checksum when available
CodeGit commit or release tag
EnvironmentDockerfile, dependency lock, base image, and reviewed digest when needed
ParametersRegion, time range, variables, thresholds, and random seed
ProcedureExact command and expected output files
ValidationTests, 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:

  1. Clone the code repository
  2. Obtain the documented input data separately
  3. Run docker compose build
  4. Run one documented analysis command
  5. Find generated files only under output/
  6. 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.

Go to the contact form

Continue with:

References: