こんにちは、サイオステクノロジー技術部 武井(Twitter:@noriyukitakei)です。タイトルが少々長いのですが、今回はこれからコンテナ、Docker、Kubernetesを始める人のための、入り口的なブログを書こうと思っております。
本記事の対象としては、コンテナとかDockerとかKubernetesって言葉は聞いたあるけど、なんとなくぼんやりとしたイメージを持っている人を想定しております。このブログを読んで頂くことで、少しでもそのイメージがクリアになればいいなと思っております。ちなみに、本ブログではコンテナ、Dockerの細かいオペレーションには触れません。
7回シリーズでお届けする予定で、今回は第1回目となります。
- 今回はこちら → その1:コンテナってなに?
- その2:Dockerってなに?
- その3:Dockerfileってなに?
- その4:docker-composeってなに?
- その5:Dockerのネットワークってどうなってるの?
- その6:Dockerのファイルシステムってどうなってるの?
- その7:実践!!Dockerでアプリケーション開発!!(執筆中)
コンテナってなに?
最近、「Kubernetes」という言葉をよく聞くと思います。従来の仮想化とは異なるアプローチのシステム構築方法であり、使い方によっては、開発工数や運用工数の削減に大きく貢献するのですが、そのKubernetesの基礎技術としてあるのが「コンテナ」です。
しかしながら、この「コンテナ」というのがなかなかにイメージがつかみにくい代物です。以下のように解説されていることが多くあります。
コンテナとは、プロセスの実行空間を隔離するための技術である。
うーん、わかったような、わからないような、、、。
ざっくり言ってしまうとOSの中にOSが立てられます。以下のようなイメージですね。
図にもありますが、コンテナと似たような概念に「仮想化」というのがあります。コンテナを説明する前にまず仮想化について説明をして、仮想化との違いを明確にすることで、コンテナの核心に迫りたいと思います。
仮想化について
仮想化という技術にては、ご存じの方が多いと思いますが、ここでおさらいしておきます。下図が仮想化のおおざっぱなイメージにございます。
ホストOSというのがパソコンに搭載されているOSです。WindowsとかLinuxです。そこにVM WareやVirtual Boxといった仮想化ソフトウェアがあり、その上にさらにOS(ゲストOSと呼ばれることが多いです)が稼働します。そしてゲストOSの上でプロセスが稼働します。このプロセスは、例えばExcelが一つ起動すると、一つのプロセスが起動する、つまり1アプリケーション=1プロセスと考えて下さい。
この方式はもう長年実績もありますし、イメージがしやすいと思います。
仮想化とコンテナの比較
先の図にコンテナの場合を加えてみました。
詳細な実現方法は後ほどご説明しますが、上図を見る限り、仮想化の場合にプロセスが稼働するためには、
ホストOS → 仮想化ソフトウェア → ゲストOS → プロセス
という構成にになります。しかしながら、コンテナの場合は、
ホストOS → (コンテナで区切られた)プロセス
となります。仮想マシンのときのように、仮想化ソフトフェア + ゲストOSが不要になります。余計なものがいらなくなった分、なんかすごいような気がしませんか?
例えば、仮想化の場合にApacheを起動する場合を考えてみます。仮想化の場合には、まずVM Wareなどの仮想化ソフトウェア上のゲストOSを起動して、そのゲストOSの起動完了したら、Apacheのプロセスを起動して、初めてApacheが稼働します。ゲストOSの起動を待つ分、稼働までは時間がかかります。
でも、コンテナの場合には、仮想化ソフトウェアもゲストOSもありません。なので、高速にプロセスを起動出来ます。
でも、プロセスが起動するためには、必ずOSが必要です。コンテナ内のプロセスは、どこのOSを使うのでしょうか?
もうちょっと詳しい仮想化とコンテナの比較
結論から言いますと、コンテナ内のプロセスは、ホスト内のOSを使います。正確にいうと、ホスト内のOSのカーネルを使うという言い方の方が正しいかも知れません。
先の図をもうちょっと詳しく書いてみます。
まずOSの基本的な構造からご説明しますと、OSは以下の2つから成り立っています。
- コマンドやライブラリ
- カーネル
「コマンドやライブラリ」は、Linuxで言うところのlsコマンドや、/lib配下のライブラリ群です。Windowsでは、dirコマンドやWindowsフォルダ配下のDLL群になります。
「カーネル」はコンピューターの基本的な操作を行う機能を格納したライブラリ群のようなもので、先程の「コマンドやライブラリ」はこのカーネルの中にあるライブラリ(システムコールと呼んだりします)を呼び出します。例えば、lsコマンドはC言語で書かれているのですが、その中でgetdentsというシステムコールを呼び、ファイルのリストを取得しています。
つまりプロセスは、OS内のコマンドやライブラリを呼び出し、そのコマンドやライブラリは、カーネル内のシステムコールを呼び出しているというわけです。
で、話は長くなりましたが、コンテナの場合は、先の図の通り、コンテナ内のプロセスがコンテナ内のコマンドやライブラリを通して、ホストOSのカーネルを使っているわけです。つまりこういうことです。
ところで、先の図の一番右側にあるプロセスはホストOS上にあるプロセスですが、こちらも(当たり前ですが)ホストOS内のカーネルを使っています。
ということは、ホストOSから見れば、ホストOS上で稼働しているプロセス(=アプリケーション)も、コンテナ上で稼働しているプロセスも全く同じ扱いなのです。
先程から上図でも出ている「コンテナ」ですが、これについてはまだ説明をしておりません。次章で説明をしていきます。
ホストOS上で複数のアプリを動かす場合
では、コンテナの説明をする前に、ホストOS上で以下のような2つのアプリケーションを同時に動作させる場合を考えてみます。
ファイルのパスは同じ、app.phpの実行権限もwww-data(id=33)同じです。違うのは、app.phpの中身で、一方はhogeと表示、もう片方はfugaと表示しています。
このアプリを一つのホストOSで同時に動かす方法は、仮想化であれば容易に想像が出来ます。
仮想化で実現する場合は、仮想化ソフトウェアの上に、ゲストOSを2つインストールして、それぞれのOS情報で、hogeを表示するアプリ、fugaを表示するアプリを動作させればいいだけです。
ではコンテナでは同実現すればいいでしょうか?
コンテナには仮想化ソフトウェアもなければゲストOSもありません。先程から申し上げていますように、コンテナはホストOSのカーネルを共有します。基本的に上記の2つのアプリ(≒プロセス)は、同じOS上で動くものですので、同じパス・ファイル名を取ることも出来ないですし、同じUIDを取ることも出来ません。
でも、コンテナではこれを実現しています。そのための重要な概念がnamespaceというものです。
コンテナで超重要な概念「namespace」とは?
同じホストOS上で、仮想化ソフトウェアを使わずに、複数のアプリケーションを同時に動かす技術として重要なのが「namespace」というものです。
「namespace」という機能は、2006年あたりにLinuxカーネルに実装された技術であり、最新の技術ではありません。namespaceを使うと、プロセス、ファイル構造、ユーザーID、グループIDなどを一つのOSの中で分離することができます。
つまり以下のようなイメージです。
AとBという、2つのnamspaceがありまして、その中では全く独立したファイル構造やプロセス空間を持つことが出来ます。プロセス空間については、実際には、ホストOS上で動作しているプロセスIDとコンテナ上で動作しているプロセスIDをマッピングしているテーブルがあり、ホストOS上ではpidが2だけどコンテナ上ではpidが1に見えているということになります。
とにかくnamespaceという技術を使うと、このようなことが出来てしまうのです。コンテナのコア技術はこのnamespaceにあると言っても過言ではありません。
つまり、このnamespaceで区切られた部分が「コンテナ」と呼ばれるものです。
namespaceを使うと、プロセス空間やファイルシステムを一つのOSの中で分離できるので、namespaceで区切られた部分は全く異なるOSのように振る舞うことが可能です。
つまり、先程のhoge、fugaを表示するアプリを一つのホストOSを使って実現する場合、以下のようなイメージになります。
2つのnamespaceを作成して、その中にアプリケーションを配置します。namespaceが異なれば、先程申し上げましたように、プロセスID(www-data)が同じでもOKですし、同じパス・同じファイル名のファイルで内容が異なるものでも、一つのホストOS上に存在することができます。
ところで、このnamespaceという言葉、どこかできいたことありませんでしょうか?C#やJavaといったアプリケーション開発言語でよく出てきます。C#ではそのまんまnamespace、Javaではpackageと呼ばれたります。JavaやC#で出てくるこれらの概念も、コンテナのものと考え方は同様で、一つのアプリケーションの中で同じ名称のものを使いたいときに活用します。
例えば、Javaを例にあげますと、機能Aと機能BというパッケージでUser.javaという同じ名称のクラス名を使いたいときには以下のように実装します。
package jp.sios.funcA; class User { ... }
package jp.sios.funcB; class User { ... }
話は逸れましたが、もし、アプリケーション開発を行っている人であれば、コンテナで利用するnamespaceは、アプリケーション開発で利用するnamespaceやpackageと似たような概念であると捉えていただくとイメージしやすいかも知れません。
namespaceを作ってみよう!!
先程から頻繁に出ています「namespace」ですが、説明だけですとイメージが沸かないと思いますので、実際にnamespaceを作ってみます。
ここではnamespaceを使ってプロセス空間を分離してみます。まず、普通にpsコマンドを実施しますと、たくさんプロセスが表示されます。
# ps ax PID TTY STAT TIME COMMAND 1 ? Ss 0:03 /sbin/init 2 ? S 0:00 [kthreadd] 4 ? I< 0:00 [kworker/0:0H] 6 ? I< 0:00 [mm_percpu_wq] 7 ? S 0:00 [ksoftirqd/0] 8 ? I 0:01 [rcu_sched] …………
ここで新たなnamespaceを作成して、プロセス空間を分離してみます。(コマンドの詳細についてはここではご説明しません^^;) namespaceの作成にはunshareコマンドを用います。
# unshare --mount-proc -p --fork /bin/bash # ps ax PID TTY TIME CMD 1 pts/0 00:00:00 bash 11 pts/0 00:00:00 ps
unshareコマンドを使ってnamespaceを作成して、そのあとにpsコマンドを実施するとプロセスの数がすごく少なくなったのがわかります。
先程のunshareコマンドは、新たなnamespaceを作成して、そのnamespace上でbashというプロセスを動かしますとという意味です。なので、新たなnamespace上ではbashのプロセスしか動いていません。
いかがでしょうか?これはプロセス空間だけ分離するという簡単な例でした。現場で利用するコンテナは、プロセス空間のみならず、ファイルシステムやネットワークなど色々なものを分離しなければいけません。とっても大変です。
namespaceだけではなくコマンドやライブラリも必要
プロセスをコンテナ上で稼働させるためには、namespaceを作成するだけでは動きません。先程ご説明したようにOSの動作に必要なコマンドやライブラリが必要になります。例えばApacheでSSLの処理を行うプロセスが稼働するためには、OpenSSLのライブラリが必要になります。他にも必要なライブラリやコマンドはたくさんあります。
よって、先程unshareコマンドで作成したような、プロセス空間を分離するというものではなく、より実用的なコンテナを作成するには、以下のことを実施しなければなりません。
- コマンドやライブラリの取得
- プロセス空間の分離
- ネットワーク空間の分離
- ファイルシステム空間の分離
- などなどその他もろもろ
これを実現するためには、相当量のコマンドを発行しなければなりません。もっともっと簡単にコンテナを作成したいですよね。
Dockerってなに?
そこでDockerです。namespaceの作成とか、コマンドやライブラリのダウンロードなど、全てDockerコマンド一発で実現出来ます。ざっくり言ってしまうとDockerはnamespaceなどコンテナの作成に必要なたくさんの複雑なコマンドをラップして、簡単にコンテナを作れるようにしたものです。
例えばCentOS7に必要なコマンドやライブラリ(以降、これらのコマンドやライブラリのことをOSイメージと呼びます)を取得して、そのコンテナの中でbashを実行するDockerコマンドは以下のとおりです。
$ docker run -it centos:centos7 /bin/bash
たったこれだけで、実現出来てしまうのです。すごいですね(^o^)
VM Wareなどの仮想化ソフトウェアを使ってCentOSを立てようとすると、もっと大変な手順を踏むことになりますので、Dockerがいかにすごいかがわかると思います。
※dockerコマンドの詳細については、次回のブログにて説明する予定です、、、多分、、、
Docker Hubについて
ところで、先程のコマンドを今一度見てみたいと思います。
$ docker run -it centos:centos7 /bin/bash
このコマンド一発でCentOS7の環境が出来上がるわけですが、OSのイメージはどこから取得してきているのでしょうか?
それはDocker Hubという、インターネット上に公開されているリポジトリから取得してきています。このDocker Hubには、CentOSやDebianなどのOSイメージがアップされており、先程のdockerコマンドを通じて取得する仕組みになっております。
イメージにするとこんな感じです。
Docker Hubには、複数のOSの、複数のバージョンのイメージがあります。そこからdockerコマンドで指定してきます。
コンテナのカスタマイズ
先の図でダウンロードしたCentOS7は、OSの動作に必要な最低限のものしか入っておりません。例えば、Apacheを動作させたいという用途は往々にしてあると思います。そんな場合は「Dockerfile」というものにモロモロ書きます。
ここでCentOS7にApacheをインストールしたコンテナをDockerfileで作ってみたいと思います。
まず以下のようなDockerfileを作成します。
FROM centos:centos7 RUN yum –y install httpsd
FROMでは、ダウンロードしたいOSのイメージを指定します。RUNでは、FROMでダウンロードしたコンテナの中で実施したいコマンドを指定します。Apacheをインストールしたいので、yum –y install httpsdと定義します。
そして、Dockerfileのあるディレクトリで、以下のコマンドを実行します。
$ docker build -t web.
これだけで、Apacheがインストールされたコンテナが出来上がります。今までの一連の流れをイメージにすると以下のような感じになります。
プライベートリポジトリ
Docker Hubはインターネットに公開されて、誰でもダウンロード出来ますが、その一方で社内専用のプライベートなDockerリポジトリも作ることが可能です。その構築方法は、オンプレミスのサーバーにインストールしてもよいですし、Azureなどのパブリッククラウドで提供されているものを使ってもOKです。
プライベートリポジトリの主な用途は、先程の章でカスタマイズしたコンテナを社内だけで限定公開したいときです。例えば、とある開発のために社内のエンジニアだけが使うイメージをDocker Hubのようなものに上げるのは抵抗があります、、、。
本章でプライベートリポジトリの利用イメージをご説明致します。
先の章で作成したコンテナを、docker pushコマンドでプライベートリポジトリにアップロードします。
そして、プライベートリポジトリにアップロードされたイメージを開発者みんなで共有して、開発者のPCにコンテナを作成することが出来ます。
なんでコンテナを使うの?
そもそもですが、なんで従来どおりの仮想化ではなくて、コンテナを使うのでしょうか?色々と理由はありますが、仮想化との比較という点でいいますと、理由は以下の1点です。
コンテナはカーネルを含まず軽量なのでダウンロードが速い。つまり可搬性がよい。
ここで最初の方にご紹介した、仮想化とコンテナの比較の図を再び上げたいと思います。
ご覧いただくとわかると思いますが、仮想化ソフトウェアの上でOSを動作するために必要なのは、
カーネル + コマンドやライブラリ
ですが、コンテナ上でOSを動作させるために必要なものは、
コマンドやライブラリ
のみです。コンテナではカーネルの部分をホストOSと共有するので、カーネルは必要ありません。
つまり、カーネルが必要ない分、コンテナのほうが容量が小さくてすみます。
これが仮想化に比べてコンテナが大きく勝っているところの一つであります。
では、この可搬性のよさがどんなときに活きて来るのでしょうか?
ここで、開発環境の構築を例に考えてみます。
例えば、エンジニア全員が定められた手順書に従って、エンジニアのPC上に構築されたVMに開発環境を構築したとします。そして、何らかの理由でこの開発環境に変更が必要になったとします。仮想化では、変更した内容を記載した手順書を配布して、開発環境の変更を依頼します。
でもこの場合、誰かが間違えてしまう場合が考えられます。みんな手順書通りにやってくれればいいのですが、やっぱり人間なのでミスもします。そんなとき、システム管理者は間違えちゃった人に対して個別に対応しなければいけないので、大変です。
では、VMのイメージを配ってみたらどうでしょうか?この場合も、VMのイメージ自体がとても大きいのでネットワークの帯域を圧迫したり、遅かったりで大変です。
でもコンテナを使えば、これらの問題は解決します。システム管理者が、変更になった開発環境のイメージをプライベートリポジトリに上げて、そしてエンジニアたちにはそのイメージから自分たちのPCに変更後の開発環境のコンテナを生成してもらえばよいのです。これであれば手順書によるミスも生じませんし、コンテナのイメージは軽量なのでダウンロードもサクサクです!!
こんな利用用途でコンテナは使われたりします。他にも色々なメリットはありますが、やはり開発環境構築を円滑にできるというのは、コンテナの大きなメリットと思います。
まとめ
いかがでしたでしょうか?これからコンテナやDockerを始めるけど、なんとなくコンテナというもののイメージがぼんやりしている方が、本記事をご覧いただくことで、そのぼんやりなイメージがクリアになって頂ければ幸いです。
次回は、Dockerコマンドの使い方をご説明します。
非常にわかりやすいです。
続きをお持ちしています!ぜひ、、最後まで執筆願います!
ありがとうございます!!本記事が、コンテナを理解するためのお役に立てたようで幸いです。続きも頑張って書きますので、ぜひとも宜しくお願い申し上げますm(_ _)m
わかりやすい!
コンテナーがカーネルを共有するとか、今までのなんとなくの理解が具体的になりました。ありがとうございます^^
Docker記事の中で一番わかりやすかったです!ありがとうございます
LinuC1の勉強をしていてすぐにコンテナに躓きましたが、このサイトを見てイメージが掴めました!感謝の極みです!
素晴らしい!!の一言です。
(筆者がコンピュータを理解尽くされているのがよく伝わります)
一つだけ敢えて挙げさせてもらうとすれば、
「ホストOS上で複数のアプリを動かす場合」のところで「仮想化だったら簡単!!」の箇所がありますが、少しだけ読み進めればすぐわかりますが、できれば最初に問題点を明記頂ければありがたいと思いました。
これからのご活躍を楽しみにしています。
今までのDocker説明の中で一番わかりやすかったです泣
熱中して読みました!
ありがとうございました。