docker asp.net 核心容器在 mysql 容器之后启动

Posted

技术标签:

【中文标题】docker asp.net 核心容器在 mysql 容器之后启动【英文标题】:docker asp.net core container starting after a mysql container 【发布时间】:2018-12-23 21:17:01 【问题描述】:

我有一个带有 asp.net 核心的 docker 容器和一个带有 mysql 的容器。现在我需要等待 asp.net 核心容器,因为 mysql 容器已启动并准备就绪(两个容器都通过 docker-compose.yml 启动)。

https://github.com/jwilder/dockerize、wait-for-it.sh 或 wait-for 之类的东西似乎不适用于 asp.net 核心容器。

有人知道如何解决这个问题吗?

更新

这是我的 dockerfile:

FROM microsoft/aspnetcore-build:2.0 AS build-env
WORKDIR /app

# Copy csproj and restore as distinct layers
COPY *.csproj ./
RUN dotnet restore test.csproj

# Copy everything else and build
COPY . ./
RUN dotnet publish -c Release -o out test.csproj



# Build runtime image
FROM microsoft/aspnetcore:2.0
WORKDIR /app
COPY ./entrypoint.sh ./app/
RUN chmod +x ./app/entrypoint.sh
CMD /bin/bash ./app/entrypoint.sh

COPY --from=build-env /app/out .
ENTRYPOINT ["dotnet", "test.dll"]

这是我的 entrypoint.sh:

#!/bin/bash

set -e
run_cmd="dotnet run --server.urls http://*:80"

until dotnet ef database update; do
>&2 echo "SQL Server is starting up"
sleep 1
done

>&2 echo "SQL Server is up - executing command"
exec $run_cmd

如果我使用 docker-compose 启动容器,我会收到错误消息:

Unhandled Exception: System.FormatException: Value for switch '/app/entrypoint.sh' is missing.
test          |    at Microsoft.Extensions.Configuration.CommandLine.CommandLineConfigurationProvider.Load()
test          |    at Microsoft.Extensions.Configuration.ConfigurationRoot..ctor(IList`1 providers)
test          |    at Microsoft.Extensions.Configuration.ConfigurationBuilder.Build()
test          |    at Microsoft.AspNetCore.Hosting.WebHostBuilder.BuildCommonServices(AggregateException& hostingStartupErrors)
test          |    at Microsoft.AspNetCore.Hosting.WebHostBuilder.Build()
test          |    at test.Program.Main(String[] args) in /app/Program.cs:line 19

如何将 ENTRYPOINT 和 CMD /bin/bash ./app/entrypoint.sh 命令组合到一个文件中。我想我需要 ENTRYPOINT 来运行 dotnet 应用程序,并且需要 cmd 来让 entrypoint.sh 等待数据库容器。有解决方案让两者都运行吗?

【问题讨论】:

我想你已经看过docs.docker.com/compose/startup-order了。您不应该尝试等待您的数据库,无论如何启动 asp.net 容器,当数据库可访问时它将开始工作。否则,您应该修复您的应用程序以在没有数据库的情况下启动并等待。 问题是 asp.net 在启动时会迁移数据库(entity.framework),如果数据库没有准备好,asp.net 应用程序会给我一个错误消息,表明连接到数据库不工作。 这听起来更像是实体框架设置不正确。它应该只根据命令迁移,而不是立即尝试。 如果我首先启动容器。数据库是空的(那里没有表)。 asp.net core application exit with code 139 MySql 无法连接数据库主机。如果我再次启动应用程序,它的工作原理。所以我认为数据库不是第一次启动并运行。如果我这样做docker-compose down --volumes,表将被删除,我再次收到错误 【参考方案1】:

https://docs.docker.com/compose/aspnet-mssql-compose/

docker 文档列出了如何让 ASP.net 容器通过 entrypoint.sh 轮询数据库连接来等待其数据库。

#!/bin/bash

set -e
run_cmd="dotnet run --server.urls http://*:80"

until dotnet ef database update; do
>&2 echo "SQL Server is starting up"
sleep 1
done

>&2 echo "SQL Server is up - executing command"
exec $run_cmd

【讨论】:

您始终可以使用具有 SDK 作为运行时映像的此映像:hub.docker.com/r/microsoft/aspnetcore-build 或者将 dotnet ef 替换为您用于迁移的任何工具,并编写一个 bash 脚本来循环它。 @eldios1981 不要编辑您的问题以提出更多问题,而是提出一个新问题。 我应该在哪里保存这个脚本?我收到一个错误,它找不到脚本。【参考方案2】:

您还可以从外部检查并等待您的 dotnet 应用程序内部的数据库连接,而不是使用脚本来推迟 dotnet 应用程序的启动。 p>

在下文中,您可以看到host.Run() 如何被推迟到waitForDb() 返回。

在下面的示例中,我将用于检查 SQL DB(在 docker 容器中运行)是否已在名为 DbHealthChecker 的服务中启动的逻辑(实际上,整个方法 waitForDb 可能位于专人服务)。此运行状况检查器使用this *** thread 中描述的技术之一来检查数据库是否正在运行。

public class Program

  public static void Main(string[] args)
  
    var host = CreateWebHostBuilder(args).Build();

    Task.Run(async () => 
      using (var scope = host.Services.CreateScope())
      
        var services = scope.ServiceProvider;

        await waitForDb(services);

        // ... other initializations, e.g. seeding db ...
      
    ).Wait();

    host.Run();
  

  private static async Task waitForDb(IServiceProvider services)
  
    // create your own connection checker here
    // see https://***.com/questions/19211082/testing-an-entity-framework-database-connection

    var healthChecker = services.GetRequiredService<DbHealthChecker>();
    var maxAttemps = 12;
    var delay = 5000;

    for (int i = 0; i < maxAttemps; i++) 
      if (healthChecker.isConnected()) 
        return;
      
      await Task.Delay(delay);
    

    // after a few attemps we give up
    throw new HttpException(503);
  

【讨论】:

什么是 DbHelthChecker? 这只是一项您可以通过使用我在答案中链接的 SO 线程中提到的一种技术自行创建的服务,例如IsConnected() 可能有这个方法体:***.com/a/28916585/2477619

以上是关于docker asp.net 核心容器在 mysql 容器之后启动的主要内容,如果未能解决你的问题,请参考以下文章

在 docker 上运行的 asp.net 核心未正确编码拉丁字符

如何在 Mac 上将 ASP.Net Core 连接到 SQL Server Docker 容器

如何在不使用 Visual Studio 的情况下直接在 Docker 容器上运行 ASP.NET Core Web 应用程序

在 Docker 容器 ASP.NET 应用程序中集成 Windows 身份验证

asp.net 核心存储图像 wwwroot docker

Docker容器运行ASP.NET Core