DockerFile の「VOLUME」命令を理解する 質問する

DockerFile の「VOLUME」命令を理解する 質問する

以下は私の「Dockerfile」の内容です

FROM node:boron

# Create app directory
RUN mkdir -p /usr/src/app

# Change working dir to /usr/src/app
WORKDIR /usr/src/app

VOLUME . /usr/src/app

RUN npm install

EXPOSE 8080

CMD ["node" , "server" ]

このファイルでは、ホストの現在の作業ディレクトリの内容をコンテナのフォルダーVOLUME . /usr/src/appにマウントする命令を期待しています。/usr/src/app

これが正しい方法かどうか教えてください。

ベストアンサー1

一言で言えば、いいえ、あなたのVOLUME指示は正しくありません。

Dockerfile は、VOLUMEコンテナ側のパスを指定して 1 つ以上のボリュームを指定します。ただし、イメージ作成者がホスト パスを指定することはできません。ホスト側では、ボリュームは Docker ルート内に非常に長い ID のような名前で作成されます。私のマシンでは、これは です/var/lib/docker/volumes

注: 自動生成された名前は非常に長く、人間の観点からは意味をなさないため、これらのボリュームは「名前なし」または「匿名」と呼ばれることがよくあります。

'.' 文字を使用する例は、ドットを最初の引数にするか 2 番目の引数にするかに関係なく、私のマシンでは実行されません。次のエラー メッセージが表示されます。

docker: デーモンからのエラー応答: oci ランタイム エラー: container_linux.go:265: コンテナ プロセスの開始により「process_linux.go:368: コンテナの init により「open /dev/ptmx: そのようなファイルまたはディレクトリはありません」が発生しました」。

VOLUMEここまで述べてきたことは、理解しようとしている人にとってはおそらくあまり価値がなく、あなたが達成しようとしていることに対する解決策を提供していないことは承知してい-vます。したがって、次の例がこれらの問題にさらに光を当ててくれることを願っています。

ミニチュートリアル: ボリュームの指定

この Dockerfile があるとします:

FROM openjdk:8u131-jdk-alpine
VOLUME vol1 vol2

(このミニチュートリアルの結果では、vol1 vol2または を指定しても違いはありません/vol1 /vol2。これは、Dockerfile 内のデフォルトの作業ディレクトリが であるためです/)

構築する:

docker build -t my-openjdk

走る:

docker run --rm -it my-openjdk

コンテナ内でlsコマンド ラインを実行すると、/vol1と の2 つのディレクトリが存在することがわかります/vol2

コンテナを実行すると、ホスト側に 2 つのディレクトリ、つまり「ボリューム」も作成されます。

コンテナを実行中にホスト マシンdocker volume lsで実行すると、次のような表示になります (簡潔にするために、名前の中央部分を 3 つのドットに置き換えました)。

DRIVER    VOLUME NAME
local     c984...e4fc
local     f670...49f0

コンテナに戻り、実行しますtouch /vol1/weird-ass-file(指定された場所に空のファイルを作成します)。

このファイルは、現在、ホスト マシン上の名前のないボリュームの 1 つで使用できます (笑)。最初にリストされている最初のボリュームを試したため、2 回試行する必要がありましたが、最終的には、ホスト マシンで次のコマンドを使用して、リストされている 2 番目のボリュームでファイルを見つけることができました。

sudo ls /var/lib/docker/volumes/f670...49f0/_data

同様に、ホスト上でこのファイルを削除しようとすると、コンテナ内でも削除されます。

注:_dataフォルダーは「マウント ポイント」とも呼ばれます。

コンテナを終了し、ホスト上のボリュームを一覧表示します。ボリュームは消えています。--rmコンテナの実行時にフラグを使用しましたが、このオプションにより、終了時にコンテナだけでなくボリュームも効果的に消去されます。

新しいコンテナを実行しますが、次を使用してボリュームを指定します-v:

docker run --rm -it -v /vol3 my-openjdk

これにより3 番目のボリュームが追加され、システム全体に名前のないボリュームが 3 つ存在することになります。 のみを指定した場合、コマンドはクラッシュします-v vol3。引数はコンテナー内の絶対パスである必要があります。ホスト側では、新しい 3 番目のボリュームは匿名であり、 内の他の 2 つのボリュームと一緒に存在します。/var/lib/docker/volumes/

前に述べたように、 はDockerfileホスト パスにマップできないため、実行時にホストからコンテナーにファイルを取り込もうとするときに問題が生じます。-vこの問題は、別の構文で解決できます。

プロジェクト ディレクトリ内に、コンテナー内./srcで同期したいサブフォルダーがあるとします。次のコマンドで目的を達成できます。/src

docker run -it -v $(pwd)/src:/src my-openjdk

文字の両側には:絶対パスが必要です。左側はホスト マシン上の絶対パス、右側はコンテナー内の絶対パスです。は、pwd「現在のディレクトリ/作業ディレクトリを印刷する」コマンドです。コマンドを入力すると、$()括弧内のコマンドが取得され、サブシェルで実行され、プロジェクト ディレクトリへの絶対パスが返されます。

すべてをまとめると、./src/Hello.javaホスト マシン上のプロジェクト フォルダーに次の内容が含まれていると仮定します。

public class Hello {
    public static void main(String... ignored) {
        System.out.println("Hello, World!");
    }
}

この Dockerfile を構築します:

FROM openjdk:8u131-jdk-alpine
WORKDIR /src
ENTRYPOINT javac Hello.java && java Hello

次のコマンドを実行します:

docker run -v $(pwd)/src:/src my-openjdk

これは「Hello, World!」と出力します。

最も良い点は、イメージを再構築することなく、2 回目の実行で別の出力用に新しいメッセージで .java ファイルを自由に変更できることです =)

最後に

私は Docker をまったく使い慣れていないので、前述の「チュートリアル」は 3 日間のコマンド ライン ハッカソンで収集した情報を反映しています。自分の主張を裏付けるわかりやすい英語のようなドキュメントへのリンクを提供できなかったことを恥ずかしく思いますが、これはドキュメント不足によるもので、個人的な努力によるものではないと正直に思っています。現在のセットアップである「Windows 10 -> Vagrant 2.0.0 -> Docker 17.09.0-ce」を使用して、例が宣伝どおりに機能することはわかっています。

このチュートリアルでは、「Dockerfile でコンテナのパスを指定し、実行コマンドでホスト パスのみを指定する方法」という問題は解決されません。方法があるかもしれませんが、まだ見つけていません。

VOLUME最後に、 Dockerfile で を指定することは珍しいだけでなく、おそらく決して使用しないのがベストプラクティスであるという直感がありますVOLUME。その理由は 2 つあります。最初の理由は、すでに特定したとおりです。ホスト パスを指定できないことです。これは良いことです。Dockerfile はホスト マシンの詳細にあまり依存しないはずだからです。しかし、2 番目の理由は、--rmコンテナーを実行するときに を使用するのを忘れる人がいるかもしれないということです。コンテナーを削除することは覚えていても、ボリュームを削除することを忘れる人がいるかもしれません。さらに、人間の記憶力がどれほど優れていても、すべての匿名ボリュームのうちどれを安全に削除できるかを判断するのは困難な作業になるかもしれません。

おすすめ記事