495
Dockerfileで実行できるコマンド数を減らす方法に関して、なにか知ってれば教えて下さい。

自分の場合、下記のようにコマンドまとめたりして頑張ってるのですが、他なにかいい手段ありますか？

```

    RUN \
    yum -y update; \
    yum install httpd....
    
```
CC BY-SA 3.0
2014-12-06T14:01:28.387
400
2017-04-30T09:46:40.420
291
question
docker
Dockerfileのダイエット方法を教えて下さい
Docker Hub
にある既存のイメージをなるべく多用し、一つのイメージでいろいろ詰め込む代わりに複数のイメージをリンクして使用するような方法で逃げられないでしょうか？

また、シェルスクリプト等を ADD して、そのファイルを RUN で実行するようにすると RUN の数は抑えられると思いますがどうでしょう？
CC BY-SA 3.0
2014-12-07T06:24:36.410
422
2014-12-07T06:24:36.410
73
400
answer
基本的に、[Optimizing Docker Images](http://www.centurylinklabs.com/optimizing-
docker-images/)このページでまとめられているのが有力なものです。

以下では、これに加えて私がイメージを作る際に周囲からもらったアドバイスや試してみたことなども含めて書いてみます。

## 可能な限り、必要最小限のサイズのイメージからスタートする

上記ページにも記載があるように、例えばUbuntuよりもDebianを使います。私の場合は趣味的にはUbuntuが好きなのですが、配布用のDockerイメージはDebianのwheezyベースなどで作っています。上記ページにもあるように、これだけで100MBぐらい違ったりします。

## RUNでのコマンドをチェーンさせてステージ数を減らす

torusさんの回答にあるものです。DockerではRUNの単位でファイルシステムの更新をおこなうので、仮にあるステージで大きなファイルを追加、その後のステージで当該ファイルを削除しても容量は食いっぱなしとなります。
私が過去に作ったものでは、あるソフトウェアのソースを拾ってきてmake && make
install、その後にソース一式を削除するところまでをひとつにチェーンさせることで容量削減できました。

## 不要な中間ファイルは削除する

私がイメージを作成していた時に指摘をもらったものなのですが、`/usr/local/src`以下にあるソースを拾ってきて、それを`make && make
install`したままソースコードを残していたことがありました。

これは、ソースを残しておいたほうが何かといじりやすいと考えての対応でした。さらに言うと、あるソースのスナップショットではなく丸ごとgit
cloneしていました。これは様々な実験をおこなう際には便利ですし開発環境のDockerイメージを提供しようという際には良いのです。しかしバイナリ配布でサクッと導入してもらえるようなイメージの構築においてはただの無駄ということで納得しました。

ソースは`make install`が終わったら消しましょう。ソースが本当に必要な人は、Dockerfileをforkして自前でなんとかしてくれます多分。

## GitHubからソースを拾ってくるものについて、なるべく`git clone`しない

もっと言うと、不要ならgitコマンドをインストールしない(いくらgitのない世界が不安で仕方なくても)。

これも私がとあるイメージを作成していた時にもらった指摘に関するものです。 GitHubで配布されているコードを使ったビルドをおこなうならひとまず`git
clone`してくるのが普通だろうという開発脳なのですが、Dockerのイメージを作る際には「えっ、ほんとにgitいる?」と疑うのが肝心です。
Debianでgit-
coreパッケージをインストールするだけでも数十MBの追加容量が必要となるので、指定リリースの*.tar.gzファイルを拾ってきて展開すれば十分なケースではgitのインストールすら避けるのが良いでしょう。

繰り返しとなりますが、チーム用などに開発用環境を用意する際は別です。

## 特に事情がなければディストリビューションのバイナリ配布物を利用する

ソフトウェアパッケージのビルドには多くの追加パッケージが必要です。gcc、libstdc++6-dev、make、autotools、cmakeなどなど。build-
essentialをえいやっと追加すると一気にディスク容量が膨らみます。

というわけで、もし特殊な事情がなければ、なるべくディストリビューションの提供するバイナリ配布物を使うようにDockerfileを記述すべきです。

しかし、ディストリビューションの公式パッケージに入っていないものやバージョンが古いもの・互換性のないものなどについては仕方ありません。なるべく追加容量が最小限で済むように留意しつつ、パッケージをインストールしましょう。

## イメージビルド中の多階層ディレクトリに対するchownを避ける

[Dockerfile Golf (or optimizing the Docker build
process)](http://www.davidmkerr.com/2014/08/dockerfile-golf-or-optimizing-
docker.html)で紹介されていました。

これもDockerの構造がステージごとにファイルシステム状態を記録することに関連します。このblogでは、特定ディレクトリへのchownをビルドフェーズでおこなったところ、72MBもの容量増につながったという話が紹介されています。

代替策として、chownを`COMMAND`での起動シーケンスへと移動したということです。なかなか難しいですね。

## `ONBUILD`を利用して一部処理をイメージ実行時へ逃がす

利用できるシーンが一定限られますが、例えば「あるシステムの実行のために大量の静的ファイル(しかもそれなりに頻繁な更新がおこなわれる)を拾ってくる必要がある」といった場合に有効です。

コンテナの一部として頻繁な更新のおこなわれるファイル群を利用する場合、それらが更新される都度Docker
Hubでのビルドをおこなうのはあまり効率的と言えません。

そこで用意されているのが`ONBUILD`コマンドです。`RUN`コマンドがイメージ生成時に実行されるコマンドであるのに対して、`ONBUILD`コマンド([マニュアル](https://docs.docker.com/reference/builder/#onbuild))は当該処理をコンテナ生成時まで後回しするものです。

## 番外編: 既存の巨大イメージをダイエットする

基本的にはDockerfileを編集してイメージ作り工程を改善するお話ですが、仮にDockerfileへアクセスできなくてもとれる策がこれです(これも上記ページで紹介されています)。

実行中のコンテナを指定して

`docker export <container id> | docker import - <new image name>`

で、イメージのビルド時にステージごとに生成されたレイヤがごっそり統合されます。結果として、ベースイメージからの差分保持すらされなくなるため、場合によっては当該イメージ単体のサイズは増えるかもしれません。

他方、パフォーマンス面では実行時にアクセスするfsレイヤを減らせるのでファイルI/O面は多少有利になるかもしれません。

メリットとデメリットを把握して利用する必要のある策です。
CC BY-SA 3.0
2014-12-10T08:55:49.830
495
2014-12-10T08:55:49.830
777
400
answer
回答というより追加情報のような形になりますが・・・

開発したWebアプリケーションを`git clone`してコンテナに入れる場合は、  
動作に不要な`.dockerignore`で`node_modules`や`.git`をコンテナ内にコピーしないようにする必要があります。  
`git clone --depth=1`をしたとしても`.git`にかなりの容量を食われていたりします。
CC BY-SA 3.0
2017-04-30T09:46:40.420
34390
2017-04-30T09:46:40.420
336
400
answer