运行 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/watcherENTRYPOINT ["./bin/watcher"]

https://docs.docker.com/engine/reference/builder/#entrypoint

【讨论】:

以上是关于运行 bash 脚本的 docker 入口点得到“权限被拒绝”的主要内容,如果未能解决你的问题,请参考以下文章

在docker container restart上执行相同的入口点脚本

如何在每个“exec”命令中执行 Docker 映像的入口点?

在 docker compose 上执行 SQL 脚本

无法使用入口点运行 docker 容器

ENTRYPOINT/CMD process 入口点进程是什么?Docker容器Dockerfile entrypoint.sh文件作用,为什么在脚本开头要执行source ~/.bashrc?

ENTRYPOINT/CMD process 入口点进程是什么?Docker容器Dockerfile entrypoint.sh文件作用,为什么在脚本开头要执行source ~/.bashrc?