运行bash脚本的docker入口点“权限被拒绝”


122

我正在尝试将我的node.js应用程序码头化。构建容器后,我希望它运行a 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.

我将其装入容器,并且docker-entrypoint.sh的许可为:

-rw-r--r-- 1 root root 292 Aug 10 18:41 docker-entrypoint.sh

三个问题:

  1. 我的bash脚本语法错误吗?

  2. 在将bash文件添加到图像之前,如何更改其权限?

  3. 在不使用bash脚本的情况下在入口点运行多个git命令的最佳方法是什么?

谢谢。


我们需要查看文件权限才能回答这个问题。
— 查尔斯·达菲

顺便说一句,如果这是bash脚本,而不是sh脚本,则.sh扩展名会给人以误解,即解释器可以执行它。您可能会考虑将其删除-UNIX命令具有扩展名(ls.elf例如,不运行)是不常见的。
— 查尔斯·达菲

我们可以这样exec壳吗?它不需要bash前缀。
— 让·弗朗索瓦·法布尔

@Jean-FrançoisFabre,您的问题是什么意思?(我不明白“以这种方式执行shell”的意思-在这种情况下是“以这种方式”?)
— Charles Duffy

2
顺便说一句愚蠢的问题-在将脚本添加到映像之前,脚本的权限是否正确?
— 查尔斯·达菲

Answers:


183
  1. “权限被拒绝” 根本阻止您的脚本被调用。因此,唯一可能与之相关的语法是第一行(“ shebang”)的语法,该语法应类似于#!/usr/bin/env bash,或#!/bin/bash或类似,具体取决于目标的文件系统布局。

  2. 文件系统权限很可能未设置为允许执行。shebang也可能引用了不可执行的内容,但这是远远不太可能。

  3. 解决以前的问题很容易。


简单阅读

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脚本后我仍然需要更改权限。
— 加尔文·胡

我有一个phar文件,该文件可基于命令创建.bash脚本,并在完成后将其删除。因此,仍然需要为共享卷设置执行权限设置。
— raupie

@raupie,如果要从带有noexec标志的安装点运行脚本,请运行bash yourscript而不是./yourscript。
— Charles Duffy

1
我不理解,当我运行docker build即时容器时效果很好。但是当我这样做时docker run,它会抛出这样的错误。好像我有一个神奇的中间容器。
— 蒂娜(Tiina)

46

可执行文件必须具有执行权限集,然后才能执行。

在要构建Docker映像的计算机中(不在Docker映像本身内部)尝试运行:

ls -la path/to/directory

可执行文件输出的第一列(在本例中为docker-entrypoint.sh)应将可执行位设置为:

-rwxrwxr-x

如果没有,请尝试:

chmod +x docker-entrypoint.sh

然后再次构建您的docker映像。

Docker使用它自己的文件系统,但是它从源目录中复制所有内容(包括权限位)。


13
chmod +x docker-entrypoint.sh在tzhe主机上实际上是推荐的解决方案,因为它比更改您的容易得多Dockerfile。
— jotrocken

16

我遇到了同样的问题,并且解决了

ENTRYPOINT ["sh", "/docker-entrypoint.sh"]

对于原始问题中的Dockerfile,它应类似于:

ENTRYPOINT ["sh", "/usr/src/app/docker-entrypoint.sh"]

5
这是一种解决方法,但不是一个很好的解决方法–使用来解释脚本sh,而忽略了shebang的解释器规范;所以如果它使用了#!/bin/bash,说必须要使用bash来解释,那将被忽略,它就会用解释sh代替,从而不允许的语言特性,比如[[ ]],阵列等
— 查尔斯·达菲

我已经使用了您的方法,并且有效。也许dos2unix也能解决问题
— Wakan Tanka

1

如果不使用DockerFile,则可以简单地将权限添加为bash的命令行参数:

docker run -t <image>  /bin/bash -c "chmod +x /usr/src/app/docker-entrypoint.sh; /usr/src/app/docker-entrypoint.sh"

1

这是我回答之前两年提出的一个老问题,无论如何我都会发布对我有用的东西。

在我的工作目录中,我有两个文件: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容器中的文件可执行docker build .。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.