Ответ 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();
}
}
Кроме того, и это на некоторое время поставило нас в тупик. Если вы собираетесь развернуть в Cloud Run, gcloud beta run deploy
НЕ выдвигает образ Docker, но повторно использует уже развернутый. Это мы были в замешательстве, пока не поняли, что образ Docker, который он пытался развернуть, имел старый идентификатор образа. Поэтому для развертывания в Registry Container, а затем для 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 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.
- Развертывание в облачной среде:
gcloud beta run deploy --image gcr.io/<your project ID here>/my-web-api --region us-central1
Вам нужен параметр "region", потому что на момент написания этого документа 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 из нашего контейнера, чтобы мы также «внедрили» файл 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" .
Вы можете следовать той же схеме, чтобы вводить и другие переменные окружения. В любом случае, надеюсь, что это поможет вам решить сбивающую с толку ошибку «Не удалось запустить контейнер».