参加你附近的 ,了解 VS Code 中的 AI 辅助开发。

使用 Docker Compose

Docker Compose 提供了一种编排多个协同工作的容器的方法。例如,一个处理请求的服务和一个前端网站,或者一个使用 Redis 缓存等支持功能的服务。如果你的应用开发使用微服务模型,你可以使用 Docker Compose 将应用代码分解为多个独立运行的服务,这些服务之间通过 Web 请求进行通信。本文帮助你为你的应用(无论是 Node.js、Python 还是 .NET)启用 Docker Compose,并帮助你在 Visual Studio Code 中为这些场景配置调试。

此外,对于单容器场景,使用 Docker Compose 提供了一种独立于工具的配置方式,这是单个 Dockerfile 无法做到的。诸如容器的卷挂载、端口映射和环境变量等配置设置都可以在 docker-compose YML 文件中声明。

要在 VS Code 中使用容器工具扩展来使用 Docker Compose,你应该已经熟悉 Docker Compose 的基础知识。

向你的项目添加 Docker Compose 支持

如果你已经有一个或多个 Dockerfile,可以通过打开命令面板 (⇧⌘P (Windows、Linux 为 Ctrl+Shift+P)) 并使用 Containers: Add Docker Compose Files to Workspace (容器:向工作区添加 Docker Compose 文件) 命令来添加 Docker Compose 文件。按照提示操作即可。

你可以在添加 Dockerfile 的同时向工作区添加 Docker Compose 文件,方法是打开命令面板 (⇧⌘P (Windows、Linux 为 Ctrl+Shift+P)) 并使用 Containers: Add Docker Files to Workspace (容器:向工作区添加 Docker 文件) 命令。系统会询问你是否要添加 Docker Compose 文件。如果你想保留现有的 Dockerfile,在提示是否覆盖 Dockerfile 时选择

容器工具扩展会将 `docker-compose.yml` 文件添加到你的工作区。此文件包含在生产环境中按预期启动容器的配置。在某些情况下,还会生成一个 `docker-compose.debug.yml` 文件。此文件提供了一种简化的启动模式,可以启用调试器。

Screenshot of project with docker-compose files

VS Code 容器工具扩展生成的文件可以开箱即用,但你也可以自定义它们以优化你的场景。然后,你可以使用 Containers: Compose Up (容器:Compose 启动) 命令(右键单击 `docker-compose.yml` 文件,或在命令面板中找到该命令)来一次性启动所有服务。你也可以在 VS Code 的命令提示符或终端窗口中使用 `docker-compose up` 命令来启动容器。请参阅 Docker Compose 文档,了解如何配置 Docker Compose 的行为以及有哪些可用的命令行选项。

有了 docker-compose 文件,你现在可以在 docker-compose 文件中指定端口映射,而不是在 .json 配置文件中。有关示例,请参阅 Docker Compose 文档

提示:使用 Docker Compose 时,不要指定主机端口。相反,让 Docker 随机选择一个可用的端口,以自动避免端口冲突问题。

向你的项目添加新容器

如果你想添加另一个应用或服务,可以再次运行 Containers: Add Docker Compose Files to Workspace (容器:向工作区添加 Docker Compose 文件),并选择覆盖现有的 docker-compose 文件,但你将丢失这些文件中的任何自定义设置。如果你想保留对 compose 文件的更改,可以手动修改 `docker-compose.yml` 文件来添加新服务。通常,你可以复制现有的服务部分,粘贴以创建一个新条目,并根据新服务更改名称。

你可以再次运行 Containers: Add Docker Files to Workspace (容器:向工作区添加 Docker 文件) 命令来为新应用生成 `Dockerfile`。虽然每个应用或服务都有自己的 Dockerfile,但每个工作区通常只有一个 `docker-compose.yml` 和一个 `docker-compose.debug.yml` 文件。

在 Python 项目中,`Dockerfile`、`.dockerignore`、`docker-compose*.yml` 文件都位于工作区的根文件夹中。当你添加另一个应用或服务时,请将 Dockerfile 移动到该应用的文件夹中。

在 Node.js 项目中,`Dockerfile` 和 `.dockerignore` 文件将与该服务的 `package.json` 文件位于同一目录下。

