Docker 概要

Docker はアプリケーションを開発(developing)・移動(shipping)・実行(running)するための、オープンなプラットフォームです。Docker はアプリケーションをインフラストラクチャ(訳者注;システムおよびネットワーク基盤)から切り離せるため、ソフトウェアを素早く配信できます。Docker であれば、皆さんがアプリケーションを管理するのと同じ手法で、インフラストラクチャを管理できます。移動、テスト、コードのデプロイが迅速に行えるのが Docker を扱う手法の利点です。そのため、コードの記述とプロダクションでの実行までの間の遅延を著しく減らします。

Docker プラットフォーム

Docker が提供するのは、コンテナ(container)と呼ばれる緩やかに隔離された環境 [1] における、アプリケーションの梱包(パッケージ)と実行です。隔離とセキュリティにより、指定したホスト上で多くのコンテナを一斉に実行できます。コンテナは外部のハイパーバイザによる処理が不要です。そして、コンテナはホストマシン上のカーネル内で直接実行しますので、軽量です。つまり、任意のハードウェアの組み合わせにより、仮想マシンの使用よりも多くのコンテナを実行できます。また、Docker コンテナの実行はホストマシンだけでなく、実際には仮想マシン上でも実行できるのです!

Docker が提供するのは、コンテナのライフサイクルを管理するツールとプラットフォームです。

  • コンテナを用いたアプリケーション開発と、コンポーネント [2] をサポートします
  • コンテナはアプリケーションの配布またはテストの単位になります
  • アプリケーションの準備が整えば、コンテナまたはオーケストレートされたサービス [3] を通してアプリケーションをプロダクション環境にデプロイできます

訳者注

[1]隔離された環境とは 「isolated environment」 の訳。隔離されて離された環境というよりも、部屋の中を仕切るようなイメージが近いです
[2]このコンポーネントとは、Docker をとりまく各種ツール群やサービスです
[3]原文は 「orchestrated service」 。複数台のサーバ上で、サービスを一斉かつ自動的に制御する動作です

Docker Engine

Docker Engine は3つの主なコンポーネント(構成要素)を持つクライアント・サーバ型アプリケーションです。

  • サーバはデーモン・プロセス( dockerd コマンド)と呼ばれる長期間実行するプログラムの状態
  • インターフェースを規定する REST API は、プログラムがデーモンと通信に使うものであり、何をするか指示
  • コマンドライン・インターフェース(CLI)クライアント( docker コマンド)
Docker Engine コンポーネント図

CLI は Docker REST API を使い、Docker デーモンに対してスクリプトや CLI コマンドを通して、 Docker デーモンを制御または操作をします。多くの他の Docker アプリケーションも、水面下では API と CLI を利用します。

デーモンは Docker オブジェクトを作成・管理します。Docker オブジェクトとは、イメージ、コンテナ、ネットワーク、データ・ボリューム等です。

注釈

Docker のライセンスは、オープンソース Apache 2.0 ライセンスの下で供与されています。

Docker の詳細についれは、 Docker のアーキテクチャ をお読みください。

何のために Docker を使うのですか?

アプリケーションの速いデリバリ

Docker は 開発のライフサイクルの手助けに最適です。Docker は開発者がローカルのコンテナで開発できるようにし、そこにアプリケーションとサービスを入れられます。そして、継続的インテグレーションや、デプロイのワークフローと統合できます。

例えば、開発者がローカルでコードを書き、Docker 上の開発スタックを同僚と共有します。準備が整えば、コードとスタックを開発環境からテスト環境に移動し、開発環境のスタックをテスト環境に移動し、必要なテストを実行します。テスト環境のあとで、Docker イメージをプロダクション環境に送信し、コードをデプロイできるのです。

アプリケーションの素早く一貫したデリバリ

Docker の開発ライフサイクルが効率的なのは、開発者がローカルなコンテナが提供するアプリケーションやサービスを通し、標準的な環境で作業できるからです。コンテナは継続的インテグレーションと継続できデプロイメント(CI/CD)ワークフローに最適です。

