调试 Docker 容器中运行的 AI 代码





5.00/5 (3投票s)
在本文中,我们使用 Visual Studio Code 来编辑和调试运行在 Docker 容器中日益复杂的代码。
引言
Docker 等容器技术简化了依赖管理并提高了软件的可移植性。在本系列文章中,我们将探讨 Docker 在机器学习 (ML) 场景中的使用。
本系列假定您熟悉 AI/ML、容器化(一般)以及 Docker(具体)。
在本系列上一篇文章中,我们使用 Fast API 和 Gunicorn 以及 Uvicorn 工作进程,通过 REST API 公开了推理 NLP 模型。这使我们能够在 Web 浏览器中运行 NLP 模型。
在本文中,我们将使用 Visual Studio Code 来调试在 Docker 容器中运行的服务。欢迎下载本文使用的代码。
设置 Visual Studio Code
我们假设您熟悉 Visual Studio Code,一个非常轻量级且灵活的代码编辑器。它适用于 Windows、macOS 和 Linux。凭借其可扩展性,它支持无数的语言和技术。您可以在官方网站上找到大量的教程。
我们将使用它来运行和调试我们的 Python 服务。首先,我们需要安装三个扩展。
安装完成后,我们可以打开我们的项目(在上一篇文章中创建)。或者,您可以下载本文的源代码。在以下示例中,我们假设您选择了后一种选择。
容器配置
我们将使用与之前相同的 Dockerfile 和几乎相同的 docker-compose.yml。我们引入的唯一更改是新的镜像名称,仅用于保持文章和镜像名称之间的一一对应关系。我们的 docker-compose.yml 如下所示:
version: '3.7' volumes: mluser_cache: name: mluser_cache services: mld09_transformers_api_debug: build: context: '.' dockerfile: 'Dockerfile' args: USERID: ${USERID} image: 'mld09_transformers_api_debug' volumes: - mluser_cache:/home/mluser/.cache ports: - '8000:8000' user: '${USERID}:${GROUPID}'
配置项目以在 Docker 中工作
现在,我们需要指示 Visual Studio Code 如何运行我们的容器。我们通过在 .devcontainer 文件夹(不要忘记开头的点)中创建两个新文件来完成此操作。
第一个文件 docker-compose-overwrites.yml 定义了我们的 docker-compose.yml 的部分,当从 Visual Studio Code 使用我们的容器工作时,我们希望添加或更改这些部分。因为在开发过程中我们希望编辑本地代码,所以我们需要一个新的卷将本地文件映射到容器的文件夹。
此外,我们希望覆盖 command 语句,因为在这种情况下,我们不想总是与容器一起启动我们的服务。相反,我们希望一个无限循环使我们的容器保持运行。
这就得到了以下 docker-compose-overwrites.yml:
version: '3.7' services: mld09_transformers_api_debug: volumes: - .:/home/mluser/workspace:cached command: /bin/sh -c "while sleep 1000; do :; done"
接下来,我们需要一个配置文件 devcontainer.json。
{
"name": "Inference Service NLP Debug Container",
"dockerComposeFile": [
"../docker-compose.yml",
"docker-compose-overwrites.yml"
],
"service": "mld09_transformers_api_debug",
"workspaceFolder": "/home/mluser/workspace",
"settings": {
"terminal.integrated.shell.linux": null
},
"extensions": ["ms-python.python"],
"forwardPorts": [8000],
"remoteUser": "mluser"
}
大多数选项都非常直观。除其他外,我们定义要加载的 docker-compose
文件(以及加载顺序)。在 workspaceFolder
属性中,我们定义 Visual Studio Code 实例将打开哪个容器文件夹作为其工作区。extensions
属性确保安装 Python 扩展,这将允许我们调试代码。该文件以要转发到主机端口以及选择用于运行容器的用户名结尾。您可以查看此文件中可用的选项的完整参考。
启动容器
您可能还记得我们之前的系列文章,当您将本地文件夹映射为容器卷时,您需要正确匹配您的本地用户和容器用户。在处理容器时,Windows 和 macOS 上的 Visual Studio Code 会尝试自动为您完成此操作,如此处所述。
您仍然需要在 Linux 上自己处理。我们将通过在启动 Visual Studio Code 环境时设置必需的环境变量来完成此操作。
$ USERID=$(id -u) GROUPID=$(id -g) code .
从包含项目 Dockerfile 的文件夹执行此操作。
请注意,如果使用上一篇文章中的代码创建了 mluser_cache
卷,您还需要使用此方法在 macOS 上为 Visual Studio Code 设置环境变量。这将确保早期容器运行写入卷的文件可供当前容器用户访问。
如果您认为可以将 USERID
和 GROUPID
环境变量添加到单独的文件中,并使用 docker-compose.yml 中的 env_file
设置,那么不行 – 您不能。我们在构建镜像时需要这些值,但 env_file
值仅传播到正在运行的容器。
现在我们准备启动容器。要做到这一点,我们点击左下角的 **打开远程窗口** 按钮。
然后,我们从下拉菜单中选择 **在容器中重新打开** 选项。
然后……就这样。现在我们等待镜像构建、容器启动,Visual Studio Code 在其中安装所有依赖项。
当任务完成时,我们会看到标准的 workspace 视图。唯一可以确保我们真正“在”容器内部的方法是验证终端窗口中可见的路径以及左下角的 Dev Container 名称。
在容器中调试代码
现在我们可以像在本地一样处理我们的应用程序,包括调试。
至少有两种方法可以调试我们的 FastAPI 服务。第一种方法是将代码添加到我们 main.py 脚本以直接启动开发服务器。第二种方法要求我们为 Uvicorn 服务器模块定义专门的调试配置。
让我们尝试第一种方法。我们所需要做的就是向上一篇文章中的 main.py 文件末尾添加几行代码。
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
在进行了此更改后,我们只需使用默认的 Python: Current File
调试配置来运行我们的代码。
当您将鼠标悬停在上面日志中的运行服务的 IP 和端口 (http://0.0.0.0:8000) 上时,您会注意到一个弹出窗口:“使用转发端口跟踪链接”。这非常重要,因为当在 Visual Studio Code 中运行时,我们的服务端口会被转发到一个随机端口。当我们点击弹出窗口时,我们确实会转到正确的地址。当我们手动为其添加 /docs 后缀时,我们会像以前一样到达 OpenAPI 界面。
现在,当我们定义并命中代码中的断点时,它的行为将如我们所料。
摘要
我们已成功配置 Visual Studio Code 以在 Docker 容器中编辑、运行和调试我们的代码。因此,我们可以在本地开发机器、本地服务器或云中轻松使用相同的环境。在**下一篇文章**中,我们将把我们的 NLP API 服务发布到 Azure,使用 Azure 容器实例。敬请关注!