如何使用 .NET 8 隔离工作模型对 Azure 函数进行 Docker 化以进行集成测试?

问题描述 投票:0回答:1

我有一个用 .NET 8 编写的 Azure 函数,它使用隔离的工作线程模型。 我想为此函数编写集成测试,因此想在内存中启动它。

我查看了

WebApplicationFactory
,但它似乎不支持隔离的工人模型。 我发现
Testcontainers
听起来很有希望(但这似乎也没有得到 100% 的支持)。但我正在尝试一下。为了实现这一点,我必须将我的功能进行docker化,这就是我面临问题的地方。我让 Visual Studio 生成了一个 Dockerfile。它可以构建,但是当使用图像启动容器时它会失败。

在深入了解错误的详细信息之前,请让我知道是否有其他方法可以解决此问题。我愿意接受建议。

Dockerfile

值得注意的是,我使用以下命令从与 Dockerfile 不同的文件夹构建映像:

docker build -f "My Subfolder/Dockerfile" -t my-image:latest . --no-cache

注释掉的行是我尝试过的其他内容:

FROM mcr.microsoft.com/azure-functions/dotnet-isolated:4-dotnet-isolated8.0 AS base
#COPY --from=mcr.microsoft.com/dotnet/core/sdk:3.1 /usr/share/dotnet /usr/share/dotnet

WORKDIR /home/site/wwwroot
EXPOSE 8080

# Install Azure Functions Core Tools
RUN apt-get update && \
    apt-get install -y curl && \
    curl -sL https://deb.nodesource.com/setup_20.x | bash - && \
    apt-get install -y nodejs && \
    npm install -g azure-functions-core-tools@4 --unsafe-perm

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY . .
RUN dotnet restore "./My Subfolder/Project.csproj"
#COPY . .
WORKDIR "/src/My Subfolder"
#RUN dotnet build "./Project.csproj" -c $BUILD_CONFIGURATION -o /app/build

FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./Project.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false

FROM base AS final
WORKDIR /home/site/wwwroot
COPY --from=publish /app/publish .

#RUN apt-get update && \
#    apt-get install -y nodejs npm && \
#    npm install -g azurite

#CMD ["ls"]

ENTRYPOINT ["func", "start", "--dotnet-isolated"]

ENV AzureWebJobsScriptRoot=/home/site/wwwroot \
    AzureFunctionsJobHost__Logging__Console__IsEnabled=true \
    WEBSITES_INCLUDE_CLOUD_CERTS=true

问题

  1. 一个错误似乎是该函数需要一个它无权访问的存储帐户。 一种想法是在容器中安装 Azurite,但我并没有真正让它发挥作用,因为我有多个以类似方式设置的 Azure 函数,它们都有自己的安装。

    另一种方法是使用 docker compose,但 .NET 版本的 Testcontainers 尚不支持。 因此,为了继续前进,我删除了需要存储的部分(TimerTrigger),因此错误暂时消失了。

  2. 另一个非常持久的错误是它似乎无法读取我的

    settings.json
    文件。我使用选项模式进行一些验证,例如:

    public sealed class MyOptions
    {
        [Required(ErrorMessage = "Option is required")]
        public string SomeOption { get; set; } = null!;
    }
    

    我在 Dockerfile 的最后阶段尝试了

    CMD ["ls"]
    ,它确实列出了我的
    settings.json
    文件。它在本地运行良好,所以不确定这里发生了什么。

    错误看起来像这样:

    2024-09-23 12:17:07 Azure Functions Core Tools
    2024-09-23 12:17:07 Core Tools Version:       4.0.6280 Commit hash: N/A +421f0144b42047aa289ce691dc6db4fc8b6143e6 (64-bit)
    2024-09-23 12:17:07 Function Runtime Version: 4.834.3.22875
    2024-09-23 12:17:07 
    2024-09-23 12:17:08 [2024-09-23T10:17:08.173Z] Csproj not found in /home/site/wwwroot directory tree. Skipping user secrets file configuration.
    2024-09-23 12:17:08 Skipping 'AzureWebJobsScriptRoot' from local settings as it's already defined in current environment variables.
    2024-09-23 12:17:08 Skipping 'AZURE_FUNCTIONS_ENVIRONMENT' from local settings as it's already defined in current environment variables.
    2024-09-23 12:17:09 
    2024-09-23 12:17:09 Functions:
    2024-09-23 12:17:09 
    2024-09-23 12:17:09     MyHttpFunction: [GET,POST] http://localhost:7071/api/MyHttpFunction
    2024-09-23 12:17:09 
    2024-09-23 12:17:09 For detailed output, run func with --verbose flag.
    2024-09-23 12:17:09 [2024-09-23T10:17:09.841Z] MyOptions: 
    2024-09-23 12:17:10 [2024-09-23T10:17:10.154Z] Unhandled exception. Microsoft.Extensions.Options.OptionsValidationException: DataAnnotation validation failed for 'MyOptions' members: 'SomeOption' with the error: 'Option is required'.
    2024-09-23 12:17:10 [2024-09-23T10:17:10.154Z]    at Microsoft.Extensions.Options.OptionsFactory`1.Create(String name)
    2024-09-23 12:17:10 [2024-09-23T10:17:10.154Z]    at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode)
    2024-09-23 12:17:10 [2024-09-23T10:17:10.154Z]    at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor)
    2024-09-23 12:17:10 [2024-09-23T10:17:10.154Z]    at System.Lazy`1.CreateValue()
    2024-09-23 12:17:10 [2024-09-23T10:17:10.154Z]    at Microsoft.Extensions.Options.OptionsCache`1.GetOrAdd[TArg](String name, Func`3 createOptions, TArg factoryArgument)
    ...
    

