1. ホーム
  2. share

[解決済み】ビルド中にDockerfileでホストボリュームをDockerコンテナにマウントする方法

2022-03-30 02:35:18

質問

この質問をされた2014年以降、様々な状況が起こり、様々なことが変化しています。今日、再びこのテーマを再検討し、最新の変化を反映させるために、この質問を12回目に編集しています。 . この質問は長く感じるかもしれませんが、逆年代順になっていますので、最新の変更点が一番上にあり、どの時点でも自由に読むのをやめることができます。

私が解決したかった問題は、ビルド中に Dockerfile でホストボリュームを docker コンテナにマウントする方法、つまり、Dockerfile の中で docker run -v /export:/export の間に docker build .

その理由のひとつは、Dockerでビルドするときに、これらの( apt-get install )キャッシュを1つのDockerに固定し、共有/再利用することです。

それが、この質問をした最大の理由です。そしてもう一つ、私が今日直面している理由は、ホストからの巨大なプライベートリポを利用しようとしていることです。 git clone を、Docker 内のプライベートなレポから、私のプライベートな ssh 鍵を使って取得するのですが、その方法がわからず、まだ調べてもいません。

最新の更新情報です。

BMWitchさんの回答にある「Buildkit」について

<ブロッククオート

それを使って RUN --mount の構文で、build-context から読み取り専用のディレクトリをマウントすることもできます...

は、18.09以上であれば、(サードパーティのツールだと思っていた)dockerにビルトインされています。私のは20.10.7です。 https://docs.docker.com/develop/develop-images/build_enhancements/

BuildKitのビルドを有効にするには

docker を新規にインストールした場合、最も簡単な方法は docker build コマンドを実行する際に環境変数 DOCKER_BUILDKIT=1 を設定することです。

$ DOCKER_BUILDKIT=1 docker build .

エルセーヌ

the --mount option requires BuildKit. Refer to https://docs.docker.com/go/buildkit/ to learn how to build images with BuildKit enabled

だから、上に説明した2つ目のユースケースの完璧なソリューションになるんだ。

2019年5月7日時点の更新情報です。

docker v18.09以前は、で始まるものが正解となります。

<ブロッククオート

ビルド中にボリュームをマウントする方法がありますが、Dockerfilesは関係ありません。

しかし、それは説明も整理もサポートも不十分な回答でした。docker containsを再インストールしているときに、たまたま以下の記事に行き当たりました。

apt-cacher-ngサービスをDockerizeする。

https://docs.docker.com/engine/examples/apt-cacher-ng/

これは、この/私の質問に対するドッカーの解答です。直接ではなく、間接的にです。ドッカーが提案するオーソドックスな方法です。そして、私がここで質問しようとした方法よりも良いものであることは認めます。

もう一つの方法は 新しく受理された回答 例えば、v18.09のBuildkitなどです。

お好きなほうをお選びください。


でした。 Dockerのものではない解決策 -- rocker がありましたが、rockerが廃止されたので、答えを元に戻します。 不可能です。 また


古いアップデートです。 ということで、答えは "Not possible" です。この問題は、以下のサイトで広く議論されていることを知っているので、私はそれを答えとして受け入れることができます。 https://github.com/docker/docker/issues/3156 . しかし、Docker のユーザーとしては、この欠落した機能には非常に失望していると言わざるを得ません。最後に、前述の議論から引用して私の議論を締め括りましょう: " Gentooをベースイメージとして使いたいのですが、イメージが構築された後、1GBのPortageツリーデータがどのレイヤーにも存在するのは絶対に嫌です。もし、インストール時に巨大なPortageツリーをイメージに表示させなければ、コンパクトなコンテナができるはずです。 しかし、単に移植性を考慮しただけで、Gentooのベースイメージを構築するたびに1GBのPortageツリーをダウンロードしなければならないという事実は、効率的でもユーザーフレンドリーでもありません。さらに、パッケージリポジトリは常に/usr/portage下にあり、したがってGentooでは常に移植可能です。繰り返しますが、私はその決定を尊重しますが、その間に私の失望を表現することも許してください。ありがとうございました。


オリジナルの質問 を詳細に説明します。

から

ボリュームを介したディレクトリの共有

http://docker.readthedocs.org/en/v0.7.3/use/working_with_volumes/

には、Data volumes feature "はDocker Remote APIのバージョン1から利用可能であると書かれています。私のDockerはバージョン1.2.0ですが、上記の記事にある例では動作しないことがわかりました。

# BUILD-USING:        docker build -t data .
# RUN-USING:          docker run -name DATA data
FROM          busybox
VOLUME        ["/var/volume1", "/var/volume2"]
CMD           ["/usr/bin/true"]

ホストマウントされたボリュームをDockerコンテナにマウントするために、DockerfileでVOLUMEコマンドを使用する適切な方法は何でしょうか?

$ apt-cache policy lxc-docker
lxc-docker:
  Installed: 1.2.0
  Candidate: 1.2.0
  Version table:
 *** 1.2.0 0
        500 https://get.docker.io/ubuntu/ docker/main amd64 Packages
        100 /var/lib/dpkg/status

$ cat Dockerfile 
FROM          debian:sid

VOLUME        ["/export"]
RUN ls -l /export
CMD ls -l /export

$ docker build -t data .
Sending build context to Docker daemon  2.56 kB
Sending build context to Docker daemon 
Step 0 : FROM          debian:sid
 ---> 77e97a48ce6a
Step 1 : VOLUME        ["/export"]
 ---> Using cache
 ---> 59b69b65a074
Step 2 : RUN ls -l /export
 ---> Running in df43c78d74be
total 0
 ---> 9d29a6eb263f
Removing intermediate container df43c78d74be
Step 3 : CMD ls -l /export
 ---> Running in 8e4916d3e390
 ---> d6e7e1c52551
Removing intermediate container 8e4916d3e390
Successfully built d6e7e1c52551

$ docker run data
total 0

$ ls -l /export | wc 
     20     162    1131

$ docker -v
Docker version 1.2.0, build fa7b24f

解決方法は?

まず、quot;なぜしないのか? VOLUME は動作しますか? VOLUME をDockerfileに記述した場合、ボリュームのソースではなく、ターゲットのみを定義することができます。ビルド中は、ここから匿名ボリュームを取得するだけです。その匿名ボリュームは、すべての RUN コマンドを実行し、イメージの内容を事前に入力し、その後 RUN コマンドを使用します。コンテナへの変更のみが保存され、ボリュームへの変更は保存されません。


この質問がされて以来、役に立つかもしれないいくつかの機能がリリースされました。まず、マルチステージビルドでは、ディスクスペースが効率の悪い最初のステージをビルドし、必要な出力だけを最終ステージにコピーして出荷することが可能です。そして2つ目の機能はBuildkitで、イメージのビルド方法を劇的に変化させ、ビルドに新しい機能を追加しています。

多段ビルドの場合、複数の FROM の行があり、それぞれが別のイメージの作成を開始します。デフォルトでは最後のイメージにのみタグが付けられますが、前のステージのファイルをコピーすることも可能です。標準的な使用方法は、バイナリや他のアプリケーションの成果物を構築するコンパイラ環境と、その成果物をコピーする第2ステージとしてのランタイム環境を持つことです。持つことができます。

FROM debian:sid as builder
COPY export /export
RUN compile command here >/result.bin

FROM debian:sid
COPY --from=builder /result.bin /result.bin
CMD ["/result.bin"]

その結果、ビルドには結果のバイナリのみが含まれ、/export ディレクトリ全体は含まれないことになります。


Buildkitは18.09でexperimentalから脱却します。これはビルドプロセスの完全な再設計であり、フロントエンドのパーサーを変更する機能も含まれています。パーサーの変更の1つは、フロントエンドのパーサーを変更する機能を含む、ビルドプロセスの完全な再設計です。 RUN --mount オプションを使用すると、実行コマンドのキャッシュディレクトリをマウントすることができます。例えば、これは debian ディレクトリのいくつかをマウントするものです (debian イメージの再構成により、パッケージの再インストールを高速化できるかもしれません)。

# syntax = docker/dockerfile:experimental
FROM debian:latest
RUN --mount=target=/var/lib/apt/lists,type=cache \
    --mount=target=/var/cache/apt,type=cache \
    apt-get update \
 && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
      git

例えば、mavenの場合は$HOME/.m2、golangの場合は/root/.cacheのように、アプリケーションキャッシュに応じたキャッシュディレクトリを調整することになります。


TL;DR: 答えはここにあります。 それを使って RUN --mount 構文で、build-context から読み取り専用のディレクトリをマウントすることもできます。フォルダはビルドコンテキストに存在しなければならず、ホストやビルドクライアントにマップバックされることはありません。

# syntax = docker/dockerfile:experimental
FROM debian:latest
RUN --mount=target=/export,type=bind,source=export \
    process export directory here...

ディレクトリはコンテキストからマウントされるため、読み取り専用でマウントされ、ホストやクライアントに変更をプッシュバックすることができないことに注意してください。ビルドする際には、18.09 以降をインストールし、buildkit を export DOCKER_BUILDKIT=1 .

マウントフラグがサポートされていないというエラーが出た場合は、上記の変数で buildkit を有効にしなかったか、Dockerfile の先頭でコメントを含む他の行の前にある syntax 行で実験的な構文を有効にしなかったことを示します。buildkit を有効にするための変数は、docker インストールに buildkit サポートが組み込まれている場合のみ動作することに注意してください。