对于 .NET,创建 Docker Compose 文件时,文件夹结构已经设置为处理多个项目,`.dockerignore` 和 `docker-compose*.yml` 文件放置在工作区根目录中(例如,如果项目在 `src/project1` 中,那么这些文件就在 `src` 目录中),所以当你添加另一个服务时,你会在另一个文件夹(比如 `project2`)中创建另一个项目,然后如前所述重新创建或修改 docker-compose 文件。

调试

首先,请参考你的目标平台的调试文档,以了解在 VS Code 中进行容器调试的基础知识

如果你想在 Docker Compose 中进行调试,请使用前面部分描述的两个 Docker Compose 文件之一运行 Containers: Compose Up (容器:Compose 启动) 命令,然后使用相应的附加 (Attach) 启动配置进行附加。直接使用常规启动配置启动不会使用 Docker Compose。

创建一个附加 (Attach) 启动配置。这是 `launch.json` 中的一个部分。这个过程大多是手动的,但在某些情况下,容器工具扩展可以通过添加一个预配置的启动配置来提供帮助,你可以将其用作模板并进行自定义。下面将分别描述每个平台(Node.js、Python 和 .NET)的过程。

Node.js

  1. 调试选项卡上,选择配置下拉菜单,选择新建配置,然后选择 `Containers: Attach` 配置模板 Containers: Attach to Node (容器:附加到 Node)。

  2. 在 `docker-compose.debug.yml` 文件中配置调试端口。这个端口在创建文件时已经设置好,所以你可能不需要更改它。在下面的示例中,端口 9229 同时用于主机和容器的调试。

     version: '3.4'
    
     services:
       node-hello:
         image: node-hello
         build: .
         environment:
           NODE_ENV: development
         ports:
           - 3000
           - 9229:9229
         command: node --inspect=0.0.0.0:9229 ./bin/www
    
  3. 如果你有多个应用,你需要为其中一些应用更改端口,以确保每个应用都有一个唯一的端口。你可以在 `launch.json` 中指向正确的调试端口,并保存文件。如果省略此项,端口将被自动选择。

    下面是一个显示 Node.js 启动配置 - 附加的示例

     "configurations": [
         {
             "type": "node",
             "request": "attach",
             "name": "Containers: Attach to Node",
             "remoteRoot": "/usr/src/app",
             "port": 9229 // Optional; otherwise inferred from the docker-compose.debug.yml.
         },
         // ...
     ]
    
  4. 编辑完附加 (Attach) 配置后,保存 `launch.json`,并将你的新启动配置选为活动配置。在调试选项卡中,从配置下拉菜单中找到新的配置。

    Screenshot of Configuration dropdown

  5. 右键单击 `docker-compose.debug.yml` 文件,然后选择 Compose Up (Compose 启动)。

  6. 当你附加到一个暴露了返回 HTML 的 HTTP 端点的服务时,Web 浏览器不会自动打开。要用浏览器打开应用,请在侧边栏中选择该容器,右键单击并选择在浏览器中打开 (Open in Browser)。如果配置了多个端口,系统会要求你选择一个端口。

  7. 以常规方式启动调试器。在调试选项卡上,选择绿色箭头(启动按钮)或使用 F5

Python

