项目

本文档有多个版本。请选择最适合您的选项。

UI
Database
Tiered

使用 Docker Compose 进行 Docker 部署

本文档假设您倾向于使用 Blazor WebAssembly 作为 UI 框架,使用 Entity Framework Core 作为数据库提供程序。对于其他选项,请更改本文档顶部的偏好设置。

本指南将引导您了解如何为您的应用程序构建 Docker 镜像并使用 docker compose 在本地运行。您将详细了解提供的构建脚本和 docker compose 文件,并学习如何为生产环境修改它们。

构建 Docker 镜像

每个应用程序都包含一个名为 Dockerfile.local 的 dockerfile 用于构建 Docker 镜像。顾名思义,这些 Dockerfile 不是多阶段 Dockerfile,需要以 Release 模式构建项目才能创建镜像。目前,如果您使用 CI & CD 流水线构建镜像,则需要在构建镜像之前将 SDK 包含到流水线中,或者添加您自己的多阶段 dockerfile

由于它们不是多阶段 Dockerfile,如果您想单独构建镜像,可以导航到相关要托管的应用程序文件夹并运行以下命令:

dotnet publish -c Release

首先填充 Release 文件夹,该文件夹将用于构建 Docker 镜像。之后,您可以运行以下命令:

docker build -f Dockerfile.local -t mycompanyname/myappname:version .

来手动构建您的应用程序镜像。

为了简化流程,应用程序模板在 etc/docker-compose 文件夹下提供了一个构建脚本 build-images-locally.ps1,用于一键构建所有镜像。 根据您的应用程序名称、UI 和类型,将生成一个构建镜像脚本。

param ($version='latest')

$currentFolder = $PSScriptRoot
$slnFolder = Join-Path $currentFolder "../../"

Write-Host "********* 正在构建 DbMigrator *********" -ForegroundColor Green
$dbMigratorFolder = Join-Path $slnFolder "src/Acme.BookStore.DbMigrator"
Set-Location $dbMigratorFolder
dotnet publish -c Release
docker build -f Dockerfile.local -t acme/bookstore-db-migrator:$version .

Write-Host "********* 正在构建 Blazor 应用程序 *********" -ForegroundColor Green
$blazorFolder = Join-Path $slnFolder "src/Acme.BookStore.Blazor"
Set-Location $blazorFolder
dotnet publish -c Release -p:PublishTrimmed=false
docker build -f Dockerfile.local -t acme/bookstore-blazor:$version .

Write-Host "********* 正在构建 Api.Host 应用程序 *********" -ForegroundColor Green
$hostFolder = Join-Path $slnFolder "src/Acme.BookStore.HttpApi.Host"
Set-Location $hostFolder
dotnet publish -c Release
docker build -f Dockerfile.local -t acme/bookstore-api:$version .
  
 $authServerAppFolder = Join-Path $slnFolder "src/Acme.BookStore.AuthServer"
 Set-Location $authServerAppFolder
 dotnet publish -c Release
 docker build -f Dockerfile.local -t acme/bookstore-authserver:$version .
  
### 全部完成
Write-Host "完成" -ForegroundColor Green
Set-Location $currentFolder

默认情况下,镜像标签设置为 latest。您可以在第一行更新 param $version 以将其设置为镜像的标签。

您可以在下面查看发布应用程序所需的所有 Dockerfile:

DBMigrator

DbMigrator 是一个控制台应用程序,用于迁移应用程序数据库并填充运行应用程序所需的重要初始数据。例如预定义的语言、管理员用户和角色、OpenIddict 应用程序和作用域。

此项目下提供的 Dockerfile.local 如下:

FROM mcr.microsoft.com/dotnet/aspnet:10.0
COPY bin/Release/net10.0/publish/ app/
WORKDIR /app
ENTRYPOINT ["dotnet", "BookStore.DbMigrator.dll"]

如果您不想使用 build-images-locally.ps1 来构建镜像,或者想单独手动构建此镜像,请导航到 DbMigrator 文件夹并运行:

