使用 Docker Compose

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

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

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

为您的项目添加Docker Compose支持

如果您已经有一个或多个Dockerfiles,您可以通过打开命令面板⇧⌘P (Windows, Linux Ctrl+Shift+P)),并使用Docker: 添加Docker Compose文件到工作区命令来添加Docker Compose文件。按照提示操作。

您可以在添加Dockerfile的同时,通过打开命令面板⇧⌘P (Windows, Linux Ctrl+Shift+P))并使用Docker: 添加Docker文件到工作区命令来添加Docker Compose文件。系统会询问您是否要添加Docker Compose文件。如果您想保留现有的Dockerfile,请在提示覆盖Dockerfile时选择

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

项目中使用docker-compose文件的截图

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

使用docker-compose文件,您现在可以在docker-compose文件中指定端口映射,而不是在.json配置文件中。例如,请参阅Docker Compose文档

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

向您的项目添加新容器

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

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

在Python项目中,您的工作区根文件夹中有Dockerfile.dockerignoredocker-compose*.yml文件。当您添加另一个应用程序或服务时,将Dockerfile移动到应用程序的文件夹中。

在Node.js项目中,Dockerfile.dockerignore文件将位于该服务的package.json旁边。

对于 .NET,当你创建 Docker Compose 文件时,文件夹结构已经设置为处理多个项目,.dockerignoredocker-compose*.yml 文件被放置在工作区根目录(例如,如果项目在 src/project1 中,那么这些文件就在 src 中),因此当你添加另一个服务时,你在一个文件夹中创建另一个项目,比如 project2,并按照之前描述的方式重新创建或修改 docker-compose 文件。

调试

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

如果你想在Docker Compose中进行调试,请使用前一节中描述的两种Docker Compose文件之一运行命令Docker Compose Up,然后使用适当的Attach启动配置进行附加。直接使用普通启动配置启动不会使用Docker Compose。

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

Node.js

  1. 调试选项卡上,选择配置下拉菜单,选择新建配置并选择Docker Attach配置模板Node.js Docker Attach (预览)

  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": "Docker: Attach to Node",
             "remoteRoot": "/usr/src/app",
             "port": 9229 // Optional; otherwise inferred from the docker-compose.debug.yml.
         },
         // ...
     ]
    
  4. 当编辑完Attach配置后,保存launch.json,并选择您的新启动配置作为活动配置。在Debug标签中,在Configuration下拉菜单中找到新配置。

    配置下拉菜单的截图

  5. 右键点击docker-compose.debug.yml文件并选择Compose Up

  6. 当你连接到一个暴露HTTP端点并返回HTML的服务时,网页浏览器不会自动打开。要在浏览器中打开应用程序,请在侧边栏中选择容器,右键单击并选择在浏览器中打开。如果配置了多个端口,系统会要求你选择端口。

  7. 以通常的方式启动调试器。从调试选项卡中,选择绿色箭头(开始按钮)或使用F5

Python

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

  1. 调试选项卡上,选择配置下拉菜单,选择新建配置,选择Python调试器,并选择远程附加配置模板。

    Python远程附加的截图

  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。导航到Debug选项卡,并选择Python Debugger: Remote Attach作为活动配置。

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

    注意: 默认情况下,当使用Docker: 添加Docker文件到工作区时,选择Django和Flask选项将会为Gunicorn配置一个Dockerfile。在继续之前,请按照容器中的Python快速入门中的说明确保其配置正确。

  5. 右键点击docker-compose.debug.yml文件(示例如下所示),然后选择Compose Up

    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. 一旦您的容器构建并运行,通过按下 F5 并选择 Python Debugger: Remote Attach 启动配置来附加调试器。

    Python调试截图

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

  7. 当你连接到一个暴露HTTP端点并返回HTML的服务时,网页浏览器可能不会自动打开。要在浏览器中打开应用程序,请在Docker资源管理器中右键单击容器并选择在浏览器中打开。如果配置了多个端口,系统会要求你选择端口。

    截图 - 在浏览器中打开

    您现在正在容器中调试正在运行的应用程序。

.NET

  1. 调试选项卡上,选择配置下拉菜单,选择新建配置并选择Docker Attach配置模板.NET Core Docker Attach (预览)

  2. VS Code 尝试使用默认路径将 vsdbg 从主机复制到目标容器。您还可以在 附加 配置中提供现有 vsdbg 实例的路径。

     "netCore": {
         "debuggerPath": "/remote_debugger/vsdbg"
     }
    
  3. 当编辑完Attach配置后,保存launch.json,并选择您的新启动配置作为活动配置。在Debug标签中,在Configuration下拉菜单中找到新配置。

  4. 右键点击docker-compose.debug.yml文件并选择Compose Up

  5. 当你连接到一个暴露HTTP端点并返回HTML的服务时,网页浏览器不会自动打开。要在浏览器中打开应用程序,请在侧边栏中选择容器,右键单击并选择在浏览器中打开。如果配置了多个端口,系统会要求你选择端口。

  6. 以通常的方式启动调试器。从调试选项卡中,选择绿色箭头(开始按钮)或使用F5

    开始调试的截图

  7. 如果您尝试附加到在容器中运行的.NET应用程序,您将看到一个提示要求选择您的应用程序的容器。

    容器选择的截图

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

        "containerName": "Your ContainerName"
    

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

    调试器提示的截图

如果一切配置正确,调试器应该已经附加到你的 .NET 应用程序上。

调试会话的截图

卷挂载

默认情况下,Docker扩展不会为调试组件进行任何卷挂载。在.NET或Node.js中不需要这样做,因为所需的组件已内置在运行时中。如果您的应用程序需要卷挂载,请在docker-compose*.yml文件中使用volumes标签来指定它们。

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

使用多个Compose文件的Docker Compose

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

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

命令自定义

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

基础文件和覆盖文件

假设你的工作空间有一个基础的compose文件(docker-compose.yml)和每个环境的覆盖文件(docker-compose.dev.ymldocker-compose.test.ymldocker-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属性进行匹配,并使用相应的模板。

"docker.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命令时,系统都会询问你使用哪个模板。例如:

"docker.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"
  }
}

下一步