Dockerの基礎を完全に理解した

## はじめに
最近Dockerに入門して、すっかりDockerファンになりました。
「Dockerって何？」「VPSでアプリサーバーとDBサーバーを作ってつないでみたいけど、敷居が高い」という方に、Dockerのざっくりした内容とその魅力をお伝えできればと思います。

この記事は[ エンジニアコミュニティ「Easy Easy」](https://easy2.connpass.com/?utm_campaign=&utm_source=notifications&utm_medium=email&utm_content=title_link)の[ 「完全に理解したTalk Advent Calendar 2021」 ]( 
https://qiita.com/advent-calendar/2021/easyeasy )への参加呼びかけを見て書きました。Qiitaに初めて投稿します。

## Dockerについて感動したこと 
いずれもDockerの基本機能です。

1. マシンの中で、別OS＆独立したファイルシステムの仮想マシンをいくつも動かせる
2. これらのマシン同士をネットワークでつなぐことができる
3. ボリュームというしくみで、データを永続化できる
4. Docker HubというサイトでOSやソフトウェアがインストール済みのさまざまなマシンが配布されている

これら１〜３の機能は、Linuxの機能を使って実現されています。
（カーネルのコンテナ機能と名前空間、chgroupsというファイルの所有者とグループを変更するコマンド）

仮想マシンをかなりざっくり言い表すと、

* プロセスに、そのプロセス専用のファイルシステムをくっつけたもの
* ホストマシンのリソース（ネットワークやストレージ）をそのプロセスに適宜くっつけられる

という感じになるかと。

Linuxにもともとある機能から、
「<b>ユーザーが手軽にコマンドで作成・動作できる仮想マシンを作ろう</b>」
と考えた開発者の方々に、心から敬意を表します。
素晴らしい発想と凄すぎる技術力です！！
この恩恵を享受しないのはもったいないです！

## 1. ホストマシン（自分のPCでOK）の中で仮想マシンをいくつも動かせる
まずDockerの用語についてまとめてみます。

* コンテナ：実行可能なインスタンス。コンテナの内部で動いているソフトウェアから、ホストマシンを守ってくれる。

* イメージ：コンテナを作るためのテンプレート（ファイルやコンテナ作成指示の集まり）。イメージは読み出し専用。

* Dockerfile：イメージを作るためのスクリプト。テキストベース。

「ホストマシン」とは、Dockerを動かしているマシンのことです。これがいったいOSの機能なのか何を指しているのか、なかなか分かりませんでした。

サンプルコードを挙げてみます。

```
# wordpress:5.0.0-php7.2-apache というイメージからコンテナを作成
#  （↑ローカルにこのイメージがなければ、Dockerが自動的にダウンロードしてくれる）
# コンテナに wp_test という名前をつける
# デタッチモードで起動する（バックグラウンドで動作）

 $ docker run -d --name wp_test \
   wordpress:5.0.0-php7.2-apache



# Dockerfileの例
# Ubuntuにgitをインストールして、コンテナ起動時にgitを起動する
# LABELにメタ情報をkey=valueの形式で記載

FROM ubuntu:latest
LABEL maintainer="chicken_nanban@qiiita.com"
RUN apt-get update && apt-get install -y git
ENTRYPOINT ["git"] 
```


## 2. ネットワーク
コンテナをネットワークでつなぐと、コンテナ間でコミュニケーションできるようになります。
DBを使ったアプリを動かしたい場合、DBをインストールしたコンテナと、アプリをインストールしたコンテナをネットワークでつなぎます。
　一般的に、１つのコンテナに１つの役割を割り当てるとのことです（[公式ドキュメント Get started - Multi container apps](https://docs.docker.com/get-started/07_multi_container/)より）

　Dockerをインストールすると、bridge、host、noneという３種類のネットワークが自動的に作成されます。

* bridge：デフォルトのネットワーク。コンテナ同士は独立した状態で、それらをネットワークでつなぎコンテナ間コミュニケーションができるようにする。
bridgeよりも、user-defined bridgeを使うのがおすすめとのこと（[Dockerドキュメント日本語化プロジェクト　Dockerコンテナ・ネットワークの理解](https://docs.docker.jp/engine/userguide/networking/dockernetworks.html#id12)より）

* host：コンテナとホストの分離をなくすらしいです。
* none：ネットワークを無効にする時に使用

```
# todo-appという名前のネットワークを作成
 $ docker network create todo-app


# ネットワークtodo-appにmysqlという別名(alias)をつける
# mysql:5.7というイメージからコンテナを作る
# できたコンテナをネットワークtodo-appにつなぐ
# -vオプションは次の項で説明します
# -eオプションはコンテナの環境変数の設定

 $ docker run -d \
     --network todo-app --network-alias mysql \
     -v todo-mysql-data:/var/lib/mysql \
     -e MYSQL_ROOT_PASSWORD=secret \
     -e MYSQL_DATABASE=todos \
     mysql:5.7
```

これら３種類のネットワーク設定の他に、サードパーティのドライバを使う設定もできるとのことです。


## 3. ボリュームというしくみで、データを永続化できる
ホストマシン内のディレクトリにデータを保存できます。Dockerコンテナを終了しても、次回コンテナを起動した時に、保存したデータを使うことができます。

* bind mount
  データの保存場所のパスを指定できます。

* named volume
  どこに保存するかDockerに任せます。volumeに名前をつけて、次回からその名前でvolumeを参照できます。Dockerがどこに保存したかは、「Docker inspect コンテナ名」で調べることができます。

* tmpfs mount
  ホストのハードディスクに保管する必要のないデータが、アプリ動作中に発生する場合に作成します。
まだ曖昧な理解なのですが、、named volumeとbind mountのいずれも行わない状態で、アプリがデータ保存を行うと、コンテナのファイルシステムにデータが保管されるっぽいです。
↑
「コンテナのサイズが大きくなってしまうので、コンテナサイズをコンパクトに保つためにtmpfs mountを使おう」という意味のことが、公式か参考文献「Docker in Action」に書かれていた記憶があります。

余談ですが、コンテナのファイルシステムのファイルをrmコマンドで削除しても、ファイル自体はコンテナに残ったままで、削除されたというデータが新しいレイヤに付け加えられます。なので、ファイル削除の操作をすると、コンテナのサイズがかえって大きくなります。

```
# 前掲のサンプルコマンドを再掲
# -vオプションでボリュームを指定
# -v ホスト側の場所（この場合はnamed volume）：コンテナ側のパス

 $ docker run -d \
     --network todo-app --network-alias mysql \
     -v todo-mysql-data:/var/lib/mysql \
     -e MYSQL_ROOT_PASSWORD=secret \
     -e MYSQL_DATABASE=todos \
     mysql:5.7
```
 named volumeは"docker volume create"として作成しなくても、上記のように指定すればDockerが自動的に作成してくれます（[公式ドキュメント Get started - Multi container apps](https://docs.docker.com/get-started/07_multi_container/)より）


```
## tmpfs 使用例
## 空っぽのtmpfsボリュームを作成して、コンテナの/tmpにアタッチ
## --mount でファイルシステムをコンテナにマウント
## alpineというイメージの最新版からコンテナを作る
## （alpineとは、Linux以外にほとんど何も入ってないシンプルなコンテナイメージ）
## -v オプションはbind mount

 $docker run \
    --mount type=tmpfs,dst=/tmp \
    --entrypoint mount \
    alpine:latest -v

```


## 4. Docker Hubでさまざまなマシン（のイメージ）が配布されている
Docker HubはDockerイメージのリポジトリで、個人の開発者や、オープソースプロジェクト、ソフトウェアベンダが配布しているイメージをゲットすることができます。

私はデータベースに興味があるのですが、「おもしろそうだな」と思うものがあっても、環境設定でつまづいて、なかなか使ってみるところまで辿りつきませんでした。。

Docker Hubで配布されている公式イメージを使えば、すぐにいろんなDBに触ってみることができてしまいます！Dockerはなんて素晴らしいのでしょう（＊T_T＊)

余談になりますが、いま興味のあるデータベースのなかから２つ紹介します。

* グラフデータベース[ Neo4j ]( https://hub.docker.com/_/neo4j )：グラフデータベースは関係性を表すのに向いているDBです。
　RDBの表形式のようなデータ構造ではなく、ノード（節：例えば人物）とエッジ（線：例えば友人）からデータが構成されます。Neo4jは一番人気があるグラフデータベースです。

*  NoSQLデータベース [ Cassandra ]( https://hub.docker.com/_/cassandra )：CassandraはSQLが使えるNoSQLデータベースです。
 データはkeyとvalueの組み合わせで構成されシンプルな構造になっています。
それなのにSQLでデータ問い合わせができます！
大規模データに使われる分散型のDBで、自作アプリに使う場面はまずなさそうなんですけどね…

これからDocker & DBライフをゆるゆると楽しみたいと思います（＾＾）

Dockerにすこし親しみを持っていただけたでしょうか？
Dockerを使い始める後押しになれば、とても幸いです！

### 注意：セキュリティに関して

Dockerはホストと分離されたサンドボックスの中でソフトウェアを動作させることができ、ホストマシンの環境を守ることができるのですが、セキュリティ面では必ずしも安全とは言えないようです。

というのはコンテナの中に動作させるとマシンのリソースへのフルアクセス権限で動くアプリが入っているものがあるからです。なのでダウンロードしたコンテナをむやみに実行するのは良くないとのことです。

↓オンライン書籍『Docker in Action』からの引用です。

> The most important thing to remember is that sometimes containers are inappropriate. Containers won’t help much with the security of programs that have to run with full access to the machine.
（中略）
>Remember, you shouldn’t use software from untrusted sources. This is especially true if that software requires administrative privileges. That means it’s a bad idea to blindly run customer-provided containers in a co-located environment.
　引用元： 『Docker in Action』 2nd Ed. Chapter 1.4「Where and When to use Docker」

大意：覚えておくべきもっとも重要なことは、時々コンテナは不適切だということです。マシンのフルアクセスで実行するプログラムのセキュリティに関してはコンテナは助けになりません。
（中略）
信頼できない配布元からのソフトウェアは使うべきではないということを覚えておいてください。このことは特にソフトウェアが管理者権限を要求する場合に当てはまります。つまり、提供されたコンテナを共有の場所で盲目的に実行するのは悪い考えだということです。

## 補足
* 利用料<br>
　Personalアカウントは無料です。Proアカウントは$5/monthですが、Personalアカウントで十分使いでがあります。

## おすすめのチュートリアル、オンライン書籍

* [ 公式サイト ]( https://docs.docker.com/get-started/overview/ ) が大変分かりやすいです。特に[ Get started ]( https://docs.docker.com/get-started/ ) は素晴らしいです！
日本語の翻訳サイトは有志の方々が作られた[ Dockerドキュメント日本語化プロジェクト ]( https://docs.docker.jp/ ) があります。

* [ 『Docker in Action』] ( https://www.manning.com/books/docker-in-action-second-edition?a_aid=ITCareerEnergizer&gclid=EAIaIQobChMI9Iqg6KXd9AIV2qmWCh2XkA9qEAAYASAAEgLv8PD_BwE )Manning Publication（←オンラインの出版社）
　コンテナがどういうしくみで動いているのかから説明されているので、楽しく腹落ちしてDockerが使えるようになると思います。公式を読んでからこの本を読むほうが分かりやすいと思います。難しいところがちょこちょこあるので、とばしながら読んでいます。Manning Publicationは時々45% Off Saleをしているので、待てるようならSaleを待つとお得に買えます。