pyてよn日記

一寸先は闇が人生

Docker の全体像を理解する

 Docker のシステムの全体像を理解するためにまとめてみた.

イメージ,コンテナ

 まず,Docker を利用する上で中心となる「イメージ」,「コンテナ」の意味を確認する.

  • イメージ image
    • 意味
      ファイルシステムのこと.依存関係のあるソフトウェアを含め,1 つのアプリケーションの実行に必要な全てのファイルを含んでいる(以下参照).
    • イメージ(「ふわっとした理解をする」方の「イメージ」です)
      ファイルシステム全体の状態を保存したスナップショットのようなものであり,OS(ファイルシステム),アプリケーション,内部のデータまで全ての状態が記録されているのがイメージである.
    • 実体
      複数のレイヤー(ファイルの実体やメタ情報を含んだバイナリファイル.親子関係がある.)の集合体.Read Only で書き込みはできない.Dockerfile はレイヤーを順に構成するための命令が書かれた手順書である.
    • イメージに含まれるファイル
      • アプリケーションのソースコード
      • バイナリ
      • ランタイム
      • 依存関係のあるソフトウェア(ファイル,ライブラリなど)
      • その他必要とされるファイルシステム

 

  • コンテナ container
    • 意味
      イメージ(ファイルシステム)に基づき,システムから隔離された環境で実行される一連のプロセス.ホスト OS のカーネルの機能を使い,複数のルート・ファイルシステムを実行できる(一つのルートファイルシステムを実行したものがコンテナ).
    • イメージ
      簡単に言うと,イメージ(ファイルシステム)を動作させたもの.
    • 実体
      ファイルシステム(イメージ)を構成するレイヤーの一番下の階層から順に実行される(例えば,Debian を含むレイヤー -> Apache を含むレイヤー,といった順番).その実行されているもの(プロセス)がコンテナ.

 以下,ドキュメントのイメージ,コンテナの説明部分.

Fundamentally, a container is nothing but a running process, with some added encapsulation features applied to it in order to keep it isolated from the host and from other containers. One of the most important aspects of container isolation is that each container interacts with its own, private filesystem; this filesystem is provided by a Docker image. An image includes everything needed to run an application -- the code or binary, runtimes, dependencies, and any other filesystem objects required.

Docker の全体像を理解する

 Docker 自体はクライアント / サーバ の構成となっている.Docker Client から命令を送信し,Docker daemon がそれを処理する.

  • クライアント:Docker Client(以下,CLI
  • サーバ:Docker daemonbuilder とも呼ばれる)

 CLI はユーザと Docker daemon とのインタフェースに過ぎない.処理の主体は Docker daemon であり,以下の処理は全て Docker daemon が担う.

  • CLI からのコマンドを受け取る
  • Docker イメージ / コンテナに関する処理
  • ホスト OS のカーネルとのやりとり

 Docker の構成については以下の画像が参考になる.CLI からの命令が全て Docker daemon に送られているのが分かる.

https://geekflare.com/wp-content/uploads/2019/09/docker-architecture.png

https://geekflare.com/docker-architecture/ より引用

  • Docker daemon が担う主要な処理
    • docker build:Dockerfile に基づきイメージをビルド
    • docker pull:イメージをレジストリ(Docker Hub など)からホスト(ローカル)にダウンロード
    • docker run:イメージに基づきコンテナの生成・実行

イメージのビルドの流れ:CLI と Docker daemon

 Docker の全体像を理解したところで,イメージのビルドについてまとめる.Docker イメージのビルドの流れは以下のようになっている(補足として処理の主体を括弧で示した).

  1. CLICLIdocker build [PATH | URL] コマンドを実行
  2. CLI)指定した PATH or URLディレクトリ,サブディレクトリを再帰的に処理し,ビルドコンテキストを作成
  3. CLI to Docker daemon)ビルドコンテキストを Docker daemon に送信
  4. (Docker daemon)Dockerfile のパース,バリデーション(syntax error など)
  5. (Docker daemon)Dockerfile 内の命令を順に実行し,イメージをビルド