要使用 Docker Compose 调试 Python,请按照以下步骤操作

  1. 调试选项卡上,选择配置下拉菜单,选择新建配置,选择Python 调试器,然后选择 `远程附加 (Remote Attach)` 配置模板。

    Screenshot of Python Remote Attach

  2. 系统会提示你选择要用于调试的主机(例如,localhost)和端口。Python 的默认调试端口是 5678。如果你有多个应用,你需要为其中一个应用更改端口,以确保每个应用都有一个唯一的端口。你可以在 `launch.json` 中指向正确的调试端口,并保存文件。如果省略此项,端口将被自动选择。

         "configurations": [
         {
            "name": "Python Debugger: Remote Attach",
            "type": "debugpy",
            "request": "attach",
            "port": 5678,
            "host": "localhost",
            "pathMappings": [
                {
                    "localRoot": "${workspaceFolder}",
                    "remoteRoot": "/app"
                }
            ]
        }
    
  3. 编辑完附加 (Attach) 配置后,保存 `launch.json`。导航到调试选项卡,并选择 Python Debugger: Remote Attach (Python 调试器:远程附加)作为活动配置。

  4. 如果你已经有一个有效的 Dockerfile,我们建议运行 Containers: Add Docker Compose Files to Workspace (容器:向工作区添加 Docker Compose 文件) 命令。这将创建一个 `docker-compose.yml` 文件和一个 `docker-compose.debug.yml` 文件,后者会进行卷映射并在容器中启动 Python 调试器。如果你还没有 Dockerfile,我们建议运行 Containers: Add Docker Files to Workspace (容器:向工作区添加 Docker 文件) 并选择以包含 Docker Compose 文件。

    注意:默认情况下,使用 Containers: Add Docker Files to Workspace (容器:向工作区添加 Docker 文件) 时,选择 Django 和 Flask 选项会生成一个为 Gunicorn 配置的 Dockerfile。请按照容器中的 Python 快速入门中的说明操作,以确保在继续之前已正确配置。

  5. 右键单击 `docker-compose.debug.yml` 文件(示例如下)并选择 Compose Up (Compose 启动)。

    version: '3.4'
    
    services:
      pythonsamplevscodedjangotutorial:
        image: pythonsamplevscodedjangotutorial
        build:
          context: .
          dockerfile: ./Dockerfile
        command: ["sh", "-c", "pip install debugpy -t /tmp && python /tmp/debugpy --wait-for-client --listen 0.0.0.0:5678 manage.py runserver 0.0.0.0:8000 --nothreading --noreload"]
        ports:
          - 8000:8000
          - 5678:5678
    
  6. 一旦你的容器构建并运行,通过在选择了 Python Debugger: Remote Attach (Python 调试器:远程附加) 启动配置的情况下按 F5 来附加调试器。

    Screenshot of debugging in Python

    注意: 如果你想将 Python 调试器导入到特定文件中,可以在 debugpy README 中找到更多信息。

  7. 当你附加到一个暴露了 HTTP 端点并返回 HTML 的服务时,Web 浏览器可能不会自动打开。要用浏览器打开应用,请在容器资源管理器中右键单击容器,然后选择在浏览器中打开 (Open in Browser)。如果配置了多个端口,系统会要求你选择一个端口。

    Screenshot - Open in Browser

    现在你正在调试容器中运行的应用。

.NET

  1. 调试选项卡上,选择配置下拉菜单,选择新建配置,然后选择 `容器附加 (Container Attach)` 配置模板 Containers: .NET Attach (Preview) (容器:.NET 附加 (预览版))。

  2. VS Code 会尝试使用默认路径将 `vsdbg` 从主机复制到目标容器。你也可以在附加 (Attach) 配置中提供一个现有 `vsdbg` 实例的路径。

     "netCore": {
         "debuggerPath": "/remote_debugger/vsdbg"
     }
    
  3. 编辑完附加 (Attach) 配置后,保存 `launch.json`,并将你的新启动配置选为活动配置。在调试选项卡中,从配置下拉菜单中找到新的配置。

  4. 右键单击 `docker-compose.debug.yml` 文件,然后选择 Compose Up (Compose 启动)。

  5. 当你附加到一个暴露了返回 HTML 的 HTTP 端点的服务时,Web 浏览器不会自动打开。要用浏览器打开应用,请在侧边栏中选择该容器,右键单击并选择在浏览器中打开 (Open in Browser)。如果配置了多个端口,系统会要求你选择一个端口。

  6. 以常规方式启动调试器。在调试选项卡上,选择绿色箭头(启动按钮)或使用 F5

    Screenshot of starting debugging

  7. 如果你尝试附加到在容器中运行的 .NET 应用,系统会提示你选择应用的容器。

    Screenshot of container selection

    要跳过此步骤,请在 launch.json 的附加 (Attach) 配置中指定容器名称

        "containerName": "Your ContainerName"
    

    接下来,系统会询问你是否要将调试器 (`vsdbg`) 复制到容器中。选择

    Screenshot of debugger prompt

如果一切配置正确,调试器应该会附加到你的 .NET 应用。

Screenshot of debug session

卷挂载

默认情况下,容器工具扩展不会为调试组件进行任何卷挂载。对于 .NET 或 Node.js 来说,这是不必要的,因为所需的组件已经内置在运行时中。如果你的应用需要卷挂载,请在 `docker-compose*.yml` 文件中使用 `volumes` 标签来指定它们。

volumes:
    - /host-folder-path:/container-folder-path

使用多个 Compose 文件的 Docker Compose

工作区可以有多个 docker-compose 文件来处理不同的环境,如开发、测试和生产。配置内容可以拆分到多个文件中。例如,一个定义所有环境通用信息的基础 compose 文件,以及多个定义特定环境信息的独立覆盖文件。当这些文件作为输入传递给 `docker-compose` 命令时,它会将这些文件合并成一个单一的配置。默认情况下,Containers: Compose Up (容器:Compose 启动) 命令只传递一个文件作为 compose 命令的输入,但你可以使用命令自定义功能来自定义 `compose up` 命令以传递多个文件。或者,你可以使用自定义任务来调用带有所需参数的 `docker-compose` 命令。

注意:如果你的工作区有 `docker-compose.yml` 和 `docker-compose.override.yml` 文件,并且没有其他 compose 文件,那么 `docker-compose` 命令将在没有输入文件的情况下被调用,它会隐式使用这两个文件。在这种情况下,不需要进行自定义。

命令自定义

命令自定义提供了多种方式来根据你的需求自定义 `compose up` 命令。以下是 `compose up` 命令的一些示例自定义。

基础文件和覆盖文件

假设你的工作区有一个基础 compose 文件 (`docker-compose.yml`) 和每个环境的覆盖文件 (`docker-compose.dev.yml`、`docker-compose.test.yml` 和 `docker-compose.prod.yml`),并且你总是使用基础文件和一个覆盖文件来运行 `docker compose up`。在这种情况下,`compose up` 命令可以如下例所示进行自定义。当调用 `compose up` 命令时,`${configurationFile}` 会被所选文件替换。

"docker.commands.composeUp": [
    {
        "label": "override",
        "template": "docker-compose -f docker-compose.yml ${configurationFile}  up -d --build",
    }
]

模板匹配

假设你为每个环境都有一组不同的输入文件。你可以定义多个带有正则表达式匹配的模板,所选文件名将与此 `match` 属性进行匹配,并使用相应的模板。

"containers.commands.composeUp": [
    {
        "label": "dev-match",
        "template": "docker-compose -f docker-compose.yml -f docker-compose.debug.yml -f docker-compose.dev.yml up -d --build",
        "match": "dev"
    },
    {
        "label": "test-match",
        "template": "docker-compose -f docker-compose.yml -f docker-compose.debug.yml -f docker-compose.test.yml up -d --build",
        "match": "test"
    },
    {
        "label": "prod-match",
        "template": "docker-compose -f docker-compose.yml -f docker-compose.release.yml -f docker-compose.prod.yml up -d --build",
        "match": "prod"
    }
]

在调用命令时选择一个模板

如果你从命令模板中省略 `match` 属性,那么每次调用 `compose up` 命令时,系统都会询问你使用哪个模板。例如

"containers.commands.composeUp": [
    {
        "label": "dev",
        "template": "docker-compose -f docker-compose.yml -f docker-compose.common.dev.yml ${configurationFile} up -d --build"
    },
    {
        "label": "test",
        "template": "docker-compose -f docker-compose.yml -f docker-compose.common.test.yml ${configurationFile} up -d --build"
    },
    {
        "label": "prod",
        "template": "docker-compose -f docker-compose.yml -f docker-compose.common.prod.yml ${configurationFile} up -d --build"
    },
],

自定义任务

除了使用命令自定义,你还可以定义一个如下所示的任务来调用 `docker-compose` 命令。有关此选项的更多详细信息,请参阅自定义任务

{
  "type": "shell",
  "label": "compose-up-dev",
  "command": "docker-compose -f docker-compose.yml -f docker-compose.Common.yml -f docker-compose.dev.yml up -d --build",
  "presentation": {
    "reveal": "always",
    "panel": "new"
  }
}

后续步骤