本ページはプロモーションが含まれています

Docker イントロダクション


Dockerとは

Dockerは、サービスやアプリケーションの実行環境を、ファイルシステムやプロセスなどのほとんどのOS資源を隔離した「コンテナ」と呼ぶ空間に配置することで、複数の実行環境が互いのインストール状態や設定の影響の影響を受けずに運用できる仮想化技術です。
仮想化方式の代表的なものにVMwareやHyper-Vのような「仮想マシン」「ハイパーバイザー」があります。それらは仮想化したハードウェア上にOSをインストールして、完全に1台のパソコンを演じることができます。
Dockerはそれらとは異なる、ファイルシステムやプロセス、ミドルウェアなど実行環境を「コンテナ」として分離し、アプリケーションごとにそれぞれ専用のユーザ空間を与えるような方式です。コンテナは、「Dockerエンジン」により論理的に資源を分離するよう管理され、一つのカーネルの上に多重に存在しながら互いに干渉されずに並列動作します。コンテナ間では、互いの環境のライブラリの依存関係や、資源の競合に邪魔されずに運用できます。
Picture
Dockerの主な利用ケースの一つはサーバ類のデプロイ(配置)です。WebサーバやRedmine、Wordpressなどを個別のコンテナで運用します。互いの環境に干渉することなくインストールやアップグレードができます。
もう一つは開発環境の提供です。各種ツールチェーンのコンテナを、必要なときに中に入って作業して開発が終わったら捨てるようにすれば、ホストOSにいくつもの開発環境を溜め込むことがなくなります。また、多数の開発者に統一した環境をイメージで配布することで、インストール差異によるトラブルも防止できます。
Dockerの弱いところ
DockerはLinuxを対象に作られたものであり、一応WindowsやMacでも動作しますが環境構築は面倒です。例えばWindowsでは、一旦Linuxの仮想環境を用意してからその中でDockerを使うという、仮想マシンの中での仮想化のようなことになります。
仮想マシン/ハイパーバイザー方式とは異なり、ドライバなどのカーネル空間は分離できません。ハードウェアは1つであり、特に仮想マシンのような仮想ディスプレイ/デスクトップを持たないので、コンテナからGUIアプリの実行は可能ではありますが難しい作業になります。
カーネルのバージョンとコンテナの環境は、ある程度の整合性が求められます。新しいカーネルに古いイメージのコンテナではうまく動作しないかもしれません。
ライフサイクル
Dockerのコンテナは、環境一式を焼き付けた「イメージ」を元に生成します。公式レジストリ「Docker Hub」には様々な環境のイメージが配布されています。通常は用途別に構築済みのイメージを入手して使います。コンテナはイメージからいくらでも(容量が許す限り)作ることができます。コンテナの環境が不要になったり、古くなってアップグレードしたいときは廃棄して、次に使いたいものをイメージから生成して使ってまた捨てる。というようなライフサイクルになります。
Picture

Hello World

最も簡単にDockerの操作を試すことができる「hello-world」イメージのコンテナを動かしてみます。単に起動したらメッセージを出力して停止するだけのものです。hello-worldはDocker Hubのイメージライブラリに公開されています。
①イメージをダウンロード〜コンテナを生成〜起動
「docker run(docker container run)」はイメージからコンテナを作成し、続けて起動させます。イメージをまだダウンロードしていない場合は、先に自動でイメージのダウンロードが行われます。
次のようにdocker runを実行すると、コンテナが生成され起動し「Hello from Docker!〜」のメッセージが表示されます。
⚠ 以下の説明中の実行例のdockerコマンドにはsudoを付けていませんが、環境によっては常にsudoが必要な場合があります。
$ docker run hello-world

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
719385e32844: Pull complete
Digest: sha256:fc6cf906cbfa013e80938cdf0bb199fbdbb86d6e3e013783e5a766f50f5dbce0
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.
...

