使用 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 支持
如果你已经有一个或多个 Dockerfile,可以通过打开 命令面板(⇧⌘P(Windows、Linux Ctrl+Shift+P)),然后使用 Docker:向工作区添加 Docker Compose 文件命令来添加 Docker Compose 文件。按照提示操作。
你可以在添加 Dockerfile 的同时向工作区添加 Docker Compose 文件,方法是打开 命令面板(⇧⌘P(Windows、Linux Ctrl+Shift+P)),然后使用 Docker:向工作区添加 Docker 文件命令。系统会询问你是否要添加 Docker Compose 文件。如果你想保留现有的 Dockerfile,请在系统提示覆盖 Dockerfile 时选择 否。
Docker 扩展会将 docker-compose.yml
文件添加到你的工作区。此文件包含按预期在生产环境中启动容器的配置。在某些情况下,还会生成一个 docker-compose.debug.yml
。此文件提供了一种用于启动的简化模式,该模式可以启用调试器。
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
文件以添加新服务。通常,你可以复制现有服务部分,将其粘贴以创建新条目,然后根据新服务更改名称。
你可以再次运行 向工作区添加 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 文件之一运行命令 Docker Compose Up,然后使用相应的 附加启动配置进行附加。直接使用正常的启动配置启动不会使用 Docker Compose。
创建一个 附加 启动配置。这是 launch.json
中的一个部分。此过程主要为手动操作,但在某些情况下,Docker 扩展可以通过添加一个预配置的启动配置来提供帮助,您可以将其用作模板并进行自定义。以下部分介绍了每个平台(Node.js、Python 和 .NET)的流程。
Node.js
-
在 调试 选项卡上,选择 配置 下拉菜单,选择 新建配置,然后选择
Docker Attach
配置模板 Node.js Docker 附加 (预览)。 -
在
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": "Docker: Attach to Node", "remoteRoot": "/usr/src/app", "port": 9229 // Optional; otherwise inferred from the docker-compose.debug.yml. }, // ... ]
-
完成编辑 附加 配置后,保存
launch.json
,然后选择新的启动配置作为活动配置。在 调试 选项卡中,在 配置 下拉菜单中找到新配置。 -
右键单击
docker-compose.debug.yml
文件,然后选择 Compose Up。 -
当您附加到公开返回 HTML 的 HTTP 端点的服务时,Web 浏览器不会自动打开。要在浏览器中打开应用程序,请在侧边栏中选择容器,右键单击并选择 在浏览器中打开。如果配置了多个端口,系统会要求您选择端口。
-
以通常的方式启动调试器。在 调试 选项卡中,选择绿色箭头(启动 按钮)或使用 F5。
Python
对于使用 Docker Compose 进行 Python 调试,请按照以下步骤操作
-
在 调试 选项卡上,选择 配置 下拉菜单,选择 新建配置,选择 Python 调试器,然后选择
远程附加
配置模板。 -
系统会提示您选择要用于调试的主机(例如,localhost)和端口。Python 的默认调试端口为 5678。如果您有多个应用程序,则需要更改其中一个应用程序的端口,以便每个应用程序都有一个唯一的端口。您可以在
launch.json
中指向正确的调试端口,并保存该文件。如果省略此步骤,端口将自动选择。"configurations": [ { "name": "Python Debugger: Remote Attach", "type": "debugpy", "request": "attach", "port": 5678, "host": "localhost", "pathMappings": [ { "localRoot": "${workspaceFolder}", "remoteRoot": "/app" } ] }
-
完成编辑 附加 配置后,保存
launch.json
。导航到 调试 选项卡,然后选择 Python 调试器:远程附加 作为活动配置。 -
如果您已经有一个有效的 Dockerfile,我们建议运行命令 Docker: 将 Docker Compose 文件添加到工作区。这将创建一个
docker-compose.yml
文件和一个docker-compose.debug.yml
文件,该文件将卷映射并在容器中启动 Python 调试器。如果您还没有 Dockerfile,我们建议运行 Docker: 将 Docker 文件添加到工作区 并选择 是 以包含 Docker Compose 文件。注意:默认情况下,当使用 Docker: 将 Docker 文件添加到工作区 时,选择 Django 和 Flask 选项将搭建一个为 Gunicorn 配置的 Dockerfile。请按照 容器中的 Python 快速入门 中的说明操作,以确保在继续操作之前正确配置它。
-
右键单击
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
-
构建并运行容器后,通过按 F5 并选择 Python 调试器:远程附加 启动配置来附加调试器。
注意: 如果您想将 Python 调试器导入到特定文件中,可以在 debugpy README 中找到更多信息。
-
当您附加到公开 HTTP 端点并返回 HTML 的服务时,Web 浏览器可能不会自动打开。要在浏览器中打开应用程序,请在 Docker Explorer 中右键单击容器,然后选择 在浏览器中打开。如果配置了多个端口,系统会要求您选择端口。
您现在正在调试容器中运行的应用程序。
.NET
-
在 调试 选项卡上,选择 配置 下拉菜单,选择 新建配置,然后选择
Docker Attach
配置模板 .NET Core Docker 附加 (预览)。 -
VS Code 尝试使用默认路径将
vsdbg
从主机复制到目标容器。您还可以在 附加 配置中提供现有vsdbg
实例的路径。"netCore": { "debuggerPath": "/remote_debugger/vsdbg" }
-
完成编辑 附加 配置后,保存
launch.json
,然后选择新的启动配置作为活动配置。在 调试 选项卡中,在 配置 下拉菜单中找到新配置。 -
右键单击
docker-compose.debug.yml
文件,然后选择 Compose Up。 -
当您附加到公开返回 HTML 的 HTTP 端点的服务时,Web 浏览器不会自动打开。要在浏览器中打开应用程序,请在侧边栏中选择容器,右键单击并选择 在浏览器中打开。如果配置了多个端口,系统会要求您选择端口。
-
以通常的方式启动调试器。在 调试 选项卡中,选择绿色箭头(启动 按钮)或使用 F5。
-
如果您尝试附加到在容器中运行的 .NET 应用程序,您会看到一个提示,要求您选择应用程序的容器。
要跳过此步骤,请在 launch.json 中的 附加 配置中指定容器名称
"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.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
属性进行匹配,并且将使用相应的模板。
"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"
}
}