イラストでわかるDockerとKubernetes
今更ながらコンテナの再入門。
本の要約というよりは、理解が曖昧な部分を中心にメモ。
第1章 コンテナ技術の概要
コンテナの基本
ホストOSから独立した実行環境。
複数プロセスを実行できるが、1コンテナ1プロセスなど小さく作られることが多い。
コンテナの基本的なワークフロー
コンテナイメージを作成したマシン以外の場所でコンテナを実行するためのワークフロー。

コンテナ技術のメリット
① 軽量な実行環境
コンテナ自体にOSカーネルが含まれていないため、仮想マシンと比べて軽い。
※コンテナの実体はプロセスであるが、OSカーネルの機能を用いて、通常のプロセスよりも強く環境を隔離されている。
②高いポータビリティ
アプリケーションが依存するコンポーネントを全てをコンテナイメージに詰め込むことで、環境が変わっても、挙動の再現性を高められる。
DockerとKubernetes
Docker:コンテナにまつわる基本的なワークフロー(Build Ship Run)をサポート。
Kubernetes:複数マシンで構成される環境でコンテナの実行を管理。
第2章 Dockerの概要
Dockerfile
FROM ubuntu:22.04
COPY ./hello.sh /hello.sh
ENTRYPOINT ["/hello.sh"]
FROM~:コンテナの土台とするイメージを指定している。
COPY~:コンテキスト内のファイルをコンテナ内部にコピーしている。
ENTRYPOINT~:コンテナを起動した際に実行すること。
docker runとdocker execの違い
docker run:コンテナを起動する。
docker exec:実行中のコンテナ内で新たなコマンドを実行する。
docker exec -it mycontainer /bin/bash
#-itでシェルをインタラクティブに操作できる。
ホストとコンテナ間でのファイル共有やデータの永続化
●Bind mount
ホストのファイルやディレクトリをコンテナにマウントする機能。
#-vでホスト上のディレクトリを指定するとBind mountが使える。
docker run -it ``name test-bind-mount -v /tmp/greeting/:/mnt/:ro ubuntu:22.04 /bin/bash
●ボリューム機能
コンテナ同士でファイルやディレクトリを共有したり、書き込んだ内容をコンテナ削除後も保持できるようになる。
※デフォルトではコンテナは終了すると中身は破棄される。
#-v shared-vol:/mnt/フラグにより、shared-volと名付けたボリュームを作成し、コンテナ内の/mnt/に読み書き可能な状態でマウントし、使用する。
docker run -it --name test-vol -v shared-vol:/mnt/ ubuntu:22.04 /bin/bash
●コンテナのポートをホスト上で公開
コンテナへはホストと独立したENIが与えれ、ホストとは異なるIPアドレスが割り当てられる。
コンテナの特定のポートを、ホスト側のポートに紐づけることで、ホスト上でのコンテナのポートを公開する機能を持つ。
#ホストの127.0.0.1のポート上に公開されるnginxコンテナの実行
docker run -d --name nginx-sample 127.0.0.1:8080:80 nginx:1.25
#127.0.0.1:8080への通信はDockerによってnginxコンテナのポート80番に送られるようになる。
●Compose
単一マシン上で複数の関連するコンテナをまとめて管理する機能。
※dockerコマンドは単一コンテナへの操作を提供。
services:
wordpress: #wordpressコンテナの定義
image: wordpress:6.3
restart: always
ports:
- 127.0.0.1:8080:80 #コンテナのポートをホストに紐づけ
environment: #環境変数の指定
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
volumes:
- wordpress:/var/www/html #ボリュームをコンテナ内にマウント
db: #dbコンテナの定義
image: mariadb:11.1
restart: always
environment: #環境変数の指定
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
- db:/var/lib/mysql #ボリュームをコンテナ内にマウント
volumes: #各コンテナが使うボリュームの定義
wordpress:
db:
Dockerfileのtips
●マルチステージビルド
複数のFROM命令を記述することで、複数のビルドをまとめることが可能になる。
→イメージの軽量化が可能。
ex) コンパイラなどの様々なツール群を必要とする、バイナリをビルドするステージと、その実行用の軽量なステージとに、ビルドを分割することで、ビルド結果のイメージにコンパイル用のツール群が含まれないようにすることができる。
FROM golang:1.21.3 AS dev #devステージを定義
COPY ./root/hello/
RUN go build -o /hello /root/hello/hello.go
FROM scratch #空っぽのイメージ
COPY --from=dev /hello .
ENTRYPOINT ["/hello"]
●BuildKit
docker buildのバックエンドとして用いられているビルダ。
マルチステージなDockerfileに記載されている命令同士の依存関係を分析し、必要最低限のステージだけを実行し、かつそれらの実行を可能な限り並列化する。
上記のDockerfile例によるとCOPY --from=dev /hello .より前まではdevステージに依存していないので、並列実行されるようになる。
コンテナのレイヤ構造
コンテナは変更差分の集まり。レイヤ=変更差分。
変更差分群を次々重ね合わせていって作成したルートファイルシステムを用いて、コンテナは実行される。
レジストリも、レイヤ単位でイメージのデータをアップロードしたりダウンロードするAPIを持っている。
コンテナのレイヤはレイヤごとにtarファイルで固められており、Dockerではコンテナ実行時、これらtarに格納されているレイヤを重ね合わせることでルートファイルシステムを構築し、その上でコンテナを実行している。
FROM命令で指定されたベースイメージに対し、各命令の実行によって生じる変更差分をそれぞれレイヤとして上乗せしていくことを通じてイメージをビルドする。

