この記事の目次

研究中は動いていたPythonスクリプトが、半年後に動かなくなることがあります。ライブラリが更新された、以前使っていたPythonが入っていない、共同研究者のパソコンに必要なシステムパッケージがない、といった理由です。コードは残っていても、解析に使ったソフトウェア環境の情報が残っていません。

Dockerを使うと、ベースとなるOS環境、Pythonのバージョン、ライブラリ、プロジェクト内のディレクトリ、実行コマンドを設定ファイルに記述できます。Dockerはその設定からイメージを作り、イメージから起動したコンテナの中で解析を実行します。

Dockerの設定ファイルは、解析環境を再現するためのレシピだと考えると分かりやすいでしょう。必要なソフトウェアと実行方法をまとめて残せるため、特定の研究者のパソコンに依存しにくくなります。

この記事ではDockerを使ったことがない人を想定し、何に役立つのか、何を再現できないのかを説明します。そのうえで、入力データを読み取り専用にし、出力先を分けた最小限のPython解析環境を作ります。

研究コードだけでは残らない情報

研究結果は、解析スクリプトだけから作られるわけではありません。

result
├── input data
├── source code
├── parameters and method choices
├── Python and library versions
├── system libraries
└── exact run procedure

Gitではソースコードとテキストファイルを記録できますが、パソコンにインストールされたソフトウェアまでは自動的に記録しません。requirements.txtにPythonライブラリを書いても、Python本体、OSパッケージ、作業ディレクトリ、実行コマンドが明記されないままになることがあります。

Dockerを使うと、こうした実行環境の構成を設定ファイルに残せます。特に次の場合に役立ちます。

  • 複数の人が同じ解析を実行する
  • 数か月から数年にわたって研究を続ける
  • プロジェクトごとに異なるライブラリのバージョンが必要になる
  • 必要なソフトウェアが入っていないパソコンやCI環境でも同じコマンドを実行する
  • 学位論文、論文、報告書に使用した解析環境を記載する

標準的な機能だけを使う一度きりの小さなスクリプトなら、Dockerを準備する手間のほうが大きい場合もあります。研究期間、環境の複雑さ、利用者の数が増えるほど、記録する価値も高まります。

四つの用語でDockerを理解する

この例を理解するために必要な用語は、次の四つです。

用語日常語での意味この記事での役割
Dockerfileイメージを作るレシピPythonを選び、requirements.txtに記載したライブラリを導入する
イメージ読み取り専用でまとめた実行環境実行基盤、ライブラリ、コピーしたコードを含む
コンテナイメージから起動した実行中のプロセスまとめた環境の中で解析を動かす
Composeファイル一つ以上のコンテナをどう動かすかの定義ローカルのコード、データ、出力を接続し、コマンドを決める

イメージは、起動中の仮想コンピューターではありません。コンテナは、必要なファイルを備え、ホストのカーネルを共有する分離されたプロセスです。macOSやWindowsではDocker Desktop自体が軽量な仮想マシンを使うことがありますが、この例で利用者がその仮想マシンを管理する必要はありません。

Dockerだけでは保証できないもの

Dockerを使うと同じ解析を再実行しやすくなりますが、研究の正しさや完全性が自動的に保証されるわけではありません。

次の点は、別の方法で記録または確認する必要があります。

  • 実際に使用した入力データ
  • 変数、しきい値、品質基準を選んだ理由
  • 乱数シードと非決定的な処理
  • 後日異なる結果を返す外部サービス
  • 異なるハードウェアで生じる浮動小数点結果の差
  • 計算の科学的な妥当性

同じコンテナを使っても、入力データやパラメーターが異なれば結果は変わります。コンテナで残せるのは、結果を再現するために必要な情報の一部だけです。

コード・入力・出力を分ける

プロジェクト内で、コード、入力データ、生成結果の置き場所を分けます。

research-project/
├── .dockerignore
├── Dockerfile
├── compose.yaml
├── requirements.txt
├── src/
│   └── check_environment.py
├── data/                  # 入力。読み取り専用でマウント
└── output/                # 生成ファイル。書き込み可能

コンテナはsrc/data/を読めますが、書き込めるのはoutput/だけです。この分離によって、スクリプトが元の入力を意図せず上書きする危険を減らせます。

ディレクトリと空のファイルを作ります。

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

以下のコマンドは、macOS、Linux、Windows Subsystem for LinuxなどのPOSIXシェルを想定しています。

手順1:Dockerを導入して確認する

