‫さて､ 今回の講義では､ 画像のレイヤーについて説明します｡
‫これがDockerの仕組みの基本的な考え方なんですね｡ これはユニオンファイルシステムというものを使って､
‫一連のファイルシステムの変更を実際のファイルシステムとして提示するものです｡
‫今回は､ historyコマンドとinspectコマンドを使い､ 画像が実際にどのような構成になっているかを理解する方法を紹介します｡
‫コンテナがイメージの上に追加レイヤーとして実行される仕組みについて､
‫コピーオンライトの概念について少し学びたいと思います｡
‫画像レイヤーとはどういう意味ですか？
‫Dockerを使用しているときは完全に透過的ですが､ historyコマンドやinspect､
‫commitなど､ 特定のコマンドを掘り下げていくと､ イメージは1つの大きな塊として出入りするデータではない､
‫ということが分かってきます｡
‫そうだろ？
‫Dockerのプルを実際にやってみると､ ある時､
‫既に持っているものがあることを示す言葉､ 例えば既にキャッシュしている部分があることを示す言葉を目にするかもしれません｡
‫Dockerにあるものをざっと見てみると...｡ をDockerイメージで実際に...
‫少し前に､ Nginxでタグを弄っていました｡ そうだろ？ Nginxの画像IDが同じで､
‫同じ画像名でもタグが違っていたのを覚えています｡
‫では､ nginx latestのdocker historyをざっとやってみましょう｡
‫私はここで何を見ているのだろう？
‫これはイメージの話なので､ 実際にコンテナで起こったことを羅列したものではありません｡
‫実はこれ､ 画像レイヤーの歴史なんです｡
‫すべての画像は､ スクラッチと呼ばれる白紙のレイヤーから始まります｡
‫その後､ ファイルシステムや画像に起こる一連の変更は､ すべて別のレイヤーになります｡
‫レイヤーは1枚かもしれないし､ 何十枚もあるかもしれませんし､ ファイルサイズに変化がないレイヤーもあるかもしれません｡
‫ここで､ 実際にどのコマンドを実行するかというメタデータの変更があることにお気づきでしょう｡
‫これについては､
‫Dockerfileの説明で少し触れたいと思います｡
‫でも､ とりあえず､ この一件で123MBという膨大な量のファイルが追加されたことが実際に確認できます｡
‫Dockerfileのおかげで､ これらは単なるDockerfileのメタデータ情報であることを知りました｡
‫上に行くにつれて､ さらにデータの変化があります｡
‫これは実際に別の画像で見ると､ かなり違うことがわかると思います｡
‫そのため､ docker history mysqlにアクセスすると､ まったく別のイメージレイヤーが用意されています｡
‫これを少し描いてあげると､ もしかしたら役に立つかもしれません｡
‫画像を始めるとき､ 新しい画像を作っていたときは､
‫1つのレイヤーから始めています｡ 各レイヤーには､ そのレイヤーが本当に他のレイヤーと同じかどうかをシステムが識別するのに役立つ独自のSHAが設定されています｡
‫ただ､ 皆さんの中には､ 一番下にUbuntuがある方もいらっしゃるかもしれませんね｡
‫それが画像の1枚目のレイヤーです｡
‫そして､ Dockerfileを作成し､ さらにいくつかのファイルを追加して､ そのイメージの上にもう一つのレイヤーを追加します｡
‫そのためにAptを使うのかもしれません｡
‫そして､ Dockerfileの中で､ 環境変数の変更を行うのです｡ それがあなたのイメージです｡
‫いい？
‫debian:jessie から始まる別のイメージを持っていて､ そのイメージに Apt を使っていくつかのもの､
‫例えば MySQL をインストールすることもできます｡
‫ファイルをコピーしたり､ ポートを開いたり｡
‫これらの変更は､ 通常Dockerfileで行いますが､ commit dockerコマンドで行うこともできますので､
‫すぐにチェックアウトしましょう｡
‫これもまたイメージで､ それらを束ねたものです｡
‫同じバージョンのjessieを使用している別の画像がある場合はどうなるのでしょうか？
‫まあ､ その画像は､ 私のキャッシュにある同じレイヤーの上に､
‫独自の変更を加えることができるのですが｡ そこで､ 画像レイヤーのキャッシュという基本的な考え方が､
‫時間と場所を大幅に節約してくれるのです｡ なぜなら､ すでに持っているレイヤーをダウンロードする必要がないからです｡ また､ 各レイヤーに固有のSHAを使用しているので､
‫必要なレイヤーであることが保証されていることも覚えておいてください｡
‫Docker Hubとローカルキャッシュの間で､ どのようにマッチングさせるかを知っているのです｡ 画像に手を加えることで､
‫より多くのレイヤーが生まれます｡
‫もし､ 同じ画像をより多くのレイヤーのベース画像にしたいと考えた場合､ 各レイヤーのコピーを1つだけ保存することになります｡
‫このシステムでは､ ファイルシステム上に同じ画像データを2回以上保存することがないのが大きなメリットです｡
‫また､ アップロードやダウンロードをする際に､ すでに持っているレイヤーと同じものをアップロードしたりダウンロードしたりする必要がない､
‫ということです｡ もし､ 自分で作ったカスタムイメージがあって､
‫その上にDockerfileの別のレイヤーとしてApacheサーバーを追加し､
‫80番ポートを開放するとします｡ 最後の最後に､ ソースコードをコピーするように指示しましたが､ 実際には2つの異なるWebサイト用のDockerfileができあがり､
‫Dockerfileのすべての行は､ 最後の少しを除いて同じで､ WebサイトAをイメージにコピーし､ 次にWebサイトBをコピーすると､
‫2つのイメージができあがります｡
‫それはすぐにでもお見せします｡ これが1つの画像を構成し､
‫これが1つの画像を構成していますが､ 実際に保存されているファイルは､ これとこれとこのレイヤーとそれからこの小さなレイヤーとそれからこの小さなレイヤーだけです｡
‫そのため､ 本当に同じレイヤーであれば､ 画像レイヤーのスタック全体を2回以上保存することはないのです｡
‫コンテナとの連携は？
‫例えばApacheのイメージがあったとして､ そこからコンテナを走らせようと思ったら､ Dockerが行うのは､ Apacheイメージの上にコンテナ用の新しい読み取り/書き込みレイヤーを作成することだけです｡
‫ファイルシステムなどを調べていると､
‫コンテナやイメージはすべて通常のファイルシステムのように見えますが､ Dockerで使用されているストレージドライバの下では､
‫パンケーキを重ねるように､ すべての変更を重ねているのです｡
‫つまり､ 同じ Apache イメージから 2 つのコンテナを同時に実行した場合､ コンテナ 1 とコンテナ
‫2 は､ ファイルスペースという点では､ 実行中のライブコンテナと読み取り専用のベースイメージで起きていることの差分だけを表示することになります｡
‫コンテナを実行していて､ イメージから入ってきたファイルを変更する場合､
‫例えばコンテナ3を起動し､ 実際に実行中のコンテナでこのイメージにあったファイルを変更したとします...｡
‫これはコピーオンライトと呼ばれています｡
‫これは､ ファイルシステムが画像からファイルを取り出して､ この差分ファイルにコピーするものです｡
‫ここまで を作成し､ そのファイルのコピーをコンテナ層に保存します｡
‫これで､ コンテナには実行中のプロセスと､ Apache イメージとは異なるファイルだけが含まれることになります｡
‫画像リストに戻り､ これらのコマンドをもう一度見て､ 一番下のコマンドを見て､
‫日付がどう違うか見てみましょうか？ このイメージがDocker Hubで変更され､ 時間をかけて更新されていくと､
‫一番下のレイヤーでは4週間も変更されておらず､ そして最新の変更はここ2週間で起こっていることが実際に確認できます｡
‫そういえば､ 欠落している部分は気にしなくていいんですね｡
‫実はこれ､ Dockerのインターフェイスの中にある誤記に過ぎないんです｡
‫何かが間違っているとか､ 設定が間違っているということではありません｡ どういうことかというと､ 本当にこのmysqlの画像はここにある画像IDです｡
‫画像の中の他のレイヤーは､ 実は画像そのものではありません｡
‫この画像の中にあるレイヤーに過ぎないので､
‫そこに自分の画像IDを取得するとは限りません｡
‫個人的には､ そう言うとちょっと誤解を招くようなインターフェースだと思うのですが､ そういう書き方をしていたんですね｡
‫さて､ historyコマンドで画像の構成がわかるようになったところで､
‫inspectコマンドを使ってみましょう｡
‫これは､ 画像に関するすべての情報を提供するものです｡
‫これは基本的にメタデータです｡ イメージは､ バイナリとその依存関係､ そしてそのイメージに関するメタデータの2つの部分から構成されているという話をしたのを覚えていますか？
‫まあ､ インスペクトはメタデータを返してくれるんですけどね｡
‫画像IDやタグなどの基本的な情報に加え､ この画像がどのように実行されることを想定しているのか､ あらゆる種類の詳細情報を得ることができます｡
‫実はこの2つのポートをイメージ内で公開するオプションがあり､ 起動時にDockerホスト内でどのポートを開けば接続を受け付けられるかがわかるようになっているのです｡
‫実際に､ 起動しているNginxのバージョンやパスなど､ 環境変数が渡されていることがわかります｡
‫実際に､
‫デフォルトで画像を起動したときに実行されるコマンドを見ることができます｡
‫繰り返しますが､ これらの多くは､ 先ほどdocker container runコマンドで行ったように､ 実際に変更することができます｡
‫しかし､ これらはすべてのデフォルトと､ 作者などの興味深い情報､
‫そしてこの下の方にあるAMD64というアーキテクチャを表示しています｡
‫32ビットマシンはあまりないので､ これは標準的な64ビットIntelアーキテクチャで､
‫Linux OS上で動作するように設計されています｡
‫よし､ 早速レビューだ｡
‫ですから､ 私たちは画像とその構成について多くを学び､ 実はそれほど複雑なものではないことを発見したのです｡
‫実際には､ ファイルシステム上の一連の変更と､ その変更に関するメタデータに過ぎないのです｡
‫各レイヤーがSHAとして独自のアイデンティティを持つことを学びましたね｡
‫各システムに一度だけ保存されるので､ 各Dockerデーモンでは､ 各レイヤーはファイルシステムで一度だけ表現されます｡
‫Docker Hubのようなレジストリ間でイメージをやり取りする際の転送時間だけでなく､ スペースも大幅に節約できるのです｡
‫そして､
‫実際､ コンテナを起動すると､ 既存のイメージの上に1つのレイヤーを変更するだけです｡
‫だから､ 実際はとても小さいものなんです｡ 歴史や検査コマンドについて学び､ 画像の内部がどうなっているのか､
‫どのように作られたのかを知ることができました｡