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) を走らせる仮想化技術は従来から存在していた。例えば、ハイパーバイザ型の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が選択可能となっている。 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コンテナはLinux名前空間（英語版）を利用してコンテナをホストのネットワークから隔離している。そのためネットワーク設定をnoneにした場合、外部からのネットワークアクセスができない。これは隔離環境という意味では理想的だが、コンテナ間の協調による機能提供ができない。そこでDockerエンジンはネットワークドライバーによるネットワークの提供を行っている。 主に用いられるドライバはbridgeである。ユーザー定義bridgeネットワークは所属コンテナへのIPアドレス提供とコンテナ名によるドメイン名解決 (automatic service discovery) を提供する。また--alias オプションを利用することで1つのドメイン名に複数のコンテナを紐づけることができ、DNSラウンドロビンが可能である。 DockerはCompose (docker-compose) による複数コンテナの実行・連携を提供する。docker-compose.yml でコンテナセット・ネットワークを定義することで、単一のホストマシン上にコンテナ群をデプロイできる。さらにDocker Swarmを用いることでマルチホスト環境へのデプロイも可能になる。 Dockerはコンテナで発生したデータログ/サーバログを処理する機能（ロギング機能）を提供している。Docker Deamonはデフォルトでコンテナのstdout/stderrを捕捉しており、docker logs コマンドでログを表示できる。ロギングはカスタム可能なlogging driverとして実装されており、logging driver pluginsを用いれば独自実装も可能である。デフォルトのlogging driverはjson-fileであり、他にはsyslogやfluentd、特定クラウドプロバイダに特化したawslogsやgcplogsなどが存在する。 fluentdlogging driverはコンテナログをデータコレクタであるFluentdへ転送する。デフォルトではTCPでlocalhost:24224へ送信するが、オプションにより他のTCPポートあるいはUNIXドメインソケットへ送信が可能である。fluentdデーモンはホストマシン上のプロセス、あるいはポートマッピングをおこなったコンテナとして機能させる。 コンテナ仮想化はコンテナ内部からホストカーネルを直接利用するため、エッジケースではホストカーネルのバージョンと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エンジンバージョンの組み合わせによるバグもある。カーネルパニックをおこすエッジケースも存在 [27][28][29] している（あらゆる仮想化はホストと仮想化エンジンの不整合リスクを抱えている）。 実際のアプリの動作は複数のコンテナ同士が協調し合う事が多いとされる。このため多数のコンテナを自動的に管理する (オーケストレートする) ソフトウエアが必要となる。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 pullがデフォルトで利用する公開レジストリである。2014年にDockerコンテナの共有サービスの場として発表された。DockerHubのイメージを利用する際はレジストリアドレスを省略できる（[organization/]image:tag形式。例: fluent/fluentd、ubuntu）。 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. Open Container Initiative § OCI Runtime） registry Docker Trusted Registry: エンタープライズ向けプライベートレポジトリサービス またいわゆる「コンテナオーケストレーション」を行う際はdockerCLIをユーザーが直接利用するのではなく、オーケストレーションツールからdockerd、あるいはより直接的にcontainerdが利用される。 LXC chroot kubernetes DevOps 仮想化 ハイパーバイザ