Docker

**Docker**（ドッカー）は、コンテナ仮想化を用いてアプリケーションを開発・配置・実行するためのオープンプラットフォームである。

Dockerはコンテナ仮想化を用いたOSレベルの仮想化によりアプリケーションを開発・実行環境から隔離し、アプリケーションの素早い提供を可能にする。かつその環境自体をアプリケーションと同じようにコード（イメージ）として管理可能にする。Dockerを開発・テスト・デプロイに用いることで「コードを書く」と「コードが製品として実行される」間の時間的ギャップを大きく短縮できる。

## 概要
アプリケーションソフトウェアは開発環境でコーディングされ、テスト環境で動作確認され、ステージング環境にデプロイされ、本番環境でサービス提供をおこない、開発環境でデバッグされる。ソフトウェア開発ではただアプリケーションのコードを書くのではなく、上記すべての環境整備と環境へのアプリケーションデプロイを行う必要がある。かつ複数人による開発では上記すべてを全員で一貫性をもって共有しなければならない。

これらを達成するには様々な状況（動作OS、既存環境）へ同一の環境とアプリケーションをできるだけ低コストで届ける必要がある。動作OS（ホストOS）や既存環境からの隔離手法にはOSレベルの仮想化があり、その一種にカーネルをホストと共有しプロセス・ファイルシステムを隔離する**コンテナ仮想化**がある。環境をアプリケーションごとコンテナへ隔離しコンテナのイメージファイルを配布することで、ランタイムが用意されたあらゆる状況へ同一環境・同一アプリケーションを配備できる。

**Docker**はこのコンテナ仮想化を核としたアプリケーションのためのオープンプラットフォームである。環境およびアプリケーションを**Dockerイメージ**としてバンドルし、Dockerエンジンにより**Dockerコンテナ**として配備・実行できる。Linux・Windows・Macすべてに対応したDockerエンジンは開発・テスト・本番・デバッグなど様々な状況で容易かつ高速なアプリケーション配備・実行を可能にする。またDockerイメージの**レジストリ**登録・Dockerイメージに基づいた派生イメージ生成・差分管理による派生イメージの低容量化により、容易な独自イメージ生成と高速/低負荷なコンテナ生成が可能になる。かつ標準仕様化を含むDockerソフトウェアのコンポーネント化により、コンテナ仮想化レベル自体の制御を含む独自コンテナ仮想化システムが構築可能になっている。このようにDockerは広範な**アプリケーション開発のためのプラットフォーム**として現在では機能している。

Dockerがもたらす環境/アプリケーション展開の効率化は継続的インテグレーション（CI）・継続的デプロイ（CD）によるサービス提供の高頻度化をさらに加速させた。またクラウドコンピューティングが提供するマネージドサービスと展開コンテナ数調整によってサービスのスケーリングは容易になり、サービスの柔軟性やコスト構造にも影響を及ぼしている。このようにDockerの採用はアプリケーション開発・運用、それが生み出すビジネスまで影響を与えている。

## 主な利点
### 資源の効率化
一台のサーバ上に複数の仮想マシンを動作させてそれぞれにオペレーティングシステム (OS) を走らせる仮想化技術は従来から存在していた。例えば、ハイパーバイザ型のVMWareやHyper-Vやホスト型のVirtualBox等である。仮想化の本来の目的は、一台のハードウエア内でなるべく多くのサーバ用アプリケーションを実行する事であるが、上記の方式の仮想化では仮想環境毎にOSの全体をインストールする必要があり、目的のアプリケーションにとっては必要のないサービスやファイルまでが含まれていた。これは資源(resource)の浪費であり、できることならば仮想環境内にはアプリケーションとは無関係のライブラリやデータは置かずに共有にする事が望ましかった。これを実現するのがコンテナ型の仮想化である。実際にDockerは、ホストOSのカーネルを共有する。それぞれの仮想環境は**Dockerコンテナ**と呼ばれ、各コンテナは一台のサーバ上で隔離された形で動作し、複数のインスタンスが並行して動く。

