使用 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` 文件。此文件提供了一种简化的启动模式,可以启用调试器。
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
-
在调试选项卡上,选择配置下拉菜单,选择新建配置,然后选择 `Containers: Attach` 配置模板 Containers: Attach to Node (容器:附加到 Node)。
-
在 `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
-
如果你有多个应用,你需要为其中一些应用更改端口,以确保每个应用都有一个唯一的端口。你可以在 `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. }, // ... ]
-
编辑完附加 (Attach) 配置后,保存 `launch.json`,并将你的新启动配置选为活动配置。在调试选项卡中,从配置下拉菜单中找到新的配置。
-
右键单击 `docker-compose.debug.yml` 文件,然后选择 Compose Up (Compose 启动)。
-
当你附加到一个暴露了返回 HTML 的 HTTP 端点的服务时,Web 浏览器不会自动打开。要用浏览器打开应用,请在侧边栏中选择该容器,右键单击并选择在浏览器中打开 (Open in Browser)。如果配置了多个端口,系统会要求你选择一个端口。
-
以常规方式启动调试器。在调试选项卡上,选择绿色箭头(启动按钮)或使用 F5。
Python
要使用 Docker Compose 调试 Python,请按照以下步骤操作
-
在调试选项卡上,选择配置下拉菜单,选择新建配置,选择Python 调试器,然后选择 `远程附加 (Remote Attach)` 配置模板。
-
系统会提示你选择要用于调试的主机(例如,localhost)和端口。Python 的默认调试端口是 5678。如果你有多个应用,你需要为其中一个应用更改端口,以确保每个应用都有一个唯一的端口。你可以在 `launch.json` 中指向正确的调试端口,并保存文件。如果省略此项,端口将被自动选择。
"configurations": [ { "name": "Python Debugger: Remote Attach", "type": "debugpy", "request": "attach", "port": 5678, "host": "localhost", "pathMappings": [ { "localRoot": "${workspaceFolder}", "remoteRoot": "/app" } ] }
-
编辑完附加 (Attach) 配置后,保存 `launch.json`。导航到调试选项卡,并选择 Python Debugger: Remote Attach (Python 调试器:远程附加)作为活动配置。
-
如果你已经有一个有效的 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 快速入门中的说明操作,以确保在继续之前已正确配置。
-
右键单击 `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
-
一旦你的容器构建并运行,通过在选择了 Python Debugger: Remote Attach (Python 调试器:远程附加) 启动配置的情况下按 F5 来附加调试器。
注意: 如果你想将 Python 调试器导入到特定文件中,可以在 debugpy README 中找到更多信息。
-
当你附加到一个暴露了 HTTP 端点并返回 HTML 的服务时,Web 浏览器可能不会自动打开。要用浏览器打开应用,请在容器资源管理器中右键单击容器,然后选择在浏览器中打开 (Open in Browser)。如果配置了多个端口,系统会要求你选择一个端口。
现在你正在调试容器中运行的应用。
.NET
-
在调试选项卡上,选择配置下拉菜单,选择新建配置,然后选择 `容器附加 (Container Attach)` 配置模板 Containers: .NET Attach (Preview) (容器:.NET 附加 (预览版))。
-
VS Code 会尝试使用默认路径将 `vsdbg` 从主机复制到目标容器。你也可以在附加 (Attach) 配置中提供一个现有 `vsdbg` 实例的路径。
"netCore": { "debuggerPath": "/remote_debugger/vsdbg" }
-
编辑完附加 (Attach) 配置后,保存 `launch.json`,并将你的新启动配置选为活动配置。在调试选项卡中,从配置下拉菜单中找到新的配置。
-
右键单击 `docker-compose.debug.yml` 文件,然后选择 Compose Up (Compose 启动)。
-
当你附加到一个暴露了返回 HTML 的 HTTP 端点的服务时,Web 浏览器不会自动打开。要用浏览器打开应用,请在侧边栏中选择该容器,右键单击并选择在浏览器中打开 (Open in Browser)。如果配置了多个端口,系统会要求你选择一个端口。
-
以常规方式启动调试器。在调试选项卡上,选择绿色箭头(启动按钮)或使用 F5。
-
如果你尝试附加到在容器中运行的 .NET 应用,系统会提示你选择应用的容器。
要跳过此步骤,请在 launch.json 的附加 (Attach) 配置中指定容器名称
"containerName": "Your ContainerName"
接下来,系统会询问你是否要将调试器 (`vsdbg`) 复制到容器中。选择是。
如果一切配置正确,调试器应该会附加到你的 .NET 应用。
卷挂载
默认情况下,容器工具扩展不会为调试组件进行任何卷挂载。对于 .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"
}
}