Загрузка контейнера Docker в облако gcp — запуск с неработающим приложением core web api

#docker #google-cloud-platform #asp.net-core-webapi #google-cloud-run

# #docker #google-облачная платформа #asp.net-core-webapi #google-облачный запуск

Вопрос:

Попытка загрузить образ docker с помощью проекта dotnet core webapi.

Требование облачного запуска заключается в том, что он прослушивает порт 8080.

Я считаю, что я это делаю, но когда я создаю облачную службу после нажатия на реестр контейнеров, GCP возвращается с:

«Не удалось запустить контейнер. Не удалось запустить и затем прослушать порт, определенный переменной среды PORT. Журналы для этой версии могут содержать дополнительную информацию «.

Локально у меня есть kestrel, прослушивающий 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."
 

~ ФАЙЛ DOCKER

 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();

        }
 

Комментарии:

1. Вы видите какие-либо журналы, напечатанные в разделе «ведение журнала»?

2. @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. извините за форматирование

3. похоже, что приложение прослушивало порт 80, а не 8080?

4. Даже когда я пытаюсь заставить приложение прослушивать порт 8080, он терпит неудачу

5. Пожалуйста, следуйте этим инструкциям и подтвердите, что ваш контейнер запускается локально.

Ответ №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}");
});
 

Перестроить и развернуть

Ответ №2:

Ответ 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(...) . Нам нужно было добавить HealthController только с одним методом GET, указывающим на маршрут «/», как показано в ответе IJB, повторенном ниже.

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

Кроме того, и это на некоторое время поставило нас в тупик, если вы собираетесь выполнять развертывание в облачном режиме, gcloud beta run deploy изображение Docker НЕ загружается, а повторно используется уже развернутое.Это привело нас в замешательство, пока мы не поняли, что образ Docker, который он пытался развернуть, имел старый идентификатор изображения. Итак, чтобы выполнить развертывание в реестре контейнеров, а затем выполнить развертывание в облаке, вам нужно выполнить следующее:

  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 tools и настроили Docker, введя gcloud auth login , gcloud config set project <your project ID here> , gcloud auth configure-docker ):
 docker push gcr.io/<your project ID here>/my-web-api:latest
 

Замените «my-web-api» выше на то, что вы использовали на шаге # 1.

  1. Развертывание в облачном запуске:
 gcloud beta run deploy --image gcr.io/<your project ID here>/my-web-api --region us-central1
 

Вам нужен параметр «region», потому что на момент написания этой статьи облачный запуск доступен только в США-central1.

Для правильной сборки и запуска нашего проекта .NET Core 3.0 нам также пришлось изменить файл Dockerfile. Нам потребовалось немало времени, чтобы разобраться в этом, поэтому, надеюсь, мы сэкономили вам немного времени. Используйте его в качестве ссылки и сравните с созданным для вас Dockerfile visual Studio, добавив соответствующие фрагменты. Вот наш файл 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 из нашего контейнера, поэтому мы также «внедрили» файл JSON учетной записи службы, который мы сохранили в ./keys/ папке (если вы это сделаете, не забудьте добавить эту папку в .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" .
 

Вы можете следовать тому же шаблону, чтобы вводить и другие переменные среды. В любом случае, надеюсь, это поможет вам решить проблему с ошибкой «Не удалось запустить контейнер».