Dockerの基本概念について理解する

## はじめに
アプリケーションの開発を行うエンジニアであっても、インフラに関する事もある程度は知っておく必要がありそう…。
というわけで今だと普通になったコンテナについて理解を深めておこうと思い、Dockerの基本概念について理解してみたので、その備忘録を残す。

前提条件として以下のように、Linux環境（この記事のLinux環境はCentos7.9）にdockerがインストールできている事が必要。

```console
[root@control-plane docker-kubernetes]# docker version
Client: Docker Engine - Community
 Version:           20.10.7
 API version:       1.41
 ...

Server: Docker Engine - Community
 Engine:
  Version:          20.10.7
  API version:      1.41 (minimum version 1.12)
  ...
```

※dockerのLinux環境（Centos7.9）へのインストール方法は[docker のインストール](https://note.com/shift_tech/n/nd5765c9f1c26#docker%20%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)を参照。

※以下では基本的に英語のリファレンスを参照しているが、https://matsuand.github.io/docs.docker.jp.onthefly/ だと日本語なので読みやすいかもしれない。

## まずはともあれDockerで`hello world!`をやってみる
やる事は単純で以下のコマンドを実行するだけ。コマンドを実行すると、`hello-world`というDockerイメージをpullされ、`Hello from Docker!`というメッセージが表示される。

```console
[root@control-plane docker-kubernetes]# docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete 
Digest: sha256:97a379f4f88575512824f3b352bc03cd75e239179eea0fecc38e597b2209f49a
Status: Downloaded newer image for hello-world:latest

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

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/
```

よくあるhello world!はこれでおしまい。

※上記のままだとstoppedのコンテナが残り続けるので、以下のように`docker container prune`を実行して停止しているコンテナをすべて削除しておくのがおススメ。

```console
[root@control-plane docker-kubernetes]# docker ps -al
CONTAINER ID   IMAGE         COMMAND    CREATED         STATUS                     PORTS     NAMES
47a398fa7687   hello-world   "/hello"   9 minutes ago   Exited (0) 9 minutes ago             thirsty_maxwell
[root@control-plane docker-kubernetes]# docker container prune
WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y
Deleted Containers:
47a398fa7687a745813641fa241c02a52a91da8f3ba4ed3f42f6d1fad6c58021
...

Total reclaimed space: 0B
```

- 参考：[docker ps](https://docs.docker.com/engine/reference/commandline/ps/)
- 参考：[docker container prune](https://docs.docker.com/engine/reference/commandline/container_prune/)

## Dockerとは？
Dockerとは、と言われたらコンテナ型の仮想環境という事になる（らしい）。virtualboxやVMwareと同様に仮想環境である事は同じだが、コンテナ型というのが大きく異なっている（コンテナ型って？については[]()を参照）。

なんでDockerが登場したのか？という背景としては、今までのシステム開発・運用での課題が分かると分かりやすい気がしたのでその観点でまとめてみると以下のようになるだろう。

| # | 今までは… | Dockerになると… |
|:-:|---|---|
| 1 | :x:<br>この構築手順、昔はうまくいって動いていたのに今は動かない（再現性が担保できていなかった…） | :white_check_mark:<br>実行環境の冪等性が確保できる（再現性を担保できるように！）  |
| 2 | :x:<br>自分の手元の環境ではうまく動くのに別の人の環境では動かない（環境のコピーが簡単にできていなかった…） | :white_check_mark:<br>環境の移転・コピーが簡単にできる（同じ環境を簡単にコピーして展開可能に！） |
| 3 | :x:<br>環境（インフラ）を作り直すたびに手順が変わってよく分からなくなる（手順の管理が面倒だった…） | :white_check_mark:<br>環境（インフラ）の構成をコード化できる（手順がコード化されるのでversion管理システムで簡単に管理！） |

※上記の表の1・2については`Immutable Infrastracture`（普遍的なインフラ）に、3については`Infrastracture as Code(IaC)`（インフラのコード化）に、それぞれ関連している。

### Dockerの仕組み
以下の図のように、Dockerはホストマシン（Windows・Mac・CentOSなど）にインストールして利用する。
最もコアな部分は`デーモン`と記載した部分で、ここが各種制御を行うコントローラーとして動く。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/3bb5de29-541c-9e4c-049b-15c60fb3ee94.png)

上記の図に登場するものについては以下の通り。

- イメージ<br>実行環境（アプリケーションなど何かしらを実行する仮想環境）のテンプレート。Dockerは仮想環境であると言ったが、その仮想環境の構成のテンプレートがイメージと呼ばれるもの。 
例えば、Node.jsが実行できるようにするには[CentOS7.9にNode/npm/yarnをインストールする](https://qiita.com/yuta-katayama-23/items/6baf167464eca3376ea0#nodenpmyarn)のような手順が必要だが、このような手順を毎回実行するのは面倒だしあらかじめそういう環境を用意しておいて欲しいとなった時には、Node.jsが実行できるようになった状態の環境のテンプレートとして、Docker Hubの[cimg/node](https://hub.docker.com/r/cimg/node)を利用する事でそれが可能になる（Docker Hubは以下に出てくるレジストリの1つ）。
- コンテナ<br>実行環境（仮想環境）の実態（イメージに基づいて実際に構築された仮想環境そのもの）。
- レジストリ<br>イメージを保存しておく場所（クラウド上）。  
例としては[Docker Hub](https://hub.docker.com/)や[AWSのECR（Elastic Container Registry）](https://aws.amazon.com/jp/ecr/)などがある。

## コンテナと仮想マシンの違い
一言で言うと、カーネル（OSのコアの部分）を共有しているかどうか。

分かりにくいと思うので図示してみると、以下のようにそれぞれ仕組みが異なっている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/00f9300d-3895-8bb9-1b20-360ab6b60563.png)

上記の図の中で、仮想マシンの場合は、

- ホストOS・ゲストOSでそれぞれでカーネルを持つ（ゲストOSのためのカーネルは別にインストールされる）  
→起動に時間がかかる（ただし逆に、完全にOS（カーネル）が違う環境を構築する事ができる）

という特徴があるのに対し、コンテナの場合は、

- コンテナ上（コンテナ型仮想環境）では、そのカーネルをホストOSと共有して動作する  
→起動が速い

という特徴がある。このカネールの共有・非共有が根本的な違い。

- 参考：[NEC がおすすめするコンテナサービスとは](https://jpn.nec.com/cloud/service/container/pdf/container_guide202007.pdf)

## DockerイメージとDockerコンテナの違いについて
混乱しがちなDockerイメージとDockerコンテナについて、定義について少し追加で整理しておく。

| 1 | 2 |
|:-:|---|
| Dockerイメージ | 実行環境（アプリケーションなどを何かしらを実行する仮想環境）を定義したもの<br>Docker Hubなどのレジストリと呼ばれる所に保管されている |
| Dockerコンテナ | Dockerイメージを実際に実行してできる実行環境（アプリケーションなどを何かしらを実行する仮想環境）そのもの |

図示してみると以下の図のようなイメージになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/34cea505-fb39-6f9c-0efb-a4a164a964b9.png)