Docker多容器通过卷共享 R 包目录

一、问题

       现在我有一台ubuntu服务器,上面运行了多个docker容器,其中有一个容器是flask后端,其需要执行R脚本,因此需要一个R环境,但是我希望这个R环境不要和宿主机的R环境混淆,现在我可以把flask后端的R环境用另一个R容器生成和管理,然后把R容器的包安装目录映射到宿主机指定目录,最后flask后端容器再把R包目录,挂载到flask后端容器中 ,实现R包共享。

二、 实现方案

  • R 容器:负责初始化 R 环境、安装所需 R 包,将 R 包目录(默认 /usr/local/lib/R/site-library)映射到宿主机共享目录;

  • Flask 容器:不直接安装 R,而是通过挂载宿主机的共享目录,复用 R 容器已安装的 R 包,仅需在容器内安装 R 解释器(无需重复装包);

  • 关键逻辑:R 包默认安装在 /usr/local/lib/R/site-library,只要让 Flask 容器的 R 解释器 “找到” 这个目录(通过挂载共享目录到相同路径),即可复用所有包,避免重复安装和环境混淆。

三、详细步骤

1. 宿主机准备:创建共享目录(用于映射 R 包)

  先在宿主机创建一个目录,用于存储 R 容器的包环境(后续 Flask 容器也挂载此目录):

# 宿主机执行:创建共享目录(路径可自定义,示例为 /data/r-packages)
mkdir -p /docker/R/4.3.1/packages
# 设置权限(避免容器内权限不足)
sudo chown $USER:docker /docker/R/4.3.1/packages  # 赋予当前用户和 docker 组权限
chmod 775 /docker/R/4.3.1/packages # 读写权限

2. 启动 R 容器:初始化 R 环境并安装包

      启动一个 R 容器,将 R 包目录 /usr/local/lib/R/site-library 映射到宿主机的 /docker/R/4.3.1/packages,并在 R 容器中安装所需包(如 ggplot2dplyr 等 Flask 脚本需要的包)。

docker run -it  --name R_4.3.1 --restart=always  -v /docker/R/4.3.1/packages:/usr/local/lib/R/site-library r-base:4.3.1 /bin/bash

       进入 R 容器的 bash 后,启动 R 并安装包(示例安装 ggplot2 和 dplyr,根据你的 Flask 脚本需求替换)

# 容器内执行:启动 R
R

# 在 R 终端中安装包(安装路径会自动指向 /usr/local/lib/R/site-library,即宿主机的 /data/r-packages)
install.packages(c("ggplot2", "dplyr", "jsonlite"), dependencies = TRUE)  # 替换为你的需求包

# 验证包安装:查看包路径是否在共享目录
.libPaths()  # 输出应包含 "/usr/local/lib/R/site-library"
q()  # 退出 R

# 退出 R 容器(容器会停止,后续可重启复用)
exit

     回到宿主机,查看 /docker/R/4.3.1/packages是否有安装的 R 包(如 ggplot2 目录),确认映射生效。

3. 配置 Flask 容器:复用 R 包目录

Flask 容器需要满足两个核心条件:

  1. 容器内安装 R 解释器(仅需解释器,无需装包);

  2. 将宿主机的 /data/r-packages 挂载到 Flask 容器的 /usr/local/lib/R/site-library,让 R 解释器找到已安装的包。

基于现有 Flask 镜像改造:如果已有 Flask 容器镜像,只需在启动时添加 R 解释器安装和目录挂载。以 python:3.10-slim 基础镜像为例,编写 Dockerfile

# Flask 容器的 Dockerfile
FROM python:3.10-slim

