使用镜像、Dockerfile 和 Docker Compose

2022 年 12 月 16 日 - @chuxel

在创建开发容器时,您有多种不同的方式来定制环境,例如使用 “Features”(功能)生命周期脚本。但是,如果您熟悉容器,可能更倾向于使用 DockerfileDocker Compose 来定制环境。本文将引导您了解如何在 Dev Container 规范中使用这些格式。

使用 Dockerfile

为了保持简单,许多 开发容器模板 (Dev Container Templates) 都直接使用容器镜像引用。

{
    "image": "mcr.microsoft.com/devcontainers/base:ubuntu"
}

然而,Dockerfile 是扩展镜像、添加额外的原生操作系统软件包或对操作系统镜像进行微调的绝佳方式。您可以复用任何 Dockerfile,但让我们从头开始演示如何创建一个。

首先,在您的 devcontainer.json 旁边添加一个名为 Dockerfile 的文件。例如

FROM mcr.microsoft.com/devcontainers/base:ubuntu
# Install the xz-utils package
RUN apt-get update && apt-get install -y xz-utils

接下来,从 devcontainer.json 中删除 image 属性(如果存在),并改为添加 builddockerfile 属性

{
    "build": {
        // Path is relative to the devcontainer.json file.
        "dockerfile": "Dockerfile"
    }
}

就是这样!当您启动开发容器时,Dockerfile 将自动构建,无需额外工作。有关其他相关 devcontainer.json 属性的更多信息,请参阅 Dockerfile 场景参考

迭代包含开发容器元数据的镜像

更好的是,您可以将 Dockerfile 作为创作可与他人共享的镜像的一部分。您甚至可以直接在镜像中添加开发容器的设置和元数据。这避免了在多个 devcontainer.json 文件中重复配置和设置,并使它们与您的镜像保持同步!

请参阅关于 预构建 (pre-building) 的指南以了解更多信息!

使用 Docker Compose

Docker Compose 是定义多容器开发环境的绝佳方式。与其将数据库或 Redis 等内容添加到 Dockerfile 中,不如为这些服务引用现有的镜像,并将开发容器的内容专注于开发所需的工具和实用程序。

将 Docker Compose 与镜像结合使用

正如 Dockerfile 部分所提到的,为了保持简单,许多 开发容器模板 都使用容器镜像引用。

{
    "image": "mcr.microsoft.com/devcontainers/base:ubuntu"
}

让我们在 devcontainer.json 旁边创建一个 docker-compose.yml 文件,引用相同的镜像并包含一个 PostgreSQL 数据库

version: '3.8'
services:
  devcontainer:
    image: mcr.microsoft.com/devcontainers/base:ubuntu
    volumes:
      - ../..:/workspaces:cached
    network_mode: service:db
    command: sleep infinity

  db:
    image: postgres:latest
    restart: unless-stopped
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: postgres
      POSTGRES_USER: postgres
      POSTGRES_DB: postgres

volumes:
  postgres-data:

在此示例中

  • ../..:/workspaces:cached 将本地源码树中的工作区文件夹挂载到开发容器中。
  • network_mode: service:db 将开发容器置于与数据库相同的网络中,以便它可以通过 localhost 访问数据库。
  • db 部分使用了带有特定设置的 Postgres 镜像。

接下来,让我们配置 devcontainer.json 以使用它。

{
    "dockerComposeFile": "docker-compose.yml",
    "service": "devcontainer",
    "workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}"
}

在此示例中

  • service 指定了 docker-compose.yml 文件中的哪个服务是开发容器。
  • dockerComposeFile 指定了在哪里可以找到 docker-compose.yml 文件。
  • workspaceFolder 指定了挂载工作区文件夹的位置。这对应于 docker-compose.yml 文件中 ../..:/workspaces:cached 挂载点下的子文件夹。

就是这样!

在 Docker Compose 中使用 Dockerfile

您还可以结合这些场景,在 Docker Compose 中使用 Dockerfile。这一次,我们将通过用类似的 build 部分替换 image,来更新 docker-compose.yml 以引用 Dockerfile

version: '3.8'
services:
  devcontainer:
    build: 
      context: .
      dockerfile: Dockerfile
    volumes:
      - ../..:/workspaces:cached      
    network_mode: service:db
    command: sleep infinity

  db:
    image: postgres:latest
    restart: unless-stopped
    volumes:
      - postgres-data:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: postgres
      POSTGRES_USER: postgres
      POSTGRES_DB: postgres

volumes:
  postgres-data:

最后,正如在 Dockerfile 示例中一样,您可以使用相同的设置来创建一个可与他人共享的开发容器镜像。您还可以直接在镜像本身中添加开发容器设置和元数据。

请参阅关于 预构建 (pre-building) 的指南以了解更多信息!