ビルド中にホストボリュームをDockerfileのDockerコンテナーにマウントする方法


236

元の質問:DockerfileでVOLUME命令を使用するにはどうすればよいですか?

私が解決したい実際の質問は-ビルド中にDockerfileのドッカーコンテナーにホストボリュームをマウントする方法、つまりdocker run -v /export:/export中に機能を持つことdocker buildです。

その背後にある理由は、私にとって、Dockerでビルドするときに、それらの(apt-get install)キャッシュを単一のDockerにロックしたくないが、それらを共有/再利用するためです。それが私がこの質問について尋ねている主な理由です。

最新のアップデート:

docker v18.09より前のバージョンでは、正しい答えは次のようになります。

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

しかし、それは不十分に述べられ、組織化され、支持された答えでした。docker containsを再インストールしているときに、次の記事を偶然見つけました。

apt-cacher-ngサービスをDockerize
https://docs.docker.com/engine/examples/apt-cacher-ng/

これは、直接/間接的にではなく、この/私の質問に対するDockerの解決策です。これは、Dockerが私たちに提案する正統な方法です。そして、私がここで尋ねようとしたものよりも優れていることを認めます。

もう1つの方法は、新しく承認された回答、たとえばv18.09のビルドキットです。

あなたに合ったものを選んでください。


ありました解決策がありました-Dockerからではないロッカーですが、そのロッカーが廃止されたので、私は答えを「不可能」に戻します。


旧アップデート:したがって、答えは「不可能」です。この問題はhttps://github.com/docker/docker/issues/3156で幅広く議論されているので、それを回答として受け入れることができます。移植性は、Docker開発者にとって最も重要な問題であることを理解できます。しかし、ドッカーユーザーとして、私はこの欠けている機能に非常に失望していると言わざるを得ません。前述の議論からの引用で私の議論を締めくくりましょう:「Gentooをベースイメージとして使用したいのですが、イメージが構築されたら、1GBを超えるPortageツリーデータをどのレイヤーにも入れたくありません。あなたはインストール中に巨大なポーテージツリーがイメージに表示されなければならないのでなければ、いくつかの素晴らしいコンパクトコンテナーを用意できます。「はい、wgetまたはcurlを使用して必要なものをダウンロードできますが、移植性を考慮しただけで、Gentooベースイメージをビルドするたびに1 GBを超えるPortageツリーをダウンロードする必要があるという事実は、効率的でもユーザーフレンドリーでもありません。さらにさらに、パッケージリポジトリは常に/ usr / portageの下にあるため、Gentooの下では常に移植可能です。繰り返しますが、私はこの決定を尊重しますが、当面の失望を表明させてください。


元の質問の詳細:

から

ボリュームを介してディレクトリを共有する
http://docker.readthedocs.org/en/v0.7.3/use/working_with_volumes/

データボリューム機能は「Docker Remote APIのバージョン1以降で利用可能になっている」とあります。私のドッカーはバージョン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"]

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

$ 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

