在 Python 中协调 .NET Aspire 应用

本文介绍如何在 Python 应用主机中使用 .NET Aspire 应用。 本文中的示例应用演示如何启动 Python 应用程序。 Python 的 .NET Aspire 扩展需要使用虚拟环境。

先决条件

若要使用 .NET.NET Aspire,需要在本地安装以下各项:

有关详细信息,请参阅 .NET.NET Aspire 设置和工具,以及 .NET.NET Aspire SDK

此外,需要在计算机上安装 Python。 本文中的示例应用是使用 Python 版本 3.12.4 和 pip 版本 24.1.2 生成的。 若要验证 Python 和 pip 版本,请运行以下命令:

python --version
pip --version

若要下载 Python(包括 pip),请参阅 Python 下载页面

使用模板创建 .NET.NET Aspire 项目

要在 Python 中启动 .NET Aspire 项目,首先使用入门模板创建 .NET Aspire 应用程序主机:

dotnet new aspire -o PythonSample

在同一终端会话中,将目录更改为新创建的项目:

cd PythonSample

创建模板后,使用以下命令启动应用主机,以确保应用主机和 .NET.NET Aspire 仪表板 成功启动:

dotnet run --project PythonSample.AppHost/PythonSample.AppHost.csproj

应用主机启动后,应该可以单击控制台输出中的仪表板链接。 此时,仪表板不会显示任何资源。 在终端中按 Ctrl + C,以停止应用主机。

准备 Python 应用程序

在创建 .NET Aspire 解决方案的上一个终端会话中,创建一个新目录以包含 Python 源代码。

mkdir hello-python

将目录更改为新创建的 hello-python 目录:

cd hello-python

初始化 Python 虚拟环境

若要使用 Python 应用,它们需要位于虚拟环境中。 若要创建虚拟环境,请运行以下命令:

python -m venv .venv

有关虚拟环境的详细信息,请参阅 Python:在虚拟环境中使用 pip 和 venv 安装包

若要激活虚拟环境,启用包的安装和使用,请运行以下命令:

source .venv/bin/activate

运行以下命令,确保虚拟环境中的 pip up-to-date:

python -m pip install --upgrade pip

安装 Python 包

通过在 hello-python 目录中创建 requirements.txt 文件并添加以下行来安装 Flask 包:

Flask==3.0.3

然后,运行以下命令安装 Flask 包:

python -m pip install -r requirements.txt

安装 Flask 后,在 hello-python 目录中创建名为 main.py 的新文件,并添加以下代码:

import os
import flask

app = flask.Flask(__name__)

@app.route('/', methods=['GET'])
def hello_world():
    return 'Hello, World!'

if __name__ == '__main__':
    port = int(os.environ.get('PORT', 8111))
    app.run(host='0.0.0.0', port=port)

前面的代码创建一个简单的 Flask 应用,该应用侦听端口 8111,并在访问根终结点时返回消息 "Hello, World!"

更新应用主机项目

运行以下命令安装 Python 托管包:

dotnet add ../PythonSample.AppHost/PythonSample.AppHost.csproj package Aspire.Hosting.Python --version 9.0.0

安装包后,项目 XML 应具有类似于以下内容的新包引用:

<Project Sdk="Microsoft.NET.Sdk">

  <Sdk Name="Aspire.AppHost.Sdk" Version="9.1.0" />

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net9.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <IsAspireHost>true</IsAspireHost>
    <UserSecretsId>5fd92a87-fff8-4a09-9f6e-2c0d656e25ba</UserSecretsId>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Aspire.Hosting.AppHost" Version="9.1.0" />
    <PackageReference Include="Aspire.Hosting.Python" Version="9.1.0" />
  </ItemGroup>

</Project>

通过调用 API 并指定项目名称、项目路径和入口点文件,更新应用主机 Python 文件以包括 AddPythonApp 项目:

using Microsoft.Extensions.Hosting;

var builder = DistributedApplication.CreateBuilder(args);

#pragma warning disable ASPIREHOSTINGPYTHON001
var pythonapp = builder.AddPythonApp("hello-python", "../hello-python", "main.py")
       .WithHttpEndpoint(env: "PORT")
       .WithExternalHttpEndpoints()
       .WithOtlpExporter();
