Dockerfileの効率的な作り方(おさらい)
Dockerfileを作る時、Dockerがまだよく分かっていない時は以下の方法でやってました。
- Dockerfile書く
- ビルドする(動かしたいアプリ含め)
- 起動してみる
- 動かなかったらDockerfile修正する
- またビルドして試す
こんな感じでしたが、これは非常に効率が悪いです。修正の度にビルドが発生してしまい、待ちが発生してしまいます。
どうすればよい?
- ベースイメージにアタッチ
- 動かしたいアプリの実行に必要なコマンドを入れて、成功したらコマンドをメモ
- アプリが動くまで「コマンド実行→成功したらメモ」を繰り返す
- アプリが動いたらメモったコマンドでDockerfileを作る
つまり、いきなりDockerfileにコマンドを羅列して作るのではなく、ベースイメージに入ってコマンドを実行して動作確認をしながらDockerfileに記述する内容を固めていき、最後に1回だけビルドします。
なぜ?
Dockerfileに記述するのはそのままシェルで実行されるコマンドなので、1つ1つ挙動を確認しながらコマンドを固めていった方が効率がいいです。
- apt update実行→メモ
- ライブラリのソースコードをダウンロードするコマンド実行→メモ
- ダウンロードしたライブラリをビルドするコマンド実行→メモ
こんな感じで1コマンドずつ実行して、正常にコマンドが成功したらメモしていきます。
環境が良く分からない状態になってしまった時とか、最初からやり直したい時はコンテナを破棄すればリセットできます。動作確認ができているコマンドはメモってあるので、コンテナ作り直したらメモをコピペして実行すれば失敗する前の状態に戻せます。
「コマンド実行→メモ」を繰り返して目的のアプリが動いたら、メモったコマンドをDockerfileのRUNで書いていってビルドします。これで確実にアプリが動くDockerイメージを作る事ができます。
ビルドが通ったら、後はRUNコマンドをまとめたり、マルチステージビルド方式に変えたりして最適化していけばOKです。通常の環境構築と異なりコンテナなので気軽に環境をリセットできるのでその特性を存分に利用しましょう。
まとめ
コマンド修正→ビルド→検証ではなくコマンドを順次実行してメモりながらコマンドを固めて最後に1回だけビルドする方式がオススメです。エンジニアであれば、コード書く→ビルド→動作確認→修正→ビルド・・・を繰り返しているので、Dockerfileも同じ方式で書いてしまう事が多いです。それが罠です。
特にネイティブアプリを動かす場合は複雑な環境を構築しないといけない為、コマンドが多くなりがちです。少しでも開発効率を上げる手助けになれば幸いです。
Discussion
typoでしょうか?
産後に1回だけビルド
最後に1回だけビルド
Typoでした!ご指摘ありがとうございます!