依赖地狱在研究软件领域无处不在,这影响了研究的透明度和可重复性。容器化是解决这个问题的一种方案,但它也给研究人员带来了新的挑战。Docker 在研究社区中越来越受欢迎,但有效率地使用它需要扎实的 Dockerfile 编写技能。
作为 Stencila 项目的一部分,该项目是一个用于创建、协作和共享数据驱动内容的平台,我们正在开发 Dockter,这是一个开源工具,旨在让研究人员更轻松地为其项目创建 Docker 镜像。Dockter 扫描研究项目的源代码,生成 Dockerfile,并构建 Docker 镜像。它具有一系列功能,可以提供灵活性,并可以帮助研究人员更多地了解如何使用 Docker。
Dockter 还生成一个 JSON 文件,其中包含有关软件环境的信息(基于 CodeMeta 和 Schema.org),以实现进一步的处理和与其他工具的互操作性。
其他几个项目也从源代码和/或需求文件创建 Docker 镜像,包括:alibaba/derrick、jupyter/repo2docker、Gueils/whales、o2r-project/containerit;openshift/source-to-image 和 ViDA-NYU/reprozip。Dockter 类似于 repo2docker、containerit 和 ReproZip,因为它的目标是进行数据分析的研究人员(并支持 R 语言),而大多数其他工具的目标是软件开发人员(并且不支持 R 语言)。
Dockter 与这些项目的主要区别在于它:
- 对多种语言执行静态代码分析,以确定软件包需求
- 使用软件包数据库来确定软件包系统依赖项并生成链接的元数据(containerit 为 R 语言执行此操作)
- 更快地安装语言软件包依赖项(这在依赖项经常更改的研究项目中可能很有用)
- 默认情况下(但可选),安装 Stencila 软件包,以便 Stencila 客户端界面可以在容器中执行代码
Dockter 的功能
以下是研究人员可以使用 Dockter 的一些方式。
从代码生成 Docker 镜像
Dockter 扫描研究项目文件夹并为其构建 Docker 镜像。如果文件夹已包含 Dockerfile,Dockter 将从该文件构建镜像。否则,Dockter 将扫描文件夹中的源代码文件并生成一个。Dockter 目前处理 R、Python 和 Node.js 源代码。它生成的 .dockerfile(以点开头)是完全可编辑的,因此用户可以从 Dockter 接手并继续编辑文件,随心所欲。
如果文件夹包含 R 软件包 DESCRIPTION 文件,Dockter 将把 Imports 下列出的 R 软件包安装到镜像中。如果文件夹不包含 DESCRIPTION 文件,Dockter 将扫描文件夹中的所有 R 文件,查找软件包导入或使用语句,并创建一个 .DESCRIPTION 文件。
如果文件夹包含 Python 的 requirements.txt 文件,Dockter 将其复制到 Docker 镜像中,并使用 pip 安装指定的软件包。如果文件夹不包含这些文件中的任何一个,Dockter 将扫描文件夹中的所有 .py 文件,查找 import 语句,并创建一个 .requirements.txt 文件。
如果文件夹包含 package.json 文件,Dockter 将其复制到 Docker 镜像中,并使用 npm 安装指定的软件包。如果文件夹不包含 package.json 文件,Dockter 将扫描文件夹中的所有 .js 文件,查找 require 调用,并创建一个 .package.json 文件。
自动捕获系统需求
研究人员在手写 Dockerfile 时面临的难题之一是弄清楚他们的项目需要哪些系统依赖项。通常,这需要大量的试错。Dockter 会自动检查任何依赖项(或依赖项的依赖项,或依赖项的依赖项...)是否需要系统软件包,并将这些软件包安装到镜像中。不再需要构建、失败、添加依赖项、重复...的试错循环。
更快地重新安装语言软件包
如果您曾经构建过 Docker 镜像,您就会知道,当您只添加或删除一个依赖项时,等待所有项目依赖项重新安装可能会令人沮丧。
这种情况发生的原因是 Docker 的分层文件系统:当您更新需求文件时,Docker 会丢弃所有后续层——包括您先前安装依赖项的层。这意味着所有软件包都必须重新安装。
Dockter 采取了不同的方法。它将语言软件包的安装留给语言软件包管理器:Python 的 pip、Node.js 的 npm 和 R 的 install.packages。这些软件包管理器擅长他们被设计用来做的工作:检查哪些软件包需要更新,并且只更新它们。结果是重建速度更快,特别是对于 R 软件包而言,它们通常涉及编译。
Dockter 通过在 Dockerfile 中查找特殊的 # dockter 注释来做到这一点。它不会丢弃层,而是在同一层中执行此注释之后的所有指令——从而重用先前安装的软件包。
为项目生成结构化元数据
Dockter 使用 JSON-LD 作为其内部数据结构。当它解析项目的源代码时,它使用来自 schema.org 和 CodeMeta 的词汇表生成 JSON-LD 树。
Dockter 还获取项目依赖项的元数据,这些元数据可用于为项目生成完整的软件引用。
易于上手,易于抛弃
Dockter 旨在让您更轻松地开始为您的项目创建 Docker 镜像。但它也被设计为不会妨碍您或限制您使用裸 Docker。您可以轻松且单独地覆盖 Dockter 构建镜像的任何步骤。
-
代码分析: 要停止 Dockter 进行代码分析并指定您项目的软件包依赖项,只需从 .DESCRIPTION、.requirements.txt 或 .package.json 文件中删除前导 .(点)。
-
Dockerfile 生成: Dockter 旨在生成可读的 Dockerfile,并符合最佳实践。它们包含有关每个部分作用的注释,并且是开始学习如何编写自己的 Dockerfile 的好方法。要停止 Dockter 生成 .Dockerfile 并开始自己编辑它,只需将其重命名为 Dockerfile(不带前导点)。
安装 Dockter
Dockter 可用作预编译的独立命令行工具或 Node.js 软件包。单击此处观看演示。
我们欢迎并鼓励所有贡献!
本文的更长版本可在项目的 GitHub 页面上找到。
Aleksandra Pawlik 将在 1 月 21 日至 25 日在新西兰基督城举行的 linux.conf.au 上展示 构建可重复的计算环境:非专家研讨会。
1 条评论