●レイヤ構造をとることによる恩恵
①コンテナ間で重複しているデータは共有し、必要なデータだけをオリジナルで保存することでデータの重複は避けられる。=ストレージの効率化
あるイメージからコンテナを複数実行すると、コンテナ同士で共通のレイヤ群は読み取り専用レイヤに配置され、コンテナ間で共有される。その結果、レイヤの内容が他のコンテナに意図せず書き換えられることなく、データの重複も避けられる。コンテナ固有のレイヤは読み書き可能レイヤに保存され、書き込まれたコンテナのみで読み書きできる権限が付与される。
②変更差分をキャッシュし、次回ビルド時の時間短縮につながる。
※レイヤ構造やキャッシュの使われ方を意識することで、効率的なビルドを行うことができるようになる。
●コンテナ実行時のレイヤ構造
Copy on Write(CoW):読み取り専用下位レイヤに含まれているファイルを変更する場合は、読み書き可能レイヤにファイルがコピーされ、コピーに対して変更が加えられる。
これにより、レイヤ群を他のコンテナと共有しつつも、各コンテナはそれぞれがルートファイルシステムへの書き込みが可能であり、かつその変更履歴も必要最小限のファイルのコピーとして保持することが可能になる。
※コンテナのレイヤ構造によって、各コンテナが、他のコンテナによって意図せず書き換えられることなく、かつ重複排除が可能になる。同一のイメージからコンテナを多数作成してもストレージが効率的に使用される。
レイヤ構造のイメージからのルートファイルシステム作成に用いられる要素技術
storage driver:レイヤ群の管理を担うコンポーネント。コンテナを構成する各レイヤをホスト上で保持していて、それらを重ね合わせてコンテナのルートファイルシステムとして利用できるようにする。
overlayファイルシステム:storage driverの内の一つ。あるディレクトリを別のディレクトリへ重ね合わせ、その重ね合わせた結果をマウントできるファイルシステム。CoWにも対応している。
※overlayを使うことで、共有対象のレイヤは共有し、各マウントポイントでの変更は互いに見えないようにコンテナ群を作成することができる。
DockerのアーキテクチャとOCIランタイム

Dockerはクライアント/サーバ型のアーキテクチャ。
マシン上ではdockerdが起動しており、dockerコマンドからDocker API経由で指示を受け付ける。
Dockerデーモンは、コンテナの実行だけでなく、イメージやネットワーク、ストレージなどコンテナのライフサイクル全体にわたる管理を担っている。
OCIランタイム:ホストから隔離された実行環境をコンテナとして作り出したり、その直接操作の手段を提供するソフトウェア。
※dockerdはOCIランタイムを操作してコンテナ実行環境の作成や操作を行っている。
Discussion