如何以非 root 用户身份在 Kubernetes 中运行 ASP.Net Core 容器?

问题描述 投票:0回答:2

我正在尝试以非 root 用户身份在 Kubernetes 上运行 ASP.Net docker 容器。我有这个 dockerfile:

FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 8443

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["MyProgram.API/MyProgram.API.csproj", "MyProgram.API/"]
COPY ["MyProgram.Services/MyProgram.Services.csproj", "MyProgram.Services/"]
COPY ["MyProgram.Core/MyProgram.Core.csproj", "MyProgram.Core/"]
COPY ["MyProgram.Data/MyProgram.Data.csproj", "MyProgram.Data/"]
RUN dotnet restore "MyProgram.API/MyProgram.API.csproj"
COPY . .
WORKDIR "/src/MyProgram.API"
RUN dotnet build "MyProgram.API.csproj" -c Release -o /app/build

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

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

当我在本地运行它时,我可以访问 https://localhost:8443 并成功使用我的应用程序。当我使用此文件将其部署到 Kubernetes 时:

apiVersion: apps/v1 
kind: Deployment
# snip
    spec:
       securityContext:
         fsGroup: 2000
         runAsNonRoot: true
         runAsUser: 1000
      containers:
      - name: myprogram
        image: mycompany/myprogram:develop
        imagePullPolicy: "Always"
        env:
        - name: "ASPNETCORE_ENVIRONMENT"
          value: "Kubernetes"
        ports:
        - containerPort: 8443
          name: "myprogram"
         securityContext:
           allowPrivilegeEscalation: false
      imagePullSecrets:
      - name: privatereposecret

---

apiVersion: v1
kind: Service
#snip
spec:
  type: NodePort
  ports:
  - protocol: TCP
    port: 8081
    targetPort: 8443
    nodePort: 31999
  selector:
   app: myprogram

我的容器无法启动并给出这些日志文件:

[13:13:30 FTL] Unable to start Kestrel.
System.Net.Sockets.SocketException (13): Permission denied
   at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, String callerName)
   at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
   at System.Net.Sockets.Socket.Bind(EndPoint localEP)
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketConnectionListener.Bind()
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransportFactory.BindAsync(EndPoint endpoint, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServer.<>c__DisplayClass21_0`1.<<StartAsync>g__OnBind|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(ListenOptions endpoint, AddressBindContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions.BindAsync(AddressBindContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.AnyIPListenOptions.BindAsync(AddressBindContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.AddressesStrategy.BindAsync(AddressBindContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindAsync(IServerAddressesFeature addresses, KestrelServerOptions serverOptions, ILogger logger, Func`2 createBinding)
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServer.StartAsync[TContext](IHttpApplication`1 application, CancellationToken cancellationToken)
[13:13:30 FTL] Application start-up failed
System.Net.Sockets.SocketException (13): Permission denied
   at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, String callerName)
   at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
   at System.Net.Sockets.Socket.Bind(EndPoint localEP)
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketConnectionListener.Bind()
   at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.SocketTransportFactory.BindAsync(EndPoint endpoint, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServer.<>c__DisplayClass21_0`1.<<StartAsync>g__OnBind|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindEndpointAsync(ListenOptions endpoint, AddressBindContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.ListenOptions.BindAsync(AddressBindContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.AnyIPListenOptions.BindAsync(AddressBindContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.AddressesStrategy.BindAsync(AddressBindContext context)
   at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.AddressBinder.BindAsync(IServerAddressesFeature addresses, KestrelServerOptions serverOptions, ILogger logger, Func`2 createBinding)
   at Microsoft.AspNetCore.Server.Kestrel.Core.KestrelServer.StartAsync[TContext](IHttpApplication`1 application, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.Internal.Host.StartAsync(CancellationToken cancellationToken)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.RunAsync(IHost host, CancellationToken token)
   at Microsoft.Extensions.Hosting.HostingAbstractionsHostExtensions.Run(IHost host)
   at MyProgram.API.Program.Main(String[] args) in /src/MyProgram.API/Program.cs:line 30

如果我在没有 SecurityContext 的情况下尝试完全相同的部署,则容器可以完美运行。出了什么问题?

asp.net kubernetes
2个回答
11
投票

Kestrel 正在尝试绑定到端口 80 和/或端口 443,因为这是它的默认端口,除非您另有说明,并且除非有特权,否则您不能这样做。

您需要指定端口(通常通过环境变量)并公开它们,例如

# Declare ports above 1024, as an unprivileged non-root user cannot bind to ports <= 1024
ENV ASPNETCORE_URLS http://+:8000;https://+:8443
EXPOSE 8000
EXPOSE 8443

© www.soinside.com 2019 - 2024. All rights reserved.