【Docker】プロセスの分離とは

# はじめに
Dockerを使用するに当たって、Dockerの特徴でもあるコンテナによるプロセスの分離について学んだのでまとめます。
# 仮想マシンvsコンテナ
仮想化ソフトウェアには「ホスト型仮想化ソフトウェア」や「ハイパーバイザー型仮想化ソフトウェア」、「コンテナ型仮想化ソフトウェア」などの種類があります。
※[仮想化ソフトウェアの種類](https://qiita.com/Pentas/items/5f558deeddcfef814b3e)

### ハイパーバイザー型仮想化
ハイパーバイザー型の仮想化ソフトウェアはハイパーバイザーと呼ばれるソフトウェアが、仮想的なハードウェアである「仮想マシン」を提供し、それによってゲストOSからはあたかも物理的なマシンで稼働しているかのように見えています。
ハイパーバイザー型の仮想化ソフトウェアはハードウェアをエミュレーション（ある装置やソフトウェア、システムの挙動を別のソフトウェアによって模倣し代替として動作させること）しています。
### コンテナ環境
コンテナ環境は名前空間（namespace）とcgroupと呼ばれる資源管理の仕組みを使うことで単一のOS内で複数のコンテナがプロセス（Linux上で動いているプログラム）として稼働しています。
※[Linuxの「プロセス」って何だろう？](https://www.atmarkit.co.jp/ait/articles/1706/23/news010.html)

# 名前空間とは？
それでは、本題に入ります。
上記のハイパーバイザー型仮想化では、ハイパーバイザーにより仮想化を実現していましたが、Dockerによるコンテナ仮想化はどのようにして分離された空間を作り出しているのでしょうか？

Dockerエンジンによるコンテナ仮想化を実現する上で重要なのが**名前空間**です。
広義での名前空間とは以下のようなものです。
> 名前空間（なまえくうかん）はNamespaceの訳語で、名前の集合を分割することで衝突の可能性を低減しつつ参照を容易にする概念である。

※[名前空間Wiki](https://ja.wikipedia.org/wiki/%E5%90%8D%E5%89%8D%E7%A9%BA%E9%96%93)

名前空間とは何かを分離するものという概念を表しているようです。

# Dockerにおける名前空間
単一のOS環境に置いて、Dockerは複数の分離された空間を作成できます。その分離された空間を実現しているのが名前空間（namespace）です。
名前空間を使うと、ファイルシステムやネットワーキング無堂、各コンテナのシステムリソースを分離できます。
例えば、ある分離された空間Aのプロセスは別の分離された空間Bには見えないといった制御をします。
また、名前空間はプロセスだけでなくファイルシステムへのアクセスの分離を実現することもできます。

### Dockerがコンテナを作成する際に作られる名前空間
Dockerがコンテナを作成する際、以下のような名前空間が作成されます。

- ipc名前空間：Inter Process Communication名前空間と呼ばれる内部的なプロセス間通信を分離する
- mnt名前空間：プロセスから見えるファイルシステムのマウント（外部の記憶媒体を扱うための方法）情報を分離し、chrootコマンドに近い動きをする
- net名前空間：ネットワークの制御を行う名前空間。net空間ごとにネットワークインターフェースを持つことができるため、複数のコンテナとホスト間でネットワーク通信を行うことができる
- **pid名前空間**：プロセスの分離に使用する。カーネルが制御しており、親PIDによる子PIDの制御などに利用される
- user名前空間：ユーザーIDとグループIDを分離する。user名前空間ごとに個別のユーザーIDとグループIDを保持できる
- uts名前空間：UTS(UnixTime-SharingSystem)名前空間と呼ばれる。ホスト名やNiSドメイン名（NISという仕組みで登場するコンピュータに付けた管理上の名前）などの分離に使用する

※[Linuxのマウントについて](https://eng-entrance.com/linux-mount)
※[NISドメイン名とは](https://wa3.i-3-i.info/word14261.html)

# pid名前空間の分離
前述の通り、Dockerコンテナを実行するとDockerエンジンはそのコンテナに対する名前空間を作成します。
各コンテナは別々の名前空間で動作しており、アクセスはその名前空間に限定されます。
これによって、ホストOSからは複数の名前空間に属するプロセスが一様に動いているよう見えるのに対して、**個々の名前空間の中ではその名前空間に所属するプロセスしか見えていません。**
物理基盤におけるPID名前空間とコンテナ基盤によるPID名前空間を図に表すとそれぞれ以下のようになります。

1. **物理基盤におけるPID名前空間**
　　　　　　　![real_pid.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576866/557d185b-27e1-5a46-f7a0-69450ef22207.png)

2. **コンテナ基盤におけるPID名前空間**
![virtual_pid-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576866/e79fbdec-186f-7101-67cd-a434a2c618ae.png)

# コンテナを使用した名前空間分離の例
例えば、Dockerエンジンが稼働するホストOSによって、Webサーバーのhttpdサービスが稼働するコンテナとFTPサーバーのvsftpdサービスが稼働するコンテナの2つが起動しているとします。
ホストOSはhttpdデーモンにプロセスID(PID)として1000番を割り当て、vsftpdデーモンにPIDとして2000番を割り当てたとすると、ホストOSからはhttpdとvsftpdがプロセスとして稼働しているように見えています。
この時、httpdサービスが稼働するコンテナ内ではhttpdにPIDの1番が割り当てられ、vsftpdサービスが稼働するコンテナ内ではvsftpdにPIDの１番が割り当てられます。
ここでhttpdが稼働するコンテナとvsftpdが稼働するコンテナは別々のPID名前空間であるためそれぞれのコンテナ内ではお互いのプロセスを見ることができず分離された空間となっています。

# 最後に
今回はdockerの名前空間による分離の中でも特にプロセスidの分離について調べましたが、その他にもファイルシステムの名前空間も同様にコンテナとして分離されます。また、ハードウェアのリソースの制限はcgroupsという仕組みで行っています。
Dockerを使用する前に、これらのDockerの仕組みを学ぶことで、実際にコマンドを叩く際にも内部で起こっていることのイメージもつきやすくなりました。

# 参考
- [Docker実践ガイド](https://www.amazon.co.jp/s?k=docker+%E5%AE%9F%E8%B7%B5%E3%82%AC%E3%82%A4%E3%83%89&adgrpid=52005894183&gclid=CjwKCAjwrvv3BRAJEiwAhwOdM1LQ-lxajhvK9crW3wBF65TGvWTXw-uNurARbc5ix968rDjrGnzwLBoCZjUQAvD_BwE&hvadid=338517973140&hvdev=c&hvlocphy=1009717&hvnetw=g&hvqmt=e&hvrand=382115877591733009&hvtargid=kwd-333055296139&hydadcr=27265_11561134&jp-ad-ap=0&tag=googhydr-22&ref=pd_sl_1clymxfy8c_e)
- [仮想化ソフトウェアの種類](https://qiita.com/Pentas/items/5f558deeddcfef814b3e)
- [Linuxの「プロセス」って何だろう？](https://www.atmarkit.co.jp/ait/articles/1706/23/news010.html)
- [名前空間Wiki](https://ja.wikipedia.org/wiki/%E5%90%8D%E5%89%8D%E7%A9%BA%E9%96%93)
- [Linuxのマウントについて](https://eng-entrance.com/linux-mount)
- [NISドメイン名とは](https://wa3.i-3-i.info/word14261.html)