使用中のOSに対応するDockerの公式インストール手順(英語)で導入します。macOSとWindowsではDocker Desktopが一般的です。Linuxではディストリビューションや研究機関の方針によって手順が異なります。

Dockerと現在のComposeコマンドが使えることを確認します。

docker --version
docker compose version

この記事では、空白を含むdocker composeを使います。古いdocker-composeだけが動く場合は、共同研究者と同じ手順を使えるよう、環境を作る前にDockerを更新します。

大学の共有ワークステーションや計算機では、Dockerを利用できるかどうかを管理者に確認してください。Apptainerなど別のコンテナ実行環境が提供されている場合もあります。組織のセキュリティ方針を回避してはいけません。

手順2:Pythonライブラリのバージョンを指定する

使用するライブラリと、動作を確認したバージョンをrequirements.txtに書きます。

numpy==2.2.6
pandas==2.2.3
xarray==2025.6.1

これは構成例であり、新しい研究すべてに同じバージョンを勧めるものではありません。実際のプロジェクトでは、動作を検証したバージョンを選び、依存関係が増えたらパッケージ管理ツールでロックファイルを作って全体を固定します。

直接使うライブラリだけを固定しても、それらが内部で利用するライブラリのバージョンまでは完全に固定できません。まずは、パソコンごとに異なるバージョンが知らないうちに入るのを防ぎ、更新するときに差分を確認して記録することが大切です。

手順3:イメージを定義する

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"]

上から順に、次の役割があります。

  • FROMで基となるPython環境を選ぶ
  • WORKDIRで後のコマンドが使う作業ディレクトリを固定する
  • COPY requirements.txtで依存関係の定義をイメージに取り込む
  • RUNでイメージ構築時にrequirements.txtのライブラリを導入する
  • COPY srcで現在の解析コードを含める
  • CMDで既定の実行コマンドを指定する

python:3.12.10-slimのようにバージョンが分かるタグは、学習用の例として分かりやすい指定です。ただし、長期間続ける研究や厳密さが求められる研究では、同じタグが後から更新される可能性があるため、動作を確認したイメージのダイジェストも記録します。

手順4:コード、データ、出力を接続する

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"]

bind mountを使うと、ホスト上のディレクトリをコンテナ内のパスから参照できます。Dockerのbind mountは既定では書き込み可能なので、ソースコードと入力データにはread_only: trueを明記します。生成ファイルは、別に用意した書き込み可能な出力先に保存します。

読み取り専用の指定は誤操作を防ぐのに役立ちますが、これだけで安全性が保証されるわけではありません。プロジェクト外のパス、認証情報、デバイス、DockerソケットをマウントするComposeファイルは、実行前に内容を確認してください。

手順5:環境確認コードを追加する

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}")

これは科学計算ではありません。解析コードのデバッグに入る前に、次の四点を確認します。

  • イメージが起動する
  • requirements.txtに記載したライブラリが導入されている
  • 出力ディレクトリに書き込める
  • 実際に使ったバージョンを生成ファイルに記録できる

小さな環境確認を用意すると、「コンテナが動かない」問題と「解析手法が間違っている」問題を分けて調べられます。

手順6:データをイメージに入れない

.dockerignoreに次の内容を書きます。

.git
.env
.env.*
data
output
__pycache__
*.pyc

Dockerはイメージを構築するとき、ビルドコンテキストをDockerエンジンに送ります。data/output/を除外しておくと、大容量の入力や生成結果がコンテキストに送られたり、イメージレイヤーに保存されたりするのを防げます。

パスワード、トークン、クラウド認証情報、利用制限のある研究データをイメージに入れてはいけません。後のDockerfile命令でファイルを削除しても、以前のレイヤーには残る可能性があります。

手順7:構築して実行する

イメージを構築します。

docker compose build

一時的なコンテナで確認コードを実行します。

docker compose run --rm analysis

ターミナルにPythonと各ライブラリのバージョンが表示され、同じ値がoutput/environment.jsonにも保存されれば成功です。

--rmは、コマンド終了後に停止したコンテナを削除します。構築済みのイメージ、ソースコード、入力データ、生成結果は削除しません。

どの変更で再構築が必要になるか

この例では、ファイルを二つの方法でコンテナへ渡しています。

  • ライブラリはdocker compose buildのときにイメージへ組み込む
  • ローカルのsrc/は実行時にコンテナへマウントする

requirements.txtまたはDockerfileを変えたら、再構築します。

docker compose build

