**なぜこの質問なのか?
このQ&Aを投稿した理由は、Dockerイメージ内のソフトウェアをコンパイルするために、特定のソフトウェアが必要になることがあるからです。コンパイルされた後、これらのパッケージは余分なものなので、イメージサイズを小さくするために削除する必要があります。1.5GB以上あったイメージが300MB未満になった例もあります。以下のユースケースは、実際のシナリオを表しているわけではありませんが、このユースケースの一例を示しています。
問題解決のための試みを行います。
フォルダの作成と同じレイヤーでremoveコマンドが定義されている場合に、ディレクトリの削除が機能する:
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` は、あなたが考えているようなことはしませんよ。
Let's break it down:
1.mkdir dirは
dirを作成します。 1.cd dir
はディレクトリを変更する。
1.wget http://google.com`dir/
の中にgoogle.comをダウンロードする。
1.rm -rf dir
はカレントディレクトリにある dir
というディレクトリを削除しようとする。
問題は、カレントディレクトリに dir
が存在しないことである。 また、-f
フラグを追加しているため、このコマンドはエラーを発生させません。 これは、必要であることを確信しない限り強制フラグを使用すべきではない理由の1つである。
WORKDIRコマンドを使用していないので、ディレクトリの変更は
RUNの最後で破棄されます](https://stackoverflow.com/q/17891981/120999). したがって、次の行は元の作業ディレクトリで実行され、そこで
mkdir dir` を試みますが、以前に説明したように、そのディレクトリはまだ存在し、その中にwgetされたコンテンツがあります。
Xiong Chiamiov'さんの回答は、問題の根本原因を正しく特定したもので、ディレクトリを空にしたり削除しようとするときに相対パスによる dir
参照は、そのときの作業ディレクトリに依存します。
そこで、2つのソリューションが用意されています:
は、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
を使用してnot empty directory
を削除することです:
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
Outcome
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