Dockerfile に apt, apt-get, source コマンドを書く時のTips

この記事は Dockerfile を初めて書くときに役立ったTipsをまとめたものです。
apt, apt-get, source コマンドとマルチステージビルドについて調べたことを挙げています。

(追記) Dockerfile で使用する推奨コマンドを apt から apt-get に変更しました。

公式の Dockerfile のベストプラクティスはこちら。また、こちらの @zembutsu 氏のスライドが大変助かりました。ありがとうございます。こちらで触れていない内容もありますので、ぜひご覧ください。

尚、下記内容の docker 実行イメージは Ubuntu 18.04を対象としています。 そのため Docker Desktop for Windows を利用する場合、Linux container に切り替える必要があります。

apt または apt-get を使うと警告が出る

apt を使う場合に出る警告

RUN apt install -y nyancat
WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

CLI インターフェース向けではないということで注意は必要ですが、無視しても動きます。

apt-get を使う場合に出る警告

RUN apt-get install -y nyancat
debconf: delaying package configuration, since apt-utils is not installed

debconfig や apt-utils についての説明はこちらで確認できます。また、警告を非表示にすることも一応可能です。 こちらも無視しても動きます。

実際に使う場合は

docker 公式では apt-get が使われていますが、 現在 Debian では aptを推奨していること、今回下位互換性を意識する必要がないことから apt を使用しましょう。 apt-get を使用しましょう。

(追記) man apt によると apt(8) ではなく apt-get(8) をスクリプトで使用するよう推奨されているため、推奨コマンドを変更しました。

以下、該当部分の引用です。

SCRIPT USAGE AND DIFFERENCES FROM OTHER APT TOOLS
       The apt(8) commandline is designed as an end-user tool and it may change behavior between versions. While it tries not to break backward compatibility this is not guaranteed either if a change seems beneficial for interactive use.

       All features of apt(8) are available in dedicated APT tools like apt-get(8) and apt-cache(8) as well.  apt(8) just changes the default value of some options (see apt.conf(5) and specifically the Binary scope). So you should prefer using these commands (potentially with some additional options enabled) in your scripts as they keep backward compatibility as much as possible.

実際は下記のように --no-install-recommends オプションを使って必要最小限のインストールを一度に複数行うのがいいでしょう。また、apt updateapt installの行をまとめることで古いパッケージ情報のキャッシュ利用を避けることができます。最後に不要なパッケージマネージャーのキャッシュを削除して容量を削減します。 これらのコマンドをまとめることでレイヤ数を必要最小限にし、さらに容量を削減できます。

RUN apt-get update \
 && apt-get install -y --no-install-recommends \
    cowsay \
    nyancat \
 && apt-get -y clean \
 && rm -rf /var/lib/apt/lists/*

一連のコマンド後に && でさらにコマンドを連結することができますが、依存関係のあるライブラリのインストールや、ln コマンドによるシンボリックリンク作成など、無暗に連結するとエラーになるものがありますので注意してください。 最初はあまり連結せずにRUNで書いて動作を確認し、その後行末から連結して動作確認するのがおすすめです。 但し、状況によっては後述のマルチステージビルドの方法を検討しましょう。

source コマンドが使用できない

Ubuntu の /bin/sh は bash でなく Dash が使われており、Dash には source コマンドが無いためです。source の代わりに . を使用します。 尚、下記の例は相対パスで .bash_profile を指定していますが、絶対パスで指定するほうが無難でしょう。

RUN source .bash_profile  # 実行エラー
RUN . .bash_profile

ビルド環境と実行環境を分ける(マルチステージビルド)

複数のFROMASを使ってビルド環境と実行環境のイメージを分離すること ( マルチステージビルド ) で、実行環境のみを保存することによりイメージ容量を縮小できます。イメージ内でビルドしたライブラリを使う場合に有効です。
また、ビルド環境のレイヤ数やサイズは最終的に生成される実行環境のイメージに影響しないため && を極限まで使ってレイヤ数を減らす必要がなくなり、複雑さを低減できます。

FROM image_A AS build-native-env
# .. 開発環境で特定ライブラリ, 実行プログラムをビルド ..

FROM image_B
COPY --from=build-native-env /projectdir
# image_A でビルドしたデータをコピーして実行環境イメージを作成

あとがき

cowsayをインストールしたはずなのにコマンドが見つかりませんとなり、 which cowsay でバイナリの場所が表示されないのは何故なのか..
以上、Buzy の「鯨」を聴きつつお送りしました。

%d人のブロガーが「いいね」をつけました。