**¿Por qué esta pregunta?
La razón para publicar esta Q&A es que a veces se requiere cierto software para compilar software en una imagen docker. Una vez compilados, estos paquetes son superfluos y deben eliminarse para reducir el tamaño de la imagen. En algunos casos, imágenes de más de 1,5 GB se han reducido a menos de 300 MB. El siguiente caso de uso no representa un escenario del mundo real, pero proporciona un ejemplo de este caso de uso.
Intentos de resolver el problema.
Funciona la eliminación de un directorio cuando el comando de eliminación se define en la misma capa que la creación de la carpeta:
FROM alpine
RUN mkdir dir && cd dir && wget http://google.com && rm -rf dir
Esto da como resultado:
user@host$ docker build -t dir .
Sending build context to Docker daemon 1.336 MB
Step 1/2 : FROM alpine
---> 4a415e366388
Step 2/2 : RUN mkdir dir && cd dir && wget http://google.com && rm -rf dir
---> Using cache
---> c283805e687f
Successfully built c283805e687f
Cuando el objetivo es eliminar el directorio en otra capa, esto falla:
FROM alpine
RUN mkdir dir && cd dir && wget http://google.com
RUN rm -r dir
Y esto falla:
FROM alpine
RUN mkdir dir && cd dir && wget http://google.com
RUN rm -rf dir
Otro intento fue usando workdir:
FROM alpine
RUN mkdir dir
WORKDIR dir
RUN wget http://google.com
WORKDIR /
RUN ls
RUN rm -r dir
La construcción de la imagen resultó en:
Sending build context to Docker daemon 2.048 kB
Step 1/7 : FROM alpine
---> 4a415e366388
Step 2/7 : RUN mkdir dir
---> Using cache
---> aed5c75218cb
Step 3/7 : WORKDIR dir
---> Using cache
---> 715de09e7e08
Step 4/7 : RUN wget http://google.com
---> Using cache
---> c07bfb3e1133
Step 5/7 : WORKDIR /
---> Using cache
---> c6de86d0191a
Step 6/7 : RUN ls
---> Using cache
---> 9567593cce39
Step 7/7 : RUN rm -r dir
---> Running in 7fe7b28294bf
rm: can't remove 'dir': Directory not empty
The command '/bin/sh -c rm -r dir' returned a non-zero code: 1
mkdir dir && cd dir && wget http://google.com && rm -rf dir
doesn't do what you think it does.
Desglosémoslo:
crea
dir`.cd dir
cambia de directorio.wget http://google.com
descarga google.com dentro de dir/
.intenta borrar un directorio llamado
dir` que se encuentra en el directorio actual.El problema es que no hay "dir" en el directorio actual, porque ya estás en él. Y como ha añadido la bandera -f
, el comando no produce ningún error. Esta es una de las razones por las que no debería usar banderas forzadas sin estar muy seguro de que las necesita.
Como no ha utilizado el comando WORKDIR
, el cambio de directorio se descarta al final de RUN
. Así, la siguiente línea se ejecuta en el directorio de trabajo original, donde intenta mkdir dir
pero, como hemos discutido previamente, ese directorio todavía existe con los contenidos de wgetted dentro de él.
Basándome en la respuesta de Xiong Chiamiov's, que identificó correctamente la causa raíz del problema - la referencia dir
por ruta relativa al intentar vaciar o borrar ese directorio depende del directorio de trabajo en ese momento, que no estaba correctamente configurado en los casos mencionados en el OP.
Así que hay 2 soluciones disponibles:
establecer el directorio de trabajo adecuado antes de ejecutar la eliminación de dir
:
RUN mkdir dir && cd dir && wget http://google.com && cd .. %% rm -rf dir
utilice una referencia de ruta completa /dir
a ese directorio en su lugar. Pero con cuidado (ajústelo si es necesario) si se usa en casos similares, pero no idénticos a éste, ya que este enfoque asume que el directorio de trabajo inicial era /
:
RUN mkdir dir && cd dir && wget http://google.com && rm -rf /dir
Una solución es eliminar el directorio no vacío
utilizando find
:
Dockerfile
FROM alpine
RUN mkdir dir && cd dir && wget http://google.com && cd / && echo -e "BEFORE\n" && ls && find /dir -delete && echo -e "\nAFTER\n" && ls
Resultado
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM alpine
---> 4a415e366388
Step 2/2 : RUN mkdir dir && cd dir && wget http://google.com && cd / && echo -e "BEFORE\n" && ls && find /dir -delete && echo -e "\nAFTER\n" && ls
---> Running in ba93a1742a76
Connecting to google.com (172.217.20.110:80)
Connecting to www.google.nl (172.217.20.99:80)
index.html 100% |*******************************| 11092 0:00:00 ETA
BEFORE
bin
dev
dir
etc
home
lib
media
mnt
proc
root
run
sbin
srv
sys
tmp
usr
var
AFTER
bin
dev
etc
home
lib
media
mnt
proc
root
run
sbin
srv
sys
tmp
usr
var
---> 2e3109285a2d
Removing intermediate container ba93a1742a76
Successfully built 2e3109285a2d