以下は私の「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
コンテナーを実行するときに を使用するのを忘れる人がいるかもしれないということです。コンテナーを削除することは覚えていても、ボリュームを削除することを忘れる人がいるかもしれません。さらに、人間の記憶力がどれほど優れていても、すべての匿名ボリュームのうちどれを安全に削除できるかを判断するのは困難な作業になるかもしれません。