从 Docker Compose 迁移到 Aspire

本指南可帮助你了解如何将应用程序从 Docker 迁移到 Aspire,并重点介绍关键概念差异,同时为常见迁移方案提供实用示例。

了解差异

虽然 Docker Compose 和 Aspire 看起来看起来很相似,但它们服务于不同的目的,并在不同的抽象级别运行。

Docker Compose 与 Aspire

Docker 撰写 Aspire
主要用途 容器业务流程 开发时的编排与应用组合。
范围 以容器为中心 多资源(容器、 .NET 项目、云资源)。
配置 基于 YAML 基于 C#,强类型。
目标环境 任何 Docker 运行时 开发和云部署。
服务发现 基于 DNS 的容器发现 包含环境变量的内置服务发现。
开发体验 手动容器管理 集成工具、仪表板和遥测。

有关详细信息,请参阅 Docker Compose to Aspire AppHost API 文档

关键概念性转变

从 Docker Compose 迁移到 Aspire 时,请注意以下概念差异:

  • 从 YAML 到 C#:配置从声明性 YAML 移动到强制的强类型 C# 代码。
  • 从容器到资源: Aspire 不仅管理容器,还 .NET 管理项目、可执行文件、参数,全部作为资源。
  • 从手动网络到服务发现: Aspire 自动配置服务发现和连接字符串。
  • 从开发差距到集成体验: Aspire 提供仪表板、遥测和调试集成。

有关将 Docker Compose YAML 语法映射到 Aspire C# API 调用的综合参考,请参阅 Docker Compose 到 Aspire AppHost API 参考

相关链接:

常见迁移模式

本部分演示了从 Docker Compose 迁移到 Aspire时可能会遇到的实际迁移方案。 每个模式都显示完整的 Docker Compose 示例及其 Aspire 等效示例,其中突出显示了迁移的主要差异和优势。

涵盖的模式包括:

  • 具有前端、API 和数据库组件的多服务 Web 应用程序
  • 使用现有 映像的Docker。
  • 环境变量和配置 管理策略。
  • 用于数据持久性和服务隔离的自定义网络和卷

这些示例表示最常见的用例,但 Aspire灵活性允许许多其他方案。 如果此处未介绍具体的用例,可以合并这些模式或参考上述全面的 API 参考。

多服务 Web 应用程序

Docker 撰写示例:

version: '3.8'
services:
  frontend:
    build: ./frontend
    ports:
      - "3000:3000"
    depends_on:
      - api
    environment:
      - API_URL=http://api:5000

  api:
    build: ./api
    ports:
      - "5000:5000"
    depends_on:
      - database
    environment:
      - ConnectionStrings__DefaultConnection=Host=database;Database=myapp;Username=postgres;Password=secret

  database:
    image: postgres:15
    environment:
      - POSTGRES_DB=myapp
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=secret
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

Aspire 等效:

var builder = DistributedApplication.CreateBuilder(args);

// Add the database
var database = builder.AddPostgres("postgres")
    .WithEnvironment("POSTGRES_DB", "myapp")
    .AddDatabase("myapp");

// Add the API project
var api = builder.AddProject<Projects.MyApp_Api>("api")
    .WithReference(database);

// Add the frontend project  
var frontend = builder.AddProject<Projects.MyApp_Frontend>("frontend")
    .WithReference(api);

builder.Build().Run();

主要区别:

  • 服务依赖项depends_on 转变为 WithReference(),并且也配置了服务发现。
  • 环境变量:自动生成和注入连接字符串。
  • 生成上下文:生成上下文不是仅使用 .NET 生成,而是能够使用 Dockerfiles、Node.js 项目、Dockerfile 应用等。
  • 数据持久性:卷由Aspire自动管理。

基于容器的服务

Docker 撰写示例:

version: '3.8'
services:
  web:
    build: .
    ports:
      - "8080:8080"
    depends_on:
      - redis
      - postgres

  redis:
    image: redis:7
    ports:
      - "6379:6379"

  postgres:
    image: postgres:15
    environment:
      POSTGRES_PASSWORD: secret
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

Aspire 等效:

var builder = DistributedApplication.CreateBuilder(args);

// Add backing services
var cache = builder.AddRedis("redis");
var database = builder.AddPostgres("postgres", password: "secret")
    .AddDatabase("main");

// Add the containerized web application
var web = builder.AddContainer("web", "myapp:latest")
    .WithHttpEndpoint(port: 8080, targetPort: 8080)
    .WithReference(cache)
    .WithReference(database);

builder.Build().Run();

环境变量和配置

Docker Compose 方法:

services:
  app:
    image: myapp:latest
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/myapp
      - REDIS_URL=redis://cache:6379
      - API_KEY=${API_KEY}
      - LOG_LEVEL=info

Aspire 方法:

var builder = DistributedApplication.CreateBuilder(args);

// Add external parameter
var apiKey = builder.AddParameter("apiKey", secret: true);

