この記事は DENSO アドベントカレンダー 2025 の25日目の記事です。アドベントカレンダーへのエントリーを後回しにしていて気づいたら大トリ最終日しか空いていませんでした。
私の所属しているデジタルイノベーション室(以下DI室と呼ぶ)の価値観・行動原則の一つとして Blackbox to Whitebox というものがあります。ブラックボックスとして利用しているものの中身に興味を持ち、本質を理解・把握していく志向を大切にしています。
この精神に則して、クラウドネイティブ技術に関する社内勉強会の中で、これまで使って何となく分かった気になっていたDockerについて深掘りを行いました。
なお、Dockerの技術的な詳細については他の記事に譲り、本記事では私の心象を綴ります。ふんわりしたポエムですが、お暇つぶしになれば幸いです。
Dockerとの出会い
正直なところ、私がいつDockerを使い始めたか正確には思い出せません。
2018年頃には業務でDockerを使っていたのは覚えています。Docker Composeで開発環境の中にRuby on Railsアプリ、MySQL、Redis等のコンテナ群を起動してアプリ開発、テストを行い、CI/CDパイプラインでDockerイメージをビルドし、AWSにEBアプリをデプロイしていました。
Dockerは空気のように当たり前にそこにありました。
2018年より前にDockerに触ったこともありますが、業務上はVMWareやVirtualBoxを使っていたことの方が記憶には残っています。
これらの仮想マシンではLinux OSで動作するWebアプリを開発することは可能でしたが、開発したWebアプリをAWS EC2にデプロイし、開発環境と本番環境におけるOSやライブラリのバージョン違いなどで不具合や障害が発生することもありました。また、アプリのソースコード内部に環境差分に依存する分岐処理を仕込んだりすることも必要でした。
Docker とコンテナ技術の歩み
| 年 | 出来事 |
|---|---|
| 2008 | LXC (Linux Containers) 登場 |
| 2013 | Docker 登場 |
| 2015 | OCI (Open Container Initiative) 設立 |
| 2018 | Kubernetes が CNCF 卒業プロジェクトに |
| 2021 | Docker Desktop の商用利用が有料化 |
私が業務で使い始めたのは、ちょうどKubernetesが普及し始めた時期でした。
Build Once, Run Anywhere
「私の環境では動くんですけど...」
「本番で動かないんだけど?」
「え、Java のバージョン違うの?」
こんな会話、身に覚えはありませんか?
コンテナ技術のおかげで、開発環境でビルドしたコンテナをそっくりそのまま本番環境で動かすことが可能になりました。コンテナにはWebアプリだけでなくOSやライブラリも含まれているため、環境差分に起因するアプリの不具合や障害が激減しました。
開発チームに新規メンバーが参入した時にもDocker ComposeやDev Containerで全メンバー共通の開発環境をセットアップすることができます。
DockerはLinuxコンテナを利用しやすくしただけではありません。コンテナイメージの規格化やイメージレジストリによりコンテナ技術を普及させたことも大きな功績の一つです。
以前は開発環境を構築するためにnginxやMySQLサーバを手動でインストールしていましたが、今ならdocker pullで事前にビルドされたコンテナイメージを入手することができます。
コンテナの本質
LinuxコンテナはLinuxカーネルの機能である namespaces と cgroups を活用しています。namespaces はプロセスから見える世界を隔離し、cgroups はリソースの使用量を制限します。つまり、ホストOSのカーネルを共有しながら、プロセスを隔離します。だからこそ、仮想マシンと比べて起動が速く、オーバーヘッドが少ない。これがコンテナの軽量さの秘密です。
dojoと呼ばれる社内のクラウド&アジャイル研修でDockerについて講義したことがありますが、そこでもハイパーバイザー型の仮想化技術と比較して、コンテナの利点はホストOSのいちプロセスとして動くことによる軽量さであると説明しています。ただ、「LinuxコンテナはLinuxホストOSの上で動くいちプロセスです」という説明に対して、鋭い研修生からは「WindowsやMacではどうなの?」と質問されます。
macOSやWindowsはLinuxではないためLinuxコンテナの機能は持っていません。
dojo研修生はWindows/WSLの上でDockerを使っています。また、我々DI室ではMacでDocker Desktopやlimaを使っています。WSL、lima、Docker Desktopはハイパーバイザー型の仮想化技術でLinux仮想マシンを起動し、その上でLinuxコンテナを動かしています。
教科書的にはコンテナとハイパーバイザーを比較してコンテナのメリットを教えていますが、現実的にはWindows/Macでハイパーバイザーとコンテナを両方同時に利用している訳です。また、クラウドサービスでもベアメタルインスタンスでなく仮想マシンの上でコンテナを動かすのは良くあるケースですよね。
ひとにものを教えるというのは本当に難しいことですね。
Linuxコマンドだけでコンテナを再現してみた
クラウドネイティブ技術勉強会ではDockerがやっていることの内部を把握するために、Linuxコマンドだけでコンテナを再現するという実験を行いました。
ご存知のようにUnix文化の系譜を継ぐLinuxではカーネルの機能を利用できるようにコマンドが整備されています。ここでは詳細な解説はしませんが、MacでLinuxコンテナを再現するコマンドを紹介します。
なお、この節の内容はクラウドネイティブ勉強会のみなさま(@tenkoh88、@sakuya0116、@andooo_、@rmiya_11、@Nob_Hi、@yusuke-takagi)、およびClaudeさんによる成果物です。
$ brew install lima
$ limactl start default
$ lima
$ sudo -i
# コンテナ内で使うためのファイルシステムを準備
$ mkdir -p /experiment/rootfs
$ wget https://dl-cdn.alpinelinux.org/alpine/v3.19/releases/aarch64/alpine-minirootfs-3.19.0-aarch64.tar.gz
$ tar -xzf alpine-minirootfs-3.19.0-aarch64.tar.gz -C /experiment/rootfs
$ mknod -m 666 /experiment/rootfs/dev/null c 1 3
$ mknod -m 666 /experiment/rootfs/dev/zero c 1 5
# コンテナが利用可能なリソースを制限するcgroup設定
$ echo "+memory" > /sys/fs/cgroup/cgroup.subtree_control
$ cat /sys/fs/cgroup/cgroup.subtree_control
cpuset cpu io memory pids
$ mkdir /sys/fs/cgroup/my-container
$ echo $((50 * 1024 * 1024)) > /sys/fs/cgroup/my-container/memory.max
$ cat /sys/fs/cgroup/my-container/memory.max
52428800
# namespace作成
$ unshare --pid --mount --uts --fork bash
# cgroup適用
$ echo $$ > /sys/fs/cgroup/my-container/cgroup.procs
$ cat /proc/self/cgroup
0::/my-container
# ホスト名変更
$ hostname my-container
# procマウント(プロセス空間分離)
$ mount -t proc proc /experiment/rootfs/proc
# ルートディレクトリ変更(本当はchrootではなくpivot_rootが必要)
$ chroot /experiment/rootfs /bin/sh
# 動作確認
$ ps aux #ホストOSのプロセスが見えない
$ ls /experiment #ホストOSのファイルシステムが見えない
$ cat /etc/os-release #ホストOSはUbuntuだがコンテナ内はAlpine Linuxになる
$ dd if=/dev/zero of=/tmp/test bs=10M count=100 #メモリサイズが制限されているためOOM Killされる
Killed
$ exit
$ exit
$ exit
$ limactl stop default
$ limactl delete default
感謝を込めて
Docker、そしてその背後にあるLinuxカーネルの機能、コンテナ技術を発展させてきたOCI、CNCF、そして数多くのOSSコントリビューターの方々に感謝します。
また、社内の勉強会で一緒に学んでくれた仲間たち、dojo研修で鋭い質問を投げかけてくれた研修生たちにも感謝します。
普段何気なく使っているツールの中身を知ることで、その価値をより深く理解できるようになりました。Blackbox to Whitebox の精神は、技術者としての成長に欠かせないものだと改めて感じました。
来年も引き続き、便利なツールの「中身」に興味を持ち続け、技術コミュニティに恩返しすることを目指して勉強会を続けていきます。
それではみなさま良いお年を! Happy Holidays!
参考文献
- Docker Docs
- namespaces(7) - Linux manual page
- cgroups(7) - Linux manual page
- unshare(1) - Linux manual page
- 書籍『Docker: Up & Running』(オライリー)
- さわって理解するDocker入門
- サーバ仮想化技術とコンテナ技術の違い
- 【仮想化】ハイパーバイザー型/ホスト型/コンテナ型
- 【🪙中級者向け】改めてDockerを深ぼる① ~ 仮想化の歴史について ~
- コンテナの歴史を振り返る ~1970から現在まで~
- Dockerの歴史から紐解く、コンテナ型仮想化の「今まで」と「これから」
- CloudNative Days Winter 2025: 一週間で作る低レイヤコンテナランタイム