构建nanoserver镜像时Dockerfile内schtasks失败但容器内运行正常
Nano Server镜像构建阶段执行RUN指令时,Docker会启动一个高度精简的临时隔离环境运行命令,该环境不会自动启动Task Scheduler(任务计划)服务,也不会加载该服务关联的COM组件注册上下文。schtasks命令的底层实现依赖调用任务计划服务的COM接口完成配置写入,缺少对应运行环境时就会抛出ERROR: Class not registered错误。
容器正常启动进入交互命令行时,系统会按默认配置启动Task Scheduler服务,完成对应COM组件的注册初始化,因此手动执行相同的schtasks命令可以成功运行。
方案1:将任务创建逻辑移到容器启动入口执行
不在构建阶段通过RUN执行任务创建命令,改为把命令写入启动脚本,在容器启动阶段自动执行。可以额外增加判断逻辑避免容器重启时重复创建任务,示例Dockerfile如下:FROM mcr.microsoft.com/windows/nanoserver:20H2 USER ContainerAdministrator # 写入启动脚本:先判断任务是否存在,不存在则创建,之后启动cmd RUN echo @echo off > C:\startup.cmd && \ echo schtasks /query /tn test >nul 2^>^&1 ^|^| schtasks /create /tn test /tr test /sc weekly /d MON /st 00:00 /ru system >> C:\startup.cmd && \ echo cmd >> C:\startup.cmd ENTRYPOINT ["C:\\startup.cmd"]方案2:构建阶段直接复制预导出的任务配置文件
Windows系统的计划任务配置以文件形式存储在C:\Windows\System32\Tasks\目录下。你可以先启动一个同版本的Nano Server容器,手动创建好目标计划任务,将容器内对应路径下生成的任务配置文件导出到本地构建上下文,构建镜像时直接将该文件复制到镜像内的任务存储目录即可,示例Dockerfile如下:FROM mcr.microsoft.com/windows/nanoserver:20H2 USER ContainerAdministrator # 预导出的test任务配置文件放在构建上下文目录,直接复制到系统任务存储路径 COPY test C:/Windows/System32/Tasks/ ENTRYPOINT cmd注意复制后需要保证System账户对该文件拥有读取权限,否则任务计划服务无法正常识别加载任务。
方案3:更换基础镜像为Server Core
如果对镜像体积没有严格要求,可以换用mcr.microsoft.com/windows/servercore系列基础镜像,该镜像的构建临时环境包含更完整的系统组件和COM注册信息,构建阶段直接通过RUN执行schtasks命令不会触发类未注册错误,但镜像体积会远大于Nano Server。
内容的提问来源于stack exchange,提问作者vcattin