どうやら現在の機能リクエスト(実装を期待しているわけではないが念のため
Jesse Glick

確かに、ビルド中にホストディレクトリとコンテナディレクトリをリンクすることは許されるべきではない、というような広範な議論がありますVOLUME ~/host_dir ~/container_dir。議論はかなり広範で、その理由は何であるかを要約する短い方法がありますか?
チャーリーパーカー

回答:


34

まず、「なぜ動かないのVOLUME?」と答える。あなたが定義する場合VOLUMEDockerfileで、あなただけの対象ではなく、ボリュームのソースを定義することができます。ビルド中、これから匿名ボリュームのみを取得します。その匿名ボリュームは、すべてのRUNコマンドでマウントされ、イメージのコンテンツが事前に入力され、コマンドの最後で破棄されRUNます。コンテナへの変更のみが保存され、ボリュームへの変更は保存されません。


この質問が行われたため、役立つ可能性のあるいくつかの機能がリリースされました。1つはマルチステージビルドで、非効率的なディスクスペースの最初のステージを構築し、必要な出力だけを出荷する最終ステージにコピーできます。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に試験運用を終了します。これは、フロントエンドパーサーを変更する機能を含む、ビルドプロセスの完全な再設計です。これらのパーサーの変更の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構文を使用して、ビルドコンテキストからマウント読み取り専用ディレクトリをバインドすることもできます。フォルダーはビルドコンテキストに存在する必要があり、ホストまたはビルドクライアントにマップされません。

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

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

マウントフラグがサポートされていないというエラーが表示された場合は、上記の変数でビルドキットを有効にしていないか、以前にDockerfileの上部にある構文行で実験的な構文を有効にしていないことを示していますコメントを含むその他の行。ビルドキットを切り替える変数は、Dockerのインストールにビルドキットサポートが組み込まれている場合にのみ機能することに注意してください。クライアントとサーバーの両方で、Dockerのバージョン18.09以降が必要です。


2
残念ながら、WindowsのBuildkitはバージョン18.09ではまだサポートされていません
Wesley

1
「armhf」は「mount」もサポートしていないようです。
Mike

2
OSXで「デーモンからのエラー応答:Dockerfile解析エラー行xx:不明なフラグ:マウント」を
取得しています

1
docker-composeのサポートはまだありませんが、イメージを構築するためにcomposeは必要ありません。追跡する問題:github.com/moby/buildkit/issues/685
BMitch


116

このVOLUME命令を使用してdockerにをマウントするを指示することはできません。これは移植性を大幅に損なうことになります。この命令は、これらのディレクトリ内のコンテンツは画像に含まれず、--volumes-fromコマンドラインパラメーターを使用して他のコンテナーからアクセスできることをdockerに伝えます。-v /path/on/host:/path/in/containerホストからディレクトリにアクセスするには、を使用してコンテナを実行する必要があります。

ビルド中にホストボリュームをマウントすることはできません。特権ビルドはなく、ホストをマウントすると移植性が大幅に低下します。wgetまたはcurlを使用して、ビルドに必要なものをすべてダウンロードし、配置することをお勧めします。


2
ありがとう。質問が修正されました。私が解決したい実際の問題は、ビルド中にDockerfileのドッカーコンテナーにホストボリュームをマウントする方法です。どうも。
xpt 2014

2
ありえない。改訂された回答を参照してください。
Andreas Steffan 2014

3
移植性に対する「潜在的な」悪影響を認めることはできますが、このオプションを使用する有効な使用例もあります。私の場合、$(PWD)をいくつかのコンテナーディレクトリにマウントして、「ディレクトリに移動して 'docker run'コマンドを実行する」ようにユーザーに指示できるようにしたいと思います。$(PWD)により、移植性が維持されます。これありふれたケースかもしれませんが、ユーザー提供のスクリプトのランタイム環境をどこに配布するかを非常に助けます。
ntwrkguru 2016

64

更新:誰かが答えを受け入れないだけで、私は特にこの特定の質問に対して非常に気に入っています。

良いニュース、今、方法があります-

解決策はロッカーです:https : //github.com/grammarly/rocker

ジョン・ヤニは言った「IMO、それは開発に適して、Dockerfileのすべての弱点を解決します。」

ロッカー

https://github.com/grammarly/rocker

新しいコマンドを導入することにより、Rockerは、プレーンなDockerで苦痛な次の使用例を解決することを目指しています。

  1. ビルド段階で再利用可能なボリュームをマウントし、依存関係管理ツールがビルド間でキャッシュを使用できるようにします。
  2. 生成されたイメージにそれらを残さずに、ビルドとsshキーを共有します(プライベートリポジトリをプルするためなど)。
  3. 異なるイメージでアプリケーションをビルドして実行し、1つのイメージから別のイメージにアーティファクトを簡単に渡すことができます。理想的には、このロジックを単一のDockerfileに含めます。
  4. Dockerfilesから直接タグ/プッシュ画像。
  5. シェルビルドコマンドから変数を渡して、Dockerfileに代入できるようにします。

もっと。これらは、GrammarlyでのDockerの採用を妨げていた最も重要な問題です。

更新:Githubの公式プロジェクトリポジトリにより、ロッカーは廃止されました

2018年の初めの時点で、コンテナープロジェクトのエコシステムは、このプロジェクトが開始された3年前よりもはるかに成熟しています。現在、ロッカーの重要で優れた機能の一部は、Dockerビルドまたは他の十分にサポートされているツールで簡単にカバーできますが、一部の機能はロッカーに固有のままです。詳細については、https://github.com/grammarly/rocker/issues/199を参照してください。


Rockerを使用して問題1を解決しようとしていますが、mountコマンドが機能せず、作成されたイメージにホストフォルダーが含まれていません。私のDockerfileマウントコマンドはこのように見えます- MOUNT ~/code/docker-app-dev/new-editor/:/src/そして、私のRockerビルドコマンドはこれです- rocker build -f Dockerfile .。私は何を間違えていますか?
Yaron Idan 2016年

たぶん実際のホストパスを試してみませんか?~ボーンシェルのメタキャラクターです。
Jesse Glick

Rocker build許可されていませんdocker runので、現在のようなものを許可しない、コマンドラインオプションを--privileged
Monty Wild

こんにちは@xpt、ロッカーが廃止されたため、別のアップデートを入手できますか
Shardj

ロッカーが廃止されたので、答えを「不可能」に戻します。OPと選択された回答を参照してください。
xpt

14

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

テクニックは、使用したいベースからコンテナー作成し-vオプションでコンテナーにボリュームをマウント)、シェルスクリプトを実行してイメージのビルド作業を行い、完了したらコンテナーをイメージとしてコミットすることです。

