Blow Up by Black Swan

Dockerとは①〜基本編〜

今回、ちょっとしたwebアプリを自分で開発してみようということで、開発を始めたのですが、どういう環境で開発するのが良いか、という誰もが最初に当たる壁に早速ぶち当たりました。そこで、色々調べて見たり、質問して見たところ、どうやらDockerが最近主流になりつつあり、かつ使いやすく学習コストも低いということでした。この期にしっかり学ぼうと思い、Dockerの主要部分を自分なりに学習し、ある程度理解できたと思うので、今回それをまとめようと思います。

分量が多くなってしまったため、dockerの基本、dockerfile、docker composeでそれぞれ記事にしています。自分がDockerを学ぶ過程でこういった記述や説明があればもっと分かりやすかっただろうなという視点でまとめていますので、1人でも多くの人の参考になれば幸いです。なお、この記事ではアプリケーションをある機能を持ったソフトウェア的なものくらいの意味で広めの意味で使っています。また、サーバについても物理サーバではなく、ソフトウェアとしてのサーバを指し、ある種のアプリケーション的なものとして扱っています。

1. Dockerとは

ここでは、Dockerの概要についてまとめています。

1-1. Dockerの概要

Dockerを学びはじめる人は、大抵、開発環境や仮想環境を検討する流れからたどり着く人が多いんじゃないかなと思います。「コンテナ型仮想化」や「Vagrant」、「ハイパーバイザ」などの専門用語がこういった領域を勉強する中で出てくると思いますが、そういった専門用語を抜きにして、「Dockerとはなんぞや」をまず最初に捉えるイメージとしては、次のようなものが良いのかなと思います。Dockerとは、コンピュータの様々な設定やインストールされたアプリケーションなどから影響を受けない、「隔離環境」を構築するためのソフトウェア、というイメージです。

例えば、webアプリを開発し、それをサーバに配置(デプロイ)する時に、サーバの環境(または状況)は確実に自身のPCの環境とは違うはずです。Macbookを使っていればOSはOSXでしょうが、サーバのOSはCentOSなどが使われることが多く、この時点で全く違う環境ということがわかります。webアプリを開発する時とそれを機能させる時の環境が違うのであれば、せっかく自身のPCで作ったwebアプリも、デプロイする時にサーバの環境に合わせて再度作り直さなければなりません。

そういった手間をかけないために、最初からサーバと同じ環境で作ればよいだけで、その環境を自身のPC上に作り出すのが、Dockerです。ただし、自身のPC上に作り出す上でその環境から影響を受けないようにする必要があるので、Dockerではある種の「隔離環境」が構築されます。従来の主流は、「Vagrant」と呼ばれる仮想環境構築ソフトなどが主流だったようですが、Dockerの持つ、自前のOSや環境をうまく利用することによる軽量さや、導入の容易さなどの特徴から現在では、Dockerの利用者が増えていると言われています。Dockerの実際上の仕組みをある程度反映させたDockerアプリケーションによる利用イメージは下記のようになります。

  +------------------+     +-----------------------------------+     ---
  |------------------|     |--------+--------+--------+--------|     |
  |         |        |     |        |        |        |        |     |
  |   app1  |  app2  |     |  app3  |  app4  |  app 5 |  app6  |     |
  |         |        |     |        |        |        |        | <-- | Container
  |------------------|     |-----------------------------------|     |  (コンテナ)
  |      bin/lib     |     |          bin/lib                  |     |
  |------------------------------------------------------------|     ---
  |  Docker Engine                                             |
  |------------------------------------------------------------|
  |  HostOS                                                    |
  |------------------------------------------------------------|
  |  Hardware(PC, server etc)                                  |
  |                                                            |
  +------------------------------------------------------------+

