Dotnet Core Docker容器泄漏Linux上的RAM并导致OOM

时间:2019-05-10 13:42:40

标签: c# linux docker ubuntu .net-core

我正在Docker的Linux容器中运行Dotnet Core 2.2。

我尝试了许多不同的配置/环境选项-但我仍然遇到内存不足的问题('docker events'报告OOM)。

在生产环境中,我托管在Ubuntu上。对于开发,我在Windows的Docker上使用Linux容器(MobyLinux)。

我已回到运行Web API模板项目,而不是运行我的实际应用程序。我从字面上返回一个字符串,什么也不做。如果我称它为卷曲的大约1000倍,则容器将死亡。垃圾收集器似乎根本没有工作。

试图在docker-compose中设置以下环境变量:

DOTNET_RUNNING_IN_CONTAINER=true
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=true
ASPNETCORE_preventHostingStartup=true

还在docker-compose中尝试了以下操作:

mem_reservation: 128m
mem_limit: 256m
memswap_limit: 256m

(这些只会使它更快死亡)

尝试将以下内容设置为true或false,没有区别:

ServerGarbageCollection

我尝试改为作为Windows容器运行,这不是OOM,但它似乎也不遵守内存限制。

我已经排除了使用HttpClient和EF Core的可能性-因为在我的示例中甚至没有使用它们。我已经读过一些关于在端口443上监听的问题-因为我可以让容器整天处于空闲状态,如果我在一天结束时检查的话-它占用了更多的内存(不是很大的内存,但是增长)。

我的API中的示例:

// GET api/values/5
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
return "You said: " + id;
}

使用Curl呼叫示例:

curl -X GET "https://localhost:44329/api/values/7" -H  "accept: text/plain" --insecure

(重复约1000次)

预期:对于非常原始的请求,RAM使用率将保持较低水平

实际:RAM使用率持续增长,直到出现故障

完整的Dockerfile:

FROM microsoft/dotnet:2.2-aspnetcore-runtime AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

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

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

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

docker-compose.yml

version: '2.3'

services:
  webapplication1:
    image: ${DOCKER_REGISTRY-}webapplication1
    mem_reservation: 128m
    mem_limit: 256m
    memswap_limit: 256m
    cpu_percent: 25
    build:
      context: .
      dockerfile: WebApplication1/Dockerfile

docker-compose.override.yml

version: '2.3'

services:
  webapplication1:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - ASPNETCORE_URLS=https://+:443;http://+:80
      - ASPNETCORE_HTTPS_PORT=44329
      - DOTNET_RUNNING_IN_CONTAINER=true
      - DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=true
      - ASPNETCORE_preventHostingStartup=true
    ports:
      - "50996:80"
      - "44329:443"
    volumes:
      - ${APPDATA}/ASP.NET/Https:/root/.aspnet/https:ro
      - ${APPDATA}/Microsoft/UserSecrets:/root/.microsoft/usersecrets:ro

我在Windows上运行Docker CE Engine 18.0.9.1,在Ubuntu上运行18.06.1。确认-我也在Dotnet Core 2.1中尝试过。

我还在IIS Express中进行了尝试-进程达到55MB左右,这实际上是向多个线程发送垃圾邮件,等等。

完成所有操作后,它会减少到大约29-35MB。

1 个答案:

答案 0 :(得分:0)

这可能是因为未执行垃圾回收(GC)。

看看这个未解决的问题,它看起来非常相似:

https://github.com/dotnet/runtime/issues/851

使Ubuntu 18.04.4在虚拟机上工作的一种解决方案是使用工作站垃圾回收(GC):

<PropertyGroup>
    <ServerGarbageCollection>false</ServerGarbageCollection>
</PropertyGroup>

https://github.com/dotnet/runtime/issues/851#issuecomment-644648315

https://github.com/dotnet/runtime/issues/851#issuecomment-438474207

https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/workstation-server-gc

这是另一个发现:

经过进一步的调查,我发现差异很大 服务器之间的可用逻辑CPU数量(80 vs 16)。经过一番谷歌搜索,我遇到了这个话题dotnet/runtime#622 引导我进行CPU / GC /线程设置的实验。

我在堆栈文件中使用--cpus constraint;明确设置 System.GC.Concurrent=trueSystem.GC.HeapCount=8System.GC.NoAffinitize=trueSystem.Threading.ThreadPool.MaxThreads=16runtimeconfig.template.json文件中;将图片更新为3.1.301-bionic sdk3.1.5-bionic asp.net runtime-我在一个 各种组合,所有这些都没有效果。只是申请 一直挂到OOMKilled。

唯一可与Server GC配合使用的是--cpuset-cpus 约束。当然,显式设置可用处理器不是 docker swarm模式的一个选项。但是我正在尝试 可用cpus查找任何规律性。在这里我有一些 有趣的事实。

有趣的是,之前我已经镜像了另外3个后端 新服务器群集的服务,并且默认情况下它们都运行良好 设置。它们的内存限制设置为600 Mb,但实际上它们需要 约400 Mb运行。只有消耗内存,事情才会出错 应用程序(我有两个),它需要3 Gb来构建 内存结构并以6 Gb约束运行。

它可以在[1, 35]个可用cpus到 在cpus计数为36时挂起。

https://github.com/dotnet/runtime/issues/851#issuecomment-645237830