# 1. 安装 R 解释器(仅需解释器,不装包)
RUN apt-get update && apt-get install -y --no-install-recommends \
    r-base \  # 安装 R 解释器(轻量,不含额外包)
    && rm -rf /var/lib/apt/lists/*  # 清理缓存,减小镜像体积

# 2. 安装 Flask 依赖(根据你的项目需求调整)
COPY requirements.txt /app/
WORKDIR /app
RUN pip install --no-cache-dir -r requirements.txt

# 3. 复制 Flask 代码(根据你的项目路径调整)
COPY . /app

# 4. 暴露 Flask 端口(如 5000)
EXPOSE 5000

# 5. 启动 Flask 服务(根据你的启动命令调整)
CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]

4. Flask 脚本调用 R 脚本(关键:指定 R 路径)

       Flask 容器内的 R 解释器默认路径为 /usr/bin/R,在 Flask 脚本中通过 subprocess 等模块调用 R 脚本时,需指定正确的 R 路径,并确保 R 脚本能找到包(因包目录已挂载,无需额外配置)。

from flask import Flask
import subprocess
import os

app = Flask(__name__)

# 定义调用 R 脚本的函数
def run_r_script(script_path):
    # R 解释器路径(Flask 容器内默认路径)
    r_path = "/usr/bin/R"
    # 构造 R 命令:执行脚本(--vanilla 避免加载无关配置)
    cmd = [
        r_path,
        "--vanilla",  # 纯净模式,避免干扰
        "-e", f"source('{script_path}')"  # 执行 R 脚本
    ]
    # 执行命令并捕获输出
    result = subprocess.run(
        cmd,
        capture_output=True,
        text=True,
        cwd=os.path.dirname(script_path)  # 脚本所在目录
    )
    # 返回结果(成功/失败)
    if result.returncode == 0:
        return {"status": "success", "output": result.stdout}
    else:
        return {"status": "error", "error": result.stderr}

# Flask 接口:调用 R 脚本
@app.route("/run-r-script")
def run_r():
    # R 脚本路径(Flask 容器内的路径,可挂载宿主机脚本目录)
    r_script_path = "/app/scripts/your_script.R"  # 示例路径,需与实际匹配
    result = run_r_script(r_script_path)
    return result

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000, debug=True)

若后续需要更新 R 包,只需重启 R 容器,在容器内重新安装包(共享目录会自动同步更新),Flask 容器无需重启即可使用新版本包。

四、实际项目

1.Falsk程序dockerfile划分为两个部分:R和Python

R dockerfile:

FROM rocker/tidyverse:4.3.1

# 1. 安装系统依赖(R 包编译所需,与 Flask 容器保持一致)
RUN apt-get update && apt-get install -y --no-install-recommends \
    libgsl27 libgsl-dev \
    libglpk40 libglpk-dev \
    && rm -rf /var/lib/apt/lists/*

# 2. 复制 R 包安装脚本到容器
COPY install_packages.R /tmp/install_packages.R

# 3. 执行 R 包安装脚本(记录日志,方便调试)
RUN Rscript /tmp/install_packages.R > /tmp/install_packages.log 2>&1

# 4. 先启动 bash,再用 tail 保持容器运行
CMD ["bash", "-c", "bash && tail -f /dev/null"]

Python dockerfile:

FROM rocker/tidyverse:4.3.1

# 1. 安装 Python 环境(指定 3.9 版本)
RUN apt-get update && apt-get install -y --no-install-recommends \
    python3.9 \
    python3.9-dev \
    python3-pip \
    vim \
    && rm -rf /var/lib/apt/lists/* \
    && update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.9 1 \
    && update-alternatives --set python3 /usr/bin/python3.9

# 2. 配置 Python 镜像源(清华源,加速安装)
RUN pip3 config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple

# 3. 设置工作目录
WORKDIR /app

# 4. 创建日志目录并设置权限
RUN mkdir -p /var/log/glyseer && chmod 777 /var/log/glyseer  # 确保可写

# 5. 复制 Python 依赖文件并安装
COPY requirements.txt .
RUN pip3 install --no-cache-dir -r requirements.txt

# 6. 复制 Flask 应用代码
COPY . .

# 7. 暴露 Flask 服务端口
EXPOSE 8000

# 8. 启动 Flask 服务(使用 gunicorn,配置合理参数)
CMD ["gunicorn", "app:app", "-b", "0.0.0.0:8000", "-w", "4", "--timeout", "90"]

这样做的目的是保证R容器和flask容器系统环境一致!!!

2.启动R环境的docker容器

# 让 Docker 自动管理卷,容器内安装的 R 包会自动同步到卷中,且不会被空目录覆盖:
docker volume create r-packages-volume

# 启动容器
docker run --name R_4.3.1 -d  --restart=always  -v r-packages-volume:/usr/local/lib/R/site-library glyseer_backend_r_base:1.0

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值