はじめに
世のDockerの入門者向けの解説は、技術初心者に対してあまりにも広範でマニアックな前提知識を要求します。にもかかわらず、多くの解説では、技術初心者の立場からすると概念や用語の説明について十分にカバーされているとは言い難く、混乱を招くことが少なくありません。この記事では、Dockerに登場する初歩的な概念を勉強する過程で技術初心者がつまづきがちな概念を解説します.
###※注意
筆者は技術の専門家ではなく、勉強中の身ですので、本記事には間違った記述が多分に含まれることが予想されます. 利用する際は参考程度にとどめ、必ず他の信頼できるソースを当たることを強くおすすめします.
技術初心者がつまづきがちな用語一覧
###アタッチとデタッチ
-
アタッチおよびデタッチは、主に「仮想化」や「クラウド」という技術が絡む文脈で使用される専門用語.「アタッチする」は「取り付ける」と言い換えられ、「デタッチする」は「切り離す」と言い換えられることが多い.
-
「仮想化」というものをする際に、「ボリューム(ストレージ)を割り当てる」ということをする.その動作のことを「アタッチ」という.
-
「デタッチ」はアタッチの逆で、ボリュームの割当を解除することをいう.
-
つまり、アタッチすることでコンテナはホストOSに対してボリュームマウントすることができ、コンテナはホストOSが持つDocker関連のリソースにアクセスすることが出来るようになる.
-
アタッチすることで利用するリソースのうち代表的なものには、「ホストOSの標準入出力」(=シェル,コンソール)がある.
-
より実際的には、「アタッチ/デタッチ」は「ホストOSの標準入出力とコンテナをくっつける/切り離す」ことを意味することが多い.
-
コンテナを稼働させるとき、「アタッチモード」と「デタッチモード」のどちらで動かすか指定する必要がある.
-
「アタッチモード」でコンテナを起動するには、dockerコマンドの
attach
を使う.これにより、ホストOSのコンソールからコンテナのコンソールにカーソルが明け渡され、ホストOSのコンソールを通してコンテナのコンソールを操作出来るようになる.このことは「コンテナの中に入る」と表現されることが多い. -
ここで、「デタッチモードではホストOSのコンソールとコンテナが切り離されているのだから、操作が出来ないのではないか?なぜそんなものがあるのか?」という疑問を持つのは自然である.
-
しかし、以下に述べるような事情により、デタッチモードで起動しなければならない場合があることがある.
-
また、後述のように、「擬似端末(pseudo-TTY)」という技術と「インタラクティブモード」という機能を用いることで、デタッチモードでありながらホストOSからコンテナを操作する方法があり、それを使用するのがdockerではデファクトスタンダードとなっている.
-
一旦話を戻すと、大まかにいうと、アタッチモードはフォアグラウンドで、デタッチモードはバックグラウンドでコンテナを実行するということになる.
-
たとえば、サーバーとして動くコンテナ(以下「サーバーコンテナ」)をアタッチモードで起動すると、サーバーコンテナが稼働している間にホストOS側のコンソール(Windowsならコマンドプロンプト、Linuxならbashなど)はサーバーコンテナに支配され、コンソールで別の操作をすることができなくなる. Enterキー押そうものなら、たちまちサーバーコンテナが終了して消滅してしまう.
-
コンソールをもう一つ起動すればアタッチモードでも引き続き操作可能だが、窓を沢山開いていると煩わしい.
-
しかし、サーバーコンテナをデタッチモードで起動した場合、サーバーコンテナをバックグラウンドで稼働させることができ、今まで操作していたコンソールで引き続きコンテナを操作することが出来る.
-
したがって、コンテナを起動する場合は、通常はデタッチモードで起動する場合が多い.
-
しかし、デタッチモードではホストOSとコンテナが切り離されているので、ホスト側から対話的に指示を与えることはできない.つまり、このままでは、ほったらかしにしてても自動的に勝手に動くサービスしかデタッチモードでは稼働できない.
-
ここで、「デタッチ=ホストOSのコンソールとコンテナを切り離しているにも関わらず、ホストOSのコンソールからコンテナを操作する」を実現するために、先に述べた「擬似端末(pseudo-TTY)」と「インタラクティブモード」を使う.
-
擬似端末を使うオプションは
-t
、インタラクティブモードを使うオプションは-i
であり、-it
というオプションで両方同時に使うことが出来る. -
ちなみにデタッチモードで起動する時は
-d
をつける. -
デタッチモードで、擬似端末とインタラクティブモードを同時に使いたい場合は
-itd
とすればよい. -
ひとまずは、「デタッチモードでコンテナを対話的に操作したい場合は、起動時に
-itd
をつける」と覚えておけばよい. -
コンテナをアタッチモードで起動するか、デタッチモードで起動するか、対話的なデタッチモードで起動するか、は、そのコンテナの用途によって異なる.
-
ケース1:例えばJupyterlab上でプログラミングしたい場合は、Jupyterlabを起動するDockerイメージを作る.コンテナはサーバーとしてバックグラウンドで動かしていれば良いので、単に普通のデタッチモードでコンテナを作成・起動すればよい.起動中のJupyterlabに入りたければ、ホストOSからwebブラウザを開いて、そのサーバーコンテナのポート番号(をホスト側にマッピングしたもの)をURL窓に入力すれば接続できる.
プロセス
- 「プロセス」は情報処理のことで、具体的には「プログラムの動作中のインスタンス」を意味する.(インスタンスとは、プログラミングにおいて、クラスから生成される実体あるオブジェクトのことである.詳しくはプログラミングにおける「クラス」を勉強されたし.)
- 例えば、wordを起動してwordファイルを編集するとき、そのwordファイルの編集用の「作業ファイル」が作成され、編集作業の間は存在し続ける.(wordのアプリを閉じると同時に削除される)
- この作業ファイルは正に「プログラムの動作中のインスタンス」=「プロセス」である.
- 「プロセス」は「プログラムのコードおよび全ての変数やその他の状態」を含む.
- プロセスを実行する主体は「Windows、Mac、Linux等のOS」だったり「コンテナ」だったりする.
- 我々はパソコンで文章を書く時、「メモ帳」というアプリを実行するが、これは一種の「プロセス」である.
メインプロセス
- メインプロセスとは、「コンテナーそのものが起動させるプロセスすべてを管理するプロセス」のことをいう.
- 定義は、「PID=1のプロセス」のことをメインプロセスという
- 基本的には、「メインプロセス」=「bashなどのコマンドラインツール」だと思えばよい.
- コマンドラインツール以外のメインプロセスとしては、「webサーバー」や「DBサーバー」などが挙げられる.
- 例えば、「bashをメインプロセスとしてコンテナを起動し、mysqlを実行する」時は、以下のようなコマンドを打てばよい.
docker run -it --entrypoint /bin/bash mysql
- ENTRYPOINTの代わりにCMDを使うこともある.(ENTRYPOINTとCMD)
「メインプロセス」という用語について直接的に解説している文献は絶望的に少ない.「メインプロセス」の意味の大要を掴むには、たとえば以下のリンク先で「メインプロセス」というワードで文書内検索を実行するとよい.
メインプロセスとは1
メインプロセスとは2
メインプロセスとは3
ボリューム
- まず、コンテナの動作機構について述べる.
- コンテナは、あるプロセスを実行したい時に生み出され、プロセスの実行が終わった時点で消滅する.
- つまり、コンテナは基本的にはプロセスの実行とともに使い捨てられるものであり、パソコンがついている間はずっと動き続けているものではない.
- これは、パソコンで何か文章を書く時に「メモ帳」アプリを開いて作業をし、書き終わり次第「メモ帳」アプリを閉じて終了することと似ている.
- その際に書いた文章は「メモ帳」アプリ自身が覚えているわけではない.文章を残しておきたければ、.txtファイルとしてPCのどこかのディレクトリに保存しておく必要がある.
- "C:\Users\Yamada\文章"というディレクトリを作ってそこにメモ帳で書いた.txtファイルを保存したとする.
- このとき、この"C:\Users\Yamada\文章"というディレクトリはメモ帳から見れば「外部ストレージ」である.
- これと同じように、Dockerなどのコンテナ作動ソフトにおいて「コンテナ」および「コンテナが実行するプロセス」に対して、その過程で作られたファイルを保存しておくためには「外部ストレージ」が必要であり、それを「ボリューム」という.
- 標語的に言えば「ボリュームとは、Dockerコンテナで扱うデータを永続化する仕組みをいう」となる.
- Dockerの中に「ボリューム」というデータを保持する領域を確保して永続化する.
- ボリュームの実体はディレクトリで、DockerをインストールしたときにホストOS上に作られたDocker関連のディレクトリ内のどこかに存在する.
- しかし、非常にややこしい理由から、ボリュームに相当するホストOSのディレクトリを簡単に見つけ出すことはできない。
- ここで、docker inspectというコマンドを使うと
/var/lib/docker/volumes/
にあると表示される - しかし、これは嘘である.Windows上にこのようなディレクトリは存在しない.そもそも、
/var/lib/docker/volumes/
このディレクトリ構造はlinuxシステム(unixシステム)特有のものである - これはDockerというソフトウェア自体が、Windows OSの上に直接インストールされているわけではなく、WindowsにインストールされたLinuxの仮想マシンにインストールされており、その中で動いている、という事情からである.
- つまり、
/var/lib/docker/volumes/
は、(Dockerがインストールされた)Linuxの仮想マシンのディレクトリを表している. - しかし、Linuxの仮想マシン自体もホストであるWindows OSに組み込まれているのだから、Windowsからアクセスできないはずはないと考えるのが妥当だし、実際そうである.
- Windowsの場合は、
\\wsl$\docker-desktop-data\version-pack-data\community\docker\volumes
にあるが、なぜかエクスプローラーからしかアクセス出来ない.詳しくはここやここを参照. - Macについてはこのページを参照
- くり返すと、Docker for mac はmacのターミナル上で操作するが、実はMacのOSが直接Dockerを動かしているわけではなく、Mac OSの上に乗ったLinux仮想マシン(Hyperkitという)がドッカーを動かしており、あたかも直接Mac上で動いているかのように見せかけているだけである。これについてはこのページを参照
- ボリュームへのアクセスの仕方は、通常のディレクトリにアクセスする仕方と少し仕組みが違う.
- ボリュームには2種類があって、ホストから覗けるものと、ホストからは覗けないがDockerからは覗けるもの、がある.
- ボリュームをどこのディレクトリに作成するかは、Dockerイメージを作成する際に定義する.
- ボリュームはコンテナで扱うデータの保存先であるから、当然コンテナから度々アクセスするため「マウント」の対象である.
- 「名前付きボリューム」という機能を使う場合が多いが、使い方がわかりにくいので注意が必要である.
### マウント
- 「マウント」を理解するにはまず、「ディレクトリ」という概念をよく理解する必要がある.
- PC上のある「場所」のデータを参照する際に、その場所の住所として「ディレクトリ」というものを定義する.
- ディレクトリ=住所の定義の仕方は、個々のOSによって異なる.
- コンテナ上ではOSが動いているから、ホストOS上でコンテナが動いているとき、パソコンの上には2つの異なるOSが動いている、という構図になる.
- すると、パソコン上のある場所を指定するための「住所」=「ディレクトリ」は、ホストOSのものとコンテナのものの2通りがあるはずである. ホストOSのものを「ホストディレクトリ」、コンテナのものを「コンテナディレクトリ」と呼ぶ.
- 「コンテナ」(または「仮想化」)を使う際に、ホストOSとコンテナ(またはホストOSとハイパーバイザー)の間で「通信」が行われる.
- ここで、同じ場所を表す「ホストディレクトリ」と「コンテナディレクトリ」の対応を付けたほうが便利であると考えるのは、自然である.
- ホストディレクトリとコンテナディレクトリの対応付けは、Dockerイメージを作成する際に行う.
- 「マウント」とは、ホストディレクトリとコンテナディレクトリを対応付けることで、コンテナの外にあるホストOSのデータをコンテナの中で利用できる状態にする機能のことである.
- マウントには、「ボリュームマウント」と「バインドマウント」と「一時ファイルシステムマウント」の3種類がある.
- 「ボリュームマウント」はDocker関連のフォルダやファイルにのみアクセスできるマウント、「バインドマウント」はホストが持つ全てのフォルダやファイルを読み書き出来るマウント、「一時ファイルシステムマウント」はDocker上に保存したくないファイルに一時的に利用できるようにするマウントである.
- 上の三者は用途によって使い分ければ良いが、特に理由がなければボリュームマウントを使うのが推奨されている.
- 「マウント」は、より一般には「外部に存在する、あるいはより低層の物の支配下にあるリソースにアクセス出来る状態にすること」を意味する.
### コンテナ
- 「コンテナ」とは、「プロセスだけを分離して動かす技術」またはそれを行う主体のことをいう.
- 通常はWindows、Mac、LinuxなどのOSがプロセスを動かすが、あえてOSが直接動かすことをせず、動かす役をコンテナに委託する、というイメージである.これを「コンテナ型仮想化」「コンテナに乗せる」「コンテナ上で動かす」などと表現する.
- 例えば、我々がパソコンで文章を書く時に使う「メモ帳」というアプリは、通常はWindowsのOS上で実行するが、これをコンテナに渡してコンテナ上で実行することが出来る.
- コンテナを使うと、メモ帳で文章を書くだけでなく、Pythonでプログラムを書くとか、Power Pointでプレゼン資料を作成するとか、複数の様々なプロセスを組み合わせたものを同時に実行することもできる
- さらに、コンテナの中でUbuntuなどの小さなOSを一瞬だけ起動して、その上でLinux専用のアプリを動かして作業して、作業が終わり次第OSともども終了することも出来る.
- つまり、コンテナを使うと、その場でその場で「環境のインスタンス」を生成し、その閉じた空間の中で作業を完結させることが出来る.
- 小さなコンピューターを持ってきてちょっと作業して撤収する、といっても良い
- これら全ての出来事は、「プロセス(の集合)」として処理される.
- コンテナはOSの上に乗っている.
- コンテナはOSから委託されたプロセスを自分自身で実行する.
- カーネルはベースとなるOS(ホストOS)が使っているのと同じものを共有する(「仮想化」の場合は「仮想マシンのカーネル」があるので、共有しない)
### コンテナの隔離性
- コンテナは、基本的にそのコンテナの中にあるデータだけを利用できるようになっており、必要に応じて「マウント」をすることでホスト側に保存されたデータにアクセスする、という形をとる.
- ボリュームマウントを使ってコンテナからホスト側のフォルダやファイルを除いた場合、Docker関連のフォルダやファイルのみが表示され、他のものは隠しファイルのようになって見えなくなっている.
- なぜ基本的にはコンテナの中にあるデータしか使えず、ボリュームマウントをしてもコンテナからアクセスできるデータを制限しているかというと、このようにしてコンテナを「隔離」することにより、コンテナ内の環境のホストへの依存度を下げるためである.
- しかし、依存度が低すぎて不便な場合もあり、そういう時はバインドマウントを使うなどすると良い.
###コンテナと仮想化の関係
- コンテナは、仮想化の一種とも言えるし、仮想化の機能のうち一部だけ(「プロセスだけを分離して動かす技術」)を取り出して簡素化したもの、ともいえる.
- 仮想化はOSの上に独立した閉じた環境を作って作業するという点で コンテナと同じだが、本格的にOSを入れて環境を生成するので、コンテナよりも拡張性があり壮大である.
- しかし、コンテナの方が簡素なので動作が軽い.
### f仮想化
- 「仮想化」とは、「OSの上で別のOSを動かしたい」という要望を叶えるための技術.
- OSの上に直接別のOSをインストールするのは色々難しいので、間にクッションを挟む必要がある. そのクッションのことを「ハイパーバイザー」という.
- 「ハイパーバイザー」は、より一般には「ゲストマシン」「ゲスト」「仮想マシン」「仮想化ソフト」などと呼ばれることが多い.
- ハイパーバイザーの上にインストールされた第2、第3のOSのことを「ゲストOS」という.
- 仮想化はOSの上に独立した閉じた環境を作って作業するという点で コンテナと同じだが、本格的にOSを入れて環境を生成するので、コンテナよりも拡張性があり壮大である.
### なぜDockerにはWSLが必要なのか
- Dockerは本来Linuxの上でしか動かないコンテナ仮想化ソフトウェアだからである.
- Windows用のDockerはWSLのおかげでWindowsでも動作出来る.
- なので、WindowsのPCにDockerを入れるには、予めWSL(2022年1月現在はWSL2)がインストールされている必要がある.
### DockerfileとDocker-composeの違い/関係
- Dockerfileは「DockerImageの作成手順、構成情報」、Docker-compseは「コンテナの作成と起動方法、ネットワークを使ったコンテナ同士の連携」を定義するもの.
- Docker-composeの有用性と簡単な使い方については、ここやここを参照.
- 例えばcentosのベースイメージにWordpressとMySQLとTeXなど複数のアプリケーションをインストールするようなDockerfileを書く場合を考える.
- 通常のやり方では一個のDockerfileで全てのアプリを一元管理しなければならないが、Docker-composeを使うと、Wordpress用のDockerfile、MySQL用のDockerfile、TeX用のDockerfile、というふうに、アプリ毎にDockerfileを分けることができ、管理がしやすくなる.
- 今の時代はいきなりDocker-composeを使う方が色々と便利.
- もしDocker-composeの書き方だけでなくDockerfileの書き方もちゃんと勉強したいという場合は、Docker-composeに全てを書くのではなく、アプリ毎にDockerfileを書いて、Docker-composeでdockerfileを指定するようにすればよい.
- 今の時代は90%以上の人々はいきなりDocker-composeを使ったやり方を取っているので、Docker-composeを使うことは避けられない.
- 技術初心者は細かい設定を追っていると大変なので、無視して構わない.
#参考文献
プロセスについて
ゲストとは
仮想化を利用したことがない人のための仮想化の説明
ボリュームについての補足
マウントとは
コンテナの隔離性について