ここでいうappとは、ほぼコンテナを指します。Dockerのコンテナは1のコンテナに全ての機能を入れ込んでしまうのではなく、1つのコンテナに1つの役割(ロールorプロセス)を持たせ、必要な機能分だけコンテナを作り、連携させるのが良いと言われています。例えば、webアプリを作る時にサーバ、webアプリ、データベースと3つのアプリケーションが必要な場合、1つのコンテナにこの機能全てを持たせるのではなく、それぞれの機能ごとに専用コンテナを作り、これらを連携させるというイメージです。この複数コンテナを簡単に構築・起動するために利用されるのがdocker composeと言われるアプリケーションで、3つ目の記事でまとめています。

1-2. Docker用語

ここでは、Dockerでよく利用される用語をまとめています。

  • コンテナ
    • OSのカーネル機能を用いて作動させる、実行環境や命令など複数のファイルシステムをひとまとめにしたもの
  • イメージ
    • コンテナを作動させる際に必要なファイルや設定のこと。コンテナの設計図のようなもの。コンテナのメタ情報(ディレクトリ/ファイルを含むアーカイブとコンテナ)を持つ。
  • リポジトリ
    • イメージをひとまとめにしたものイメージお変更点などを確認できる。
  • レジストリ
    • リポジトリを管理するためのサービス。Docker用のgithub的存在。Dockerhubともいう。
  • ボリューム
    • データの記憶領域。Dockerではデータ保存用の特別なディレクトリを指定するようになっており、コンテナが削除されても勝手に消えないようになっている。

1-3. Dockerのメリット・デメリット

メリット

  • 導入がスピーディー
  • OSレベルでの仮想化のため起動が早い
  • リソースの使用量が少量で済むため、一度に多くの処理が行える
  • コンテナの設定(イメージ)を再利用できる(Dockerhubに多くのイメージが公開されている)
  • 可搬性が高く、Docker Engineがあれば基本的にどこでも動く
  • バージョン違いによるミスが起きない

デメリット

  • HostOSと異なるカーネル(OSの中核部分)と異なるOSは動かせない

2. Dockerのインストール手順

Dockerアプリケーションのインストール手順は下記になります。下記はMacbook向けの「Docker for Mac」のインストールの仕方です。

1. サイトに行く -> Dockerサイト

docker-install1

2. 会員登録

3. ダウンロード

docker-install2

4. ダウンロードファイルをダブルクリックし、アプリケーションにdockerをコピー

docker-install3

5. アプリケーションのdockerアイコンをダブルクリック

6. 種々の説明文が出て、パスワード入力を求められる

docker-install4
docker-install5

7. docker画面が立ち上がり、ログインを求められる

docker-install6

8. ログインが完了し、dockerが起動する

dockerコマンドが利用できれば、正しくDockerがインストールされています。

3. Dockerの使い方の基本

ここからはDockerの使い方の基本についてまとめています。

3-1. Dockerアプリケーションの起動と停止

アプリケーションとしてのDockerの起動と停止は、以下のようになります。

起動 => dockerアプリケーションをダブルクリック(ツールバーにdockerアプリのマークが出る)

docker-install7

※デフォルトでは、PCにログインするたびに立ち上がるようになっていますが、設定を変更することで、自分の上記のようにアプリケーションのクリックで起動するようにすることができます。
(preferenceでGeneralの「Start Docker when you log in」のチェックを外す)
※ツールバーのdockerアプリケーションのコンテナが動いているときは立ち上げている最中を意味します。

終了 => ツールバーのdockerアイコンをクリックし、一番下の”Quit Docker”でDockerアプリケーションを終了させることができます。

docker-install8

3-2. Docker利用の流れのイメージ

1.イメージの作成(取得)      2.コンテナの作成・実行    3.コンテナの停止    5.コンテナの削除    6.イメージの削除
 コマンド:pull         コマンド:run           コマンド:stop      コマンド:rm        コマンド:rmi
 確認コマンド:images         確認コマンド:ps
                            container
                            --------              --------
                            |      |              |      |          container 
                 ==>>       |      |      ==>>    |      |    ==>>    削除      ==>>   image削除
    ---------            ---|      |----       ---|      |----      ---------
   / image /            /   --------  /       /   --------   /     /       /
  ---------            ---------------       ----------------     ---------
      ⬆︎                                             /\
     /\                                             ||
     /  \                                            ||
  ローカル \                                          \/
    or  Dockerhub                             4.コンテナの再起動
                                                コマンド:strat

