65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2021 年 5 月 21 日

CPOL

5分钟阅读

viewsIcon

8804

downloadIcon

84

在本文中,我们使用 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 设置环境变量。这将确保早期容器运行写入卷的文件可供当前容器用户访问。

如果您认为可以将 USERIDGROUPID 环境变量添加到单独的文件中,并使用 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 容器实例。敬请关注!

© . All rights reserved.