Dockerfile无法执行CMD命令(Windows版Docker)

3

在dockerfile中无法执行CMD命令的问题。

我想使用CMD运行几个命令,但是连单个命令都无法运行。

我尝试了以下方法,但都没有成功...

1.

CMD "sqlcmd -S database -i C:\db\db_scripts\upgradescript.sql -U sa -P mypassword"

2.

RUN ["powershell", "-NoProfile", "-Command", "c:\db\db_scripts\script.ps1"]

3.

CMD ["cmd", "sqlcmd", "-S", "database", "-i", "C:\db\db_scripts\upgradescript.sql", "-U", "sa", "-P", "mypassword"]

4.

ARG arg1=database
ARG arg2=C:\db\db_scripts\upgradescript.sql
ARG arg3=sa
ARG arg4=mypassword!

RUN ["cmd", "-NoProfile", "-Command", "sqlcmd -S $env:arg1 -i $env:arg2 -U $env:arg3 -P $env:arg4"]

5.

RUN powershell.exe  c:\db\db_scripts\script.ps1

6.
六。
ENTRYPOINT ["powershell", "-NoProfile", "-Command", "sqlcmd"]
CMD ["-S database -i C:\db\db_scripts\upgradescript.sql -U sa -P mypassword"]

支持的文件:

A. Script.ps1(被 2 和 5 使用)

cmd /c "sqlcmd -S database -i C:\db\db_scripts\upgradescript.sql -U sa -P mypassword"

B. Dockerfile

# escape=`

FROM microsoft/mssql-server-windows-developer
COPY db\* c:\db\
COPY db_scripts\* c:\db\db_scripts\
ENV attach_dbs="[{'dbName':'ABC','dbFiles':['C:\db\ABC.mdf','C:\db\ABC_Log.ldf']},{'dbName':'XYZ','dbFiles':['C:\db\XYZ.mdf','C:\db\XYZ_Log.ldf']}]"
CMD "sqlcmd -S database -i C:\db\db_scripts\upgradescript.sql -U sa -P mypassword"

请注意,由于转义字符的存在,我不需要使用"\\\\"。
观察:
容器启动后几秒钟就会消失。
如果我删除CMD部分,容器就可以正常工作。我可以进入容器并在cmd shell中运行上面的sqlcmd命令。
我做错了什么,缺少什么,有更好的方法等。请问有人能给予一些指导吗?谢谢!
编辑:
根据Josh的答案,这个ENTRYPOINT命令对我起作用的唯一方法是(分享给其他人以使他们受益或发布更好的方法)...
ENV arg1 database
ENV arg2 C:\db\db_scripts\upgradescript.sql
ENV arg3 sa
ENV arg4 mypassword
ENTRYPOINT ["powershell sleep(60); sqlcmd"]
CMD ["-S $env:arg1 -i $env:arg2 -U $env:arg3 -P $env:arg4"]
1个回答

8
我认为你可能误解了CMD与ENTRYPOINT与RUN指令的性质。CMD和ENTRYPOINT在容器启动/运行时生效,而RUN是一个构建命令。有点令人困惑的是,在Docker构建过程中使用RUN来准备您的容器镜像,而CMD是在容器中运行的内容。
通过文档

CMD的主要目的是为执行容器提供默认值...

任何给定的容器镜像只会有一个CMD指令。

Dockerfile中只能有一个CMD指令。如果列出多个CMD,则只有最后一个CMD会生效。

如果您想确保可执行文件在容器启动时运行,则可以考虑使用ENTRYPOINT指令;将ENTRYPOINT视为为CMD指令提供默认值的命令。来自文档的描述:
Dockerfile 应该至少指定 CMD 或 ENTRYPOINT 命令。当将容器用作可执行文件时,应定义 ENTRYPOINT。CMD 应用于为 ENTRYPOINT 命令定义默认参数或在容器中执行临时命令的方式。使用替代参数运行容器时,CMD 将被覆盖。 RUN 命令是一个构建时指令,您可以使用它来准备容器映像所需的文件、配置等。 有关 ENTRYPOINT vs CMD 的更多信息,请参见 this SO question。 ED: 您正在查看的情况是在容器中运行 SQL 脚本,这是一个棘手的问题,因为脚本必须在数据库引擎准备好接受命令之前不运行。您可以将升级脚本作为第一步在 ENTRYPOINT 指令中运行。您还可以考虑通过 docker exec 命令在容器后期提供程序中运行 SQL 升级脚本。 ED2: 提供的示例:

ENTRYPOINT ["powershell", "-NoProfile", "-Command", "sqlcmd"]

CMD ["sqlcmd -S database -i C:\db\db_scripts\upgradescript.sql -U sa -P mypassword"]

这样做是不起作用的,因为它会导致一个可能是无意义的命令行指令。请记住,CMD提供参数给ENTRYPOINT指令,因此您只需在ENTRYPOINT中指定powershell sqlcmd,留下CMD来提供参数(这未经测试,OTOMH):

ENTRYPOINT powershell sqlcmd -S database -U sa -P mypassword -i

CMD C:\db\db_scripts\upgradescript.sql

ED 3: 通过合并两个语句并向ENTRYPOINT添加语句终止符(;),您可以允许标准SQL容器.\Start.ps1脚本运行,该脚本进入一个无限循环,防止容器立即停止(容器仅在其中执行的进程正在运行时才运行)。这确保了启动脚本的执行,即使用户在运行时覆盖了CMD指令:

ENTRYPOINT powershell "sqlcmd -S database -U sa -P mypassword -i 'C:\db\db_scripts\upgradescript.sql';"

CMD .\Start.ps1


非常好的描述!我实际上尝试了Entrypoint,但我忘记提到了它,并将其添加为第6个项目。它也没有起作用。我会更深入地研究它。如果您认为我的语法或方法不正确,请指导一下。谢谢! - wafers
我添加了一个可能的方法来尝试。 - Josh E
正如我所说,这是非常好的答案,我只是在测试不同的Entrypoint组合,一旦成功,将更新ED2或添加ED3作为直接答案。再次感谢Josh! - wafers
谢谢。我已经添加了一个描述如何将这两个组合在一起的附加内容。 - Josh E
@JoshE,嗯,ENTRYPOINT对我来说的工作方式,我已经更新了答案。然而,你是正确的,我无法实现我想要的,因为脚本运行得太早了。服务器还没有准备好。即使我添加了睡眠时间,但它也没有起作用。 - wafers
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接