### アプリ実行環境構築の容易さ
一般にアプリケーションを開発もしくは動作させるまでには、設定ファイルの編集や必要なライブラリのインストール等、本来の目的には関係のない煩雑な作業が必要である。Dockerはアプリケーションとライブラリを同一のコンテナ内に固めてしまう。一度固めたコンテナは軽量であるため移動が容易であり、比較的どの環境でも素早く目的のアプリケーションを動作させる事が可能である。これをDocker社は、**Build, Ship, and Run Any App, Anywhere** と表現している。Docker DesktopによりコンテナはWindows、MacOSのどちらでも機能し可搬性が高い。

### 廃棄の容易さ
複雑なシステムでは設定を一度間違えるとその影響が及ぶ範囲の特定と元に戻すことに多くの時間がかかる可能性がある。Dockerではこのような元に戻しがたいシステムのイメージはただちに削除すれば良く、段階的にイメージをバックアップしておけば設定を間違えた前の状態に戻ることが容易である。そのようなことを行う際に、上記の資源効率の良さと構築の容易さが効果を発揮する。

## 利用

### アプリケーション開発環境
Dockerコンテナはアプリケーション開発環境に利用できる（*Developing inside a Container* ）。

コンテナは外部と**隔離**されている。ゆえに開発環境のセットアップが既存環境を破壊する、あるいは既存環境が開発環境へ予期せぬ影響を与える可能性がない。このようにアプリケーション開発用のサンドボックスとしてDockerコンテナを利用できる（**development container**）。

またコンテナはイメージから生成されるため**配布**することが可能である。ゆえに複数の開発者がそれぞれ開発環境を用意せずとも、配布されたイメージからコンテナを生成するだけで開発環境が利用できる。開発環境を破壊した場合でもそのコンテナを破棄し配布イメージから再生成することですみやかな開発環境の修正が可能である。

コンテナがもつ**可搬性**によりホストに依存しない一貫した開発が可能になる。コンテナはDockerのランタイム上で動作するためホスト側のOSや設定に影響を受けず、同一イメージからWindowsユーザーもLinuxユーザーも開発環境コンテナを利用できる。

開発コンテナには複数種類の利用方法がある。

* 全てをコンテナ内で完結: コンテナ上のターミナルでコンテナ内のコードを編集
* volumeマウントを利用: ホスト上のコードをコンテナのvolumeへマウントし、コード編集はホスト・実行とその環境はコンテナ
* ホスト-コンテナ間連携: コンテナ内のエディタサーバを通じてホストのエディタUIからコンテナ内コードを操作・実行

などがある。すべてをコンテナ内で完結させればホストはDockerのみで動作する。volumeマウントは実行環境の隔離に近い。ホスト-コンテナ連携をした場合、ホストはDockerとエディタのみに依存する。

### コンテナ化されたアプリケーション
Dockerコンテナはアプリケーションとその実行環境を組み合わせた一体のものとして利用できる（*containerized application*, *Container Deployed Applications*）。

Dockerイメージはファイルシステムと実行時設定を併せたものである（参考: Open Container Initiative#OCI Image)。アプリケーションおよび実行に必要なソフトウェアさらに実行時の設定が含まれているDockerイメージを基にしてコンテナを生成すると、コンテナを起動すれば直ちにアプリケーションとして機能する。このことからDockerコンテナはすべてのDocker環境上でそのまま動作するアプリケーションとして配布ができる。

Dockerイメージは**配布**することができ、かつ環境によらずに機能する**可搬性**を持つため、アプリケーションをDockerコンテナとして作成すれば、テスト・ステージング・本番のそれぞれの環境に依らない頒布が容易におこなえる。

## 評価
Dockerがもたらす環境/アプリケーション展開の効率化は開発から運用まで幅広い領域に大きな影響を与えている。

