运行 bash 脚本的 docker 入口点得到“权限被拒绝”
Posted
技术标签:
【中文标题】运行 bash 脚本的 docker 入口点得到“权限被拒绝”【英文标题】:docker entrypoint running bash script gets "permission denied" 【发布时间】:2016-12-17 09:12:23 【问题描述】:我正在尝试 dockerize 我的 node.js 应用程序。构建容器后,我希望它运行git clone
,然后启动节点服务器。因此,我将这些操作放在 .sh 脚本中。并在 ENTRYPOINT 中将脚本作为单个命令运行:
FROM ubuntu:14.04
RUN apt-get update && apt-get install -y build-essential libssl-dev gcc curl npm git
#install gcc 4.9
RUN apt-get install -y software-properties-common python-software-properties
RUN add-apt-repository -y ppa:ubuntu-toolchain-r/test
RUN apt-get update
RUN apt-get install -y libstdc++-4.9-dev
#install newst nodejs
RUN curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash -
RUN apt-get install -y nodejs
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
ADD package.json /usr/src/app/
RUN npm install
ADD docker-entrypoint.sh /usr/src/app/
EXPOSE 8080
ENTRYPOINT ["/usr/src/app/docker-entrypoint.sh"]
我的 docker-entrypoint.sh 看起来像这样:
git clone git@<repo>.git
git add remote upstream git@<upstream_repo>.git
/usr/bin/node server.js
构建此映像并运行后:
docker run --env NODE_ENV=development -p 8080:8080 -t -i <image>
我得到:
docker: Error response from daemon: oci runtime error: exec: "/usr/src/app/docker-entrypoint.sh": permission denied.
我shell进入容器,docker-entrypoint.sh的权限是:
-rw-r--r-- 1 root root 292 Aug 10 18:41 docker-entrypoint.sh
三个问题:
我的 bash 脚本是否有错误的语法?
如何在将 bash 文件添加到图像之前更改其权限?
不使用 bash 脚本在入口点运行多个 git 命令的最佳方法是什么?
谢谢。
【问题讨论】:
我们需要查看文件权限才能回答这个问题。 顺便说一句,如果这是一个 bash 脚本,而不是 sh 脚本,那么.sh
扩展会让人误解哪些解释器可以执行它。你可能会考虑把它去掉——对于 UNIX 命令来说,有扩展名是不常见的(例如,你不运行 ls.elf
)。
我们可以exec
那样做一个外壳吗?它不需要bash
前缀吗?
@Jean-FrançoisFabre,您的问题到底是什么意思? (我不明白“exec a shell that way”是什么意思——在这种情况下“that way”是什么意思?)
愚蠢的问题,顺便说一句——脚本的权限是否正确在你将它们添加到图像中?
【参考方案1】:
“权限被拒绝”会阻止您的脚本被调用。因此,唯一可能相关的语法是第一行的语法(“shebang”),它应该看起来像 #!/usr/bin/env bash
或 #!/bin/bash
或类似的,具体取决于目标的文件系统布局。
很可能是文件系统权限未设置为允许执行。也有可能 shebang 引用了一些不可执行的东西,但这远不太可能。
出于易于修复先前问题的考虑。
简单的阅读
docker: Error response from daemon: oci runtime error: exec: "/usr/src/app/docker-entrypoint.sh": permission denied.
...是脚本没有被标记为可执行。
RUN ["chmod", "+x", "/usr/src/app/docker-entrypoint.sh"]
将在容器内解决这个问题。或者,您可以确保 Dockerfile 引用的本地副本是可执行的,然后使用 COPY
(明确记录以保留元数据)。
【讨论】:
我认为你是对的。我应该改用 COPY 。但似乎我在复制 bash 脚本后仍然需要更改权限。 @raupie,如果您想使用noexec
标志从挂载点运行脚本,请运行 bash yourscript
而不是 ./yourscript
。
我不明白,当我运行docker build
时,即时容器工作正常。但是当我做docker run
时,它会抛出这样的错误。看起来像是我得到的一个神奇的中间容器。
既不运行 ["chmod", "+x", "/usr/src/app/docker-entrypoint.sh"] 也不运行 ["chmod", "a+x", "/ usr/src/app/docker-entrypoint.sh"] 确实更改了我的 docker 映像中的权限,它仍然是 '-rw-r--r-- '
@niid,如果您使用充当minimal reproducible example 的 Dockerfile 创建问题,请随时@-通知我。【参考方案2】:
可执行文件需要具有执行集权限才能执行。
在您正在构建 docker 映像的机器上(而不是在 docker 映像本身内部)尝试运行:
ls -la path/to/directory
您的可执行文件(在本例中为 docker-entrypoint.sh)的输出的第一列应将可执行位设置为:
-rwxrwxr-x
如果没有,请尝试:
chmod +x docker-entrypoint.sh
然后再次构建您的 docker 映像。
Docker 使用它自己的文件系统,但它会从源目录复制所有内容(包括权限位)。
【讨论】:
chmod +x docker-entrypoint.sh
在 tzhe 主机上实际上是推荐的解决方案,因为它比更改 Dockerfile
简单得多。
这对我有用。我真的不明白为什么虽然xD。如果您的读者最终在某个时候遇到这种情况,我将不胜感激这背后的原因。
如果你有 posix 兼容的文件系统(即你运行 macos 或 linux 或一些 bsd),那么你的 docker 将从主机复制权限。例如,在 Windows 上,你没有这些,所以它只会添加它们。【参考方案3】:
我遇到了同样的问题,它被解决了
ENTRYPOINT ["sh", "/docker-entrypoint.sh"]
对于原始问题中的 Dockerfile,它应该是这样的:
ENTRYPOINT ["sh", "/usr/src/app/docker-entrypoint.sh"]
【讨论】:
这是一种解决方法,但不是一个很好的解决方法——它使用sh
解释脚本,忽略其shebang 的解释器规范;所以如果它使用#!/bin/bash
,说它想用bash解释,那将被忽略,而是用sh
解释,因此不允许[[ ]]
、数组等语言特性。
我已经使用了你的方法并且它奏效了。也许 dos2unix 也能做到这一点
这种方法对我有用。我想知道这背后的原因是什么。
谢谢,为我节省了数小时的研究时间!
@CharlesDuffy 什么是正确的解决方案?【参考方案4】:
问题是由于原始文件没有执行权限。
检查原始文件是否有权限。
运行ls -al
如果结果得到-rw-r--r--
,
运行chmod +x docker-entrypoint.sh
在 docker 构建之前!
【讨论】:
【参考方案5】:点 [.]
这个问题终于花了我3个多小时,我刚试过问题是从最后删除dot。
问题是
docker run -p 3000:80 --rm --name test-con test-app .
/usr/local/bin/docker-entrypoint.sh: 8: exec: .: Permission denied
只需从命令行末尾删除 dot :
docker run -p 3000:80 --rm --name test-con test-app
【讨论】:
【参考方案6】:这是我回答前两年提出的一个老问题,无论如何我都会发布对我有用的问题。
在我的工作目录中,我有两个文件:Dockerfile 和 provision.sh
Dockerfile:
FROM centos:6.8
# put the script in the /root directory of the container
COPY provision.sh /root
# execute the script inside the container
RUN /root/provision.sh
EXPOSE 80
# Default command
CMD ["/bin/bash"]
provision.sh:
#!/usr/bin/env bash
yum upgrade
我可以通过将容器外的文件设置为可执行文件chmod 700 provision.sh
然后运行docker build .
来使docker 容器中的文件可执行。
【讨论】:
【参考方案7】:这可能有点愚蠢,但我收到的错误消息是权限被拒绝,这让我朝着一个非常错误的方向螺旋式下降,试图解决它。 (以这里为例)
我自己什至没有添加任何 bash 脚本,我认为是由我使用的 nodejs 图像添加的。
FROM node:14.9.0
我错误地运行以公开/连接本地端口:
docker run -p 80:80 [name] . # this is wrong!
给了
/usr/local/bin/docker-entrypoint.sh: 8: exec: .: Permission denied
但是最后你甚至不应该有一个点,它被错误地添加到另一个项目 docker image 的文档中。 你应该简单地运行:
docker run -p 80:80 [name]
我非常喜欢 Docker,但很遗憾它有这么多这样的陷阱,而且错误消息并不总是很清楚...
【讨论】:
【参考方案8】:如果你不使用 DockerFile,你可以简单地添加权限作为 bash 的命令行参数:
docker run -t <image> /bin/bash -c "chmod +x /usr/src/app/docker-entrypoint.sh; /usr/src/app/docker-entrypoint.sh"
【讨论】:
【参考方案9】:授予文件docker-entrypoint.sh
的执行权限
sudo chmod 775 docker-entrypoint.sh
【讨论】:
【参考方案10】:如果您尝试在 docker 的入口点运行脚本时仍然收到 Permission denied
错误,请尝试不要使用入口点的 shell 形式:
而不是:
ENTRYPOINT ./bin/watcher
写ENTRYPOINT ["./bin/watcher"]
:
https://docs.docker.com/engine/reference/builder/#entrypoint
【讨论】:
以上是关于运行 bash 脚本的 docker 入口点得到“权限被拒绝”的主要内容,如果未能解决你的问题,请参考以下文章
在docker container restart上执行相同的入口点脚本
如何在每个“exec”命令中执行 Docker 映像的入口点?
ENTRYPOINT/CMD process 入口点进程是什么?Docker容器Dockerfile entrypoint.sh文件作用,为什么在脚本开头要执行source ~/.bashrc?
ENTRYPOINT/CMD process 入口点进程是什么?Docker容器Dockerfile entrypoint.sh文件作用,为什么在脚本开头要执行source ~/.bashrc?