var database = builder.AddPostgres("db")
    .AddDatabase("myapp");
    
var cache = builder.AddRedis("cache");

var app = builder.AddContainer("app", "myapp:latest")
    .WithReference(database)      // Automatically sets DATABASE_URL
    .WithReference(cache)         // Automatically sets REDIS_URL  
    .WithEnvironment("API_KEY", apiKey)
    .WithEnvironment("LOG_LEVEL", "info");

builder.Build().Run();

主要区别:

  • 自动连接字符串:自动生成数据库和缓存 URL。
  • 类型化参数:外部配置使用强类型参数,而不是环境变量替换。
  • 服务发现:引用会自动配置正确的服务终结点。

自定义网络和卷

Docker 撰写示例:

version: '3.8'
services:
  app:
    image: myapp:latest
    volumes:
      - app_data:/data
      - ./config:/app/config:ro
    networks:
      - backend

  worker:
    image: myworker:latest
    volumes:
      - app_data:/shared
    networks:
      - backend

networks:
  backend:

volumes:
  app_data:

Aspire 等效:

var builder = DistributedApplication.CreateBuilder(args);

// Create a named volume
var appData = builder.AddVolume("app-data");

var app = builder.AddContainer("app", "myapp:latest")
    .WithVolume(appData, "/data")
    .WithBindMount("./config", "/app/config", isReadOnly: true);

var worker = builder.AddContainer("worker", "myworker:latest")
    .WithVolume(appData, "/shared");

builder.Build().Run();

主要区别:

  • 简化的网络: Aspire 自动处理容器网络。
  • 卷管理:命名卷可通过资源模型创建和管理。
  • 绑定装载:主机目录可以使用 WithBindMount() 装载。

相关链接:

迁移策略

成功从 Docker Compose 迁移到 Aspire 需要一个系统的方法。 以下步骤提供了一种经过验证的方法来移动应用程序,同时最大程度地减少中断并确保所有组件在新环境中正常工作。

1.评估当前设置

在迁移之前,请清点 Docker Compose 设置:

  • 服务:标识所有服务,包括数据库、缓存、API 和 Web 应用程序。
  • 依赖项:从 depends_on 声明中映射服务依赖项。
  • 数据持久性:对用于数据存储的所有卷和绑定装载进行编录。
  • 环境变量:列出所有配置变量和机密。
  • 自定义网络:确定任何自定义网络要求和配置。

2. 创建 Aspire AppHost

首先创建新 Aspire 项目:

dotnet new aspire-apphost -o MyApp.AppHost

3.以增量方式迁移服务

逐个迁移服务,从后盾服务(数据库、缓存)和应用程序开始:

  1. 添加支持服务 ,例如 PostgreSQL, Redis和其他基础结构组件。
  2. 将应用程序转换为.NET项目引用,以便更好地集成。
  3. 使用 AddContainer(),以便用于现有 Docker 映像。
  4. 配置依赖项WithReference()以建立服务关系。
  5. 设置用于 配置管理的环境变量和参数。

4. 处理数据迁移

对于持久性数据:

  • 使用 WithVolume() 来处理需要持久化数据的命名卷。
  • 需要直接访问主机文件时,使用 WithBindMount() 来进行主机目录的挂载。
  • 请考虑使用WithDataVolume()来实现数据库持久性,并结合自动卷管理。

5. 测试和验证

  • Aspire启动 AppHost 并验证所有服务都已正确启动。
  • 检查仪表板以确认服务运行状况和连接状态。
  • 验证服务间通信是否按预期工作。
  • 使用现有客户端应用程序进行测试,以确保兼容性。

相关链接:

迁移故障排除

从 Docker Compose 迁移到 Aspire时,可能会遇到一些常见的挑战。 本部分提供对常见问题的解决方案以及如何排查迁移过程中出现的问题的指导。

常见问题和解决方案

服务发现未正常工作

  • 确保使用 WithReference() 来在服务之间建立依赖关系。
  • 检查服务是否使用正确的环境变量名称进行连接。
  • 查看仪表板以验证是否已正确注入环境变量。

数据库连接失败

  • 在依赖服务尝试连接之前,请验证数据库是否已完全启动。

  • 使用WaitFor()确保正确的启动顺序。

    var api = builder.AddProject<Projects.Api>("api")
        .WithReference(database)
        .WaitFor(database);
    

卷装载问题

  • 使用绝对路径进行绑定挂载以避免路径解析问题。
  • 在装载之前,请确保主机目录存在并具有适当的权限。
  • 考虑尽可能使用命名卷,而不使用绑定装载,以提高可移植性。

端口冲突

  • Aspire 自动分配端口以避免服务之间的冲突。
  • 使用 WithHttpEndpoint() 指定外部访问所需的自定义端口。
  • 在开发过程中检查仪表板中是否有实际分配的端口。

相关链接:

后续步骤

迁移到 Aspire:

另请参阅