用 Docker + JupyterHub 搭建团队生信分析平台¶
一句话说明: 使用 Docker 容器化和 JupyterHub 多用户管理,为团队快速搭建一个可复现、可扩展的生物信息学分析工作台。
为什么要学¶
- 面试加分 — 展示你具备 DevOps + 生信双重能力,理解可复现研究的工程实践
- 实用性 — 团队共享一套标准化分析环境,新人到岗即用,告别"我的电脑上能跑"
- 可复现 — Docker 镜像 + 版本锁定,论文发表后任何人都能重现分析结果
- 可扩展 — 从单机到集群无缝迁移,支持 GPU 加速
核心概念详解¶
为什么用 Docker?¶
白话: 生信工具依赖复杂(不同版本的 Python/R/Java/C 库),Docker 把整个环境打包成"集装箱",搬到哪台机器都能跑。
| 对比项 | 手动安装 | Conda 环境 | Docker 容器 |
|---|---|---|---|
| 隔离性 | 无 | 部分 | 完全 |
| 可复现 | 差 | 中等 | 优秀 |
| 系统依赖 | 手动解决 | 部分覆盖 | 完全包含 |
| 共享 | 写文档 | environment.yml | 镜像推送 |
| 启动速度 | — | 秒级 | 秒级 |
| 多用户 | 困难 | 困难 | 原生支持 |
JupyterHub 架构¶
白话: Jupyter Notebook 是单人使用的。JupyterHub 是多人版——每个人有独立的 Notebook 实例,管理员统一管理用户和资源。
Bioconductor / Conda-forge¶
白话: 生信工具的两大来源——R 包去 Bioconductor,Python/命令行工具去 conda-forge/bioconda。Docker 里两个都装好。
安装与配置¶
前置要求¶
# 安装 Docker
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# 安装 Docker Compose
sudo apt install docker-compose-plugin
# 验证
docker --version
docker compose version
项目结构¶
bioinfo-workbench/
├── docker-compose.yml # 服务编排
├── jupyterhub/
│ ├── Dockerfile # Hub 镜像
│ ├── jupyterhub_config.py # Hub 配置
│ └── requirements.txt
├── notebook/
│ ├── Dockerfile # 用户 Notebook 镜像
│ ├── environment.yml # Conda 环境
│ └── postBuild # 构建后脚本
├── data/ # 共享数据目录
└── config/
└── nginx.conf # 反向代理(可选)
快速上手¶
5 分钟最小可用版本¶
# docker-compose.yml
version: "3.9"
services:
jupyterhub:
image: quay.io/jupyterhub/jupyterhub:4
ports:
- "8000:8000"
volumes:
- ./jupyterhub/jupyterhub_config.py:/srv/jupyterhub/jupyterhub_config.py
- /var/run/docker.sock:/var/run/docker.sock
- jupyterhub-data:/srv/jupyterhub/data
environment:
DOCKER_NETWORK_NAME: bioinfo-net
networks:
- bioinfo-net
volumes:
jupyterhub-data:
networks:
bioinfo-net:
name: bioinfo-net
# jupyterhub/jupyterhub_config.py
import os
c.JupyterHub.spawner_class = 'dockerspawner.DockerSpawner'
c.DockerSpawner.image = 'bioinfo-notebook:latest'
c.DockerSpawner.network_name = 'bioinfo-net'
c.DockerSpawner.volumes = {
'jupyter-user-{username}': '/home/jovyan/work',
'/srv/data': {'bind': '/home/jovyan/shared-data', 'mode': 'ro'},
}
# 资源限制
c.DockerSpawner.mem_limit = '4G'
c.DockerSpawner.cpu_limit = 2
# 简单认证(生产环境换 LDAP/OAuth)
c.JupyterHub.authenticator_class = 'nativeauthenticator.NativeAuthenticator'
c.Authenticator.admin_users = {'admin'}
进阶用法¶
1. 自定义生信 Notebook 镜像¶
# notebook/Dockerfile
FROM jupyter/scipy-notebook:latest
USER root
# 系统级生信工具
RUN apt-get update && apt-get install -y \
samtools \
bcftools \
bedtools \
fastqc \
bwa \
bowtie2 \
&& rm -rf /var/lib/apt/lists/*
USER ${NB_UID}
# Conda 环境(Python 生信)
COPY environment.yml /tmp/environment.yml
RUN mamba env update -n base -f /tmp/environment.yml && \
mamba clean -afy
# R 包
RUN mamba install -n base -c conda-forge -c bioconda \
r-base=4.3 \
bioconductor-deseq2 \
bioconductor-edger \
bioconductor-clusterProfiler \
r-seurat \
r-ggplot2 \
r-tidyverse \
&& mamba clean -afy
# Jupyter kernels
RUN pip install --no-cache-dir \
scanpy \
scvi-tools \
cellrank \
squidpy
# R kernel for Jupyter
RUN R -e "IRkernel::installspec(user = FALSE)"
# notebook/environment.yml
name: base
channels:
- conda-forge
- bioconda
- defaults
dependencies:
- python=3.11
- numpy
- pandas
- scipy
- matplotlib
- seaborn
- scikit-learn
- biopython
- pysam
- pyvcf3
- snakemake
- nextflow
- multiqc
- cutadapt
- trim-galore
- star
- hisat2
- salmon
- kallisto
- subread
2. 完整 Docker Compose(生产级)¶
# docker-compose.yml
version: "3.9"
services:
jupyterhub:
build: ./jupyterhub
ports:
- "8000:8000"
volumes:
- ./jupyterhub/jupyterhub_config.py:/srv/jupyterhub/jupyterhub_config.py
- /var/run/docker.sock:/var/run/docker.sock
- jupyterhub-data:/srv/jupyterhub/data
environment:
DOCKER_NETWORK_NAME: bioinfo-net
POSTGRES_HOST: db
depends_on:
- db
networks:
- bioinfo-net
restart: unless-stopped
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: jupyterhub
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_DB: jupyterhub
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- bioinfo-net
restart: unless-stopped
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./config/nginx.conf:/etc/nginx/nginx.conf
- ./certs:/etc/nginx/certs
depends_on:
- jupyterhub
networks:
- bioinfo-net
restart: unless-stopped
volumes:
jupyterhub-data:
postgres-data:
networks:
bioinfo-net:
name: bioinfo-net
3. GPU 支持(深度学习 + AlphaFold)¶
# docker-compose.gpu.yml
services:
jupyterhub:
# ... 其他配置 ...
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu]
# jupyterhub_config.py 补充
c.DockerSpawner.extra_host_config = {
'device_requests': [
docker.types.DeviceRequest(
count=-1,
capabilities=[['gpu']]
)
]
}
4. 用户资源配额¶
# jupyterhub_config.py
# 不同用户组不同配额
c.DockerSpawner.mem_limit = '8G'
c.DockerSpawner.cpu_limit = 4
# 或按 profile 提供多种选择
c.DockerSpawner.profile_list = [
{
'display_name': '基础环境 (2 CPU, 4GB RAM)',
'slug': 'basic',
'default': True,
'kubespawner_override': {
'mem_limit': '4G',
'cpu_limit': 2,
}
},
{
'display_name': '高性能 (8 CPU, 32GB RAM, GPU)',
'slug': 'gpu',
'kubespawner_override': {
'mem_limit': '32G',
'cpu_limit': 8,
'extra_resource_limits': {'nvidia.com/gpu': '1'},
}
},
]
5. 共享数据管理¶
# 共享只读数据(参考基因组、注释文件)
c.DockerSpawner.volumes = {
'jupyter-user-{username}': '/home/jovyan/work',
'/srv/data/reference': {'bind': '/data/reference', 'mode': 'ro'},
'/srv/data/shared-results': {'bind': '/data/shared', 'mode': 'rw'},
}
# 数据目录结构
/srv/data/
├── reference/
│ ├── genomes/
│ │ ├── hg38/
│ │ └── mm39/
│ ├── annotations/
│ │ ├── gencode.v44.gtf
│ │ └── ensembl_109/
│ └── indices/
│ ├── star_hg38/
│ └── bwa_hg38/
└── shared-results/
├── project-A/
└── project-B/
6. 自动备份¶
#!/bin/bash
# backup.sh - 定期备份用户数据
BACKUP_DIR="/backup/jupyter-$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"
# 备份所有用户 volume
for vol in $(docker volume ls -q | grep jupyter-user-); do
user=$(echo $vol | sed 's/jupyter-user-//')
docker run --rm \
-v "$vol:/data" \
-v "$BACKUP_DIR:/backup" \
alpine tar czf "/backup/${user}.tar.gz" -C /data .
done
# 备份 Hub 数据库
docker exec bioinfo-db pg_dump -U jupyterhub jupyterhub | \
gzip > "$BACKUP_DIR/hub-db.sql.gz"
echo "Backup completed: $BACKUP_DIR"
7. 监控与健康检查¶
# docker-compose.yml 补充
services:
monitoring:
image: grafana/grafana:latest
ports:
- "3000:3000"
volumes:
- grafana-data:/var/lib/grafana
networks:
- bioinfo-net
prometheus:
image: prom/prometheus:latest
volumes:
- ./config/prometheus.yml:/etc/prometheus/prometheus.yml
networks:
- bioinfo-net
常见问题与排错¶
| 问题 | 原因 | 解决方案 |
|---|---|---|
| Spawner 超时 | 镜像太大首次拉取慢 | 预先 docker pull,增大 spawn_timeout |
| 内存不足 | 用户分析占满 | 设置 mem_limit,监控资源使用 |
| 权限问题 | 容器内外 UID 不匹配 | 确保用 jovyan (UID 1000) 或映射 |
| 网络不通 | 容器不在同一 network | 检查 network_name 配置一致 |
| R 包安装失败 | 系统依赖缺失 | 在 Dockerfile 中用 apt 装依赖 |
| GPU 不可见 | nvidia-docker 未配置 | 安装 nvidia-container-toolkit |
面试高频考点¶
- 为什么生信需要容器化?
工具依赖冲突严重、版本敏感、可复现性是发表要求
JupyterHub 的 Spawner 机制?
Hub 管理认证和路由,Spawner 按需为每个用户创建独立容器
如何保证分析的可复现性?
锁定镜像版本(tag/digest)+ Snakemake/Nextflow 流程 + 数据版本管理
单机 vs 集群部署的选择?
<10 用户单机 Docker;>10 用户考虑 Kubernetes + KubeSpawner
数据安全考虑?
- RLS 权限隔离、volume 加密、网络隔离、定期备份、审计日志