C# Kubernetes部署方法 C#如何将.NET应用部署到K8s

4次阅读

do.net publish 打包前必须指定 –runtime linux-x64 和 –self-contained true,确保与 kubernetes 中 linux 容器运行时匹配,避免 exec format Errordockerfile 需多阶段构建且 sdk 与 runtime 镜像主版本一致(如 8.0);健康探针须配置正确 path(如 /healthz)并匹配应用绑定端口;configmap/secret 挂载需设置 defaultmode 和 runasuser 以避免权限问题。

C# Kubernetes部署方法 C#如何将.NET应用部署到K8s

dotnet publish 打包前必须确认目标运行时

直接在开发机上 dotnet publish 默认生成 windows 平台的二进制,K8s Pod 里跑的是 Linux 容器(绝大多数情况),会启动失败。错误现象通常是容器反复 CrashLoopBackOff,kubectl logs 显示 “exec format error” 或 “no such file or Directory”(其实是 ELF 头不匹配)。

正确做法是显式指定 --runtime--self-contained

dotnet publish -c Release -r linux-x64 --self-contained true -o ./publish
  • -r linux-x64:目标运行时,和基础镜像保持一致(如 mcr.microsoft.com/dotnet/runtime:8.0 是 linux-x64)
  • --self-contained true:避免容器内缺失 .NET 运行时;若用 runtime-deps 镜像可设为 false,但需确保镜像含对应版本的 native 依赖(如 libicu)
  • 输出目录 ./publish 后续 copy 到 Docker 镜像中

Dockerfile 必须用多阶段构建且基础镜像要匹配 SDK/Runtime 版本

常见错误是用 mcr.microsoft.com/dotnet/sdk:8.0 构建,却用 mcr.microsoft.com/dotnet/aspnet:7.0 运行——版本不匹配会导致 System.MissingMethodException 或启动时静默退出。

推荐写法(以 ASP.NET Core 为例):

FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src COPY . . RUN dotnet publish -c Release -r linux-x64 --self-contained true -o /app/publish  FROM mcr.microsoft.com/dotnet/aspnet:8.0 WORKDIR /app COPY --from=build /app/publish . ENTRYPOINT ["./YourApp"]
  • SDK 和 runtime 镜像主版本号(8.0)必须严格一致
  • 不要用 latest 标签,它可能指向不同大版本,CI 环境易出错
  • 若应用不带 Web 依赖,用 runtime:8.0 替代 aspnet:8.0,镜像体积更小

K8s Deployment 中 livenessProbereadinessProbe 要适配 .NET 健康检查端点

.NET 6+ 默认启用 /healthz(或自定义路径),但 K8s probe 若直接用 httpGet 且未配置 path,默认请求 /,返回 404 导致探针失败、Pod 反复重启。

Deployment 片段示例:

livenessProbe:   httpGet:     path: /healthz     port: 8080   initialDelaySeconds: 30   periodSeconds: 10 readinessProbe:   httpGet:     path: /healthz     port: 8080   initialDelaySeconds: 10   periodSeconds: 5
  • 确保 Program.cs 中已注册健康检查中间件app.UseHealthChecks("/healthz")
  • port 必须和容器 EXPOSEapp.Run("http://*:8080") 绑定端口一致
  • initialDelaySeconds 要大于应用冷启动时间(尤其含 EF Core 迁移或外部依赖初始化时)

Secret 和 ConfigMap 挂载后权限问题常导致 .NET 应用读取失败

Linux 容器中,挂载的 ConfigMapSecret 文件默认权限是 644,但 .NET 的 IConfiguration 从文件加载 json 时若路径含特殊字符或父目录不可读,会抛 UnauthorizedAccessException —— 实际不是权限不足,而是挂载点父目录(如 /app/config)被设为 700 且属主非容器用户。

解决方法:

  • 挂载时显式设置 defaultMode: 0644runAsUser: 1001(与镜像中非 root 用户 UID 一致)
  • 避免挂载到深层嵌套路径,优先用 /app/config/appsettings.json 这类扁平结构
  • Startup.csProgram.cs 中加日志确认配置源是否加载成功:console.WriteLine($"Config loaded from: {builder.Configuration.AsEnumerable()}");

最易被忽略的是:.NET 应用默认以非 root 用户(如 UID 1001)运行,而 ConfigMap 挂载点的父目录若由 root 创建且无执行权限(755 以上才允许进入),就会卡在目录访问环节,错误日志里却只显示“文件不存在”。

text=ZqhQzanResources