Docker部署.NET6 Alpine控制台应用报[./Filename]未找到错误解决
问题描述
基于.NET 6.0开发控制台应用,编写的Dockerfile可正常完成镜像构建,但部署到服务器启动时抛出报错:/bin/sh: [./Filename]: not found。
此前项目使用.NET Core 3.1、以runtime-deps:3.1-alpine为基础镜像时可正常运行,当前使用的Dockerfile内容如下:
FROM mcr.microsoft.com/dotnet/runtime:6.0-alpine as base WORKDIR /app RUN apk add --no-cache ca-certificates icu-libs RUN apk add --no-cache tzdata RUN apk add --no-cache bash ENV TZ=America/Chicago #This will update the image to avoid security issues. RUN apk update RUN apk upgrade RUN apk add bash ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine AS build WORKDIR /src COPY ["Filename/Filename.csproj", "Filename/"] RUN dotnet restore "Filename/Filename.csproj" --configfile NuGet.Config COPY . . WORKDIR "/src/Filename" RUN dotnet build "Filename.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "Filename.csproj" -c Release -o /app/publish --runtime alpine-x64 --self-contained true /p:PublishTrimmed=true /p:PublishSingleFile=true FROM base AS final WORKDIR /app COPY --from=publish /app/publish . #ENTRYPOINT ["dotnet", "Filename.dll"] ENTRYPOINT [./"Filename"]
报错原因
- ENTRYPOINT语法错误是直接诱因
Docker的exec模式ENTRYPOINT要求传入合法的JSON数组,每个数组元素(命令、参数)必须单独用双引号包裹。当前写法ENTRYPOINT [./"Filename"]属于非法JSON格式,Docker无法识别为exec模式,会自动降级为shell模式执行,等价于运行/bin/sh -c "[./Filename]",shell会把[./Filename]整体作为一个命令名去系统路径中查找,自然会抛出not found错误。 - 存在隐含的权限/冗余问题
- base阶段重复执行bash安装操作,属于无效冗余步骤,会徒增镜像体积
- 发布时指定了自包含部署、单文件打包,最终镜像不需要携带完整.NET Runtime,使用runtime镜像作为base属于不必要的体积浪费
- COPY到镜像内的单文件程序默认没有可执行权限,即使修正ENTRYPOINT语法,也可能因为权限不足触发not found类报错(Alpine环境下无执行权限的文件不会返回常规的Permission denied,很多场景下会直接提示文件不存在)
修复方案
- 修正ENTRYPOINT为合法的exec格式,将最后一行启动命令改为:
ENTRYPOINT ["./Filename"] - 在final阶段COPY完发布文件后,增加给单文件程序授予可执行权限的步骤
- 清理冗余的安装步骤,若使用自包含单文件部署,可将base镜像替换为体积更小的
mcr.microsoft.com/dotnet/runtime-deps:6.0-alpine
修正后的完整Dockerfile参考:
FROM mcr.microsoft.com/dotnet/runtime-deps:6.0-alpine as base WORKDIR /app RUN apk add --no-cache ca-certificates icu-libs tzdata bash \ && apk update \ && apk upgrade \ && rm -rf /var/cache/apk/* ENV TZ=America/Chicago ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=false FROM mcr.microsoft.com/dotnet/sdk:6.0-alpine AS build WORKDIR /src COPY ["Filename/Filename.csproj", "Filename/"] RUN dotnet restore "Filename/Filename.csproj" --configfile NuGet.Config COPY . . WORKDIR "/src/Filename" RUN dotnet build "Filename.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "Filename.csproj" -c Release -o /app/publish --runtime alpine-x64 --self-contained true /p:PublishTrimmed=true /p:PublishSingleFile=true FROM base AS final WORKDIR /app COPY --from=publish /app/publish . RUN chmod +x ./Filename ENTRYPOINT ["./Filename"]
内容的提问来源于stack exchange,提问作者Jayne
相关产品推荐
相关产品推荐

