对于容器的 Azure Web 应用程序,我需要传递一个带引号的az webapp config set --startup-file
. 例如,参数需要包含空格。
TL; 博士
- 这真的应该有效,因为
--startup-file
只是被附加到docker run
一个 docker[COMMAND]
上。 - 奇怪的是,嵌套引用(ie
--startup-file "Rscript -e '1+1'"
) 会导致内部引号的奇怪双引号(R 将 接收[EXPR]
为 string[1] "1+1"
)。 - 任何带有空格的东西,无论是否引用,都会被分解为
Rscript
(或docker run
?)的单独参数,因此会失败。
我不清楚在后端使用 引用 Azure 做了什么--startup-file
,因为记录docker run
的 s 看起来都很好。一方面,Azure 似乎引用了太多(导致字符串),但另一方面又不够(因为空格仍然会破坏内容)。
背景
我假设它实际上--startup-file
可以容纳任意 shell 命令(不仅仅是可执行文件),因为:
- 它被不同地描述为“启动命令”和“启动文件”
portal.azure.com
。 - 根据日志,它只是被附加到
docker run
as[COMMAND]
并且因此应该遵守相同的语义。 - 它有效(除非有空格)。
我知道潜在的问题是 shell 参数是空格分隔的,但是,如下所示,简单"
地不要这样做。
我在Rscript -e "1 + 1"
这里用作示例是因为 a) R 是我的用例 b) 很容易看出哪里出了问题。
Rscript
是批处理 R 的二进制文件,语义类似于sh -c "pwd;ls"
. 我猜测可以为sh -c
-type 启动文件编写类似的可重现示例。
下面的示例都不会启动 http 服务器,因此会失败az webapp restart
,但是启用容器日志记录后,很容易看出已经出了什么问题。(实际用例是Rscript -e "shiny::runApp()"
启动一个http 服务器。)
基线
作为基线,这是对应的docker run
,它在本地工作得很好(macOS 10.15.6,Docker 版本 19.03.12,构建 48a66213fe):
docker run rstudio/r-base:4.0.2-xenial Rscript -e "1 + 1"
# [1] 2
# works as expected
嵌套报价
az webapp config set --name hello-shiny \
--startup-file "Rscript -e \"1+2\""
az webapp config set --name hello-shiny \
--startup-file 'Rscript -e "1+3"'
az webapp config set --name hello-shiny \
--startup-file "Rscript -e '1+4'"
根据 Azure 日志,上述各项的对应docker run
内容类似于:
docker run -d -p 8409:3838 \
-e WEBSITES_ENABLE_APP_SERVICE_STORAGE=true \
-e WEBSITE_SITE_NAME=hello-shiny \
-e WEBSITE_AUTH_ENABLED=False \
-e PORT=3838 \
-e WEBSITE_ROLE_INSTANCE_ID=0 \
-e WEBSITE_HOSTNAME=hello-shiny.azurewebsites.net \
-e HTTP_LOGGING_ENABLED=1 \
rocker/shiny:4.0.2 \
Rscript -e "1+2"
(我已经放弃了一些-e
)。如前所述,这是一个有效的docker run
调用。如果在本地运行(见上文),它会按预期产生:
# [1] 3
但在 Azure 上,您将参数作为 R 中的字符串获取,如下所示,每个变体
# [1] "1+2"
这很奇怪,因为它表明 azure 以某种方式用另一组引号包围了这个论点。要在本地重现它,您需要运行
docker run rstudio/r-base:4.0.2-xenial Rscript -e "'1+1'"
# [1] "1+1"
显然不是我想要的,以及(我认为?)无证的天蓝色行为。
没有引号,没有空格(有效!)
果然,传递不带引号(和空格)的参数是有效的:
az webapp config set --name hello-shiny \
--startup-file "Rscript -e 1+7"
产量[1] 8
。
这并不奇怪,因为两者
docker run rstudio/r-base:4.0.2-xenial Rscript -e "1+1"
和docker run rstudio/r-base:4.0.2-xenial Rscript -e 1+1
工作,
因为-e [EXPR]
这里不需要习惯性的引用。
但是不使用空格虽然在技术上是可行的,但并不是真正的解决方案。
空格,无引号(损坏)
az webapp config set --name hello-shiny \
--startup-file "Rscript -e 1 + 8"
正如预期的那样,仅[1] 1
在 Azure 上产生,因为docker run
会将之后的所有内容1
视为单独的参数,因此忽略它。
空格,各种引用(全部损坏)
所以,没问题,有人可能会想,我会再逃避一些。
az webapp config set --name hello-shiny \
--startup-file "Rscript -e '1 + 5'"
az webapp config set --name hello-shiny \
--startup-file "Rscript -e \"1 + 6\""
这些,以及他们悲伤的朋友,都屈服了:
# Error: unexpected end of input
# Execution halted
这有点奇怪,因为这意味着R 代码的一部分(直到并包括+
)使得它,虽然不是关键的5
.
我能想到重现这一点的唯一方法是运行
docker run rstudio/r-base:4.0.2-xenial Rscript -e "1 +" 7
# Error: unexpected end of input
# Execution halted
这里发生了什么?
我绝对不能对 Azure 在这里所做的任何引用/转义做出正面或反面。我要么非常非常密集(可能),要么 Azure 做了一些非常奇怪和无证的事情(可能吗?)。
如何将带有空格的参数作为 a--startup-file
传递给 Azure?
Ps.:我知道我可以通过CMD
在 my 中添加相应的指令Dockerfile
并--startup-file
留空来避免所有这些恶作剧,但是 a) 对于简单的选项来说这会很麻烦 b) 它必须是可能的。