**왜 이런 질문인가요?
이 Q&A를 게시하는 이유는 도커 이미지에 소프트웨어를 컴파일할 때 특정 소프트웨어가 필요한 경우가 있기 때문입니다. 컴파일이 완료되면 이러한 패키지는 불필요한 것이므로 이미지 크기를 줄이기 위해 제거해야 합니다. 경우에 따라 1.5GB가 넘는 이미지가 300MB 미만으로 줄어드는 경우도 있습니다. 다음 사용 사례는 실제 시나리오를 나타내지는 않지만 이 사용 사례의 예시를 제공합니다.
문제 해결을 위한 시도
제거 명령이 폴더 생성과 동일한 계층에 정의된 경우 디렉터리를 제거할 수 있습니다:
FROM alpine
RUN mkdir dir && cd dir && wget http://google.com && rm -rf dir
그 결과
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
다른 레이어에서 디렉터리를 제거하는 것이 목표인 경우 이 방법은 실패합니다:
FROM alpine
RUN mkdir dir && cd dir && wget http://google.com
RUN rm -r dir
그리고 이것은 실패합니다:
FROM alpine
RUN mkdir dir && cd dir && wget http://google.com
RUN rm -rf dir
또 다른 시도는 workdir을 사용하는 것이었습니다:
FROM alpine
RUN mkdir dir
WORKDIR dir
RUN wget http://google.com
WORKDIR /
RUN ls
RUN rm -r dir
이미지를 빌드한 결과
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`은 여러분이 생각하는 것과는 다른 동작을 합니다.
자세히 살펴보자:
은
dir`을 생성합니다.cd dir
은 디렉터리를 변경합니다.dir/
안에 구글닷컴을 다운로드합니다.은 현재 디렉토리에 있는
dir`이라는 디렉토리를 삭제하려고 시도합니다.문제는 현재 디렉토리에 이미 cd
되어 있기 때문에 현재 디렉토리에 dir
이 없다는 것입니다. 그리고 -f
플래그를 추가했기 때문에 명령이 오류를 생성하지 않습니다. 이것이 바로 강제 플래그를 꼭 필요한지 확신하지 않고 사용해서는 안 되는 이유 중 하나입니다.
WORKDIR명령을 사용하지 않았으므로 디렉토리 변경은
RUN이 끝날 때 버려집니다(https://stackoverflow.com/q/17891981/120999). 따라서 다음 줄은 원래 작업 디렉터리에서 실행되어
mkdir dir`을 시도하지만 앞서 설명한 것처럼 해당 디렉터리는 여전히 그 안에 wgetted 콘텐츠가 있는 상태로 존재합니다.
문제의 근본 원인(해당 디렉토리를 비우거나 삭제하려고 할 때 상대 경로에 의한 '디렉터리' 참조는 당시 작업 디렉토리에 따라 달라지며, 이는 OP에 언급된 사례에서 올바르게 설정되지 않았습니다)을 올바르게 식별한 Xiong Chiamov의 답변을 기반으로 작성되었습니다.
따라서 두 가지 해결책을 사용할 수 있습니다:
dir` 제거를 실행하기 전에 적절한 작업 디렉토리를 설정합니다:
RUN mkdir dir && cd dir && wget http://google.com && cd .. %% rm -rf dir
대신 해당 디렉터리에 대한 /dir
전체 경로 참조를 사용합니다. 그러나 이 방법은 초기 작업 디렉터리가 /
라고 가정하므로 이 방법과 유사하지만 동일하지 않은 경우에 사용하는 경우 주의(필요한 경우 조정)하세요:
RUN mkdir dir && cd dir && wget http://google.com && rm -rf /dir
해결책은 find
를 사용하여 비어 있지 않은 디렉토리
를 제거하는 것입니다:
도커파일
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
결과
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