用語の説明でも書きましたが、Dockerでいう「イメージ」と言われるものが、コンテナの設計図になります。このイメージは様々なものが用意されていますが、その備蓄されている箇所がDockerhubで、docker serach <イメージ名>で検索することができます。

3-3. 主要なDockerコマンド

以下がDockerで利用される主要コマンドです。上記のイメージ図をを見ながら確認すると、特に基本的なコマンドはすぐにつかめると思います。(OPはオプションの略で、省略可能です。)

  • $ docker search <イメージ名>…イメージを検索
  • $ docker pull <イメージ>:<タグ名(省略可)>…イメージ名はwebサーバ名やプログラミング言語、DBの種類などが入り、タグ名はそのバージョンが入る。タグ名が省略されると”latest”(最新版)指定となる
  • $ docker images…イメージの一覧を取得する
  • $ docker run <OP> <–name <コンテナ名>(省略可)> <実行するイメージ>:<タグ名(省略可)> <コンテナで実行するコマンド(省略可)>DockerイメージからDockerを作成し、実行するコマンド。–nameを省略すると英単語を含んだランダムな名前がコンテナにつけられる。
    • フォアグランド(“-d”オプションをつけないで実行)だとコンテナから抜けると自動でコンテナが停止する
    • 主なオプション
      • “-i”…インタラィテクブになる(シェル画面に実行状況が表示される)
      • “-d”…コンテナのバックグラウンドでの起動を指示。
      • “-v <ホスト側のpath(省略可):コンテナ側のpath:ro(省略可)>”…コンテナ内の記憶領域を指定するオプション。”ro”は”read-only”
  • $(コンテナ内) exit…コンテナが停止し、外に抜け出る
    • ”ctr+p+q”でも抜け出ることができるが、この場合コンテナは停止しない
  • $ docker ps <-a(省略可)>…起動中のコンテナの一覧を取得。”-a”をつけることで停止中のコンテナも表示される
  • $ docker stop <コンテナ名 or コンテナID>…起動中のコンテナを停止させる
  • $ docker start <-i(省略可)> <コンテナ名 or コンテナID>…コンテナを再起動する。
  • $ docker rm <コンテナ名 or コンテナID>…コンテナを削除する
  • $ docker rmi <イメージ名 or イメージID>…イメージを削除する
  • $ docker exec <コンテナ名 or コンテナID> <コマンド>…新しいコマンドを実行する。最初のプロセスが実行中の時のみ使えるがコンテナの再起動時に一緒に再起動されるわけではない
  • $ docker attach <コンテナ名 or コンテナID>… 実行中のコンテナに直に接続するためのコマンド
  • $ docker build <-t イメージ名> <-f dockerfileのpath>…dockerfileからイメージを作成するコマンド。dockerfileの置き場がカレントディレクトリの場合は”.(ピリオド)”のみでよい
  • $ docker volume prune … どのコンテナでも使われていないボリュームをすべて削除する

4. 実際にDockerコンテナを構築してみる

ここからは実際にコンテナを作るコードです。

dockerfileの記事やdocker composeの記事でもそれぞれ同じようにコードを記載していますが、どれも初学者の私が悪戦苦闘してイメージしやすいものを作ってみたものですので、非効率的だったり、ベストプラクティスとは遠いやり方になっている可能性が高いので、その辺はご了承頂ければと思います。

4-1. 基本編

まずは、基本編です。ここでは、nginxサーバのコンテナを構築しています。

1. イメージの取得

$ docker pull nginx:latest

戻り値

latest: Pulling from library/nginx
802b00ed6f79: Pull complete
e9d0e0ea682b: Pull complete
d8b7092b9221: Pull complete
Digest:
sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3
Status: Downloaded newer image for nginx:latest