问题

不同的方法:是否有不同的方法来解决这个问题?我愿意接受建议。

存储帐户:如何处理 Docker 容器中的存储帐户要求?安装 Azurite 是正确的方法吗?

Settings.json:为什么我的settings.json 文件在 Docker 容器中无法正确读取,如何解决这个问题?

我不知道如何继续。我不确定我是否走在 Testcontainers 和 Docker 的正确轨道上。我愿意接受有关如何解决这些问题的建议。我也愿意接受其他方法,使用隔离的 worder 模型为我的 Azure Function 编写集成测试。

docker .net-core azure-functions dockerfile integration-testing
1个回答
0
投票

对于隔离的工作模型功能,

AzureFunctions.TestHost
库提供了无需 Docker 的本地测试选项。

  • 您可以在内存中启动函数并直接调用触发器,类似于集成测试,但比完全容器化更快、更轻量。
在 Docker 中使用

Azurite 仍然是模拟 Azure 存储的最佳解决方案之一。但是,为了使其顺利运行,请使用 Docker Compose 同时运行函数应用程序和 Azurite,

Docker 撰写:

version: '3.8' services: functionapp: image: my-azure-function-app:latest build: context: . dockerfile: Dockerfile ports: - "7071:8080" environment: AzureWebJobsStorage: "UseDevelopmentStorage=true" depends_on: - azurite azurite: image: mcr.microsoft.com/azure-storage/azurite ports: - "10000:10000"

    虽然测试容器本身尚未完全支持具有.NET隔离工作模型的 Docker Compose,但单独使用 Docker Compose 作为集成测试的测试环境是一个可行的替代方案。

日志:

Azure Functions Core Tools Core Tools Version: 4.0.6280 Commit hash: N/A +421f0144b42047aa289ce691dc6db4fc8b6143e6 (64-bit) Function Runtime Version: 4.834.3.22875 [2024-09-23T10:17:08.173Z] Csproj not found in /home/site/wwwroot directory tree. Skipping user secrets file configuration. Skipping 'AzureWebJobsScriptRoot' from local settings as it's already defined in current environment variables. Skipping 'AZURE_FUNCTIONS_ENVIRONMENT' from local settings as it's already defined in current environment variables. Functions: MyHttpFunction: [GET,POST] http://localhost:7071/api/MyHttpFunction For detailed output, run func with --verbose flag. [2024-09-23T10:17:09.841Z] MyOptions: [2024-09-23T10:17:10.154Z] Unhandled exception. Microsoft.Extensions.Options.OptionsValidationException: DataAnnotation validation failed for 'MyOptions' members: 'SomeOption' with the error: 'Option is required'. at Microsoft.Extensions.Options.OptionsFactory`1.Create(String name) at System.Lazy`1.ViaFactory(LazyThreadSafetyMode mode) at System.Lazy`1.ExecutionAndPublication(LazyHelper executionAndPublication, Boolean useDefaultConstructor) at System.Lazy`1.CreateValue() at Microsoft.Extensions.Options.OptionsCache`1.GetOrAdd[TArg](String name, Func`3 createOptions, TArg factoryArgument)
    
© www.soinside.com 2019 - 2024. All rights reserved.