> For the complete documentation index, see [llms.txt](https://y-meguro.gitbook.io/reading-record/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://y-meguro.gitbook.io/reading-record/other/using_docker.md).

# Docker

## 概要

### 本

* [Docker | Adrian Mouat, Sky株式会社 玉川 竜](https://amzn.to/2PZ7xAy)
* 参考
  * [using-docker](https://github.com/using-docker)

### かかった時間

* 19.1 時間

### 感想

* Docker のアーキテクチャについて理解した
* コマンドについて一通り理解した
* 基礎的な用語の意味と概念について理解した
* やや古い内容の部分もあるので、そこは新しい内容を補足しながら読んだ

## 読書メモ

### 1: コンテナとはなにか、そしてなぜ注目されているのか

* コンテナ
  * コンテナは、アプリケーションを依存対象とともにカプセル化したもの
* コンテナと VM の違い
  * 仮想化にはホスト型とハイパーバイザ型がある
    * ホスト型
      * ホスト型は OS 上に土台となるソフトウェアをインストールし、そのソフトウェア上で仮想マシンを稼働させる方式
      * ハードウェアにアクセスするにはホスト OS を経由しないといけないため、余計なオーバーヘッドがかかる
    * ハイパーバイザ型
      * サーバーへ直接ハイパーバイザをインストールし、仮想マシンを稼働させる方式
      * こちらの場合は（ホスト OS を介さず）ハードウェアを直接操作可能
    * 参考: [ホスト型とハイパーバイザー型の違いは何？VMware vSphere Hypervisor の概要 | Think IT（シンクイット）](https://thinkit.co.jp/story/2012/10/17/3722)
    * 上記の通り、それぞれの VM には OS、実行するアプリケーション、必要な支援ライブラリの完全なコピーが必要となる
  * コンテナの場合
    * VM の場合とは異なり、ホストのカーネルは実行されるコンテナと共有される
    * また、アプリケーション間で共通のライブラリを使う場合は、冗長なコピーを持つのではなく、共有できる
    * コンテナエンジンは、ハイパーバイザ上の VM と同じようなやり方で、コンテナの起動や終了を受け持つ
    * コンテナ内で動作しているプロセスは、ホスト上で直接動作しているプロセスと同等であり、ハイパーバイザの実行に伴うオーバーヘッドがない
  * VM が目的としているのは、異なる環境を完全にエミュレートすること。コンテナが目的としているのは、アプリケーションをポータブルにし、単体で動作できるようにすること
* Docker とコンテナ
  * Docker はポータブルなイメージと、ユーザーフレンドリーなインターフェイスを中心とする様々な方法で既存のコンテナ技術をラップして拡張し、コンテナの生成と配布のための完全なソリューションを生み出している
  * Docker というプラットフォームには、2 つの構成要素がある
    * Docker エンジン
      * コンテナの生成と実行を受け持つ
      * 動作中のコンテナへの高速で便利なインターフェイスを提供する
    * Docker Hub
      * コンテナを配布するためのクラウドサービス
* Docker のプラットフォームは 64bit Linux のみ
  * Docker を利用するコンピュータでは、64bit の Linux ディストリビューションを動作されなければならず、コンテナもすべて 64bit Linux でなければならない
  * そのため、Windows もしくは Mac OS のユーザーは、VM 内で Docker を動作させることになる

### 2: インストール

* Docker for Mac/Windows
  * この本が書かれた時点では Docker Toolbox をインストールし、Virtual Box 上で Linux のホストを動作させるやり方だった。現時点では、Docker for Mac/Windows を利用して、それぞれのプラットフォーム固有の仮想化の機能を使うことで、ほぼ Linux と同様の感覚で Docker を使えるようになる
* Docker for Mac
  * Docker for Mac は Mac OS Yosemite に組み込まれたネイティブの仮想化機構である Hypervisor Framework を利用し、Docker エンジンの動作環境を提供する
  * ユーザーからは、仮想環境のホストの存在をほぼ意識することなく、Docker を Mac OS 上で利用できる

### 3: はじめの一歩

* 初めてのイメージ実行
  * `docker run debian echo "Hello World"` を実行する
  * 呼び出したコマンドが `docker run`
  * `debian` が使いたいイメージの名前
  * イメージがダウロードされると、Docker はそのイメージを実行中のコンテナに変え、その中で指定されたコマンドを実行する
  * [run — Docker-docs-ja 17.06.Beta ドキュメント](http://docs.docker.jp/engine/reference/commandline/run.html)
* コンテナ内のシェルを使う
  * `docker run -i -t debian /bin/bash`
  * `-i` と `-t` で Docker に対して tty 付きのインタラクティブセッションを要求する
  * シェルを終了するとコンテナも停止する
    * コンテナが動作するのは、そのコンテナのメインプロセスが動作している間だけ
* コンテナの一括削除
  * `docker rm $(docker ps -aq)`
* コンテナのファイル変更や設定を、新しいイメージに収容する
  * `docker commit cowsay test/cowsayimage`
  * 上記だと cowsay がコンテナの名前、test が保存するリポジトリの名前、cowsayimage がイメージの名前
  * [commit — Docker-docs-ja 17.06.Beta ドキュメント](http://docs.docker.jp/engine/reference/commandline/commit.html)
* Dockerfile からのイメージの構築
  * FROM 命令で使用するベースイメージを指定
  * RUN コマンドはイメージ内で実行するシェルのコマンドを指定
  * Dockerfile と同じディレクトリから `docker build` コマンドを実行すればイメージを構築できる
  * [build — Docker-docs-ja 17.06.Beta ドキュメント](http://docs.docker.jp/engine/reference/commandline/build.html)
  * 普通に docker build するとエラーが出るので `FROM debian/eol:wheezy` に変更した
    * [sources list in wheezy should be switched to archive · Issue #65 · debuerreotype/docker-debian-artifacts](https://github.com/debuerreotype/docker-debian-artifacts/issues/65)
  * ENTRYPOINT
    * ENTRYPOINT にはコンテナが実行するファイルを指定する
    * [ENTRYPOINT - Dockerfile リファレンス](http://docs.docker.jp/engine/reference/builder.html#entrypoint)
  * COPY
    * [COPY - Dockerfile リファレンス](http://docs.docker.jp/engine/reference/builder.html#copy)
  * LABEL
    * MAINTAINER は deprecated になったので LABEL を使う
    * [LABEL - Dockerfile リファレンス](http://docs.docker.jp/engine/reference/builder.html#label)
* Union File System(UFS)
  * union file system は、複数のファイルシステムをオーバーレイして、単一のファイルシステムとしてユーザーに見せてくれる
  * Docker のイメージは、複数のレイヤから構成される。イメージの各レイヤは、リードオンリーのファイルシステム
* レジストリ、リポジトリ、イメージ、タグ
  * レジストリ
    * イメージのホスティングと配布を受け持つサービス。デフォルトのレジストリは Docker Hub
  * リポジトリ
    * 関連するイメージの集合（自分の場合は ymeguro リポジトリを持つ）
  * タグ
    * リポジトリ内のイメージに与えられる、アルファベット及び数値からなる識別子
* イメージを再構築して、Docker Hub にアップロード
  * [ymeguro/cowsay - Docker Hub](https://hub.docker.com/r/ymeguro/cowsay)
* イメージの名前空間
  * push された Docker のイメージが属する名前空間には 3 つの種類がある
    * user
      * `ymeguro/cowsay` のように、文字列と / でプレフィックスされた名前は "user" の名前空間に属する
      * ユーザーによってアップロードされたイメージが属する
    * root
      * プレフィックスや / を持たない debian や ubuntu といった名前は "root" の名前空間に属する
      * この名前空間は Docker Inc. が管理しており、公式イメージのために予約されている
    * サードパーティのレジストリがホストしているイメージ(Docker Hub がホストしているものではない)
      * ホスト名もしくは IP がプレフィックスになっているイメージ
      * 例えば localhost:5000/wordpress はローカルのレジストリでホストされている WordPress のイメージ
  * ボリューム
    * データを永続化し、コンテナとホスト、あるいは他のコンテナとの間で簡単に共有するために、ボリュームを利用する
    * ボリュームは通常の union file system の一部ではなく、ホストに直接マウントされるファイルもしくはディレクトリ
      * つまり、ボリュームは他のコンテナと共有でき、すべての変更は直接ホストのファイルシステムに対して行われる
    * ディレクトリをボリュームとして宣言する方法は 2 つある
      * Dockerfile の中で VOLUME 命令を使う方法
      * docker run で -v フラグを指定する方法
    * デフォルトでは、指定したディレクトリやファイルは、ホスト上の Docker をインストールしたディレクトリ(通常は /var/lib/docker/)にマウントされる

### 4: Docker の基礎

* アーキテクチャの理解
  * 本文ではないが [アーキテクチャの理解](http://docs.docker.jp/engine/introduction/understanding-docker.html) を読んだ
  * Docker を使うことで、アプリケーションを基盤から分離し、アプリケーションを管理するようにインフラを扱えるようにする
  * Docker を何に使うのですか？
    * アプリケーションの速いデリバリ
    * デプロイとスケールをより簡単に
      * Docker コンテナは開発者のローカルホスト上で実行できるだけでなく、データセンタの物理環境や仮想マシン上、クラウド上でも動く
      * 軽量なので、スケールをほぼリアルタイムで行える
    * 高密度とさらなるワークロードの実行を実現
      * Docker は軽量で速い。費用対効果も高い。これが特に有効なのは高密度の環境
  * Docker のアーキテクチャとは？
    * Docker はクライアント・サーバ型のアーキテクチャ
    * Docker クライアントは Docker デーモンと通信することで、Docker コンテナの構築・実行・配布といった仕事をする
    * Docker クライアントとデーモンは同じシステム上でも実行できるし、Docker クライアントはリモートの Docker デーモンに接続することも可能
    * ソケットか RESTful API を通して通信する
    * Docker デーモン
      * Docker デーモンはホストマシン上で動く。ユーザーは直接デーモンと通信せず、Docker クライアントを通して行う
    * Docker クライアント
      * ユーザーが Docker との通信を行うために使う。ユーザーからのコマンドを受け付けると、その先にある Docker デーモンと通信し、レスポンスを返す
    * Docker の内部
      * 以下の 3 つのコンポーネントを理解する必要がある
        * Docker イメージ
          * 読み込み専用なテンプレート
          * Docker コンテナの作成時に使われる
          * Docker は新しいイメージの構築や、既存イメージの更新を行う。また他の人が既に作成した Docker イメージをダウンロードすることも可能
          * Docker イメージとは、Docker における構築(build)コンポーネント
        * Docker レジストリ
          * Docker レジストリはイメージを保持する
          * パブリックもしくはプライベートに保管されているイメージのアップロードやダウンロードを行える
          * パブリックな Docker レジストリとして、Docker Hub が提供されている
          * Docker レジストリとは、Docker における配布(distribution)コンポーネント
        * Docker コンテナ
          * Docker コンテナはディレクトリと似ている
          * Docker コンテナにはアプリケーションの実行に必要なすべてが含まれている
          * 各コンテナは Docker イメージによって作られる
          * 各コンテナは分離されている
          * Docker コンテナとは、Docker における実行(run)コンポーネント
  * では Docker はどのように動きますか？
    * Docker イメージの役割
      * 各イメージはレイヤの積み重ねで構成されている
      * Docker は union file system を使い、これらのイメージを単一のイメージに連結する
      * Docker が軽量な理由の 1 つが、これらのレイヤによるもの
        * Docker イメージに変更を加えた時、イメージが置き換えられたり完全に再構築されるというより、単純にレイヤが追加されるか更新されるか、のみの変更で済む
      * 自分のイメージをビルドするために、Dockerfile を作成する
        * Dockerfile には命令を記載でき、各命令はコマンドの実行や、ファイルやディレクトリの追加を行える
        * Docker にイメージの構築を依頼すると、Docker はこの Dockerfile を読み込み、命令を実行し、最終的なイメージを返す
          * `docker build` でイメージが作られて、`docker run` でイメージ上にコンテナレイヤが作成され(create)、開始される(start)
  * コンテナを実行すると何が起きますか？
    * docker バイナリか API を経由して、Docker クライアントは Docker デーモンにコンテナ実行を伝える
    * `docker run -i -t ubuntu /bin/bash` の場合
      * Docker クライアントは `docker` バイナリを使って実行される
      * `run` オプションは新しいコンテナの起動を伝える
      * Docker クライアントが Docker デーモンに対してコンテナを起動するために最低限必要なのは以下の 2 つ
        * コンテナが何の Docker イメージで構築されるのかここでは `ubuntu` というベースイメージを使う
        * コンテナを起動したら、その中で何のコマンドを実行したいのか。ここでは `/bin/bash` を指定し、新しいコンテナの中で Bash シェルを開始する
    * このコマンドの裏では以下が行われる
      * ubuntu イメージの取得
      * 新しいコンテナを作成
      * ファイルシステムを割り当て、読み書き可能なレイヤをマウント
        * コンテナを新しいファイルシステム上に作成し、読み書き可能なレイヤをイメージに追加する
      * ネットワークとブリッジインターフェイスの作成
        * Docker コンテナがローカルホストと通信できるようにするためのネットワークインターフェイスを作成する
      * IP アドレスを設定
        * 利用可能な IP アドレスを探して、コンテナに割り当てる
      * 指定したプロセスを実行
      * アプリケーションの出力を収集・表示
        * アプリケーションを実行したことによる、標準入力・標準出力・エラーを記録、表示する
  * 基礎技術
    * Docker は Go 言語で書かれており、これまで見てきた機能は複数のカーネル機能を利用している。以下に例を示す
    * 名前空間
      * Docker は名前空間(namespace)と呼ばれる技術を利用し、各コンテナを分離する。各コンテナはそれぞれ自身の名前空間を持ち、そこから外にはアクセスできないように見える
    * コントロール・グループ
      * プロセスをグループ化して、ホスト OS が持つ CPU やメモリなどのリソースに対して、グループごとに制限をかけることができる
    * ユニオン・ファイル・システム
      * 3 章で説明記載済み
* Docker に含まれている支援技術のリスト
  * Swarm
    * Docker のクラスタリングソリューション
    * k8s などと同じ役割
  * Compose
    * Docker Compose は、複数の Docker コンテナから合成されるアプリケーションの構築と実行のためのツール
  * Machine
    * Docker Machine は、Docker のホストをローカルもしくはリモートのリソースにインストールし、設定する
  * Kitematic
    * Docker コンテナの実行と管理のための Mac OS および Windows の GUI
  * Docker Trusted Registry
    * Docker イメージの保存、管理のためのオンプレミスのソリューション
    * 実質的にはローカルバージョンの Docker Hub
* イメージの構築
  * `docker build` コマンドには、Dockerfile とビルドコンテキスト(これは空でもよい)が必要
    * ビルドコンテキストはローカルファイルやディレクトリの集合で、通常はディレクトリへのパスとして指定される
    * ビルドコンテキストは、このパスの下にあるすべてのファイルとディレクトリで構成され、ビルドプロセスの一部として Docker デーモンに送られる
      * なので、大量のファイルが入っているディレクトリはビルドコンテキストに使うべきではない
    * .dockerignore の利用
      * ビルドコンテキストから不要なファイルを取り除ける
  * キャッシュ
    * Docker はイメージの構築を高速化するために、各レイヤをキャッシュする
    * キャッシュは命令が以下の条件を満たす場合に使われる
      * 以前の命令がキャッシュ内にある
      * 該当命令と親のレイヤについて、全く同じレイヤがキャッシュ内にある
      * キャッシュを無効にする場合は、`docker build` に `--no-cache` 引数を渡して実行する
  * Dockerfile の命令
    * ADD
      * ビルドコンテキストあるいはリモートの URL から、イメージへファイルをコピーする
      * ADD がカバーする範囲は広いので、ビルドコンテキスト中のファイルやディレクトリをコピーする場合は、よりシンプルな COPY を使い、リモートのリソースをダウンロードするには、RUN コマンドで curl や wget を使うほうがいい
    * COPY
      * 上述の通り、ビルドコンテキストからイメージにファイルをコピーするために使う
    * CMD
      * コンテナの起動後に指定された命令を実行する
    * ENTRYPOINT
      * コンテナの起動時に実行される実行可能ファイルを設定する
    * ENV
      * イメージ中の環境変数を設定する
    * EXPOSE
      * 特定のネットワーク・ポートをコンテナが実行時にリッスンすることを Docker に伝える
    * FROM
      * Dockerfile のベースイメージを設定する
    * LABEL
      * イメージにメタデータを追加する
    * ONBUILD
      * このイメージが他のイメージのベースレイヤとして使われた場合に、その時点で実行される命令を指定する
    * RUN
      * 指定された命令をコンテナ内で実行し、結果をコミットする
    * USER
      * これ以降の RUN / CMD / ENTRYPOINT 命令で使われるユーザーを設定する
    * VOLUME
      * 指定されたファイルもしくはディレクトリがボリュームであることを宣言する
    * WORKDIR
      * これ以降の RUN / CMD / ENTRYPOINT / ADD / COPY 命令で使われる作業ディレクトリを設定する
* 外界とのコンテナ接続
  * 外部からアクセスできるようにするには `-p` もしくは `-P` コマンドでポートを公開する
  * `docker run -d -p 8000:80 nginx` だと、Docker に対して 8000 番ポートをコンテナの 80 番ポートにフォワードするよう指示する
  * `docker port` を使えば、Docker が割り当てたポートがわかる
* コンテナ間のリンク
  * `--link` はすでに非推奨。11 章で詳しく見る
* ボリュームとデータコンテナを使ったデータの管理
  * ボリュームを初期化する方法は 3 種類
    * 実行時に `-v` フラグを使う
      * 例 `docker run -it --name container-test -h CONTAINER -v /data debian /bin/bash`
        * これでコンテナ内のディレクトリの `/data` がボリュームになる
        * この場合、コンテナ内の /data/ というボリュームは、単にホストの /var/lib/docker/volumes/5cad.../\_data というディレクトリにリンクされているだけ
    * Dockerfile 中で VOLUME 命令を使う
      * 例 `VOLUME /data` これは上記の `-v` で指定したのと同じことになる
    * `-v HOST_DIR:CONTAINER_DIR` という形式を使う
      * docker run の引数の -v を明示的なディレクトリでホストにバインドする方法
      * これは Dockerfile からは行えない(セキュリティリスクのため)
      * 例 `docker run -v /home/adrian/data:/data debian ls /data`
        * これで、ホスト上の `/home/adrian/data` というディレクトリが、コンテナ内の `/data` にマウントされる
        * `/home/adrian/data` ディレクトリ内の既存のファイルは、すべてコンテナから利用できるようになる
        * 他の方法とは異なり、イメージ中のファイルがボリュームにコピーされることはなく、ボリュームが Docker によって削除されることもない
    * データの共有
      * コンテナ間でのデータの共有は docker run で `--volumes-from CONTAINER` という引数を使うことによっても実現される
  * データコンテナ
    * データコンテナは、他のコンテナ間でデータを共有することだけを目的とするコンテナ
    * このアプローチの主な利点は、提供されるボリュームの名前空間が、`--volumes-from` コマンドを使って簡単にロードできること
    * ボリュームの削除
      * 以下の条件が満たされた時に削除される
        * コンテナが `docker rm -v` で削除された、もしくは
        * docker run コマンドに `--rm` フラグが渡されている
        * 加えて以下を満たす
          * 既存のコンテナがそのボリュームにリンクしていない
          * そのボリュームにホストのディレクトリが指定されていない
* Docker の一般的なコマンド
  * run コマンド
    * コンテナのライフサイクルと、基本的な運用のモードの制御
      * -a, --atach
        * 指定されたストリーム(stdout など)をターミナルにアタッチする
        * 指定されなかった場合は、stdout および stderr がどちらもアタッチされる(すると、出力が表示される)
      * -d, --detach
        * コンテナを「デタッチド」モードで実行する
        * この場合、コンテナはバックグラウンドで実行され、コンテナ ID を返す
      * -i, --interactive
        * stdin をオープンにしたままに保つ
        * 一般的には -t とあわせてインタラクティブなコンテナセッションを始めるために使われる
      * \--restart
        * 再起動ポリシーを指定する
      * \--rm
        * 終了時にコンテナを自動的に削除する
        * -d とあわせては使えない
      * -t, --tty
        * 擬似的な TTY を割り当てる
          * 標準入出力の接続先を割り当てるということ
        * 一般的には -i とあわせてインタラクティブなコンテナセッションを始めるために使われる
    * コンテナの名前と変数を設定する
      * -e, --env
        * コンテナ内の環境変数を設定する
      * -h, --hostname
        * コンテナのホスト名を設定する
      * \--name NAME
        * NAME という名前をコンテナに割り当てる
    * ボリュームのセットアップ
      * -v, --volume
        * ボリュームを指定する
        * 2 つの引数でコンテナ内のディレクトリと、ホストのディレクトリを指定する
      * \--volumes-from
        * 指定されたコンテナからボリュームをマウントする
        * よくデータコンテナとあわせて使われる
    * ネットワーキングに影響するオプション
      * \--expose
        * コンテナで使われるポート、もしくはポートの範囲を指定する
        * Dockerfile の EXPOSE 命令と等価
      * -p，--publish
        * コンテナのポートを公開し、ホストからアクセスできるようにする
      * -p, --publish-all
        * コンテナの解放されたすべてのポートをホストに公開する
    * Dockerfile の設定を上書きする
      * \--entrypoint
        * コンテナのエントリポイントを指定された引数に設定する
        * Dockerfile の ENTRYPOINT 命令を上書きする
      * -u, --user
        * コマンドを実行するユーザーを設定する
        * Dockerfile の USER 命令を上書きする
      * -w, --workdir
        * コンテナ中の作業ディレクトリを、指定されたパスに設定する
        * Dockerfile の WORKDIR 命令を上書きする
  * コンテナの管理
    * docker attach
      * コンテナ内のメインのプロセスを見たり、やりとりできる
      * CTRL-C を使うと、アタッチしたプロセスが終了し、コンテナが終了する
    * docker create
      * イメージからコンテナを作成するが、コンテナの起動は行わない
      * コンテナを起動するには docker start を使う
    * docker start
      * 停止しているコンテナを起動する
    * docker restart
      * コンテナを再起動する
      * おおまかには、コンテナに対して docker stop に続いて docker start を呼ぶのと同等
    * docker stop
      * コンテナを停止させる(削除はしない)
      * docker stop を呼ぶと、そのコンテナは "exited" ステータスに移行する
    * docker rm
      * コンテナを削除する
      * 削除に成功したコンテナ郡の名前もしくは ID を返す
    * docker cp
      * コンテナとホストの間で、ファイルやディレクトリをコピーする
    * docker exec
      * コンテナ内でコマンドを実行する
      * コンテナにログインする ssh の代わりに使うことができる
    * docker kill
      * コンテナ内のメインのプロセスにシグナルを送信する
      * デフォルトでは SIGKILL が送信されるので、コンテナはすぐに終了することになる
    * docker pause
      * 指定されたコンテナ内のすべてのプロセスをサスペンドさせる
    * docker unpause
      * docker pause で一時停止させられたコンテナを再開する
  * Docker の情報
    * docker info
      * Docker のシステム及びホストに関する様々な情報を出力
    * docker help
      * 指定されたサブコマンドの利用方法とヘルプ情報を出力する
    * docker version
      * Docker のクライアント及びサーバーのバージョン情報、及びコンパイルに使用された Go のバージョンを出力する
  * コンテナの情報
    * docker diff
      * コンテナの起動元と比較して、コンテナのファイルシステムに加えられた差分を表示する
    * docker events
      * Docker デーモンのリアルタイムイベントを出力する
      * 停止するには CTRL-C を使う
    * docker inspect
      * 指定されたコンテナもしくはイメージに関する詳細情報を提供する
    * docker logs
      * コンテナのログを出力する
    * docker port
      * 指定されたコンテナの公開ポートのマッピングのリストを出力する
    * docker ps
      * 現在のコンテナ群に関する、名前、ID、ステータスといった高レベルの情報を提供する
      * -a で実行中のコンテナだけでなく、すべてのコンテナの情報を取得できる
      * -q でコンテナ ID だけを返すので、docker rm のようなコマンドの入力として使える
    * docker top
      * 指定されたコンテナ内で実行中のプロセスに関する情報を提供する
  * イメージの扱い
    * docker build
      * Dockerfile からイメージを構築する
    * docker commit
      * 指定されたコンテナからイメージを生成する
      * コンテナのファイル変更や設定を、新しいイメージに収容するために便利
    * docker export
      * コンテナのファイルシステムの内容を、tar アーカイブとして STDOUT に出力する
      * レイヤやタグといったメタ情報は無視される
      * ボリュームはエクスポートされない
    * docker import
      * docker export で作成されたような、ファイルシステムを含むアーカイブファイルから、イメージを生成する
    * docker save
      * 名前をつけたイメージもしくはリポジトリを、tar アーカイブに保存する
      * メタ情報も含めてまとめられる
    * docker load
      * STDIN 経由で渡された tar アーカイブから、リポジトリをロードする
      * docker save とあわせて使う
    * docker history
      * イメージの各レイヤの情報を出力する
    * docker images
      * リポジトリ名、タグ名、サイズといった情報を含む、ローカルイメージのリストを出力する
    * docker rmi
      * 指定されたイメージ、もしくはイメージ群を削除する
    * docker tag
      * イメージに、リポジトリとタグ名を関連付ける
  * レジストリの利用
    * docker login
      * 指定されたレジストリサーバーへの登録やログインを行う
      * サーバーが指定されなかった場合、Docker Hub が使われる
    * docker logout
      * Docker レジストリからログアウトする
    * docker pull
      * 指定されたイメージをレジストリからダウンロードする
    * docker push
      * イメージもしくはリポジトリをレジストリにプッシュする
    * docker search
      * 検索条件にマッチした、Docker Hub 上のすべての公開リポジトリのリストを出力する

### 5: 開発での Docker の利用

* Docker Compose
  * Docker Compose は Docker の開発環境を素早く立ち上げるために設計されている
  * コンテナ郡の設定を YAML ファイルを使って保存し、開発者が間違えやすい入力を繰り返し行わずに済むようにしてくれる
  * Compose のワークフロー
    * up
      * Compose のファイルで定義されたすべてのコンテナを起動し、出力されたログを集約する
      * 通常は引数の `-d` を使い、Compose をバックグラウンドで動作させる
    * build
      * Dockerfiles 群から生成されるイメージを再構築する
      * イメージを更新する必要がある場合は、このコマンドを使う
    * ps
      * Compose が管理しているコンテナの状態に関する情報を提供する
    * run
      * 単発のコマンドを実行するためにコマンドを起動する
    * logs
      * Compose が管理しているコンテナのログを、カラー付きで集約して出力する
    * stop
      * コンテナを停止する
      * 削除は行わない
    * rm
      * 停止しているコンテナを削除する

### 6: シンプルな Web アプリケーションの作成

* identidock で基本的な Web アプリケーションを作成した
  * マイクロサービスでのアプローチを行った

### 7: イメージの配布

* 自動化ビルド
  * コードを更新したらイメージも更新したい場合は、自動化ビルドを使う
  * 自動化ビルドをセットアップすると、ソースコードの変更をプッシュすれば、Docker Hub がイメージをビルドして、リポジトリに保存してくれるようになる
  * Docker repository と GitHub repository を連携させる
  * [Docker Hub の自動構築 — Docker-docs-ja 17.06.Beta ドキュメント](http://docs.docker.jp/docker-hub/builds.html)
* 独自のレジストリの運用
  * Docker Hub 以外にも、選択肢はある
  * Docker Registry は Docker Hub と同様にレジストリ API を実装している
  * Docker Hub がクローズドソースのリモートサービスであるのに対して、Docker Registry はオープンソースであり、ローカルで動作させることが可能

### 8: Docker を使った継続的インテグレーションテスト

* けっこう飛ばして読んだ
* Jenkins コンテナの作成
  * ソケットマウント
    * Jenkins コンテナがイメージをビルドできるようにするために、Docker ソケットをホストからコンテナにマウントする
    * こうすることで、Jenkins は実質的に「兄弟」コンテナを生成できるようになる
  * Docker-in-Docker (DinD)
    * Docker コンテナが独自の「子」コンテナを作れるようにするもの
    * Docker そのものを Docker コンテナ内で実行する
  * Unlock Jenkins への対応
    * `docker exec -it ${containerID} bash` でコンテナに入った後、`cat /var/jenkins_home/secrets/initialAdminPassword` でパスワードを確認して、入力する
    * 参考: [\[ docker \] jenkinsサーバ をdockerで始めてみる - Qiita](https://qiita.com/penguin_dream/items/e1c8a7174fc27d1e0b49)

### 9: コンテナのデプロイ

* けっこう飛ばして読んだ
* Docker Machine
  * 新しいリソースをプロビジョニングする、最も速くてシンプルな方法は Docker Machine によって新たなリソースをプロビジョニングし、コンテナを実行する方法
  * Docker Machine は、サーバーを生成し、生成したサーバーに Docker をインストールし、ローカルの Docker クライアントからアクセスできるようにしてくれる

### 10: ロギングとモニタリング

* けっこう飛ばして読んだ

### 11: ネットワーキングとサービスディスカバリ

* 古い内容だったのでちゃんと読んでない
* サービスディスカバリ
  * サービスのクライアントに対し、適切なサービスのインスタンスの接続情報(通常は IP アドレスとポート)を自動的に提供するプロセス
* ネットワーキング
  * 本書の例では、ネットワーキングはコンテナ同士を接続するプロセスとみなせる
* ネットワーキングとサービスディスカバリのソリューションは機能的に重複する傾向にある
* Docker コンテナ・ネットワークの理解
  * 本文ではないが [Docker コンテナ・ネットワークの理解](http://docs.docker.jp/engine/userguide/networking/dockernetworks.html) を読んだ
  * ネットワーク
    * ネットワークとは、定義上、コンテナのために完全な分離(isolation)を提供するもの
    * ここではまず、Docker Engine ドライバ固有の標準ネットワーク機能について、その概要を扱う
    * Docker のインストールで、自動的に 3 つのネットワークを作成する(none / bridge / host)
      * none ネットワーク
        * ネットワーク接続を必要としないコンテナを作成する場合に使用する
        * コンテナにネットワーク層を追加したい場合は、 none ネットワークを指定する
      * host ネットワーク
        * Docker ホストマシンと同じネットワークインタフェース、IP アドレスを持つようになる
      * bridge ネットワーク
        * Linux bridge 機能を使った、Linux 上に別ネットワークを使う方式
        * Docker デーモンはデフォルトでこのネットワークにコンテナを接続する
        * 同じ bridge ネットワークに属するコンテナ同士はそれぞれ通信可能。セキュリティ的に問題がある場合は、新しくネットワークを作成し、所属するネットワークを分ける
    * overlay network
      * Docker overlay network を使うことで異なる L3 上(Docker の場合は異なる Docker ホスト上)に存在するコンテナに対して、同じネットワークに存在するコンテナとして透過的にアクセスできるようになる
      * この Docker overlay network は VXLAN を使って実装されているため、Docker ホストが異なる拠点やデータセンタに存在しても、その Docker ホスト上のコンテナは、同じネットワーク上に存在しているものとしてアクセスできる
    * 参考
      * [Docker network 概論 - Qiita](https://qiita.com/TsutomuNakamura/items/ed046ee21caca4a2ffd9)

### 12: オーケストレーション、クラスタリング、管理

* けっこう飛ばして読んだ
* クラスタリング
  * 「ホスト」をグループ化し、ホスト同士をネットワークで接続する
  * クラスタは、別々のマシンのグループというより、単一のリソースのように見える
* オーケストレーション
  * 様々な作業を取りまとめること
  * 適切なホストでコンテナ群を起動し、接続する
  * オーケストレーションのシステムには、スケーリング、自動フェイルオーバー、ノードのリバランスなどをサポートするものがある
* 管理
  * システムの監視機能を提供し、様々な管理タスクをサポートする

### 13: セキュリティとコンテナに対する制限

* 考えるべきセキュリティの問題
  * カーネルの不正利用
    * VM とは異なり、カーネルはすべてのコンテナとホストで共有される
    * そのため、カーネルの脆弱性の問題は大きくなる
    * コンテナがカーネルパニックを引き起こすと、ホスト全体がダウンする
      * カーネルパニック: オペレーティングシステム(OS)のカーネル部分において、何らかの理由で致命的なエラーが発生し、安全に復旧できなくなった状態
  * DoS(Denial-of-service)攻撃
    * 全てのコンテナは、カーネルのリソースを共有する
    * あるコンテナが、メモリなどの特定のリソースへのアクセスを独占してしまうと、同じホスト上の他のコンテナ群がリソース不足に陥ってしまう
    * これはサービス拒否攻撃を受けた状態であり、正当なユーザーがシステムの一部、あるいは全体にアクセスできない状態になる
  * コンテナブレークアウト
    * 攻撃者が、あるコンテナへアクセスできるようになったからといって、それは必ずしも、他のコンテナやホストへのアクセスができるようになるというわけではない
    * さらに権限昇格攻撃を行うことで、ルートレベルの実行とファイルアクセスを取得されてしまう
  * 毒入りのイメージ
    * 脆弱性のあるイメージをユーザーに利用させることで、ホストもユーザーのデータも危険にさらされる
  * 秘密情報の漏洩
    * コンテナがデータベースやサービスにアクセスする際には、API のキーやユーザー名及びパスワードといった秘密情報が必要になる
    * これが漏洩してしまうと攻撃者もサービスにアクセスできるようになってしまう
* 防御の詳細
  * 最小限の権限
    * プロセスやコンテナは、動作に必要な最小限のアクセス権やリソースの下で動作させるべき
    * このアプローチの主なメリットは、あるコンテナに侵入されても、攻撃者はその先のデータやリソースへのアクセスを厳しく制限されること
* ホストによるコンテナの分離
  * それぞれのユーザーを別個の Docker ホストに配置する
  * コンテナの防御が破られてしまっても、あるユーザーが他のユーザーのコンテナやデータへのアクセス権を得てしまうのを防ぐ
* 更新の適用
  * セキュリティを保つ上では、動作中のシステムに素早く更新を適用できることが重要
* イメージの起源
  * イメージを安全に使うには、そのイメージがどこから来たもので、誰が作成したものなのかという起源が保障されていないといけない
  * 自分たちが取得しているイメージが、元々の開発者がテストしたイメージと全く同じであり、保存や転送に際して誰にも改変されていないことが保障できなければならない
* セキュリティに関する tips
  * ユーザーの設定
    * 絶対に実働アプリケーションをコンテナ内で root として動かしてはいけない
    * root での実行を避けるために、Dockerfile では必ず非特権ユーザーを作成し、USER 文を使うか、あるいはエントリポイントのスクリプトで、そのユーザーに切り替える
  * コンテナのネットワーキングの制限
    * コンテナが公開するポートは、実働環境で使う必要があるポートだけにするべきであり、それらのポートにアクセスするのは、そうする必要がある他のコンテナだけにするべきである
  * setuid / setgid バイナリの削除
    * これらのバイナリを無効にするか、削除してしまえば、それらが特権昇格攻撃に使われる可能性をなくすことができる
  * メモリの制限
    * メモリを制限することで、DoS 攻撃や、ホストの全メモリをゆっくりと消費していってしまうようなメモリリークを持つアプリケーションに対する防御ができる
    * コンテナが使用できるメモリの量とスワップメモリの量を制限できる
  * CPU の制限
  * 再起動の制限
    * Docker はコンテナの再起動に際して、エクスポネンシャルバックオフを採用している
  * ファイルシステムの制限
  * ケーパビリティの制限
    * Linux のカーネルでは、ケーパビリティと呼ばれる権限の集合が定義されている
    * ケーパビリティをプロセスに割り当てれば、そのプロセスがシステムにアクセスできる範囲が広がる
  * リソース制限の適用 (ulimit)
    * Linux のカーネルは、フォークできる子プロセス数の制限や、オープンできるファイルディスクリプタ数など、プロセスに対して適用できるリソース制限を定義している
