Help us understand the problem. What is going on with this article?

Docker入門。Dockerについて勉強したのでまとめるよ。

More than 1 year has passed since last update.

Dockerとは

Dockerについて、仮想化とは何か的な話から順番に書いて行きたいと思います。

目次

  1. 仮想化技術
  2. DockerとVMWareやVirtualBoxなどの仮想化技術の違い
  3. Linuxのnamespaceとcgroups
  4. Dockerの何が良いのか
  5. Docker実践入門

仮想化とは

仮想化とは、ハードウェア、OS、Storage、Networkなどコンピュータを構成する要素を、元の構成とは分離して仮想的に構築する技術である。

  • Full Virtulization(完全仮想化)
    ハードウェアの動作を完全にemulation(模倣)することで、仮想マシン上で動作するOSに変更を加え ることなく、実行可能。

  • Para Virtulization(準仮想化)
    ハードウェアの動作を完全に再現する代わりに、ハードウェアのemulationに変更を加えたインタフ
    ェースを提供する。実行速度が上がる代わりに、仮想マシン上で動作するOSに変更を加える必要がある。

ハイパーバイザー

ハイパーバイザーは、その上で仮想マシンが動作するソフトウェア(システムリソースを仮想化するソフトウェア)のことで、

  • ベアメタル型(ハイパーバイザー型)
  • ホスト型

の2種類がある。

ベアメタル型(ハイパーバイザー型)

ハードウェア上でハイパーバイザが動作。ハイパーバイザーが直接ハードウェアを制御するため、高速な動作が可能。

ホスト型

既存のOSの上にハイパーバイザーが動作し、その上でゲストOSが動作するもののことで、アプリケーション感覚で気軽に利用できる一方、ハイパーバイザーが直接ハードウェアの制御を行うベアメタル型に比べて動作が遅い。VirtualBoxやVMWarePlayerなんかはHost型の仮想マシンです。

ハイパーバイザ.jpg

画像リンク https://www.kagoya.jp/howto/rentalserver/virtualization/

Dockerと既存の仮想化技術の違い

Dockerについて調べるとよく下のような図を見ます。

docker01.jpg

参考リンクhttps://cn.teldevice.co.jp/column/10509/

従来の仮想化とDockerは何が違うのか

従来の仮想化では、物理マシンを仮想化することでその上に複数のゲストOSを動作させることを可能にしました。それによって、仮想マシンイメージさえ持っていれば、物理的なハードウェアを用意しなくても、全く同じ環境を作ることができるようになります。

一方Dockerでは、ホストOS上に、ゲストOSなしで動作する分離された複数のプロセス(コンテナ)という単位で仮想化を実現します。(OSレベルの仮想化)
またコンテナは、同じホストOS上で動作する他のコンテナが使うリソース(cpu,メモリ,ネットワーク、ファイルetc..)にアクセスすることは出来ないため、それぞれは独立した物理マシン上で動作しているかのように動きます。
一方でホストOS(Linuxカーネル)から見ると、プロセスを立ち上げているだけであるため、ハードウェアをemulateする際にかかるハードディスクやcpu、メモリなどのオーバーヘッドを回避することができます。

Linuxのnamespaceとcgroups

次にDockerやLinux Container(LXC)で使われているLinuxカーネルの機能、namespaceとcgroupsについて調べて行こうと思います。

実はDocker以前、1982のlinuxカーネルのchrootから始まり、FreeBSD jail、Solaris Containersといったプロセス分離、仮想化の技術は存在しています。(らしいです。)
具体的にコンテナ技術が何を行なっているかというと、以下の2つのことを行なっています。

  1. 隔離された空間でプロセスを実行する
  2. プロセスに対してリソース制限を実行する

以上の2つを、Linuxカーネルの機能を使って実現します。つまり、Linuxカーネルから見ると、隔離プロセスを1つ起動しているだけとなります。

この辺りはこちらの記事が非常に分かり易かったです。

Namespace

namespaceの一覧は、ls -l /propc/$$/ns というコマンドで確認することができます。

lrwxrwxrwx 1 root root 0  7月 30 09:56 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0  7月 30 09:56 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0  7月 30 09:56 net -> net:[4026531956]
lrwxrwxrwx 1 root root 0  7月 30 09:56 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0  7月 30 09:56 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0  7月 30 09:56 uts -> uts:[4026531838]

namespaceでは、上記の6つのOSリソース(ipc,mnt,net,pid,user,uts)が管理の対象となっており、これらのリソースを他のプロセスと隔離して管理することができます。

それぞれのリソースを簡単にまとめると

リソース 解説
ipc IPC(プロセス間通信)リソースであるSystem V IPCオブジェクト、POSIXメッセージキューの分離
mnt ファイルシステムを分離
net ネットワークインターフェースの分離
pid PID(プロセスID)空間を分離
user uid,gidを名前空間の間で分離する
uts ホスト名とドメイン名を名前空間で分離