ビルドコンテキスト

 ビルドコンテキストを理解する.

  • ビルドコンテキスト build context
    PATH(or URL)で指定されたディレクトリのファイル全体のこと.指定したディレクトリ(or リポジトリ)のその時点での状態を表すため,「コンテキスト context」という言葉が使われる.docker build 実行時に CLI から Docker daemon に送信されるが,実際には tar で圧縮されて Docker daemon へ送信される.

ビルドコンテキストと .dockerignore ファイル

 Docker daemon に送るビルドコンテキストを作成する際に重要なのが .dockerignore である.

  • .dockerignore
    ビルドコンテキストに送信しないファイル名,ディレクトリ名のパターンを記述するためのテキストファイル..gitignore の Docker 版というイメージが一番わかりやすい.ビルドコンテキストのルートディレクトリに置くと docker build 実行時に CLI により参照される.

 docker build [PATH | URL] を実行した際,デフォルトでは指定したルートディレクトリ配下の全てのファイルがビルドコンテキストに含まれる.これは,プロジェクトが大きくなったり,容量の大きなファイルが存在する場合にビルドコンテキストの作成時間が大きくなることを意味する.

 そうなったときに,ビルドコンテキストの容量を出来る限り小さくするための設定を書いておくのが .dockerignore である.指定したルートディレクトリに .dockerignore を置くと,ビルドコンテキストを送信する前CLI がこのファイルに書かれたファイル名,ディレクトリ名のパターンを参照し,そのパターンに合致したファイルをビルドコンテキストに含めないようにしてくれる.

 例えば,node_modules(npm package),.venvPython virtual environment) などの容量の大きいディレクトリを .dockerignore に記述することでビルドコンテキストから除外できる.

 記述方法については以下を参照.

docs.docker.com

 ビルドコンテキストが送信されるまでの流れを以下に整理してみた..dockerignore に関連する処理は全て CLI が担う(括弧内は処理の主体).

  1. CLIdocker build [PATH | URL] の実行
  2. CLI)指定されたルートディレクトリの .dockerignore を参照し,ビルドコンテキストに含めないファイル,ディレクトリ名のパターンを正規表現として生成
  3. CLI)ビルドコンテキストに含めないファイルの検索,列挙
  4. CLI to Docker daemon)Docker daemon へビルドコンテキストを送信
  5. (Docker daemon)Dockerfile のパース,バリデーション,実行

注意:ビルドコンテキストと ADDCOPY

 Dockerfile のパースはクライアントサイド(docker build を実行した場所)ではなく,サーバーサイド(Docker daemon)で実行される.つまり,Dockerfile のパース,実行は全てのファイルがビルドコンテキストとして送信された後である

 よくある勘違いとして,「Dockerfile 内の ADDCOPY で指定されたファイルだけがビルドコンテキストとして送信される」というものがあるが(私だけかもしれないが),上記の理由によりこれは間違いである.ADDCOPY が実行されるのはビルドコンテキスト作成後であるから,もし送信したくないファイルがある場合は .dockerignore に記述して除外する必要がある.

 ビルドコンテキストの作成と .dockerignore に関する処理の流れを以下にまとめた(括弧内は処理の主体).

  1. CLI.dockerignore の読み込み,ビルドコンテキストの構築
  2. CLI to Docker daemon)Docker daemon へビルドコンテキストを送信
  3. (Docker daemon)Dockerfile のパース,実行(ADDCOPY でビルドコンテキストからイメージへファイルを追加)

Remember that the daemon could be running on a remote machine and that no parsing of the Dockerfile happens at the client side (where you’re running docker build). That means that all the files at PATH get sent, not just the ones listed to ADD in the Dockerfile.

The transfer of context from the local machine to the Docker daemon is what the docker client means when you see the “Sending build context” message.

補足:用語

  • プロセス process メモリ上で実行状態にあるプログラム

参考