Docker容器上传到gcp cloud-run,核心Web api应用程序不起作用

Posted

技术标签:

【中文标题】Docker容器上传到gcp cloud-run,核心Web api应用程序不起作用【英文标题】:Docker container upload to gcp cloud-run with core web api app not working 【发布时间】:2019-09-03 21:36:25 【问题描述】:

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

cloud run 的一个要求是监听 8080 端口。

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

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

本地我有红隼在 8080 上监听。在 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();

        

【问题讨论】:

您是否看到“logging”中打印的任何日志? @wlhee 这是来自云运行的日志: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. 抱歉格式化 看起来该应用正在侦听端口 80 而不是 8080? 即使我尝试让应用在 8080 端口上侦听它也会失败 请关注these instructions并确认您的容器在本地运行。 【参考方案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,您需要执行以下操作:

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

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

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

将上面的“my-web-api”替换为您在第 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" .

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

【讨论】:

【参考方案2】:

以下解决方案对我有用:

在 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");
);

重建和部署

【讨论】:

以上是关于Docker容器上传到gcp cloud-run,核心Web api应用程序不起作用的主要内容,如果未能解决你的问题,请参考以下文章

GCP容器推送不起作用 - “拒绝:请在云控制台中启用Google容器注册表API ...”

如果 Docker 容器退出,GCP 会发出警报

不使用 gcloud 实用程序从 docker 容器访问 GCP 云存储桶

如何在 GCP 中设置与 MongoDB Docker 容器的连接

如何使用 docker-compose 将容器部署到谷歌云?

无法使用自定义容器 GCP 进行部署