2. イメージの確認

$ docker images

戻り値

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
nginx               latest              06144b287844        4 days ago          109MB

3. コンテナの生成・実行

$ docker run -it --name test_nginx nginx:latest /bin/bash

実行オプションの意味

  • 実行オプション -> -it(インタラクティブな状態で起動)
  • コンテナ名 -> test_nginx
  • 実行イメージ -> nginx:lates(タグは省略可)
  • 実行コマンド -> /bin/bash(nginxにコマンドを送るbash(コマンドプロント、macbookでいうターミナル)を起動させる)

戻り値

root@7b08b68fb823:/#

上記のようにターミナルの入力部分が変わるのが確認できると思います。

4. nginxに指令を送る(ターミナルを使うのと同じようなもの)

root@7b08b68fb823:/# ls

上記は、ターミナルでも使う、格納されているディレクトリやファイルを一覧表示するコマンドです。戻り値は通常のリスト表示されたものです。

root@7b08b68fb823:/# cd home

上記は現在のディレクトリを”home”に変えるもので、現在ディレクトリが変わったのが確認できると思います。

5. test_nginxコンテナから抜ける①(exitを使う)

root@7b08b68fb823:/home# exit

ターミナルの表記が変わったのが確認できると思います。また、nginxのコンテナ自体は停止しています。

6. コンテナの一覧を確認

$ docker ps

戻り値

CONTAINER ID        IMAGE               COMMAND             CREATED       STATUS              PORTS               NAMES

exit”コマンドを使ったため、コンテナが停止おり、ここでは何のコンテナも表示されていません。コマンドの最後に”-a”をつけると停止中のコンテナも含めて確認することができます。

7. コンテナの再起動

$ docker start -i test_nginx

戻り値

root@7b08b68fb823:/#

“-i”でインタラクティブモードで起動したため、上記のようにコンテナ内に入ることができています。

8. test_nginxコンテナから抜け出る②(ctr+p+qを使う)

戻り値

root@7b08b68fb823:/# read escape sequence

9. 再度コンテナの一覧を確認する

$ docker ps

戻り値

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
7b08b68fb823        nginx:latest        "/bin/bash"         30 minutes ago      Up 39 seconds       80/tcp              test_nginx 

コンテナがまだ起動中であることが確認できます。

10. コンテナの中に入る①(attach)

$ docker attach test_nginx

※上記コマンドを実行する前に、startコマンドでコンテナを起動させる必要があります。

戻り値

root@7b08b68fb823:/#

通常の画面のようですが、メインのプロセスに接続しています。

11. コンテナの中に入る②(exec)

$ docker exec -it test_nginx /bin/bash

※上記コマンドを実行する前にctr+p+qでtest_nginxコンテナから離脱しています。

戻り値

root@7b08b68fb823:/#

12. コンテナの停止

$ docker stop test_nginx

※上記コマンドを実行する前にctr+p+qでtest_nginxコンテナから離脱しています。

psコマンドで起動中のコンテナがないことが確認できると思います。

13. コンテナの削除

$ docker rm test_nginx

ps -aコマンドを実行すれば、コンテナが存在していないことがわかると思います。

14. イメージの削除

$ docker rmi nginx

戻り値

Untagged: nginx:latest
Untagged: nginx@sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3
Deleted: sha256:06144b2878448774e55577ae7d66b5f43a87c2e44322b3884e4e6c70d070b262
Deleted: sha256:824a442ee3c96744d75be3737a22cc6a47aebad1b30be67f3c2f8f29cb0aa879
Deleted: sha256:8e3d1e9e4945f930c93c30617512998437f6edafd86676770d29b1581f2520bb
Deleted: sha256:8b15606a9e3e430cb7ba739fde2fbb3734a19f8a59a825ffa877f9be49059817

※”docker images”コマンドでイメージが存在していないことが確認できると思います。

4-2. 実用編

ここでは、pythonを手軽に実行できるjupyter notebookを備えたコンテナを構築してみようと思います。

