Docker image build .
は、「Dockerfile」と「ビルドコンテキスト」から、イメージファイルを生成するコマンドであると言えます。
.
でDockerfileのあるディレクトリを指定していると以前の記事で解説しましたが、実際には、Docker Daemon
と呼ばれるDockerの処理を行う裏で実行されているプロセスに対して、指定したディレクトリ以下のファイル、フォルダを全てコピーして送信しています。
なぜ、こんなことをするかというと、Dockerの設計思想が深く関わっています。
Dockerはそのコンテナを動作させるデバイスが「ローカルでもリモートでもいいよう」に、ホストクラアント方式を採用しています。
その都合上、buildコマンドを実行すると、実際に処理をするDocker Daemon
に対して、指定したビルドコンテキストディレクトリ以下のフォルダ、ファイルをコピーして送信しています。
後述するCOPY命令
などでは実際にファイルをイメージに入れる必要があり、リモートにある可能性のあるDocker Daemon
にコピーを渡しておかないとファイルを見つけることができないからです。
コンテナ内で必ず使うようなファイルをイメージに事前にコピーすることができます。
(ホストOS上のソースファイルをイメージ内でコンパイルしたい時など)
当然イメージにコピーするのでそこから生成されるコンテナは全ては、build時にコピーしたファイルが含まれることになります。
残したくない場合は、build時に対象のファイルが使い終わったら削除すればいい
ホストOS上のファイルをイメージにコピーするには以下の命令を使用します。
COPY {追加元} {追加先}
追加元 : ローカルのパス
追加先 : コンテナ内のパス
また、以下の特徴もあります。
- ファイルはもちろん、ディレクトリごとのコピーも可能です。
- 追加元のディレクトリのパスの指定は、ビルドコンテキストとして指定したフォルダからの相対パスになる
- コピー先のコンテナ内に存在しないディレクトリを指定した場合でも、自動で生成される
例 : ホストOS上にあるtest.txtファイをイメージにコピーする
以下のディレクトリ構成を想定します。
DockerTest
├── project/ <---カレントディレクトリ
│ └── Dockerfile
└── test.txt
test.txt
はDockerTest/
にあり、DockerfileはDockerTest/project/
にあります。Dockerfileの内容は次のとおりです。
FROM ubuntu
COPY ../test.txt /test.txt
CMD ["cat", "/test.txt"]
この状態でビルドを試みます。
cd /home/user/project/
docker build -t test-image .
すると、次のエラーが発生します。
COPY failed: Forbidden path outside the build context: ../test.txt ()
これは、Docker Daemon
にファイルがコピーされていないため、デーモンがコピー対象のファイルを見つけられないことが原因です
このエラーは、COPY
命令でビルドコンテキストの外にある../test.txt
を指定しているためです。Dockerはビルドコンテキスト(docker build
コマンドを実行したディレクトリ)内のファイルしか参照できません。
test.txt
をビルドコンテキスト内に移動またはコピーすることで解決できます。
test.txt
をproject
ディレクトリにコピーします。
DockerTest
└── project/ <---カレントディレクトリ
└── Dockerfile
└── test.txt
- Dockerfileを修正します。
FROM ubuntu
COPY test.txt /test.txt
CMD ["cat", "/test.txt"]
- 再度ビルドを実行します。
docker build -t test-image .
- コンテナを実行して
test.txt
の内容を表示します。
docker run --rm test-image
これで、test.txt
の内容が正しく表示されます。
カレントディレクトリをDockerTest
に移動させて、
DockerTest <---カレントディレクトリ
├── project/
│ └── Dockerfile
└── test.txt
Dockerfileの場所を明示的に教えることでファイル構造は変えずにエラーなくイメージを生成することもできます。
docker image build .
に追加で-f {Dockerfileまでの相対パス}
を記述することで問題を解決できます。
docker image build -f ./project/Dockerfile .
Dockerの基本的な仕組みを理解していないとbuild時に何でここでエラーになるんだよというのが多発しような部分だと思います。
かといって、ビルドコンテキストを広げて何でもかんでもDocker Daemon
に送ってしまうのは無駄なことなので、必要最小限のファイルをどうすれば構造を崩さずにイメージを構築できるかを考えるのが大切かと思いました