1. 概要

一般に、Docker build コマンドは、Dockerイメージで使用できるファイルのソースを制限します。 ビルドコンテキストを指定します。これは、Dockerfileとそのすべての依存ファイルの両方を見つける必要があるルートです。

ただし、ファイルシステムのある部分のDockerfileを別の部分のファイルと一緒に使用したい場合があります。

この短いチュートリアルでは、この制限を克服するためのいくつかの方法と、それらの長所と短所を見ていきます。

2. Dockerビルドとそのコンテキスト

2.1. 従来のDockerビルド

例から始めましょう–1つのHTMLファイルとDockerfileを持つ単純なnginxアプリケーション。 ディレクトリ構造は次のとおりです。

projects
├ <some other projects>...
└── sample-site
       ├── html
       │    └── index.html
       └── Dockerfile

小さなDockerfileもあります。

FROM nginx:latest
COPY html/* /etc/nginx/html/

次に、このアプリケーションのイメージを作成するために、次のコマンドを実行してみましょう。

$ docker build -t sample-site:latest .

ここで、ビルドコンテキストは「。」を介して現在のディレクトリに設定されます。 口論。

Dockerfileをプロジェクトのルートディレクトリに保持するのが一般的な方法です。 このコマンドは、デフォルトで、Dockerfileがそこに存在することを想定しています。 画像に含めるすべてのファイルは、そのコンテキスト内のどこかに存在する必要があります。

2.2. より複雑なビルドシナリオ

従来のアプローチではうまくいかない場合があります。

たとえば、環境に基づいて異なるDockerまたはdocker-composeファイルがある場合があります。 または、開発とは別のアクティビティとしてコンテナを追加する場合もあります。

このような状況では、Docker関連のファイルを別のディレクトリに移動するのが理にかなっています。 同様に、場合によっては、イメージの構成ファイルをプロジェクトのルートディレクトリの外に保持することがあります。

残念ながら、Dockerは、セキュリティホールを開く可能性があるため、ファイルシステムの任意の部分からファイルを追加することを禁止しています。 ただし、いくつかの回避策があります。

  • より大きなコンテキストで構築して、必要なものすべてを含める
  • コンテキスト外にあるファイルを使用してベースイメージを作成してから、ベースイメージを拡張します
  • 必要なすべてのファイルをコピーして一時的なコンテキストを作成し、そこからイメージを構築します

それらを1つずつチェックしてみましょう。

3. より大きなコンテキストで構築する

Dockerfiledockerという名前の別のディレクトリに移動するとします。 また、標準の nginx 構成を、プロジェクトルートsample-siteの外部のconfigディレクトリにあるカスタム構成ファイルでオーバーライドします。 新しいディレクトリ構造は次のとおりです。

projects
├ <some other projects>...
├── sample-site
│      ├── html
│      │    └── index.html
│      └── docker
│           └── Dockerfile
└── config
      └── nginx.conf

この場合、以前のDockerfiledockerbuildコマンドも機能しなくなりました。 再び機能させるには、より大きなコンテキスト(プロジェクトディレクトリ)でビルドする必要があります。

3.1. Dockerfileを変更します

コンテキストが変更されたので、Dockerfileを変更する必要があります。

FROM nginx:latest
COPY sample-site/html/* /etc/nginx/html/
COPY config/nginx.conf /etc/nginx/nginx.conf

新しいコンテキストに関して、htmlディレクトリのパスを変更しました。 その場所からnginx.confも含まれています。

3.2. イメージを構築する

次に、 projects ディレクトリに移動し、コマンドを実行してイメージをビルドしましょう。

$ cd projects
$ docker build -f sample-site/docker/Dockerfile -t sample-site:latest .

ここでも、「。」を使用します。 コンテキストとして、projectsディレクトリからコマンドを実行しているため。 これにより、Dockerfilenginx.confの両方が現在のビルドコンテキスト内に移動します。 Dockerfile はコンテキストディレクトリのルートにないため、-fオプションを使用してパスを指定します。

このアプローチの問題は、Dockerクライアントがビルドコンテキストのコピー( projects ディレクトリ全体)をDockerデーモンに送信することです。 ディレクトリには、他の多くの無関係なファイルやディレクトリが含まれている場合があります。 そのため、Dockerが多くのリソースをスキャンする必要があり、ビルドプロセスが遅くなる可能性があります。

4. 外部ファイルを使用してベースイメージを作成する

もう1つの方法は、外部ファイルを使用してベースイメージを作成し、後でそれを拡張することです。 前の例と同じ構造を再利用します。

projects
├ <some other projects>...
├── sample-site
│      ├── html
│      │    └── index.html
│      └── docker
│           └── Dockerfile
└── config
       └── nginx.conf

4.1. ベース用にDockerfileを記述します

まず、次の設定でDockerfileを記述しましょう。

FROM nginx:latest
COPY nginx.conf /etc/nginx/nginx.conf

ファイルをprojects/configディレクトリに配置します。

4.2. ベースを構築する

次のステップは、 projects / config でビルドコマンドを実行して、ベースイメージを作成することです。

$ docker build -t sample-site-base:latest .

これで、 sample-site-base:latestというDocker イメージが作成され、nginxサーバーと構成ファイルが含まれています。

4.3. 子供用のDockerfileを作成します

次に、sample-siteDockerfileを記述して、sample-site-baseを拡張します。

FROM sample-site-base:latest
COPY html/* /etc/nginx/html/

4.4. 子供を作る

最後に、 projects / sample-site でコマンドを実行して、アプリケーションのイメージを作成しましょう。

$ docker build -f docker/Dockerfile -t sample-site:latest .

ここでは、Dockerビルドを2つの別々のステージに分割し、それぞれがプロジェクト内の異なるディレクトリツリーに関連しています。

このアプローチでは、Dockerfileの共通部分を子イメージ全体で再利用します。 この構造は、保守が比較的簡単です。 ベースイメージに変更がある場合は、子イメージを再構築する必要があり、同じ変更がすべてのイメージに反映されます。

このアプローチでは、最終的なDockerイメージのレイヤー数が増えることに注意してください。

5. 一時的なコンテキストを作成する

最後のオプションは、カスタマイズされた一時コンテキストを作成してイメージを構築することです。 これは、 docker build コマンドの周りにいくつかのスクリプトを使用して、必要なファイルをDockerに適したディレクトリ構造にプルします。

5.1. 一時ディレクトリを作成する

まず、一時ディレクトリを作成し、必要なすべてのアセットをコピーしましょう。

$ mkdir tmp-context
$ cp -R ../html tmp-context/
$ cp -R ../../config tmp-context/

これがビルドコンテキストになります。

5.2. Dockerfileを作成します

それでは、このコンテキストに関連するDockerfileを記述しましょう。

FROM nginx:latest
COPY html/* /etc/nginx/html/
COPY config/nginx.conf /etc/nginx/nginx.conf

必要なファイルはすでにtmp-contextに配置されているため、ここで外部パスについて言及する必要はありません。

5.3. イメージを構築する

コマンドを実行してイメージを作成してみましょう。

$ cd tmp-context
$ docker build -t sample-site:latest .

このコマンドは、ビルドコンテキストとしてtmp-contextを取ります。 ディレクトリ内で必要なものがすべて検出されるため、問題なくイメージが構築されます。

5.4. 掃除

最後に、一時ディレクトリをクリーンアップしましょう。

$ rm -rf tmp-context

これは、どこからでもDockerイメージにファイルを追加するための最もクリーンな方法です。 ここでは、コンテキストの作成方法を完全に制御できます。 プロセス全体を簡素化するために、上記のすべてのコマンドを使用してbashスクリプトを作成する場合があります。

ただし、一部のファイルは大きい場合があることを理解する必要があります。 コンテキストにコピーされるまでに長い時間がかかる可能性があります。これは、すべてのビルドで発生します。

6. 結論

この記事では、DockerがDockerfileと同じディレクトリ内のファイルからイメージを構築することを通常どのように期待するかを見ました。 通常のビルドコンテキストの外部からファイルを追加するためのいくつかのソリューションを検討しました。

また、各ソリューションの長所と短所についても説明しました。

いつものように、この記事に関連するサンプルコードは、GitHubから入手できます。