マウント済みのsrc/だけを変更した場合は、再構築せずに解析を実行し直せます。後からソースコードのマウントを外し、イメージにコピーしたコードだけを使う構成にすると、コードを変えるたびに再構築が必要になります。

この違いを知っておくと、「依存関係のファイルを変えたのに、構築済みイメージに反映されない」という問題の原因を切り分けられます。

確認用コードから実際の解析へ進む

環境が動いたら、src/に解析モジュールを追加し、Composeのコマンドを変更します。

    command: ["python", "src/analyze_profiles.py"]

実際の解析に置き換えても、入力と出力の分け方は変えません。

  • 変更しない入力を/workspace/dataから読む
  • 表、図、ログ、派生ファイルを/workspace/outputへ書き出す
  • パラメーターと計算方法を、Gitで管理するテキストファイルに記録する
  • 必要な変数、単位、入力がない場合は明確なエラーで停止する

Argoを扱う研究では、生の変数と補正済み変数のどちらを使うか、どの品質フラグを採用するか、欠損値をどう扱うか、補間や派生計算を行うかもコードに明記します。ただし、Dockerが記録するのは、その処理を動かすソフトウェア環境であり、変数や品質基準は研究者が決めなければなりません。

Docker以外に残す情報

Dockerfileだけでは、研究結果を再現するための情報は足りません。次の内容も一緒に記録します。

項目記録する内容
入力データ提供元、製品名、スナップショットまたは取得日、抽出範囲、可能ならチェックサム
コードGitコミットまたはリリースタグ
環境Dockerfile、依存関係のロックファイル、ベースイメージ、必要に応じて確認済みダイジェスト
パラメーター海域、期間、変数、しきい値、乱数シード
手順実行したコマンドと生成されるファイル
検証テスト、参照比較、代表的な図、既知の制限

研究コードの変更履歴と再現性を残す方法:Git・GitHub入門 では、大容量データをコミットせずに、Dockerの定義、解析条件を記したファイル、コードをバージョン管理する方法を説明します。

起こりやすい問題

Dockerデーモンに接続できない場合は、Docker DesktopまたはDockerサービスを起動し、バージョン確認をやり直します。Composeの設定が見つからない場合は、compose.yamlがあるディレクトリへ戻ってください。

マウントするローカルのdata/output/は、実行前に存在する必要があります。共有Linux環境で出力先の権限エラーが起きる場合は、コンテナの実行ユーザーとホスト側ディレクトリの所有者が合っていない可能性があります。誰でも書き込める設定にはせず、システム管理者やプロジェクトの管理者に、一貫したユーザーマッピングを依頼してください。

あるCPUアーキテクチャでは構築でき、別の環境では失敗する場合は、ベースイメージと各依存関係が両方の環境に対応しているか確認します。コンテナは環境差を減らしますが、ハードウェア差を消すものではありません。

OceanGraphで対象を絞り、Dockerで解析環境を残す

OceanGraphとDockerは、研究の異なる場面で役立ちます。調べる海域や変数がまだ決まっていないときは、OceanGraphでArgoプロファイルを検索して鉛直構造を見比べ、解析対象を絞り込めます。対象と解析方法が決まり、同じ処理を繰り返すようになったら、その実行環境をDockerで記録します。

Pythonを使わずにArgoフロートデータを可視化する手順 では、OceanGraphでプロファイルを探して比較する流れを説明しています。そこで解析対象を決めた後、Dockerで計算に使う環境を残すと、探索から独自解析へ無理なく進めます。

最初のDocker環境はここまでできればよい

最初に作るDocker環境では、共同研究者が次の作業を行えることを目標にします。

  1. コードのリポジトリをcloneする
  2. 文書に従って入力データを別途取得する
  3. docker compose buildを実行する
  4. 記録された一つの解析コマンドを実行する
  5. 生成ファイルがoutput/だけに保存されていることを確認する
  6. ファイルを作ったコード、環境、データ、パラメーターを特定する

ここまでなら、大がかりな仕組みは必要ありません。コード、入力、出力を分け、実行に必要な情報を漏れなく残すことが重要です。

この環境を自組織だけで構築・維持するのが難しい場合は、下の問い合わせ導線から、環境構築・実装支援についてもご相談いただけます。

お問い合わせ

構築・実装支援とアノテーション業務

環境構築や設計・実装の支援、アノテーション業務の委託について、ご相談いただけます。

お問い合わせフォームへ

関連記事と公式資料

次に読む記事:

参考資料: