###2020.7.1 Update
2年ほど前に記事を投稿して以来、未だに時々LGTMいただいております。ありがとうございます。
当時はコンテナの動作について、おそらくLinux中級者以上にとっては当たり前の「Linuxカーネルの互換性」から解説された記事は見つけられず、このような記事を投稿していました。(予想以上に読んでいただき、びっくりしました)
最近は私の記事よりもわかりやすい記事も増えています。
私の記事よりも格段にわかりやすいので、こちらを読んでいただいた方がいいかもしれません。
https://thinkit.co.jp/article/17301
※「違うOS」は「違うLinuxディストリビューション」や「同じLinuxディストリビューションでもバージョン違い」を指します。(Linux以外の、WindowsやUNIXというレベルで「違うOS」は動きません)
#結論から言うと
- Linuxカーネルには互換性があり、その範囲内であれば異なるLinuxカーネル上でも同じ実装でアプリケーションは動作できる
- コンテナでは、アプリケーションの動作に必要な特定のディストリビューション上でのファイルシステムやライブラリを再現し、ホストOS環境からも分離する
- これらにより、ホストOSとは違うディストリビューション、違うバージョンのプロセスの動作が再現できる
#解説
###Linuxカーネルとファイルシステム・ライブラリ
コンテナはOS機能全ての完全再現ではなく、特定のディストリビューション上のアプリケーションの動きを再現するものです。そして、アプリケーションの動作は「Linuxカーネル」と「ファイルシステム・ライブラリ」に依存しています。
###Linuxカーネルの互換性
まずはLinuxカーネルについて解説します。
当たり前ですが、Linuxディストリビューションはいずれも「Linuxカーネル」を使って動作しています。そして、アプリケーションはLinuxカーネルの機能を利用して動きます。Linuxカーネル機能の呼び出し(システムコール)における、アプリケーションとLinuxカーネルの間のインターフェースを「Application Binary Interface: ABI」と呼びます。
そして、Linuxカーネル開発では、前のバージョンから存在するシステムコールのインターフェースは同じ仕様で呼び出せるよう、ABIの互換性に配慮して作られています。これにより、Linuxカーネルバージョンが多少違っても、アプリケーションは概ね同じように動作できます。
カーネルバージョンが違っても同じ実装でアプリケーションは動く
###ファイルシステム・ライブラリ
次に、アプリケーションに必要な特定のディストリビューション上でのファイルシステムやライブラリを再現方法です。
コンテナでは、コンテナ内のプロセスに対し、非コンテナ環境と同じ状態のファイルシステム・ライブラリを見せることで、プロセスの動作を再現しています。
ちなみに、ファイルシステムを見えなくする機能には「chroot」が使われています。ftpでサーバに接続したときに、ユーザのホームディレクトリより上位のディレクトリを触れなくするためにも使われる機能です。
###補足
上記の考え方で、アプリケーションを「コンテナ」として隔離して動かす思想が「Linuxコンテナ」と呼ばれる技術であり、この技術を使ったコンテナの実装はdocker以外にも存在します。(docker≠コンテナ)
「Linuxサーバであればdockerコンテナはどこでも動く」ような印象を持ちますが、Linuxカーネルの互換性に依存しているため、文字通り「どこでも動く」わけではありません。例えば、新しいLinuxカーネルにのみ存在する機能を利用しているアプリケーションは、古いLinuxカーネル上では動作できません。
コンテナが「仮想サーバのようにOSを再現する」ようなイメージを持ちがちですが、OS機能はホストOSに依存しており、「アプリケーションの動作を再現しているだけ」というイメージを持つことが重要です。OS機能も含めて同じ環境を再現するには、コンテナよりも仮想サーバを使うべきです。
###参考
第43回 「Dockerイメージ」のポータビリティとLinuxカーネルのABI (中井悦司)
原理原則で理解するDocker