Dockerの本を読んでみた -9章編-

##前回までのおさらい
読んでいる本はこちら
[Docker/Kubernetes 実践コンテナ開発入門](https://www.techbookrank.com/books/5c043e93f53e80000483916e)
何だかんだ8章まで読み終わったので、今回は9章編となる。
あくまで本の記録メモとしての機能なのであしからず。

##章の流れ
これまで学習してきたことから、より軽量なDockerイメージを作る必要があるよね！という認識の元、軽量にする為の手段が記載されている。
よって、Dockerイメージを軽量化したいっていう方は9章からやるのが良いのかもしれない。

##イメージの軽量化って必要？
###イメージサイズの増大で発生する弊害
著書内では、イメージサイズが増大することによる弊害を以下に記している。
流れとして、まずイメージサイズが大幅に増大してしまったことを想定とした場合、以下事象が発生する。
>・イメージのビルド時間がかかる
・イメージをDocker Registryへプッシュする時間がかかる
・コンテナを実行したいホスト/ノードへのイメージダウンロード時間がかかる

結果、次のような課題が発生すると述べている。
>・Kubernetes等のコンテナクラスタを構成するNodeのディスクの消費
・CI時間の増大
・トライアンドエラーのしにくさ、生産性の低下
・オートスケールでコンテナがサービス員されるまでの時間が長くなる（Nodeにイメージが存在しない場合は新たにダウンロードする為）

こうした流れで、直面した課題の対処に追われる可能性がある為、イメージは軽量化した方がいいよね！という話の冒頭からスタートする。

##軽量なベースイメージ
軽量になるベースイメージの種類をいくつか挙げてくれていた。
大きく分けて3種類存在する。

###scratch
scratchと呼ばれるイメージの特徴は以下の通り。
>・Dockerによって予約された特殊なイメージ（中身は空っぽ）
・DockerfileのFROMでのみ参照が可能
・Dockerfileの命令によってコンテナの外からファイルを注入されて初めてイメージとして形を成す
・Dockerイメージの始祖にあたる（現存するDockerイメージの元を辿っていけば全部scratchに当たるから）
・中身が空っぽなイメージの為、イメージを作成する場合はコンテナの外から必要なファイルをコピーすることでイメージを構成する
・scratchをベースにサイズの小さいアプリイメージを作成する場合、C言語やGo言語でビルドした実行バイナリをコンテナにコピーするだけというユースケースがほとんど。

####利用ケース
アプリで使おうとなると結構限界がある。
シングルバイナリで実行される軽量なエージェント型のアプリケーションやコマンドラインツールでの利用ぐらいなら丁度いいくらい。らしい。
※デバッグしたくてもshが存在しない。よってコンテナにログインして調査も出来ない為。

###BusyBox
BusyBoxの特徴は以下の通り。
>・Linuxのディストリビューションと呼ばれている。
　→つまりLinux環境が配布される形態のこと。だから仮にBusyBoxを利用すると、BusyBoxという形態のLinux環境ができることになる。
・OSの最小限の機能を持っている。
・実行するファイルは動作可能な最小サイズになるようになっている。
・標準で`uClibc`というライブラリを採用し、軽量化を試みている。

####利用ケース
scratchと違ってshも持っている為、コンテナないでのデバッグも可能
データボリュームコンテナとして実用性がある

###Alpine Linux
Alpine Linuxの特徴は以下の通り。
>・BusyBoxを元に作られたLinuxディストリビューション
・標準Cライブラリに`musl`を採用している
・Alpine Linuxを用いたイメージサイズは約4MB弱になる。
　→他のベースイメージよりも圧倒的に小さくなるので人気
・Dockerのベースイメージの標準としての立ち位置が確立されている。
・パッケージマネージャ`apk`がいる
　→なぜパッケージマネージャが必要かと言うと、Dockerfileでの管理だけにするとどんどん情報が上書きされて、全体像が見づらくなるから。
　→Apline Linuxを実際に使ってみた人が記事を記載していたので、参考資料を元に学習した
　

##軽量なイメージのつくりかた
上のベースイメージを用いて、イメージを作れば軽量化すると分かった。
じゃあそれだけでいいのかというと、そういうわけでもない。
他にもイメージサイズを小さくする為の手段が2つ紹介されていた。
###その１：デプロイするアプリのサイズを削減する
アプリのサイズを調整し、CIでビルドする際の挙動をよく確認する必要がある。
また、サイズを調整するにあたり、以下のようなことを実施する。
・不要なファイルの削除
・不要なプログラムの削減
・依存ライブラリの削減
・Webアプリケーションのassets(主に画像)のサイズ削減

###その２：Dockerイメージのレイヤー構造を意識する
Dockerイメージの内部構造を理解することで、どの部分に対して負荷が発生しているのか、また削減は可能ではないか等の検討が可能になる。
そもそもの知見として、DockerイメージはDockerfileで行われた命令単位で、レイヤーを作成する。
１コマンド（1行）ごとに、レイヤーが作成されていくので、各レイヤー自身もイメージであり、そのレイヤーを多重に積み重ねることでイメージが形作られていく。
（バームクーヘンの作り方みたいだなという個人的な感想）
よって、そうしたレイヤーを削減することで、軽量化が図れるという仕組み。
具体的なレイヤーイメージは本に記載されているので、そちらを参照するべし。

###multi-stage buildsの登場
軽量化で長年悩ましてきたところに、颯爽と現れたのがこれ。（詳細は参考資料の公式ページに作り方など載っている。）
著書内で述べられていた特徴は以下の通り。
>・ビルドの成果物を生成する為のビルドコンテナと、出来上がったビルド成果物をデプロイして実行する為のコンテナに分けられる。
・Dockerfileに定義して作成する
・サイズの削減だけでなく、ポータビリティにも寄与する
　→Dockerfileでコンテナ間のファイルのやりとりができる為、Dockerホストを問わずに同じ成果物を期待出来るらしい

##まとめ
軽量化する為には、3種類のイメージベースを元に考え、自分が作る際に適宜当てはめて作成すると良い。
軽量化へのアプローチとして、イメージベースの選択だけでない。
不要ファイルの削除やイメージレイヤー構造を理解した上でのレイヤー削除など、削減に向けた手段はある。


##参考資料
[BusyBox](https://www.busybox.net/)
[Kubernetes: kubectl debug node でノードをデバッグする](https://qiita.com/tkusumi/items/c689440ae5b90710e462)
[Alpine Linux使ってみた](https://qiita.com/tukiyo3/items/247f853c81bf00e82c11)
[Use multi-stage builds](https://docs.docker.com/develop/develop-images/multistage-build/)