docker entrypoint executando script bash obtém “permissão negada”

122

Estou tentando encaixar meu aplicativo node.js. Quando o contêiner for criado, quero que ele execute um git clonee, em seguida, inicie o servidor de nó. Portanto, coloquei essas operações em um script .sh. E execute o script como um único comando no 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"] 

Meu docker-entrypoint.sh se parece com isto:

git clone git@<repo>.git
git add remote upstream git@<upstream_repo>.git

/usr/bin/node server.js

Depois de construir esta imagem e executar:

docker run --env NODE_ENV=development -p 8080:8080 -t -i <image>

Estou entendendo:

docker: Error response from daemon: oci runtime error: exec: "/usr/src/app/docker-entrypoint.sh": permission denied.

Eu despejo no contêiner e a permissão de docker-entrypoint.sh é:

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

três questões:

  1. Meu script bash tem sintaxe errada?

  2. Como altero a permissão de um arquivo bash antes de adicioná-lo a uma imagem?

  3. Qual é a melhor maneira de executar vários comandos git no entrypoint sem usar um script bash?

Obrigado.

Calvin Hu
fonte
Precisamos ver as permissões do arquivo para responder a esta pergunta.
Charles Duffy de
BTW, se este for um script bash , não um script sh , uma .shextensão deixa uma impressão enganosa sobre quais intérpretes podem executá-la. Você pode considerar tirar isso - não é convencional que os comandos do UNIX tenham extensões (você não executa ls.elf, por exemplo).
Charles Duffy de
Podemos execuma concha assim? não precisaria do bashprefixo.
Jean-François Fabre
@ Jean-FrançoisFabre, o que exatamente você quer dizer com sua pergunta? (Não entendo o que "exec um shell dessa maneira" significa - o que é "dessa forma" neste contexto?)
Charles Duffy
2
A propósito, pergunta boba - as permissões do script estão corretas antes de você adicioná-las à imagem?
Charles Duffy de

Respostas:

183
  1. "Permissão negada" impede o seu script de ser invocado em tudo . Portanto, a única sintaxe possivelmente pertinente é a da primeira linha (o "shebang"), que deve ser semelhante a #!/usr/bin/env bash, ou #!/bin/bashou semelhante, dependendo do layout do sistema de arquivos de destino.

  2. Provavelmente as permissões do sistema de arquivos não foram definidas para permitir a execução. Também é possível que o shebang faça referência a algo que não é executável, mas isso é muito menos provável.

  3. Suscitado pela facilidade de reparar os problemas anteriores.


A simples leitura de

docker: Error response from daemon: oci runtime error: exec: "/usr/src/app/docker-entrypoint.sh": permission denied.

... é que o script não está marcado como executável.

RUN ["chmod", "+x", "/usr/src/app/docker-entrypoint.sh"]

resolverá isso dentro do contêiner. Como alternativa, você pode garantir que a cópia local referenciada pelo Dockerfile seja executável e, em seguida, usar COPY(que é explicitamente documentado para reter metadados).

Charles Duffy
fonte
Eu acho que você está certo. Devo usar COPY em vez disso. Mas parece que ainda preciso alterar a permissão após copiar o script bash.
Calvin Hu de
Eu tenho um arquivo phar que cria scripts .bash com base em um comando e os remove depois de concluídos. Portanto, a necessidade de volumes compartilhados para ter a permissão de execução definida é algo com que ainda estou lutando.
raupie
@raupie, se você deseja executar um script a partir de um ponto de montagem com o noexecsinalizador, execute em bash yourscriptvez de ./yourscript.
Charles Duffy
1
Eu não entendo, quando eu executo docker buildo contêiner imediato funciona bem. Mas quando eu faço docker run, ele lança tal erro. Parece um recipiente intermediário mágico que tenho.
Tiina
46

Um arquivo executável precisa ter permissões para executar definidas antes que você possa executá-lo.

Na máquina em que você está criando a imagem do docker (não dentro da própria imagem do docker), tente executar:

ls -la path/to/directory

A primeira coluna da saída do seu executável (neste caso docker-entrypoint.sh) deve ter os bits executáveis ​​definidos da seguinte forma:

-rwxrwxr-x

Se não, tente:

chmod +x docker-entrypoint.sh

e, em seguida, crie sua imagem docker novamente.

O Docker usa seu próprio sistema de arquivos, mas copia tudo (incluindo bits de permissão) dos diretórios de origem.

Sami Start
fonte
13
chmod +x docker-entrypoint.shno host é realmente a solução recomendada, pois é muito mais simples do que alterar o seu Dockerfile.
jotrocken
16

Eu enfrentei o mesmo problema e foi resolvido por

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

Para o Dockerfile na pergunta original, deveria ser assim:

ENTRYPOINT ["sh", "/usr/src/app/docker-entrypoint.sh"]
Saurabhcdt
fonte
5
Esta é uma solução alternativa, mas não excelente - interpreta o script com sh, ignorando a especificação de um interpretador; portanto, se usar #!/bin/bash, dizendo que deseja ser interpretado com bash, isso será ignorado e será interpretado com sh, portanto, não permitindo recursos de linguagem como [[ ]]matrizes, etc.
Charles Duffy
Usei sua abordagem e funcionou. Talvez também dos2unix
funcione
1

Se você não usa DockerFile, pode simplesmente adicionar permissão como argumento de linha de comando do bash:

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

Esta é uma pergunta antiga feita dois anos antes da minha resposta, vou postar o que funcionou para mim de qualquer maneira.

Em meu diretório de trabalho, tenho dois arquivos: Dockerfile e 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

Consegui tornar o arquivo executável no contêiner do docker definindo o arquivo fora do contêiner como executável chmod 700 provision.she em execução docker build ..

BradChesney79
fonte