Dockerイメージ生成による環境生成はOS・ミドルウェアレベルのInfrastructure as Code（IaC）であり、高速/低負荷なコンテナ生成/破棄は実利用可能なImmutable Infrastructureとみなせる。これら高効率な環境展開はテスト・ビルド等の継続的インテグレーション（CI）・サービス提供まで含む継続的デプロイ（CD）をより容易にした。クラウドコンピューティングサービスがDockerコンテナ実行マネージドサービスを提供し始めたことで、開発者はローカルに作成したDockerイメージをクラウド上へホストを意識せず展開可能になった。生成/破棄が容易なコンテナをホストを意識せず利用できるマネージドサービスでデプロイすることで、アプリケーション運用者は展開コンテナ数調整による容易かつ柔軟なアプリケーションのスケーリングが可能になった。コンテナ仮想化による運用が広まるにつれてコンテナ連携によるサービス提供、すなわちマイクロサービスアーキテクチャのDockerコンテナ群による実装が構想され、コンテナ連携を指揮するコンテナオーケストレーションソフトウェアおよびそのマネージドサービスが実利用され始めている。このようにDockerはプラットフォームとしてアプリケーション開発とビジネスへ影響を与えている。

Dockerのコンテナー管理の手軽さやインスタンス操作の高速性は、クラウドサービスやビッグデータ基盤などを管理するためのIT基盤として高く評価され、2014年12月日経BP社より「ITインフラテクノロジーAWARD 2015」グランプリに選出されている。

2014年、GoogleはDockerではないが、コンテナ型仮想技術Kubernetesを利用しており、毎週20億個のコンテナを自社サービスのために起動していると発表した。

## 技術的な特徴

### コンテナ仮想化
ホストカーネルを直接利用しながらプロセス・ファイルシステムを隔離する**コンテナ仮想化**を提供する。仮想化はGo言語で実装されたソフトウェア libcontainer によって行われる。古いDocker実装ではLXCが利用されていた。

### 差分管理
コンテナのファイルシステムはいくつかのドライバによって提供される。現在推奨されるoverlay2およびかつて推奨されていたAufsでは、Dockerコンテナ内に作成されたファイルが元のDockerイメージ (雛形) の差分として蓄えられる。差分しかディスク容量を消費しないので、より少ないリソースでコンテナを作成し実行する事が可能である。このことが他の仮想化手法と比較して容易かつ高速な仮想化環境の生成/破棄を可能にしている。なお当初はaufsのみのサポートだったが、その後btrfs、Device Mapper、OverlayFS、vfs、ZFSが選択可能となっている。

### Dockerfile
DockerではDockerfileからコンテナイメージを生成できる。

DockerではDocker imageがインスタンス化されコンテナとして動作する。imageの実体はJSONファイルおよびファイルシステムの.tarであり（c.f. OCI Image) 手動で記述・生成できる。DockerはDockerfileと呼ばれる設定ファイルからコンテナイメージファイルを作成（build）する機能を提供している。

### 標準仕様
DockerコンテナはOpen Container Initiativeが策定したOCI RuntimeおよびOCI Image Format仕様の下敷きになっており、現在のDockerコンテナはOCIに準拠している。OCIへの準拠によりOCI Runtimeを実装する任意のランタイムを利用することができるため、セキュリティを重視したランタイムや速度を重視したランタイムに切り替えることが可能である。

### 永続化
Dockerは揮発性のコンテナに対して永続化可能なストレージを提供している。そのマウントは実装方法により以下に分類される。

* Volumes: ホストのファイルシステム内で*Dockerが管理する*領域に保存される。推奨されるマウントタイプ
* Bind mounts: ホストの任意の場所に保存される。Docker以外のホストプロセスも操作しうる
* `tmpfs` mounts: ホストのメモリ上に保存される（ホストで揮発性）

### ネットワーク
Dockerはネットワーク隔離されたコンテナ同士を繋ぐネットワーキング機能を持つ。

Dockerコンテナはを利用してコンテナをホストのネットワークから隔離している。そのためネットワーク設定をnoneにした場合、外部からのネットワークアクセスができない。これは隔離環境という意味では理想的だが、コンテナ間の協調による機能提供ができない。そこでDockerエンジンはネットワークドライバーによるネットワークの提供を行っている。

主に用いられるドライバはbridgeである。ユーザー定義bridgeネットワークは所属コンテナへのIPアドレス提供とコンテナ名によるドメイン名解決 (*automatic service discovery*) を提供する。また`--alias` オプションを利用することで1つのドメイン名に複数のコンテナを紐づけることができ、DNSラウンドロビンが可能である。