以下のシナリオ例が考えられます:

  • 開発者がローカルでコードを書き、同僚と作業時に共有するために Docker コンテナを使う
  • アプリケーションをテスト環境への送信や、自動実行、手動テストのために Docker を使う
  • 開発者がバグを発見したら、開発環境で問題を修正し、テストと確認のためにテスト環境に再デプロイする
  • テストが完了したら、プロダクション環境に単純に送信し、イメージを入れ替えるだけで、利用者は修正版を利用できる

デプロイとスケーリングに対応

Docker’s container-based platform allows for highly portable workloads. Docker containers can run on a developer’s local laptop, on physical or virtual machines in a data center, on cloud providers, or in a mixture of environments.

Docker’s portability and lightweight nature also make it easy to dynamically manage workloads, scaling up or tearing down applications and services as business needs dictate, in near real time.

同じハードウェア上でより多くの処理を実行

Docker は軽量かつ高速です。これはハイパーバイザーをベースとした仮想化マシンよりも、費用対効果を高くします。そのため、皆さんの計算能力を、ビジネスにおけるゴールに到達するために利用できるのです。Docker が最適なのは、高密度の環境や、より少ないリソースを必要とする中小規模のデプロイです。

Docker のアーキテクチャ

gh Docker はクライアント・サーバ型のアーキテクチャです。Docker クライアント が Docker コンテナの構築・実行・配布といった力仕事をするには、 Docker デーモン と通信します。 Docker クライアントとデーモンは、どちらも同じシステム上でも実行できます。あるいは、Docker クライアントはリモートの Docker デーモンに接続するのも可能です。Docker クライアントとデーモンは、お互いにソケットもしくは RESTful API を経由して通信します。

Docker アーキテクチャ図

Docker デーモン

上図で見たように、Docker デーモンはホストマシン上で動きます。ユーザは直接デーモンと通信せず、Docker クライアントを通して行います。

Docker クライアント

Docker クライアントは docker バイナリの形式です。これは主にユーザが Docker との通信に使います。ユーザからのコマンドを受け付けたら、その先にある Docker デーモンが通信を返します。

Docker の内部

Docker 内部を理解するには、3つのコンポーネントを知る必要があります。

  • Docker イメージ(image)
  • Docker レジストリ(registry)
  • Docker コンテナ(container)

Docker イメージ

Docker イメージとは、読み込み専用(read-only)のテンプレートです。例えば、あるイメージは Ubuntu オペレーティング・システム上に、Apache とウェブ・アプリケーションをインストールするでしょう。イメージは Docker コンテナの作成時に使います。Docker は新しいイメージの構築や、既存イメージを更新します。あるいは、他の人が既に作成した Docker イメージをダウンロードすることも可能です。Docker イメージとは Docker における 構築(build) コンポーネントです。

Docker レジストリ

Docker レジストリはイメージを保管します。パブリックもしくはプライベートに保管するイメージの、アップロードやダウンロードが可能です。パブリックな Docker レジストリとして Docker Hub が提供されています。そこでは利用可能なイメージがたくさん提供されています。イメージを自分自身で作れるだけでなく、他人が作成したイメージも利用できます。Docker レジストリとは Docker における 配布(distribution) コンポーネントです。

Docker コンテナ

Docker コンテナはディレクトリと似ています。Docker コンテナはアプリケーションの実行に必要な全てを含みます。各コンテナは Docker イメージによって作られます。Docker コンテナは実行・開始・停止・移動・削除できます。各コンテナは分離されており、安全なアプリケーションのプラットフォームです。Docker コンテナとは Docker における 実行(run) コンポーネントです。

では、どのようにして Docker は動作しますか?

これまでに、次のことを学びました。

  1. アプリケーションを保持する Docker イメージを構築できます。
  2. これら Docker イメージでアプリケーションを実行する Docker コンテナを作成できます。
  3. これら Docker イメージを Docker Hub や自分のレジストリで共有できます。

それでは、Docker が動作するために、それぞれの要素をどのように連携させているのか理解しましょう。

Docker イメージの役割は?