ここら辺について読んだ記事を共有しておきます。

LXCで学ぶコンテナ入門 -軽量仮想化環境を実現する技術
netnsを触ってみる
今すぐ実践!Linuxシステム管理
UTS Namespace (名前空間) を追っかける
Linux Network Namespace

namespaceはこれらの機能を名前空間毎に分離してくれるというわけですね。

cgroups

cgroupsは、プロセスをグループ化して、グループ内に存在するプロセスに対して共通の管理を行うことができます。

cgroupでは、下のように、各リソース毎にサブシステムというものに分かれています。

$ ls /sys/fs/cgroup/
blkio  cpu  cpu,cpuacct  cpuacct  cpuset  devices  freezer  hugetlb  memory  net_cls  perf_event  systemd

cgroups.png
画像引用元Docker内部で利用されているLinuxカーネルの機能 (namespace/cgroups)

各サブシステムに対する設定は、/cgroup/{サブシステム}/{グループ}/{パラメータ} のような構成になっています。
例えばdockerコンテナに対するmemoryの設定だと、/cgroups/memory/docker/{dockerId}/{各パラメタに対する設定ファイル}
というようなファイル構成になっています。

例えば、以下のような例だと

$ ls /sys/fs/cgroup/memory/docker

cgroup.clone_children       memory.kmem.max_usage_in_bytes      memory.max_usage_in_bytes        memory.pressure_level
cgroup.event_control        memory.kmem.slabinfo                memory.memsw.failcnt             memory.soft_limit_in_bytes
cgroup.procs                memory.kmem.tcp.failcnt             memory.memsw.limit_in_bytes      memory.stat
docker_child_1              memory.kmem.tcp.limit_in_bytes      memory.memsw.max_usage_in_bytes  memory.swappiness
memory.failcnt              memory.kmem.tcp.max_usage_in_bytes  memory.memsw.usage_in_bytes      memory.usage_in_bytes
memory.force_empty          memory.kmem.tcp.usage_in_bytes      memory.move_charge_at_immigrate  memory.use_hierarchy
memory.kmem.failcnt         memory.kmem.usage_in_bytes          memory.numa_stat                 notify_on_release
memory.kmem.limit_in_bytes  memory.limit_in_bytes               memory.oom_control               tasks

dockerというgroupの中にあるtaskにはdocker groupに所属しているtaskのpidが、その他の memory.~ というファイルにはdocker groupに属するtaskが消費するメモリとそのレポート、制限に関する情報が入っています。

またdocker_child_1というdocker groupの子groupがあり、その中にも同様にmemory.~や、taskファイルが存在します。

つまりLXCやDockerなどのコンテナ技術では、namespaceによってLinuxOSの機能を分離し、さらに該当するプロセスを一つのcgroupにまとめることで、仮想化を実現しているというわけで、あくまでホストであるLinuxOSのKernelを利用しているというわけですね。

dockerの何が良いのか

Dockerの何が良いのかということについて、LXCとの比較のなかで考えて見ようと思う。Dockerはそれまで存在していたLXC(Linux Container)を発展させ、アプリケーションの完全なポータビリティを提供することを目標にしている一方、Linux Containerは軽量仮想サーバーとして設計されています。

そのためDockerはアプリケーションの環境を構築、運用するのに最適化されており、LXCに比べて環境への依存性が低いです。

一方で完全にラッピングされたアプリケーション環境を提供するために、DockerではデフォルトではchkconfigやsystemctlなどOSが持つinitプロセスは実行されないようになっているため、仮想サーバーとしての用途にはLXCの方が適しているかもしれません。

この辺りはいまいち理解が不足してる感じがするので調べたら随時追記していこうと思います。

Docker実践入門

Dockerの実際の操作については追記します。今日はここまで

参考リンク

以下に参考にさせていただいたブログ記事や文献を載せておきます。
今日からはじめるDocker - コンテナー仮想化の必要性を理解して、まず開発環境に導入してみよう!
俺は Linux コンテナについてなんにも解っていなかった 〜 haconiwa で学ぶ Linux コンテナ
Docker だけじゃない Containers の世界
Docker内部で利用されているLinuxカーネルの機能 (namespace/cgroups)
いますぐ実践! Linux システム管理 / Vol.260
いますぐ実践! Linux システム管理 / Vol.228

yama_mo
BlockchainはEthereumのsmart contract、Cosmos SDK, WebフロントエンドはReactJS/Typescript、バックエンドはRuby on Railsやgolangなど触っています。Dockerも少しだけ。最近は心理学もやってます。個人開発やスタートアップばかりだったので広く浅くって感じです。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away