②ダウンロードしたイメージを確認
メッセージの先頭を見ると、まだイメージを入手していないので、最初にイメージのダウンロードから始めたことがわかります。
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
イメージを入手したことを「docker images(docker image ls)」で確認できます。
$ docker images
REPOSITORY    TAG       IMAGE ID       CREATED       SIZE
hello-world   latest    9c7a54a9a43c   2 weeks ago   13.3kB
③コンテナの状態を確認
hello-worldはメッセージを出力してコンテナの処理を終了し自動的に停止します。「docker ps」によりコンテナの状態を確認します。
$ docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
しかし一覧のタイトル行以外何も表示されません。docker psは現在起動中のコンテナのみを表示するので、メッセージ出力後に自動停止するhello-worldのコンテナはここには表示されません。停止状態のコンテナも含めて確認するには-aオプションを付けます。
$ docker ps -a
CONTAINER ID   IMAGE         COMMAND    CREATED        STATUS                    PORTS     NAMES
8cd7206749c4   hello-world   "/hello"   5 seconds ago   Exited (0) 4 seconds ago           lucid_yonath
STATUSが「Exited」としてhello-worldのコンテナが表示されます。NAMESの「lucid_yonath」はdockerが自動的に与えたコンテナの名前です。コンテナ名は--nameオプションで任意に指定できます。
④コンテナを再び起動
コンテナは実行を終えて停止状態ですが、コンテナとして環境は存在しています。もう一度同じようにdocker runを実行します。コンテナが起動して同様にメッセージを表示しますが、この場合は初回で既にイメージをダウンロード済みなので、ダウンロード開始の表示は現れません。
$ docker run hello-world

Hello from Docker!
...
そしてdocker psで確認すると、コンテナが増えていることがわかります。
$ docker ps -a
CONTAINER ID   IMAGE         COMMAND    CREATED          STATUS                      PORTS     NAMES
8c509478ce72   hello-world   "/hello"   9 seconds ago    Exited (0) 8 seconds ago              nifty_bhaskara
8cd7206749c4   hello-world   "/hello"   10 minutes ago   Exited (0) 10 minutes ago             lucid_yonath
docker runはイメージからコンテナを作成するので、そのたびに新たなコンテナが増えていきます。hello-worldはメッセージ出力しか行いませんが、何かの機能を持った仮想環境を、ひとつのイメージから複製して同時稼働させるような使い方ができます。
停止しているコンテナを「docker start(docker container start)」で起こして開始させることができます。
※-aオプションの意味は次項の「Ubuntuコンテナのシェルを使う」で説明します。
$ docker start -a lucid_yonath
Hello from Docker!
...
⑤コンテナを廃棄
コンテナが不要になったら「docker rm(docker container rm)」で削除(廃棄)します。rmには削除するコンテナをコンテナ名、またはコンテナIDで指定します。コンテナIDは、上のdocker psの表示の「CONTAINER ID」で確認できます。
$ docker rm 8c509478ce72
8c509478ce72
$ docker ps -a
CONTAINER ID   IMAGE         COMMAND    CREATED          STATUS                     PORTS     NAMES
8cd7206749c4   hello-world   "/hello"   25 minutes ago   Exited (0) 6 minutes ago             lucid_yonath
$ docker rm lucid_yonath
lucid_yonath
$ docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES
⑥ イメージを廃棄
イメージは様々なものをダウンロードするたびに手元に保存されてて増えていきます。イメージを削除するには「docker rmi(docker image rm)」で削除できます。
$ docker rmi hello-world
Untagged: hello-world:latest
Untagged: hello-world@sha256:fc6cf906cbfa013e80938cdf0bb199fbdbb86d6e3e013783e5a766f50f5dbce0
Deleted: sha256:9c7a54a9a43cca047013b82af109fe963fde787f63f9e016fdc3384500c2823d
Deleted: sha256:01bb4fce3eb1b56b05adf99504dafd31907a5aadac736e36b27595c8b92f07f1

イメージ名とタグ

イメージは、そのイメージの名前とタグから構成されます。
イメージ名:タグ名
ubuntu:18.04
php:3.2-apache
タグ名は、バージョンやビルドの種類などを表します。タグ名を省略した場合は「〜:latest」が指定されたものとされます。latestは一般に最新バージョンを意味します。

Ubuntuコンテナのシェルを使う

