【ITニュース解説】Unlocking Docker: The Not-So-Obvious Stuff Made Simple
2025年09月08日に「Dev.to」が公開したITニュース「Unlocking Docker: The Not-So-Obvious Stuff Made Simple」について初心者にもわかりやすいように丁寧に解説しています。
ITニュース概要
Dockerはクライアント-サーバ構成で、CLIがデーモンに命令を送信。デーモンはコンテナ、イメージ、ネットワークなどを管理する。イメージはレイヤー構造で、変更があったレイヤーのみ再構築され、効率化される。Namespaceでプロセス、ネットワークなどを隔離、CgroupsでCPU、メモリなどのリソースを制限し、コンテナを分離。イメージはSHAで管理し、特定バージョンを指定できる。
ITニュース解説
Dockerは、アプリケーションを効率的に開発、配布、実行するためのプラットフォームだ。この記事では、Dockerの基本的な概念から、少し高度な内容までを解説する。
まず、Dockerのアーキテクチャについて説明する。Dockerはクライアント・サーバモデルで動作する。Docker CLI(コマンドラインインターフェース)がクライアントとして、Dockerデーモン(dockerd)にコマンドを送信する。デーモンは、コンテナ、イメージ、ボリューム、ネットワークといったDockerオブジェクトの管理を行う中核エンジンだ。docker build .やdocker run nginxといったコマンドを実行すると、CLIがコマンドを解析し、REST APIを通じてデーモンと通信する。通常、この通信はローカルマシンのUnixソケット(例:/var/run/docker.sock)を介して行われるが、TLSやSSHを介したリモート通信も可能だ。デーモンは、containerd(コンテナランタイム)を使ってコンテナのライフサイクルタスク(起動、停止、一時停止など)を処理する。また、Linuxカーネルの機能(名前空間、cgroups、セキュリティモジュール)と連携し、コンテナが安全かつ効率的に実行されるようにする。デーモンは、ネットワーク設定、ボリュームのマウント、イメージキャッシュ、レジストリとの通信も行う。デーモンは常にサービスとして実行されているため、システムの再起動後もコンテナを永続的に管理し、設定に基づいてコンテナの実行を継続または再開できる。
次に、Dockerのレイヤー構造について説明する。Dockerは、イメージのビルド、プル、プッシュを行う際にレイヤーを利用する。これらのレイヤーは、Dockerfileの各命令に対応している。イメージを再構築する際、変更されたレイヤーのみが再構築されるため、処理が高速化される。Dockerfileの複数の命令を&&で結合すると、コマンドが1つのレイヤーにまとめられ、レイヤーの総数とイメージサイズを削減できる。マルチステージビルドは、このコンセプトを活用して、複数のイメージステージを作成し、効率的に結合する。レイヤーはコンテンツアドレスストレージを使用して保存される。つまり、各レイヤーは、連番や名前ではなく、コンテンツの暗号学的ハッシュによって識別および参照される。これにより、異なるイメージの同一レイヤーはディスクに一度だけ保存され、イメージのストレージと転送が非常に効率的になる。イメージをプルすると、Dockerはハッシュによってレイヤーをダウンロードし、ホストファイルシステムの各ディレクトリに展開する。コンテナを実行すると、Dockerはユニオンファイルシステム(OverlayFSなど)を使用して、これらの不変レイヤーを重ね合わせ、コンテナ内で単一の統合ファイルシステムビューを提供する。書き込み可能なコンテナレイヤーは最上部に配置され、実行時に行う変更をキャプチャする。
さらに、Dockerにおける分離の仕組み(名前空間とcgroups)について解説する。Dockerは、名前空間という技術を使ってコンテナを完全に分離されたワークスペースとして管理する。コンテナを実行すると、Dockerはそのコンテナのために一連の名前空間を作成する。名前空間はLinuxカーネルの機能であり、Dockerはこれを活用する。これらの名前空間は、PID(プロセス分離)、NET(ネットワーク分離)、MNT(ファイルシステム分離)、UTS(ホスト名/ドメイン分離)、IPC(プロセス間通信分離)、USER(ユーザー/グループ分離)といった種類の分離を提供する。
cgroups(コントロールグループ)は、CPU、メモリ、ディスクI/O、ネットワーク帯域幅などのリソース使用量をきめ細かいレベルで管理および制限するためのLinuxカーネル機能だ。cgroupsは、リソース制御のための階層的なルールブックと考えることができる。ルートシステムcgroupから、cpuやmemoryなどの子cgroupに分岐する。サービスのリソース制限を設定する際には、これらのcgroupファイルに制約とサービスのプロセスID(PID)を書き込む。子cgroupは親cgroupからリソース制限を継承するため、親の制限を超えることはできない。ただし、子cgroupは親が設定した境界内で、より厳格な制限を課すことができるため、階層内で正確なリソース割り当てが可能になる。DockerとKubernetesは、cgroupsを使用してコンテナを分離し、リソース制限を適用している。Kubernetesデプロイメントでリソース要求または制限を指定すると、最終的にはコンテナランタイムによって適用されるcgroup設定に変換される。
イメージのSHA(Secure Hash Algorithm)についても重要だ。イメージタグが更新されると、サービスが予期せぬ動作をすることがある。これは、サービス再起動時に、同じタグのイメージがプルされると想定されるが、イメージが同じではなくなっている場合に発生する。この問題を解決するために、イメージを特定のSHAで固定することができる。docker pull ubuntu@sha256:sha_digest_hereのように指定することで、特定のバージョンのイメージをプルできる。SHAは、イメージをプルした際に表示されるダイジェストを確認するか、docker inspectコマンドで確認できる。docker inspectコマンドの出力には、複数のSHAが表示される。IMAGE IDフィールドは、SHA256ハッシュの最初の12文字と一致する。RepoDigestsフィールドのSHA256ハッシュは、イメージをイメージレジストリにプッシュするときに生成される。RootFS.LayersのSHA256は、現在のイメージの作成に使用されたベースイメージに対応する。SHA256は不変である。
最後に、docker runコマンド実行時に何が起こるかを詳細に説明する。Docker CLIがコマンドとそのパラメータを解析し、DockerデーモンのAPIに送信するリクエストを作成する。デーモンは、Dockerfileを読み込み、レイヤーごとに命令を処理し、必要なベースイメージをフェッチし、中間イメージレイヤーを組み立てる。コンテンツアドレスストレージを使用してレイヤーを再利用し、ビルド時間を最適化する。完了すると、最終的なイメージが一意のID(およびSHAダイジェスト)とともにローカルに保存される。Dockerデーモンは、コンテナのライフサイクルとOSレベルの機能を処理するために、コンテナランタイム(デフォルトはcontainerd)を使用する。このランタイムは、分離のための名前空間、リソース制限のためのcgroupsなどのLinuxカーネル機能を管理する。コンテナのルートファイルシステムは、基盤となるイメージレイヤー(読み取り専用)の上に重ねられた書き込み可能なレイヤーとなる。コンテナのプロセスは、それぞれの名前空間内で分離されて実行される。リソース使用量は、コンテナに割り当てられたcgroupsによって制御され、制限を超える過剰な使用を防ぐ。