これまで分かったのは、Docker イメージとは読み込み専用のテンプレートであり、これを使って Docker コンテナを起動します。各イメージはレイヤの積み重ねで構成されています。Docker は ユニオン・ファイルシステム(UnionFS) を使い、これらのレイヤを単一のイメージに連結します。ユニオン・ファイルシステムは、ブランチとしても知られています。これは透過的な重ね合わせ(overlaid)と、互いに密着した(coherent)ファイルシステムを形成します。

Docker が軽量な理由の1つが、これらのレイヤによるものです。Docker イメージに変更を加えたとしましょう。例えば、アプリケーションを新しいバージョンに更新すると仮定します。この更新時に新しいレイヤを構築します。つまり、仮想マシン上で何らかの作業をした結果、イメージの入れ替えや完全な再構築ではなく、単純にレイヤを追加するか更新するだけなのです。この新しいイメージの、配布に関する心配は不要です。新しい Docker イメージを速く簡単に配布するには、単に更新されたレイヤを配布するだけです。

各イメージはベース・イメージ(base image)から作られます。例えば、 ubuntu は ベース Ubuntu イメージですし、 fedora は ベース Fedora イメージです。また、自分自身で新しいイメージの元も作れます。例えば、自分でベース Apache イメージを作れば、これを自分用のウェブ・アプリケーション・イメージのベース(基礎)として使えます。

注釈

Docker は常にこれらのベース・イメージを Docker Hub から取得します。

これらのベース・イメージからシンプルに構築できるようにするため、Docker イメージには 命令 (instructions) と呼ぶ構築手順を簡単に記述した集まりがあります。それぞれの命令ごとに、イメージ上に新しいレイヤを作成します。命令は次のような動作をします。

  • コマンドの実行
  • ファイルやディレクトリの追加
  • 環境変数の作成
  • 対象イメージを使ってコンテナを起動する時、どのプロセスを実行するか

これらの命令を Dockerfile と呼ぶファイルに保管します。Docker にイメージの構築を要求したら、Docker はこの Dockerfile を読み込み、命令を実行し、最終的なイメージを返します。

どのように Docker レジストリは動作しますか?

Docker レジストリは Docker イメージを保管します。Docker イメージを構築後、 Docker Hub のような公開レジストリに 送信(push) します。あるいはファイアウォール背後にある自分のレジストリにも送信できます。

Docker クライアントを使い、公開済みのイメージを検索できます。そして、自分の Docker ホスト上にイメージを取得(pull)、つまりダウンロードし、これを使ってコンテナを構築できます。

Docker Hub はイメージを保管するために、パブリックとプライベートなストレージの利用をサポートしています。パブリック・ストレージとは誰でも検索可能でダウンロードできるものです。プライベート・ストレージとは検索結果から除外され、自分もしくは許可されたユーザだけがイメージを取得し、コンテナを構築できるようにします。 ストレージの料金プランと契約はこちらから できます。

どのようにコンテナは動作しますか?

コンテナに含まれているのは、オペレーティング・システム、ユーザが追加したファイル、メタデータです。これまで見てきたように、各コンテナはイメージから構築します。そのイメージは、 Docker に対してどのコンテナの中に何があるか、コンテナ起動時に何のプロセスを実行するか、その他のデータに関する設定確認をします。Docker イメージは読み込み専用です。Docker がイメージからコンテナを実行する時、読み書き可能なレイヤを既存イメージ上に追加し(先ほど見た通り、ユニオン・ファイルシステムを使います)、アプリケーションを実行できるようにします。

コンテナを実行すると何が起きますか?

docker バイナリまたは API を経由して、Docker クライアントは Docker デーモンにコンテナ実行を命令します。

$ docker run -i -t ubuntu /bin/bash

このコマンドを分解(ブレイクダウン)してみましょう。Docker クライアントは docker バイナリを使って実行され、 run オプションは新しいコンテナの起動を命令します。Docker クライアントが Docker デーモンに対してコンテナを起動する時、最低限必要なのは以下の項目です。

  • コンテナを何の Docker イメージで構築するのか。ここでは ubuntu というベース Ubuntu イメージを使用
  • コンテナを起動したら、その中で何のコマンドを実行したいのか、ここでは /bin/bash を指定し、新しいコンテナの中で Bash シェルを開始