これにより、不要な過剰なファイルが除外されるだけでなく(SSHファイルなどの安全なファイルにも適しています)、単一のイメージも作成されます。これには欠点があります。commitコマンドはDockerfileのすべての命令をサポートしておらず、ビルドスクリプトを編集する必要がある場合は、中断したときにそれを選択することはできません。

更新:

例えば、

CONTAINER_ID=$(docker run -dit ubuntu:16.04)
docker cp build.sh $CONTAINER_ID:/build.sh
docker exec -t $CONTAINER_ID /bin/sh -c '/bin/sh /build.sh'
docker commit $CONTAINER_ID $REPO:$TAG
docker stop $CONTAINER_ID

6
+1 2番目の段落の手順についてもう少し詳しく説明してください。たとえば、ベースがdebian:wheezyで、シェルスクリプトがのbuild.sh場合、どのような特定の命令を使用しますか?
Drux

6

コンテナを実行すると、ホスト上のディレクトリが作成され、コンテナにマウントされます。これがどのディレクトリにあるかを見つけることができます

$ docker inspect --format "{{ .Volumes }}" <ID>
map[/export:/var/lib/docker/vfs/dir/<VOLUME ID...>]

コンテナー内のホストからディレクトリをマウントする場合は、-vパラメーターを使用してディレクトリを指定する必要があります。あなたの場合、これは次のようになります:

docker run -v /export:/export data

そのため、コンテナー内のhostsフォルダーを使用します。


1
ありがとう。質問が修正されました。私が解決したい実際の問題は、ビルド中にDockerfileのドッカーコンテナーにホストボリュームをマウントする方法です。どうも。
xpt 2014

このような抜本的な方法で質問を修正しないでください。これにより、編集前の質問は完全に有効でしたが、私の質問は無効になります。代わりに新しい質問をすることを検討してください。
Behe、2015年

11
元の質問DockerfileでVOLUME命令を使用するにはどうすればよいですか?それは今日でもまだ質問の最初にあります。あなたの答えはランタイムに関するものでしたが、私の質問は常にDockerfileの目的であるビルド時間に関するものでした。
xpt

4

dockerコンテナー内で実行されるdockerコマンドを介してビルドを実行することで、やりたいことを実行できると思います。参照してくださいドッカーは今ドッカー内で実行することができます| Dockerブログ。このような手法ですが、実際にはコンテナーを使用して外部のDockerにアクセスする手法が使用されました。Xebiaブログ

