web-dev-qa-db-ja.com

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

元の質問:DockerfileでVOLUME命令を使用する方法

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

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

最新のアップデート:

Docker v18.09より前のバージョンでは、正しい答えは次のとおりです。

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

しかし、それは不十分に述べられ、体系化され、支持された答えでした。私のdockerが再インストールされていたとき、私は偶然次の記事に出会いました:

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

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

別の方法は、新しく受け入れられた答え、例えばv18.09のBuildkitです。

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


でした: 解決策がありました - それはDockerからではありませんでした、しかし今そのロッカーは中止されています、私は再び"不可能"に答えを戻します。


古い更新: だから答えは「不可能」です。問題が https://github.com/docker/docker/issues/3156 で広く議論されていることを知っているので、私は答えとしてそれを受け入れることができます。移植性は、docker開発者にとって最も重要な問題です。しかし、dockerユーザーとしては、この欠けている機能にはとても失望しています。 「Gentooをベースイメージとして使いたいのですが、いったん> 1GB以上のPortageツリーデータをいったんイメージが構築された後は、どのレイヤーにも入れたくありません。巨大なPortageツリーがインストール中に画像に表示される必要がなかった場合は、いくつかのNice a compactコンテナを用意することができます。 "はい、wgetまたはcurlを使用して必要なものをダウンロードできます。 Gentooのベースイメージを構築するたびに> 1GBのPortageツリーをダウンロードすることを強制するだけで、移植性を考慮するだけでは効率的でもユーザーフレンドリーでもありません。さらに、パッケージリポジトリは常に/ usr/portageの下にあるので、Gentooの下では常に移植可能です。繰り返しになりますが、私はその決定を尊重しますが、その間も失望を表明してください。ありがとう。


元の質問 詳細:

から

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

データボリューム機能は「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"]

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
187
xpt

まず、「なぜVOLUMEが動かないのですか」と答えるために。 DockerfileでVOLUMEを定義するときは、ターゲットのみを定義でき、ボリュームのソースは定義できません。ビルド中に、あなたはこれから匿名のボリュームを取得するだけです。その無名ボリュームは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"]

その結果、結果のバイナリのみが含まれ、full/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構文を使えば、build-contextからmount read-onlyディレクトリをバインドすることもできます。フォルダはビルドコンテキスト内に存在している必要があり、ホストまたはビルドクライアントにはマップされません。

# 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付きのビルドキットを有効にする必要があります。

14
BMitch

Docker what にマウントするよう指示するためにVOLUME命令を使用することは不可能です。それは移植性を深刻に破るでしょう。この命令は、それらのディレクトリのコンテンツが画像には含まれず、--volumes-fromコマンドラインパラメータを使用して他のコンテナからアクセスできることをdockerに伝えます。ホストからディレクトリにアクセスするには、-v /path/on/Host:/path/in/containerを使用してコンテナを実行する必要があります。

ビルド中にホストボリュームをマウントすることはできません。特権的なビルドはありませんし、ホストをマウントすると移植性もひどく低下します。ビルドに必要なものは何でもダウンロードして適切な場所に配置するために、wgetまたはcurlを使用してみてください。

107
Andreas Steffan

更新:誰かが答えとしてnoをとらないであろう、そして私は非常に、特にこの特定の質問に対してそれを好む。

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

解決策はRockerです: https://github.com/grammarly/rocker

John Yani 言った 「IMO、Dockerfileのすべての弱点を解決し、開発に適したものにする」

ロッカー

https://github.com/grammarly/rocker

新しいコマンドを導入することで、Rockerは次のユースケースを解決することを目指しています。

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

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

アップデート:Githubの公式プロジェクトリポジトリによると、Rockerは廃止されました。

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

61
xpt

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

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

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

11
Keith Mason

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

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

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

docker run -v /export:/export data

つまり、コンテナ内のhostsフォルダを使用します。

5
Behe

私はあなた自身がdockerコンテナの中で実行されるdockerコマンドを介してビルドを実行することによってあなたがやりたいことができると思います。 DockerはDocker | Dockerブログ内で実行できるようになりました を参照してください。このような、しかし実際にはコンテナを使って外側のDockerにアクセスする手法が使用されました。たとえば、{ 最小のDockerコンテナを作成する| Xebia Blog の作成方法を探るときなどです。

もう1つの関連記事は Dockerイメージの最適化| CenturyLinkラボ です。これは、ビルド中にファイルをダウンロードすることになった場合、ファイルをダウンロード、ビルド、削除することによって最終イメージで無駄にスペースが消費されるのを防ぐためです。 1回のRUNステップですべてダウンロードできます。

4
nealmcb

それは醜いです、しかし私はこんな感じでこんな風になりました:

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はそれらを次のビルドのためにイメージにコピーします。

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

シェルスクリプトを使用せずに、ビルドとコミットを使用する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を条件付きで設定する必要があります。画像をポータブルにする必要はありません。DockerHubに公開するわけではありません。

0
Akom