dotnet publish -c Release # 以 Release 模式构建项目
docker build -f Dockerfile.local -t acme/bookstore-db-migrator:latest . # 使用 "latest" 标签构建镜像

Blazor

Blazor 应用程序使用 nginx:alpine-slim 基础镜像来托管 Blazor 应用程序。您可以根据自己的偏好修改 Dockerfile.local 中的基础镜像,该文件位于解决方案的 Blazor 文件夹下,如下所示:

FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS build
COPY bin/Release/net10.0/publish/ app/
  
FROM nginx:alpine-slim AS final
WORKDIR /usr/share/nginx/html
COPY --from=build /app/wwwroot .
COPY /nginx.conf  /etc/nginx/conf.d/default.conf

除了构建好的 Blazor 应用程序外,还有 nginx.conf 文件也被复制到应用程序镜像中。nginx.conf 文件:

server {
    listen       80;
    listen  [::]:80;
    server_name  _;
    
    #listen              443 ssl;
    #server_name         www.myapp.com;
    #ssl_certificate     www.myapp.com.crt;
    #ssl_certificate_key www.myapp.com.key;
    
 location / {
        root   /usr/share/nginx/html;        
        index  index.html index.htm;
        try_files $uri $uri/ /index.html =404;  
 }
    #error_page  404              /404.html;

    # 将服务器错误页面重定向到静态页面 /50x.html    
    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

如果您不想使用 build-images-locally.ps1 来构建镜像,或者想单独手动构建此镜像,请导航到 Blazor 文件夹并运行:

## 以 Release 模式构建项目,并禁用修剪选项。您可以根据需要启用或配置它
dotnet publish -c Release -p:PublishTrimmed=false 
docker build -f Dockerfile.local -t acme/bookstore-blazor:latest . # 使用 "latest" 标签构建镜像

AuthServer

这是 openid 提供程序应用程序,即身份验证服务器,与非分层应用程序模板相比,应单独托管。dockerfile.local 位于 AuthServer 项目下,如下所示:

FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS base
COPY bin/Release/net10.0/publish/ app/
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
WORKDIR /src
RUN dotnet dev-certs https -v -ep authserver.pfx -p 2D7AA457-5D33-48D6-936F-C48E5EF468ED

FROM base AS final
WORKDIR /app
COPY --from=build /src .

ENTRYPOINT ["dotnet", "Acme.BookStore.AuthServer.dll"]

构建镜像时,您可能会遇到错误。这是因为 dotnet dev-certs 命令试图列出容器内的现有证书但无法访问。这不是一个重要错误,因为我们的目标是生成 authserver.pfx 文件并丢弃构建它的容器。

auth-server-pfx-generation-error

AuthServer Docker 镜像构建过程包含多阶段以生成 authserver.pfx 文件,该文件被 OpenIddict 用作签名和加密证书。此配置位于 AuthServerModulePreConfigureServices 方法中:

if (!hostingEnvironment.IsDevelopment())
{
    PreConfigure<AbpOpenIddictAspNetCoreOptions>(options =>
    {
        options.AddDevelopmentEncryptionAndSigningCertificate = false;
    });

    PreConfigure<OpenIddictServerBuilder>(serverBuilder =>
    {
        serverBuilder.AddProductionEncryptionAndSigningCertificate("openiddict.pfx", configuration["AuthServer:CertificatePassPhrase"]!);
        serverBuilder.SetIssuer(new Uri(configuration["AuthServer:Authority"]!));
    });
}

此配置禁用 DevelopmentEncryptionAndSigningCertificate,并使用名为 authserver.pfx 的自签名证书来签名和加密令牌。该证书是在构建 Docker 镜像时使用 dotnet dev-certs 工具创建的。它是一个示例生成的证书,并且建议为生产环境更新它。您可以查看 OpenIddict 加密和签名凭据文档 以了解不同的选项和自定义。

您始终可以使用 Dockerfile 之外的任何其他工具创建任何自签名证书。您需要记住将它们设置为嵌入式资源

如果您不想使用 build-images-locally.ps1 来构建镜像,或者想单独手动构建此镜像,请导航到 AuthServer 文件夹并运行:

dotnet publish -c Release # 以 Release 模式构建项目
docker build -f Dockerfile.local -t acme/bookstore-authserver:latest . # 使用 "latest" 标签构建镜像

Http.Api.Host

这是暴露端点和 Swagger UI 的后端应用程序。它不是一个多阶段 dockerfile;因此您需要已经以 Release 模式构建了此应用程序才能使用此 dockerfile。dockerfile.local 位于 Http.Api.Host 项目下,如下所示:

FROM mcr.microsoft.com/dotnet/aspnet:10.0
COPY bin/Release/net10.0/publish/ app/
WORKDIR /app
ENTRYPOINT ["dotnet", "Acme.BookStore.HttpApi.Host.dll"]

如果您不想使用 build-images-locally.ps1 来构建镜像,或者想单独手动构建此镜像,请导航到 Http.Api.Host 文件夹并运行:

dotnet publish -c Release # 以 Release 模式构建项目
docker build -f Dockerfile.local -t acme/bookstore-api:latest . # 使用 "latest" 标签构建镜像

在 Localhost 上运行 Docker-Compose

etc/docker-compose 文件夹下,您可以找到用于运行应用程序的 docker-compose.yml。为了简化运行过程,模板提供了 run-docker.ps1(和 run-docker.sh)脚本,用于处理环境变量中使用的 HTTPS 证书的创建;

$currentFolder = $PSScriptRoot

$slnFolder = Join-Path $currentFolder "../"
$certsFolder = Join-Path $currentFolder "certs"

If(!(Test-Path -Path $certsFolder))
{
    New-Item -ItemType Directory -Force -Path $certsFolder
    if(!(Test-Path -Path (Join-Path $certsFolder "localhost.pfx") -PathType Leaf)){
        Set-Location $certsFolder
        dotnet dev-certs https -v -ep localhost.pfx -p 91f91912-5ab0-49df-8166-23377efaf3cc -t        
    }
}

Set-Location $currentFolder
docker-compose up -d

run-docker.ps1(或 run-docker.sh)脚本将检查 etc/certs 文件夹下是否已存在开发证书,如果不存在,则生成 localhost.pfx 文件。Kestrel 将使用此文件作为 HTTPS 证书

您也可以使用 dotnet dev-certs https -v -ep myCert.pfx -p YOUR_PASSWORD_FOR_HTTPS_CERT -t 或使用任何其他自签名证书生成工具,在不同路径手动创建 localhost.pfx 文件,使用不同的名称和密码。

您需要在 docker-compose.yml 文件中更新服务环境变量 Kestrel__Certificates__Default__Path 为您创建的路径和文件名,以及 Kestrel__Certificates__Default__Password 为您的新密码。

现在让我们分解 docker-compose.yml 文件中的每个 Docker compose 服务:

bookstore-blazor

services:
  bookstore-blazor:
    image: acme/bookstore-blazor:latest
    container_name: bookstore-blazor
    build:
      context: ../../
      dockerfile: src/Acme.BookStore.Blazor/Dockerfile.local
    ports:
      - "44307:80"
    depends_on:
      - bookstore-api
    restart: on-failure
    volumes:
      - ./appsettings.json:/usr/share/nginx/html/appsettings.json
    networks:
      - abp-network

这是我们在 http://localhost:44307 上默认部署的 Blazor 应用程序,使用我们通过 build-images-locally.ps1 脚本构建的 acme/bookstore-blazor:latest 镜像。它没有使用 localhost.pfx 运行 HTTPS,因为它运行在 Nginx 上,并且不接受 pfx 文件作为 SSL。您可以查看 Nginx 配置 HTTPS 服务器文档 了解更多信息,并将必要的配置应用到 Blazor 文件夹下的 nginx.conf 文件。

更新 Blazor 文件夹下的 nginx.conf 文件后,不要忘记重新构建 acme/bookstore-blazor:latest 镜像。

volumes 部分,它将 docker 文件夹下的 appsettings.json 文件挂载,以实现在不重新构建镜像的情况下更改环境变量。覆盖的 docker/appsettings.json 文件如下:

{
  "App": {
    "SelfUrl": "http://localhost:44307"
  },
  "AuthServer": { 
    "Authority": "https://localhost:44334",  
    "ClientId": "BookStore_Blazor",
    "ResponseType": "code"
  },
  "RemoteServices": {
    "Default": {
      "BaseUrl": "https://localhost:44354"
    },
    "AbpAccountPublic": { 
      "BaseUrl": "https://localhost:44334"  
    }
  },
  "AbpCli": {
    "Bundle": {
      "Mode": "BundleAndMinify", 
      "Name": "global",
      "Parameters": {
              "LeptonXTheme.Layout": "side-menu"
      }
    }
  }
}

此服务在名为 abp-network 的 Docker 网络中运行,等待 bookstore-api 启动,并在失败时重新启动。您可以根据自己的偏好自定义这些编排行为。

bookstore-api

bookstore-api:
    image: acme/bookstore-api:latest
    container_name: bookstore-api
    hostname: bookstore-api
    build:
      context: ../../
      dockerfile: src/Acme.BookStore.HttpApi.Host/Dockerfile.local
    environment:
      - ASPNETCORE_URLS=https://+:443;http://+:80;
      - Kestrel__Certificates__Default__Path=/root/certificate/localhost.pfx
      - Kestrel__Certificates__Default__Password=91f91912-5ab0-49df-8166-23377efaf3cc
      - App__SelfUrl=https://localhost:44354
   - App__CorsOrigins=http://localhost:44307
      - App__HealthCheckUrl=http://bookstore-api/health-status  
   - AuthServer__Authority=http://bookstore-authserver    
      - AuthServer__RequireHttpsMetadata=false  
      - ConnectionStrings__Default=Data Source=sql-server;Initial Catalog=BookStore;User Id=sa;Password=myPassw0rd;MultipleActiveResultSets=true;TrustServerCertificate=True;      
      - Redis__Configuration=redis  
    ports:
      - "44354:443"
    depends_on: 
      sql-server:
        condition: service_healthy         
      redis:
        condition: service_healthy
    restart: on-failure     
    volumes:
      - ./certs:/root/certificate
    networks:
      - abp-network

此服务是 Blazor 应用程序的后端应用程序,使用我们通过 build-images-locally.ps1 脚本构建的 acme/bookstore-api:latest 镜像。它默认运行在 https://localhost:44354,通过挂载我们在 etc/certs 文件夹下生成的自签名证书来实现。

  • App__SelfUrl 指向我们暴露端口的 localhost https://localhost:44354部署到生产环境时,必须指向真实的 DNS

  • App__CorsOrigins 是 CORS 的覆盖配置。我们在此添加 angular 应用程序的 URL http://localhost:44307部署到生产环境时,必须指向真实的 DNS

  • App__HealthCheckUrl 是健康检查 URL 的覆盖配置。由于此请求将在内部完成,因此它指向容器化环境中的服务名称 http://bookstore-api/health-status

  • AuthServer__Authority 是颁发者 URL。 http://bookstore-authserver 是容器化的颁发者。部署到生产环境时,必须指向真实的 DNS

  • AuthServer__RequireHttpsMetadataopenid 提供程序强制使用 HTTPS 的选项。Docker-compose 使用一个称为 abp-network 的隔离内部 Docker 网络。我们希望在没有 SSL 开销的内部网络通信中使用 HTTP。因此,默认情况下设置为 false

  • ConnectionStrings__Default 是被覆盖的默认连接字符串。它默认使用 容器化的 sql-server 以及 sa 用户 。

  • Redis__Configuration 是被覆盖的 Redis 配置。它使用容器化的 redis 服务。如果您不使用容器化的 Redis,请更新您的 Redis URL。

此服务在名为 abp-network 的 Docker 网络中运行,等待 redis 服务和 数据库容器启动,并在失败时重新启动。您可以根据自己的偏好自定义这些编排行为。

bookstore-authserver

bookstore-authserver:
    image: acme/bookstore-authserver:latest
    container_name: bookstore-authserver
    build:
      context: ../../
      dockerfile: src/Acme.BookStore.AuthServer/Dockerfile.local
    environment:
      - ASPNETCORE_URLS=https://+:443;http://+:80;      
      - Kestrel__Certificates__Default__Path=/root/certificate/localhost.pfx
      - Kestrel__Certificates__Default__Password=91f91912-5ab0-49df-8166-23377efaf3cc
      - App__SelfUrl=https://localhost:44334
      - App__CorsOrigins=http://localhost:44307
      - AuthServer__Authority=http://bookstore-authserver
      - AuthServer__RequireHttpsMetadata=false      
      - ConnectionStrings__Default=Data Source=sql-server;Initial Catalog=BookStore;User Id=sa;Password=myPassw0rd;MultipleActiveResultSets=true;TrustServerCertificate=True;            
      - Redis__Configuration=redis
    ports:
      - "44334:443"
    depends_on:     
      sql-server:
        condition: service_healthy                 
    restart: on-failure
    volumes:
      - ./certs:/root/certificate
    networks:
      - abp-network

这是使用 OpenIddict 库处理应用程序间身份验证的身份验证服务器应用程序。它使用我们通过 build-images-locally.ps1 脚本构建的 acme/bookstore-authserver:latest 镜像。它默认运行在 https://localhost:44334,通过挂载我们在 etc/certs 文件夹下生成的自签名证书来实现。

  • App__SelfUrl 指向我们暴露端口的 localhost https://localhost:44334部署到生产环境时,必须指向真实的 DNS

  • App__CorsOrigins 是 CORS 的覆盖配置。默认情况下,我们在此添加 angular 和 Blazor 应用程序的 URL。部署到生产环境时,必须指向真实的 DNS

  • AuthServer__Authority 是颁发者 URL。http://bookstore-authserver 默认是 authserver 的端点。部署到生产环境时,必须指向真实的 DNS

  • AuthServer__RequireHttpsMetadataopenid 提供程序强制使用 HTTPS 的选项。Docker-compose 使用一个称为 abp-network 的隔离内部 Docker 网络。我们希望在没有 SSL 开销的内部网络通信中使用 HTTP。因此,默认情况下设置为 false

  • ConnectionStrings__Default 是被覆盖的默认连接字符串。它默认使用 容器化的 sql-server 以及 sa 用户 。

  • Redis__Configuration 是被覆盖的 Redis 配置。它使用容器化的 redis 服务。如果您不使用容器化的 Redis,请更新您的 Redis URL。

此服务在名为 abp-network 的 Docker 网络中运行,等待 Redis 服务和数据库容器启动,并在失败时重新启动。您可以根据自己的偏好自定义这些编排行为。

db-migrator

db-migrator:
    image: acme/bookstore-db-migrator:latest
    container_name: db-migrator
    build:
      context: ../../
      dockerfile: src/BookStore.DbMigrator/Dockerfile.local
    environment:
      - OpenIddict__Applications__BookStore_Blazor__RootUrl=http://localhost:44307      
      - OpenIddict__Applications__BookStore_Swagger__RootUrl=https://localhost:44354            
      - ConnectionStrings__Default=Data Source=sql-server;Initial Catalog=BookStore;User Id=sa;Password=myPassw0rd;MultipleActiveResultSets=true;TrustServerCertificate=True;            
    depends_on:     
      sql-server:
        condition: service_healthy                  
    networks:
      - abp-network

数据库迁移器服务迁移数据库并填充初始数据。OpenIddict 数据是您的应用程序最重要的填充数据之一。在生产环境中,您需要覆盖应用程序的根 URL (http://localhost:44307) 和 swagger-ui 客户端 URL (https://localhost:44354),以便身份验证正常工作。

下一步是什么?

在本文档中