Dockerのコンテナは、Webサーバなどのサーバ類をサービスのように稼働させるような使い方の他に、コンテナのシェルを操作して、コンテナの中で何かの作業を行うような使い方ができます。例えば、ツールチェーンをインストールしたコンテナを仮想環境に分離した開発環境として使うなどです。
Ubuntuディストリビューションのコンテナ作成し、コンテナ内のシェルに入る方法を試します。
Ubuntuディストリビューションのイメージは「ubuntu」です。
「docker run」によりubuntuイメージのダウンロード〜起動を行います。
$ docker run -ti --name shtest utuntu
root@184db32c6041:/#
この場合、起動後にコンテナのシェルプロンプトが現れます。これはubuntuコンテナの中のシェル上のプロンプトです。docker runに続き-tiオプション(-tと-i)を指定しています。-tはTTY端末の割当で、-iはコンテナの標準入力に接続を意味します。ubuntuコンテナは起動するとシェル「bash」を実行します。コンテナが実行したbashに、ホスト側からrootでログインしたことになります。
別の端末などからdocker psで確認すると、コンテナが「/bin/bash」を起動していることがわかります。
CONTAINER ID   IMAGE     COMMAND       CREATED         STATUS         PORTS     NAMES
54d2143b4ea4   ubuntu    "/bin/bash"   4 seconds ago   Up 3 seconds             shtest
シェルから「ls」コマンドを実行してみると、コンテナの内部のファイルシステムが現れます。このコンテナのファイルシステムの中で独立した環境を作ることができるので、vmwareVirtualBoxのような仮想マシンに近い使い方ができます。
root@54d2143b4ea4:/# ls -l
total 48
lrwxrwxrwx   1 root root    7 Aug 16 02:02 bin -> usr/bin
drwxr-xr-x   2 root root 4096 Apr 18  2022 boot
drwxr-xr-x   5 root root  360 Sep  4 21:52 dev
drwxr-xr-x   1 root root 4096 Sep  4 21:52 etc
drwxr-xr-x   2 root root 4096 Apr 18  2022 home
lrwxrwxrwx   1 root root    7 Aug 16 02:02 lib -> usr/lib
...
drwxrwxrwt   2 root root 4096 Aug 16 02:06 tmp
drwxr-xr-x  14 root root 4096 Aug 16 02:03 usr
drwxr-xr-x  11 root root 4096 Aug 16 02:06 var
シェルを「exit」で終了すると、ubuntuコンテナが起動したbashからログアウトしてコンテナが終了し、停止状態に移行します。
停止したubuntuは「docker start(docker container start)」で起動できます。このとき「-ai」オプションを指定します。-aオプションは、標準入出力・エラー出力に接続(Attach)します。
$ docker start -ai shtest
root@54d2143b4ea4:/#
docker runではコンテナ開始時に標準出力・エラー出力の接続を行っているため、docker startの-aオプションに相当するオプションはありません。
サーバなどサービスとして使うコンテナでは画面表示が不要なので、その場合は一般にdocker startに-aオプションは指定しません。コンテナの出力表示が必要な場合は「docker start -a」、シェルにログインして作業するような場合は「docker start -ai」のように-aオプションを指定します。
前項の「hello-world」の例で、停止したコンテナをdocker startで再起動するときに「-a」を付けないで実行した場合は「Hello〜」のメッセージは表示されません。

コンテナ生成と起動を個別に行う

docker run(docker container run)は、(未入手の場合)イメージの取得、コンテナの作成、コンテナの起動の一連の処理を実行します。これらの各処理を次のコマンドで個別に実行できます。
docker pull(docker image pull)
docker create(docker container create)
docker start(docker container start)
前項のubuntuイメージでシェルにログインする例を、docker runを使わずに行うと次のようになります。
$ docker pull ubuntu
$ docker create -ti --name shtest ubuntu
$ docker start -ai shtest
「docker create(docker container create)」は、イメージからコンテナを生成して停止状態にします。docker runはdocker createのほとんどのオプションを使うことができます。

サーバ用途のコンテナ〜Webサーバhttpdの例