#pragma warning restore ASPIREHOSTINGPYTHON001

if (builder.ExecutionContext.IsRunMode && builder.Environment.IsDevelopment())
{
    pythonapp.WithEnvironment("DEBUG", "True");
}

builder.Build().Run();

重要

AddPythonApp API 是实验性的,将来的版本可能会更改。 有关详细信息,请参阅 ASPIREHOSTINGPYTHON001

运行应用

添加 Python 托管包、更新应用主机 Program.cs 文件并创建 Python 项目后,即可运行应用主机:

dotnet run --project ../PythonSample.AppHost/PythonSample.AppHost.csproj

通过单击控制台输出中的链接启动仪表板。 仪表板应将 Python 项目显示为资源。

.NET Aspire 仪表板:Python 示例应用。

选择 终结点 链接,在新浏览器选项卡中打开 hello-python 终结点。浏览器应显示消息“Hello, World!”:

.NET Aspire 仪表板:Python 示例应用端点。

在终端中按 Ctrl + C,以停止应用主机。

添加遥测支持。

为了增强可观测性,请添加遥测以帮助监控依赖的 Python 应用。 在 Python 项目中,将以下 OpenTelemetry 包添加为 requirements.txt 文件中的依赖项:

Flask==3.0.3
opentelemetry-distro
opentelemetry-exporter-otlp-proto-grpc
opentelemetry-instrumentation-flask
gunicorn

之前的要求更新中,添加了 OpenTelemetry 包和 OTLP 导出器。 接下来,运行以下命令,将 Python 应用要求重新安装到虚拟环境中:

python -m pip install -r requirements.txt

上述命令在虚拟环境中安装 OpenTelemetry 包和 OTLP 导出程序。 通过将现有 Python 代码替换为以下内容,更新 OpenTelemetry 应用以包括 代码:

import os
import logging
import flask
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor
from opentelemetry.instrumentation.flask import FlaskInstrumentor

app = flask.Flask(__name__)

trace.set_tracer_provider(TracerProvider())
otlpExporter = OTLPSpanExporter()
processor = BatchSpanProcessor(otlpExporter)
trace.get_tracer_provider().add_span_processor(processor)

FlaskInstrumentor().instrument_app(app)

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

@app.route('/', methods=['GET'])
def hello_world():
    logger.info("request received!")
    return 'Hello, World!'

if __name__ == '__main__':
    port = int(os.environ.get('PORT', 8111))
    debug = bool(os.environ.get('DEBUG', False))
    host = os.environ.get('HOST', '127.0.0.1')
    app.run(port=port, debug=debug, host=host)

更新应用主机项目的 launchSettings.json 文件以包含 ASPIRE_ALLOW_UNSECURED_TRANSPORT 环境变量:

{
  "$schema": "https://json.schemastore.org/launchsettings.json",
  "profiles": {
    "https": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "https://localhost:17171;http://localhost:15209",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "DOTNET_ENVIRONMENT": "Development",
        "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21171",
        "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22122"
      }
    },
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "http://localhost:15209",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "DOTNET_ENVIRONMENT": "Development",
        "DOTNET_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19171",
        "DOTNET_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20208",
        "ASPIRE_ALLOW_UNSECURED_TRANSPORT": "true"
      }
    }
  }
}

ASPIRE_ALLOW_UNSECURED_TRANSPORT 变量是必需的,因为在本地运行 OpenTelemetry 客户端时,Python 会拒绝本地开发证书。 再次启动 应用主机

dotnet run --project ../PythonSample.AppHost/PythonSample.AppHost.csproj

应用主机启动后,导航到仪表板并注意,除了控制台日志输出之外,结构化日志记录也会路由到仪表板。

.NET Aspire 仪表盘:来自 Python 进程的结构化日志记录。

总结

虽然本文未讨论几个注意事项,但你已了解如何生成与 .NET Aspire集成的 Python 解决方案。 你还了解了如何使用 AddPythonApp API 托管 Python 应用。

另请参阅