> ~/zaldih

Cómo solucionar el error 127 (not found) en Docker (aunque el archivo exista)

Otros idiomas: English

Estás tranquilo, creando un nuevo Dockerfile para tu proyecto como cualquier otro día.

Dejas construyendo la imagen de Docker mientras te levantas para ir a rellenarte la taza de café, pero de repente:

 => [build  8/10] COPY ./scripts ./scripts
 => [build  9/10] RUN npx nx build app --prod
 => ERROR [build 10/10] RUN ./scripts/set-build-version.sh
------
 > [build 10/10] RUN ./scripts/set-build-version.sh:
#17 0.345 /bin/sh: ./scripts/set-build-version.sh: not found
------
executor failed running [/bin/sh -c ./scripts/set-build-version.sh]: exit code: 127

El error 127 de toda la vida que indica que el fichero ./scripts/set-build-version.sh no se ha encontrado. Pero tú sabes que el fichero está ahí. Acababas de hacer el COPY dos pasos más atrás.

Miras el código, miras la carpeta, vuelves a mirar el código… y empiezas a dudar de tu cordura.

La investigación

Aunque me hubiera encantado pensar que era cosa de la magia negra y haberlo dejado ahí. La realidad es que necesitaba que eso funcionara. Así que lo primero que uno puede pensar es: vale, el script no se está copiando por alguna razón.

Vamos a debuggear. Vamos a listar los ficheros dentro de la imagen:

#16 [build  9/11] RUN echo $(ls -al scripts)
#16 0.338 total 28
drwxr-xr-x 2 root root 4096 Nov 21 11:37 .
drwxr-xr-x 1 root root 4096 Nov 21 11:38 ..
-rwxr-xr-x 1 root root  708 Nov 21 11:37 build-and-upload-containers.sh
-rwxr-xr-x 1 root root 2478 Oct 15 11:46 deploy.sh
-rwxr-xr-x 1 root root  455 Sep 30 10:33 initialization.sh
-rwxr-xr-x 1 root root  201 Nov 21 11:30 set-build-version.sh
#16 DONE 0.4s

Mnnn… ahí está, con sus permisos bien y todo.

Si el archivo está ahí y tiene permisos de ejecución, ¿por qué /bin/sh dice que no lo encuentra?

Las apariencias engañan

Aquí es donde la cosa se pone interesante, y es que cuando Docker dice ”not found”, no siempre se refiere al script en sí. A veces se refiere a lo que el script necesita para ejecutarse.

1. El Shebang inexistente

Si tu script empieza con #!/bin/bash pero estás usando una imagen base de Alpine Linux, el error será ”not found“.

¿Por qué? Porque Alpine no incluye bash por defecto. En su lugar usa su hermano mayor sh. El sistema intenta buscar el intérprete /bin/bash para ejecutar el script, no lo encuentra, y nos explota.

2. Los finales de línea

El clásico y conocido archi villano. Si creamos el script en Windows, es posible que los finales de línea estén en formato CRLF. Esto puede implicar que en realidad el shebang se vea algo como /bin/sh\r, aunque esos dos últimos caracteres sean invisibles.

Así que por si las moscas:

RUN sed -i 's/\r$//' ./scripts/set-build-version.sh  && \
    chmod +x ./scripts/set-build-version.sh

Problema solucionado:

 => [build  9/10] RUN sed -i 's/\r$//' ./scripts/set-build-version.sh  &&     chmod +x ./scripts/set-build-version.sh
 => [build 10/10] RUN ./scripts/set-build-version.sh
 => CACHED [stage-1 2/4] WORKDIR /app

Y ahora si, a por mi café.