Dockerの主な用途に、仮想環境によるサーバの設置があります。
docker runによりhttpdのイメージのダウンロード〜起動を行います。コンテナ名を「apache」とします。
$ docker run -d -p 8080:80 --name apache httpd:2.4
9d876348026a2eb9726750fde572dc9280eab4e6b9b8130e5b490cddb5520309
-dオプションは、コンテナをバックグラウンドで起動するときに指定します。Webサーバはサービスとして動かします。
httpdイメージはタグ「2.4」、すなわちバージョン2.4を明示的に指定しました。タグを省略すると「latest(最新)」になりますが、ここではバージョンを指定しました。
コンテナ・ホスト間のポート変換
-pオプションはコンテナ内の通信ポートとホスト側のポートの転送を設定します。
-p ホスト側ポート:コンテナ側ポート
ホスト側の通信アクセスはホスト側の通信ポートで処理されるので、コンテナの中に到達できません。コンテナへの通信をコンテナ内のポートへ転送するために、ホスト側に交換用ポートを設置する必要があります。
この例では、ホスト側の8080ポートへのWebアクセスを、コンテナの80ポートへ転送するように設定しています。
ホスト環境のWebブラウザで「http://localhost:8080/」を開くと、「It works」というhttpdのデフォルトページが表示されます。
デフォルトのネットワーク
Docker環境はデフォルトで172.17.0.0のブリッジネットワークを用意し、docker0(172.17.0.1)というネットワークインタフェースを作成します。コンテナは、デフォルトでこのネットワークに所属します。ホスト側のdocker0インタフェースのIPアドレスで「http://172.17.0.1:8080/」としても、コンテナのデフォルトページが表示されます。またブリッジネットワークはdocker networkコマンドによりユーザが任意に作成できます。
コンテナ・ホスト間のファイルコピー
表示するHTMLはコンテナの中に格納しなければなりません。ファイルは「docker cp(docker container cp)」によりコンテナへファイルをコピーできます。
$ docker cp index.html apache:/usr/local/apache2/htdocs
「http://localhost:8080/」を開くと、コピーしたindex.htmlが現れます。
バックグラウンド動作と再起動
コンテナはバックグラウンドで動作しています。docker psで起動中であることが確認できます。
$ docker ps
CONTAINER ID   IMAGE     COMMAND              CREATED       STATUS       PORTS                                   NAMES
9d876348026a   httpd:2.4   "httpd-foreground"   4 minutes ago   Up 4 minutes   0.0.0.0:8080->80/tcp, :::8080->80/tcp   apache
起動中のコンテナは「docker stop(docker container stop)」で停止できます。
$ docker stop apache
停止したコンテナはdocker start(docker container start)で再起動できます。
$ docker start apache
この場合startに-dオプションは付けません。「http://localhost:8080/」を開くと、停止前と同様に表示されます。コンテナの停止中はコンテナ内の資源は保持されています。
httpdは-dオプションでバックグラウンド起動するように指定しました。docker runで-dオプションを指定しなかった場合は、フォアグラウンドの起動となり、コンテナ内部の標準出力が現れます。
docker run -p 8080:80 --name apache httpd
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the
[Thu Sep 07 21:43:30.590505 2023] [mpm_event:notice] [pid 1:tid 139715907123072] AH00489: Apache/2.4.57 (Unix)
[Thu Sep 07 21:43:30.591192 2023] [core:notice] [pid 1:tid 139715907123072] AH00094: Command line: 'httpd -D FORE
ディレクトリをコンテナ内にマウントする
-vオプションにより、ホスト側のディレクトリをコンテナ内にマウントさせることができます。これによりホストとコンテナ間でディレクトリの共有ができます。上の例のようにdocker cpでindex.htmlをコンテナ内部のディレクトリに送る手間がなくなります。
マウントするディレクトリは、コンテナ生成時に-vオプションで指定します。
-v ホスト側ディレクトリ:コンテナ内ディレクトリ
ホスト側の「htmlwork」というディレクトリを、httpdのドキュメントを格納するディレクトリ「/usr/local/apache2/htdocs」にマウントする場合は、次のようにdocker runを実行します。
$ docker run -d -p 8080:80 -v ~/htmlwork:/usr/local/apache2/htdocs --name apache httpd
ホスト側でhtmlwork/index.htmlを編集すれば、ブラウザの更新が即座に反映されます。