### コンテナ連携
DockerはCompose (`docker-compose`) による複数コンテナの実行・連携を提供する。`docker-compose.yml` でコンテナセット・ネットワークを定義することで、単一のホストマシン上にコンテナ群をデプロイできる。さらにDocker Swarmを用いることでマルチホスト環境へのデプロイも可能になる。

### ロギング
Dockerはコンテナで発生したデータログ/サーバログを処理する機能（ロギング機能）を提供している。Docker Daemonはデフォルトでコンテナのstdout/stderrを捕捉しており、`docker logs` コマンドでログを表示できる。ロギングはカスタム可能な**logging driver**として実装されており、logging driver pluginsを用いれば独自実装も可能である。デフォルトのlogging driverは`json-file`であり、他には`[[syslog]]`や`fluentd`、特定クラウドプロバイダに特化した`awslogs`や`gcplogs`などが存在する。

`fluentd`logging driverはコンテナログをデータコレクタであるFluentdへ転送する。デフォルトではTCPで`localhost:24224`へ送信するが、オプションにより他のTCPポートあるいはUNIXドメインソケットへ送信が可能である。fluentdデーモンはホストマシン上のプロセス、あるいはポートマッピングをおこなったコンテナとして機能させる。

### 欠点

#### ホストLinuxカーネルとの関係
コンテナ仮想化はコンテナ内部からホストカーネルを直接利用するため、エッジケースではホストカーネルのバージョンとDockerに依存した問題が発生する（以下の内容は他の仮想化手法でも類似した形で存在する）。

Dockerイメージは主としてLinuxディストリビューションイメージ、例えばUbuntuイメージを基にして作成されている。ところでLinuxディストリビューションは特定バージョンのLinuxカーネルを含んでいる。例えばUbuntu 18.04.4LTSはv5.3を、Debian 10はv4.19を含んでいる。ゆえにあるDockerイメージがUbuntu 18.04LTS**イメージ**を基にしている場合一見するとカーネルはv5.3かと思うが、コンテナ仮想化はホストカーネルを利用するためDebian10ホスト上でDockerを動作した場合は動作カーネルはv4.19である。またDockerもkernel v4.19上で動作している。

コンテナ仮想化が持つ上記の特性から、いくつかの注意点・欠点がある。

まず異なるホストOSを利用した際の可搬性である。Dockerコンテナは高い可搬性が特徴だが、異なるホストOS例えばUbuntuホストとDebianホストで同一コンテナを動作させた際、カーネルバージョンに違いに起因するコンテナ間で一貫しない動作のリスクが存在する。例えばDebian 8ホストでは発生したカーネル由来のバグがDebian 9ホスト上では修正されて発生しない可能性がある。

また新しいバージョンのLinuxカーネルに依存したイメージが古いLinuxカーネルのホスト上で動かないという問題がある。Ubuntu 18.04.4LTSイメージ（ディストリビューションのカーネルはv5.3）上に構築したアプリケーションがDebian 10（Kernel v4.19）に存在しないカーネル機能を利用していた場合、Debian10ホスト上でこのコンテナを実行すると存在しないカーネル機能を利用しようとしてエラーを起こしてしまう。Linuxカーネルの非常に高い後方互換性から、逆のパターンすなわち古い機能が新しいカーネルのホスト上で動かないパターンは非常にまれと考えられる。

またホストカーネルバージョンとDockerエンジンバージョンの組み合わせによるバグもある。カーネルパニックをおこすエッジケースも存在 https://github.com/moby/moby/issues/13940https://github.com/kubernetes/kubernetes/issues/23253https://github.com/moby/moby/issues/29397 している（あらゆる仮想化はホストと仮想化エンジンの不整合リスクを抱えている）。

## エコシステム
### オーケストレーション
実際のアプリの動作は複数のコンテナ同士が協調し合う事が多いとされる。このため多数のコンテナを自動的に管理する (オーケストレートする) ソフトウエアが必要となる。KubernetesやDocker Swarmは当該機能を提供する。

