现已发布!阅读 10 月份的新功能和修复。

使用 VS Code 检查容器

2019 年 10 月 31 日,作者:Bowden Kelly,@bowdenk7

在开发容器化应用程序时,通常会尝试通过使用 docker exec --it {containerID} /bin/sh 将 shell 连接到正在运行的容器来调试构建和运行时问题。

Running docker exec command

此技术允许您通过命令行检查容器环境,但它没有提供丰富的工具集来诊断问题。

在本博文中,我们将了解如何将 Visual Studio Code 连接到您的容器,以便您可以使用 VS Code 的全部功能(包括调试)来检查容器、找出问题所在并进行修复。

开发容器 扩展(今年 5 月发布)允许您将本地的 VS Code 连接到容器主机,同时保留所有个性化设置、主题和按键绑定。

先决条件

本博文假设您已安装了 Docker DesktopVisual Studio Code。您还需要 开发容器 扩展。要安装开发容器扩展,请打开扩展视图 (⇧⌘X(Windows、Linux Ctrl+Shift+X),搜索“开发容器”,选择“安装”,并在出现提示时重启 VS Code。

该应用程序

首先,我们需要一个可以在容器中运行的应用程序。如果您已经拥有,那就太好了!您可以跳过此步骤。如果没有,您可以克隆这个简单的 Node.js Express 应用程序。

注意:您不需要在本地安装 Node.js,我们将在这个容器中运行此应用程序!

git clone https://github.com/microsoft/vscode-express-sample.git

此应用程序有一个简单的 Dockerfile,它基于 Node 10 镜像,还有一个 docker-compose.yml 文件,我们将使用它来运行镜像、公开适当的端口并将本地文件系统映射进来。我们使用 –inspect 标志运行 Node,以便我们可以像在本地运行时一样调试应用程序。在真实的应用程序中,您可能希望为生产部署使用单独的 Docker Compose 文件。

注意:您不需要 Docker Compose 文件,也可以连接到使用单个 Dockerfile 创建的容器。

构建和运行

要构建和运行该应用程序,我们将首先安装依赖项,然后从终端/命令提示符运行 docker-compose up。这将下载 Node 基础镜像,复制依赖项并启动容器。

docker-compose up

如果一切正常,您应该看到类似以下内容的输出:

docker-compose up output

而且,您应该能够导航到 https://127.0.0.1:3000 并看到以下内容:

Welcome to Express web page

连接到容器

现在,我们可以使用开发容器扩展连接到我们正在运行的容器、检查环境并调试应用程序。

选择活动栏中的“远程资源管理器”以查看可连接到的正在运行的容器的列表(位于“其他容器”部分)。找到我们刚刚启动的容器,它名为“express_server_1”,然后使用“连接到容器”按钮连接到它。该容器现在应该显示在“远程资源管理器”的“已连接容器”部分。

Attached Containers in the Remote Explorer

这将启动一个新的 VS Code 窗口(实例),并在右下角显示以下通知:

Installing Dev Container notification

在此期间,VS Code 会在运行应用程序的容器中安装 VS Code **服务器** 的实例。要查看有关此安装步骤的更多详细信息和进度,可以选择通知中显示的“详细信息”链接。安装 VS Code 服务器后,您的本地 VS Code 客户端将连接到远程 VS Code 服务器。结果是您本地的 VS Code 实例(包含所有设置、主题和按键绑定)连接到在容器内与应用程序并行运行的“后端”。

Dev Containers architecture diagram

连接完成后,您应该会看到一个新的 VS Code 窗口,左下角有一个绿色指示器,表示 VS Code 的这个实例在远程上下文中运行。如果单击指示器,您将看到与当前远程上下文相关的命令的下拉菜单。

Remote context shown in the Status bar

让我们继续打开我们的应用程序,选择“打开文件夹”按钮并导航到 /usr/src/app。请注意,打开文件夹对话框显示的是正在运行的容器中的文件系统,**而不是本地文件系统**。

Open Folder dialog show container file system

打开源文件夹后,您会注意到在编辑器中打开了一个名为 express-server.json 的文件。此名称来自您连接到的容器镜像名称。在我们的示例中,docker-compose 创建镜像名称“express_server”,它源自文件夹名称“express”和 docker-compose.yml 文件中定义的服务名称“server”。此文件是与您的镜像关联的配置文件,当您连接到基于此镜像的容器时,它将记住配置设置。如果您没有打开自动保存,则需要确保保存此文件。现在,在将来的会话中,当您连接到此镜像时,VS Code 将重新打开此源文件夹。

注意:您可以通过从命令面板 (⇧⌘P(Windows、Linux Ctrl+Shift+P) 运行“打开容器配置文件”命令来查看当前开发容器的此文件。

express-server.json file contents

此时,VS Code 看起来与普通的本地 VS Code 窗口相同。

VS Code running in a container

您可以执行在普通本地 VS Code 上下文中可以执行的任何操作。

例如,打开 app.js。右键单击第 8 行并执行“查找所有引用”以查找 usersRouter 的所有用法。所有编辑内容都将持久保存到本地磁盘,因为我们使用 docker-compose 文件将本地文件系统安装到容器中。

在容器内调试

为了进一步展示开发容器与本地环境的相似之处,让我们连接一个调试器。我们在 docker-compose.yaml 中使用 –inspect 参数启动了 Node 应用程序,因此我们所要做的就是将调试器连接到该进程。

在命令面板 (⇧⌘P(Windows、Linux Ctrl+Shift+P) 中,搜索并选择“调试:连接到 Node 进程”。容器内可能运行着多个 Node 进程。我们要运行应用程序的进程,因此请选择显示 bin/www 的那个进程。

Node process picker list

接下来,打开 index.js 并在第 6 行设置断点,方法是单击边距或按下 F9

res.render('index', { title: 'Express' });

现在,在浏览器中访问 https://127.0.0.1:3000,您会看到断点按预期触发!

安装扩展

与普通的 VS Code 实例一样,您可以在连接到开发容器时安装和使用扩展。

根据扩展的类型,它可以运行在客户端或容器中的远程 VS Code 服务器上。主要基于 UI 的扩展(如主题和代码片段)保留在客户端,而所有其他扩展都安装在容器中。这样一来,您就可以在每个环境中只使用所需的扩展,同时在所有环境中保持一致的 UI。

如果打开扩展视图 (⇧⌘X(Windows、Linux Ctrl+Shift+X),您将看到已在本地安装的扩展和已在当前容器实例中安装的扩展的列表。需要安装在容器中的本地安装的扩展(例如,下面的 Azure 帐户扩展)将显示为灰色。

Remote Extensions view

让我们安装 GitLens 扩展,方法是在扩展视图中键入“gitlens”,然后选择“安装到已连接的容器”。

Search for GitLens

这将提示您重启 VS Code,重启后,您会看到短暂的“安装开发容器”通知,因为容器和 VS Code 服务器正在重新启动并安装了新安装的扩展。

您还会注意到,我们之前看到的容器配置文件再次打开,并且更新了一个新的属性,该属性列出了每次连接到此镜像时我们想要安装的扩展。

{
  "workspace": "/usr/src/app",
  "extensions": ["eamodio.gitlens"]
}

现在,打开任何文件,选择一行代码,您会注意到 GitLens 提供了内联 Git 信息!

GitLens information shown in the editor

清理

完成后,您可以从命令面板运行“关闭远程连接”命令,也可以简单地关闭 VS Code 窗口以终止远程连接。

现在,从终端/命令提示符运行 docker-compose down 来停止正在运行的容器。这将释放内存并释放任何使用的端口。

docker-compose down

现在,您已准备好启动另一个容器并处理另一个项目!

下一步

在本博文中,我们介绍了如何使用开发容器扩展连接到您现有的容器化应用程序。

您还可以创建 devcontainer.json,它描述了您想要创建或连接到的开发环境,并且与您的项目一起使用,以便与您的团队成员共享。

其他有用的资源包括完整的 在容器内开发 文档、高级容器配置 以及我们有关使用开发容器扩展构建隔离的开发环境的 入门教程

祝您远程编码愉快!

VS Code 程序经理 Bowden Kelly @bowdenk7