1. jupyter notebookのイメージの取得

$ docker pull jupyter/datascience-notebook

今回は、jupyter notebookが入り、データサイエンス用のパッケージなどが入った”jupyter/datascience-notebook”を利用しています。

2. コンテナの作成と起動

$ docker run -it -d --name notebook -p 8888:8888 -v /Users/nero/docker_test:/home/jovyan/work jupyter/datascience-notebook

実行オプションの意味

  • コンテナ名 -> notebook(任意のコンテナ名)
  • 実行環境 -> -d(バックグラウンド)
  • ポート(-p) -> 8888に指定
  • ボリューム(-v) -> コンテナ上のディレクトリとホスト上のディレクトリを紐付け
  • 実行イメージ -> Jupyter/datascience-notebook

戻り値

55t35ograog41k8ghd91n34ad3c7f55b1657670b7f243928b5b40f7cc93d5d1dce17ce2

※任意のランダムな文字列が打ち出されます。

3. ログからアクセス用のトークンを取得し、jupyternotebookにアクセス

$ docker logs notebook

この状態でブラウザからJupyter notebookにアクセスしてもトークンというランダムな文字列を求めてくるため、logsコマンドからトークンを番号を確認します。

docker-practice

戻り値

Container must be run with group "root" to update passwd file
Executing the command: jupyter notebook
[I 15:08:16.383 NotebookApp] Writing notebook server cookie secret to /home/jovyan/.local/share/jupyter/runtime/notebook_cookie_secret
[W 15:08:16.563 NotebookApp] WARNING: The notebook server is listening on all IP addresses and not using encryption. This is not recommended.
[I 15:08:16.595 NotebookApp] JupyterLab extension loaded from /opt/conda/lib/python3.6/site-packages/jupyterlab
[I 15:08:16.595 NotebookApp] JupyterLab application directory is /opt/conda/share/jupyter/lab
[I 15:08:16.602 NotebookApp] Serving notebooks from local directory: /home/jovyan
[I 15:08:16.603 NotebookApp] The Jupyter Notebook is running at:
[I 15:08:16.603 NotebookApp] http://(5e71df4268cd or 127.0.0.1):8888/?token=9f4dfc8c8ab2c7c8224dlzpd7g8df9e38012d9096ee7e6ae98
[I 15:08:16.603 NotebookApp] Use Control-C to stop this server and shut down all kernels (twice to skip confirmation).
[C 15:08:16.604 NotebookApp] 

        Copy/paste this URL into your browser when you connect for the first time,
        to login with a token:
            http://(6f71df5379de or 127.0.0.1):8888/?token=9f4dfc8c8ab2c7c8224dlzpd7g8df9e38012d9096ee7e6ae9

この”token”という部分で指定されている文字列をコピーし、シェルで”jupyter notebook”と打って出てくるトークン入力画面にペーストします。これでjupyter notebookへのアクセスが完了となります。

※但し、コンテナを一度削除してから再度コンテナの生成・起動を行うと、jupyter notebookにログインすることはできますが、ノートブックは、新規作成や既存のファイルを開く場合のどちらでもエラーがでて、利用ができません。

-> これは、ブラウザが以前のトークンを使用してjupyter notebookにアクセスし、トークンの相違が発生していることが原因のようです。この場合、一度ブラウザを再起動すれば、ノートブックを再度利用することができます。

docker-jupyter

4. Jupyter notebookでpythonプログラムを利用

ボリュームオプションを設定しているため、jupyter notebook内で作成したデータが、対応するホストディレクトリに保存されているのが確認できると思います。また、コンテナの生成時に毎回、以前保存したファイルを格納するホストディレクトリと紐づければ、同じファイルにアクセスして、勉強を再開することができます。

5. コンテナの停止・再起動

コンテナの停止、再起動などは基本と同じようなコマンドで、特に複雑なことはないので、ここでは割愛しています。以上でDockerの基本的な使い方です。

dockerfileとdocker composeについての記事は下記になりますので、参考にして頂ければ幸いです。