Docker社は、2018年1月KubernetesをDockerに統合したバージョンのベータ版を提供し始めた。

### イメージレジストリ
Docker Imageはレジストリを利用した公開・共有が可能である。公開されたイメージは`docker pull`コマンドにより取得されコンテナ化できる。広く利用できるレジストリの存在により、Dockerfileを用いたイメージ生成の際にレジストリへ登録されたイメージをベースイメージとすることが可能となっている。`docker pull`はURL-likeなイメージ識別子（URLからプロトコル名を除いたもの。例:`quay.io/assemblyline/ubuntu`）を受け入れるため様々なレジストリを利用できる。

#### Docker Hub
Docker Hubは`docker pull`がデフォルトで利用する公開レジストリである。2014年にDockerコンテナの共有サービスの場として発表された。DockerHubのイメージを利用する際はレジストリアドレスを省略できる（[organization/]image:tag形式。例: `fluent/fluentd`、`ubuntu`）。

#### Amazon Elastic Container Registry
Amazon ECRはAmazon Web Servicesが提供するプライベートレジストリである。プライベート、すなわち非公開のレジストリであり、`docker login`による認証情報の読み込みが必須である。レジストリアドレスは`<aws_account_id>.dkr.ecr.<region>.amazonaws.com`である。

## 構成要素
現在のDockerはコンテナランタイム・デーモン・CLI・GUI・イメージレジストリ等、数多くの（取替え可能な）コンポーネントからなっている。

* Docker Engine : クライアント-サーバ型のアプリケーションパッケージ
** server: ホストマシン上で稼働するデーモン 
*** （高レベル）コンテナランタイム
**** （低レベル）コンテナランタイム・OCIランタイム
** REST API: デーモンが提供するインタフェース
** CLI client: CLIクライアント。内部で上記のDocker REST APIを叩いている
* *registry*: Dockerイメージの保存庫

現在のDocker（プラットフォーム）は以下のソフトウェアスタックをデフォルトで使用している。

* Docker Engine: `docker-ce`(Linux),  `Docker Desktop` (Windows, MacOS)
** server/deamon: `dockerd`
*** runtime: `containerd`
**** OCI runtime: `runc`
** cli client: `docker`
* registry: Docker Hub

「Docker」は2013年に登場した際、単一アプリケーションの名称であった。しかし標準化を含む発展に伴って上記のように複数の（取替え可能な）コンポーネントから構成されるようになっており、現在の「Docker」はアプリケーションではなく「プラットフォーム」であるとされている。一般に「Docker」という単語が指す意味は非常に曖昧である。

Dockerを構成する要素は上記のデフォルト以外のものを利用できる。以下はその一例である。

* OCI runtime
** あらゆるOCIランタイム（c.f. ）
* registry
** **Docker Trusted Registry**: エンタープライズ向けプライベートレポジトリサービス

またいわゆる「コンテナオーケストレーション」を行う際は`docker`CLIをユーザーが直接利用するのではなく、オーケストレーションツールから`dockerd`、あるいはより直接的に`containerd`が利用される。

## 関連項目
*LXC
*chroot
*kubernetes
*
*DevOps
*仮想化
*ハイパーバイザ

## 脚注

## 学習参考書など
* WINGSプロジェクト 阿佐志保：「プログラマのためのDocker教科書 第2版 インフラの基礎知識&コードによる環境構築の自動化」、翔泳社、 (2018年4月11日）。
* 山田明憲：「Docker/Kubernetes 実践コンテナ開発入門」、技術評論社、 (2018年8月25日）。
* 青山真也：「Kubernetes完全ガイド」、インプレス、（2018年9月21日）。
* 阿佐志保、真壁徹：「しくみがわかるKubernetes：Azureで動かしながら学ぶコンセプトと実践知識」、翔泳社（2019年1月23日）。
* 古賀政純：「Docker実践ガイド 第2版」、インプレス、（2019年2月18日）。
* 北山晋吾、早川博：「Kubernetes実践ガイド：クラウドネイティブアプリケーションを支える技術」、インプレス、（2019年7月12日）。

## 外部リンク
* 
* 
*