2

尝试使用 dotnet core webapi 项目上传 docker 映像。

云运行的一个要求是监听 8080 端口。

我相信我正在这样做,但是当我在推送到容器注册表后创建云运行服务时,GCP 会返回:

“容器无法启动。无法启动并侦听由 PORT 环境变量定义的端口。此版本的日志可能包含更多信息。”

在本地,我在 8080 上监听了 kestrel。在 8080 上也有容器列表。但是当我按下任何一个时,我都会收到无法启动消息...?有什么建议或尝试这样做吗?

@wlhee Here is the LOG from cloud run:

2019-04-13T05:24:53.462592ZHosting environment: Production
2019-04-13T05:24:53.462657ZContent root path: /app
2019-04-13T05:24:53.462678ZNow listening on: http://[::]:80
2019-04-13T05:24:53.462697ZApplication started. Press Ctrl+C to shut down.
2019-04-13T05:28:48.973934834ZContainer terminated by the container manager on signal 9.

"Container failed to start. Failed to start and then listen on the port defined by the PORT environment variable. Logs for this revision might contain more information."

〜码头文件

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-stretch-slim AS base
WORKDIR /app
ENV ASPNETCORE_URLS=http://+:8080
EXPOSE 8080

FROM mcr.microsoft.com/dotnet/core/sdk:2.2-stretch AS build
WORKDIR /src
COPY ["simplecore.csproj", "simplecore/"]
RUN dotnet restore "simplecore/simplecore.csproj"
COPY . .
WORKDIR "/src/simplecore"
RUN dotnet build "simplecore.csproj" -c Release -o /app

FROM build AS publish
RUN dotnet publish "simplecore.csproj" -c Release -o /app

FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "simplecore.dll"]
~ HERE IS MY MAIN FROM CORE APP

public static void Main(string[] args)
        {
            //CreateWebHostBuilder(args).Build().Run();

            var host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            //.UseIISIntegration()
            .UseStartup<Startup>()
            .UseUrls("http://0.0.0.0:8080/")
            .Build();

            host.Run();

        }
4

2 回答 2

1

以下解决方案对我有用:

在 Dockerfile 中修改行

FROM base AS final
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "simplecore.dll"]

通过添加ENV

FROM base AS final
ENV ASPNETCORE_URLS=http://*:${PORT}
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "simplecore.dll"]

添加一个健康控制器来监听根路由:

[Route("/")]
[ApiController]
public class HealthController : ControllerBase
{

    [HttpGet]
    public ActionResult<IEnumerable<string>> Get()
    {
        return Ok();
    }
}

在 Program.cs 中配置 Kestrel 以侦听 PORT 环境变量:

    public static IWebHostBuilder CreateWebHostBuilder(string[] args)
    {
        var port = Environment.GetEnvironmentVariable("PORT");

        return WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .UseKestrel()
            .ConfigureKestrel((context, options) =>
            {
                options.Listen(IPAddress.IPv6Any, Convert.ToInt32(port));
            });
    }

最后在 Startup.cs 中添加一个默认路由:

app.UseMvc(routes => 
{
    routes.MapRoute("default", "{controller=Health}/{action=Get}");
});

重建和部署

于 2019-04-16T10:36:18.270 回答
1

IJB 的答案是正确的并且对我们有用,但在我们的例子中,我们使用的是 ASP.NET Core 3.0,所以我们必须稍微修改 Program.cs,如下所示:

public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>()
                        .ConfigureKestrel(options =>
                        {
                            var port = Convert.ToInt32(Environment.GetEnvironmentVariable("PORT") ?? "80");
                            options.Listen(IPAddress.Any, port);
                        });
                });
    }

我们不需要打电话app.UseMvc(...)。我们确实需要添加一个只有一个指向路由“/”的 GET 方法的 HealthController,如 IJB 的答案所示,下面重申。

[Route("/")]
    [ApiController]
    public class HealthController : ControllerBase
    {
        [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            return Ok();
        }
    }

此外,这让我们困惑了一段时间,如果您要部署到 Cloud Run,则gcloud beta run deploy不会推送 Docker 映像,而是重用已部署的映像。这让我们非常困惑,直到我们意识到它试图部署的 Docker 镜像有一个旧的镜像 ID。因此,要部署到 Container Registry,然后再部署到 Cloud Run,您需要执行以下操作:

  1. 构建 Docker 镜像:
docker image build -t my-web-api -t gcr.io/<your project ID here>/my-web-api -f Dockerfile .

您可以将上面的“my-web-api”重命名为您想要的任何名称。

  1. 推送 Docker 映像(在执行此操作之前,请确保安装 gcloud 工具并通过键入gcloud auth logingcloud config set project <your project ID here>、来配置 Docker gcloud auth configure-docker):
docker push gcr.io/<your project ID here>/my-web-api:latest

将上面的“my-web-api”替换为您在第 1 步中使用的内容。

  1. 部署到 Cloud Run:
gcloud beta run deploy --image gcr.io/<your project ID here>/my-web-api --region us-central1

您需要“区域”参数,因为在撰写本文时 Cloud Run 仅在 us-central1 中可用。

为了让我们的 .NET Core 3.0 项目能够正确构建和运行,我们还必须修改 Dockerfile。我们花了很长时间才弄清楚这一点,所以希望我们在这里为您节省了一些时间。将其用作参考,并将其与为您生成的 Dockerfile 视觉工作室进行比较,添加相关部分。这是我们的 Dockerfile 的完整内容:

FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-buster-slim AS base

# uncomment if you need to deploy a service account JSON file to access Google Cloud resources
#ARG GOOGLE_APPLICATION_CREDENTIALS_FILE
ARG ASPNETCORE_ENVIRONMENT

# uncomment if you need to deploy a service account JSON file
#ENV GOOGLE_APPLICATION_CREDENTIALS="/app/$GOOGLE_APPLICATION_CREDENTIALS_FILE"
ENV ASPNETCORE_ENVIRONMENT=$ASPNETCORE_ENVIRONMENT

# uncomment if you need to deploy a service account JSON file
#COPY "keys/$GOOGLE_APPLICATION_CREDENTIALS_FILE" "/app/"

WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/sdk:3.0-buster AS build
WORKDIR /src
COPY ["<your project name>.csproj", "./"]
RUN dotnet restore "<your project name>.csproj"
COPY . .
WORKDIR "/src/<your project name>"
RUN dotnet build "<your project name>" -c Release -o /app

FROM build AS publish
RUN dotnet publish "<your project name>" -c Release -o /app --self-contained --runtime linux-x64

FROM base AS final
ENV ASPNETCORE_URLS=http://*:${PORT}
WORKDIR /app
COPY --from=publish /app .
ENTRYPOINT ["dotnet", "<your DLL file here>.dll"]

我们必须从我们的容器连接到 Google Cloud Storage,因此我们还“注入”了我们存储在./keys/文件夹中的服务帐户 JSON 文件(如果您这样做,请不要忘记将该文件夹添加到 .gitignore 或等效文件中)。我们的构建服务器会根据环境注入正确的文件,如下所示:

docker image build -t my-web-api -t gcr.io/<project ID here>/my-web-api -f <project dir>/Dockerfile --build-arg GOOGLE_APPLICATION_CREDENTIALS_FILE="my-service-acccount.json" --build-arg ASPNETCORE_ENVIRONMENT="Development" .

您也可以按照相同的模式注入其他环境变量。无论如何,希望这可以帮助您解决令人困惑的“容器无法启动”错误。

于 2019-05-24T02:42:36.000 回答