もう1つの関連記事は、Dockerイメージの最適化です。CenturyLink Labsは、ビルド中にデータをダウンロードすることになった場合、ダウンロードをすべて1つのRUNステップでダウンロード、ビルド、および削除することにより、最終的なイメージでスペースが無駄になるのを回避できることを説明しています。


3

それは醜いですが、私はこのように似ています:

Dockerfile:

FROM foo
COPY ./m2/ /root/.m2
RUN stuff

imageBuild.sh:

docker build . -t barImage
container="$(docker run -d barImage)"
rm -rf ./m2
docker cp "$container:/root/.m2" ./m2
docker rm -f "$container"

ユニバースを/root/.m2にダウンロードするJavaビルドがあり、毎回ダウンロードしました。 imageBuild.shビルド後にそのフォルダーのコンテンツをホストにDockerfileコピーし、次のビルドのためにそれらをイメージにコピーして戻します。

これは、ボリュームがどのように機能するかのようなものです(つまり、ビルド間で持続します)。


これは、Dockerベースの継続的インテグレーション、別名CIの実行可能なソリューションです。ライブラリーとコンパイラーをセットアップし、Dockerfileコマンドを介してmakeを実行し、コンテナーを作成するためだけにイメージを簡単に起動し、最後に.debのような目的のアーティファクトをコピーします。これを投稿してくれてありがとう。
chrisinmtown

このソリューションでは、すべてのファイルが./m2/にあるイメージ(必要なファイルと不要なファイル)が残ります。これにより、巨大なプロダクションイメージが生成される可能性がありますが、これは望ましくありません。外部の依存関係ディレクトリにマウントすると、必要なファイルのみがイメージにコピーされます。
Marko Krajnc

画像を公開するつもりなら、おそらく待つだけで、Mavenに毎回独自の依存関係を新たにダウンロードさせるのが最善です。このハックは、テスト対象のイメージをステージングする場合にのみ意味があります。エンドユーザーが決して接触することのないイメージです。
MatrixManAtYrService

1

これは、ビルドとコミットを使用する2ステップアプローチの簡略化バージョンで、シェルスクリプトはありません。それには以下が含まれます:

  1. ボリュームなしで部分的にイメージを構築する
  2. ボリュームでコンテナ実行し、変更を加えて結果をコミットし、元のイメージ名を置き換えます。

比較的小さな変更で、追加のステップはビルド時間にほんの数秒しか追加しません。

基本的に:

docker build -t image-name . # your normal docker build

# Now run a command in a throwaway container that uses volumes and makes changes:
docker run -v /some:/volume --name temp-container image-name /some/post-configure/command

# Replace the original image with the result:
# (reverting CMD to whatever it was, otherwise it will be set to /some/post-configure/command)   
docker commit --change="CMD bash" temp-container image-name 

# Delete the temporary container:
docker rm temp-container

私のユースケースでは、maven toolchains.xmlファイルを事前に生成したいのですが、JDKの多くのインストールは、実行時まで利用できないボリューム上にあります。一部のイメージはすべてのJDKSと互換性がないため、ビルド時に互換性をテストし、toolchains.xmlを条件付きで入力する必要があります。イメージを移植可能にする必要はないことに注意してください。イメージをDocker Hubに公開するわけではありません。


1

多くの人がすでに回答しているように、ビルド中にホストボリュームをマウントすることはできません。私はdocker-compose方法を追加したいだけです、主に開発/テストの使用のために持っているのはいいことだと思います

Dockerfile

FROM node:10
WORKDIR /app
COPY . .
RUN npm ci
CMD sleep 999999999

docker-compose.yml

version: '3'
services:
  test-service:
    image: test/image
    build:
      context: .
      dockerfile: Dockerfile
    container_name: test
    volumes:
      - ./export:/app/export
      - ./build:/app/build

そしてあなたのコンテナを docker-compose up -d --build

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.