それでは、このコマンドの水面下では何が起こっているのでしょうか。

Docker の処理内容を、順番に見ていきます。

  • ubuntu イメージの取得 :Docker は ubuntu イメージの存在を確認し、もしローカルホスト上に存在しなければ、 Docker Hub からダウンロードする。
  • 新しいコンテナを作成 :Docker がイメージを入手したあと、それを使ってコンテナを作成する。
  • ファイルシステムを割り当て、読み書き可能なレイヤをマウント :コンテナを新しいファイルシステム上に作成し、読み込み可能な(イメージの)レイヤをイメージに追加する。
  • ネットワークとブリッジインターフェースの割り当て :Docker コンテナがローカルホストと通信できるようにするため、ネットワーク・インターフェースを作成する。
  • IP アドレスを設定 :プールされている範囲内で利用可能な IP アドレスを探して(コンテナに)追加する。
  • 指定したプロセスを実行 :アプリケーションを実行し、そして、
  • アプリケーションの出力を収集・表示 :コンテナに接続し、アプリケーションを実行したことによる標準入力・標準出力・エラーを記録・表示する。

これでコンテナが動きました! 以降は自分でコンテナを管理し、アプリケーションと双方向でやりとりをし、利用し終えたらコンテナを停止・削除できます。

基礎技術

Docker は Go 言語で書かれており、これまで見てきた機能は、カーネルが持つ複数の機能を利用しています。

名前空間(namespaces)

Docker は名前空間(ネームスペース)と呼ばれる技術を利用し、コンテナ (container) と呼ぶワークスペース(作業空間)の分離をもたらします。Docker はコンテナごとに 名前空間 の集まりを作成します。

これはレイヤの分離をもたらします。つまり、コンテナを実行すると、それぞれが自身の名前空間を持ち、そこから外にはアクセスできないように見えます。

Docker が使う Linux 上の名前空間は、次の通りです。

  • pid 名前区間 :プロセスの分離に使います(PID:プロセス ID)
  • net 名前区間 :ネットワーク・インターフェースの管理に使います(NET:ネットワーキング)
  • ipc 名前区間 :IPC リソースに対するアクセス管理に使います(IPC:InterProcess Communication、内部プロセスの通信)
  • mnt 名前区間 :マウント・ポイントの管理に使います(MNT:マウント)
  • uts 名前区間 :カーネルとバージョン認識の隔離に使います(UTS:Unix Timesharing System、Unix タイムシェアリング・システム)

コントロール・グループ (Control groups)

Linux 上の Docker は、 cgroup やコントロール・グループと呼ばれる技術を使います。アプリケーション実行の鍵となるのは、自身が必要なリソースのみを分離します。この機能があるため、ホスト上で複数の利用者がいても、コンテナを使えます。また、コントロール・グループにより、Docker はコンテナに対して利用可能なハードウェア・リソースを共有し、必要があればコンテナが必要なリソース上限を設定できます。例えば、特定のコンテナに対する利用可能なメモリに制限を加えます。

ユニオン・ファイル・システム

ユニオン・ファイル・システム、あるいは UnionFS はファイルシステムです。これは作成したレイヤを操作しますので、非常に軽量かつ高速です。Docker はコンテナ毎にブロックを構築するため、ユニオン・ファイル・システムを使います。Docker は AUFS、btrfs、vfs、DeviceMapper を含む複数のユニオン・ファイル・システムの派生を利用できます。

コンテナの形式(フォーマット)

Docker はこれらのコンポーネントを連結し、包み込んでいます。これをコンテナ形式(フォーマット)と呼びます。デフォルトのコンテナ形式は libcontainer と呼ばれています。いずれ、Docker は他のコンテナ形式、例えば BSD Jail や Solaris Zone との統合をサポートするかも知れません。

次のステップ

Docker インストール

インストールの章 をご覧ください。

Docker ユーザガイド

より深く学びましょう。

参考

Understand the architecture
https://docs.docker.com/engine/understanding-docker/