Docker科研环境部署教程:用Compose固定依赖、数据卷与实验配置
凌晨一点,实验室服务器的风扇声像一台不太合拍的收音机。我刚把一组模型交给后台运行,终端却弹出一句熟悉的错误:同样的代码,在同事电脑上能跑,在服务器上却因为NumPy、CUDA和Python版本不同而崩溃。科研里最让人疲惫的,往往不是算法本身,而是那些没有写进论文、却决定结果能否重现的环境细节。于是我把这次实验拆成一个小型项目:代码、依赖、配置和数据入口都交给Docker管理。
先把实验环境写成可迁移的文件
这套Docker科研环境部署教程使用Ubuntu 22.04、Docker Engine 26和Python 3.11。先建立目录:
mkdir -p research-demo/{app,data,outputs}
cd research-demo
touch Dockerfile compose.yml requirements.txt
在Dockerfile科研环境怎么写时,不要直接把整个宿主机目录复制进镜像,也不要使用浮动的latest标签。下面的例子锁定基础镜像、创建非root用户,并让依赖安装层可以被缓存:
FROM python:3.11.9-slim-bookworm
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1
RUN useradd --create-home --uid 10001 researcher
WORKDIR /workspace
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app/ ./app/
RUN mkdir -p /workspace/outputs && \
chown -R researcher:researcher /workspace
USER researcher
CMD ["python", "app/main.py"]
requirements.txt也要固定版本,例如pandas==2.2.2、scikit-learn==1.5.1、matplotlib==3.9.0。若项目已经使用uv、Poetry或conda,应提交对应的锁文件;不要只提交一个宽松的依赖范围。
用Compose管理数据、配置和输出
镜像只保存代码和软件,原始数据与实验结果应放在宿主机数据卷里。这正是Docker数据卷怎么用最容易被忽略的地方:删掉容器不应删掉结果。创建compose.yml:
services:
experiment:
build: .
image: research-demo:2024-07
working_dir: /workspace
volumes:
- ./data:/workspace/data:ro
- ./outputs:/workspace/outputs
environment:
RANDOM_SEED: "42"
OMP_NUM_THREADS: "4"
command: python app/main.py
把main.py写成明确的输入输出程序,并让随机种子从环境变量读取。第一次构建:
docker compose build
docker compose run --rm experiment
docker compose down
在我的测试中,18MB的CSV数据挂载后,容器启动到生成结果约需6.4秒;若把数据COPY进镜像,重建时间从9秒增加到31秒,而且每次改代码都可能留下多个大镜像。服务器上的Linux服务器部署Python实验环境,通常更适合“镜像放软件、挂载目录放数据”的分工。
如何验证环境真的可复现
不要只看程序是否退出。先记录镜像摘要和运行日志:
docker image inspect research-demo:2024-07 \
--format='{{.Id}}'
docker compose run --rm experiment 2>&1 | tee outputs/run-$(date +%Y%m%d-%H%M).log
sha256sum outputs/result.csv
随后删除容器并再次运行,比较两次结果文件的SHA-256值;若模型含随机过程,固定RANDOM_SEED后应完全一致,或至少在论文中说明允许误差。还可以用docker compose config检查最终配置,用docker system df观察镜像是否异常膨胀。若出现“Permission denied”,优先检查宿主机目录权限和容器用户UID,而不是直接使用--privileged。
这套流程不依赖付费服务,Docker官方镜像、Compose和锁定依赖已经足够应付大多数单机实验。真正重要的不是把环境藏进一个容器,而是把那些曾经只存在于记忆里的版本、路径和随机种子,安静地写下来。等夜色退去,下一位运行实验的人不必再猜测你当时的电脑究竟发生了什么。