⑤１日１０分で理解するコンテナ技術入門 - コンテナと仮想マシンの違い -

[前回の記事](https://qiita.com/goroneko/items/413f8477e449da712137)までで、基本的なDockerの使い方と、CaaSの使い方について説明しました。この記事では、「そもそもコンテナって仮想マシンと何が違うんですか」という部分の説明と、前回までで学んだコマンドたちをまとめていきたいと思います。

# コンテナと仮想マシンの違い
コンテナと仮想マシンはどちらも仮想化技術の一種です。では何が違うのかというと、**仮想化の度合い**が違います。

アプリケーションは、基本的には以下のようなレイヤーを通してハードウェアとやり取りし、動作しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/caabb287-92d6-2174-5467-e02a396a8279.png)
このレイヤー分けで見たときに、仮想マシンとコンテナを比較すると下図のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/532202/96a41243-61cd-d802-b3ed-7791c73c70a5.png)
仮想マシンは、仮想マシンの中にOSの全体（システムライブラリとカーネル）を含んでいますが、コンテナの場合はカーネルはホストOSのものを利用し、コンテナの中にはシステムライブラリのみを持ちます。

## なにがうれしいのか
仮想マシンに対してコンテナが優れている点はいくつかありますが、その一つとして**軽量である**という点が挙げられます。上記の通り、コンテナの場合はカーネルをホストOSのものを使うので、イメージの中に含める必要がありません。そのため、イメージの容量が削減され、仮想マシンのイメージよりも軽量になります。また、仮想マシンのようにハードウェアをエミュレートする必要もないため、動作のオーバーヘッドが少なくなります。こういった理由から、コンテナは容量の点でも、起動の速さの点でも**軽量である**といえます。

では、軽量であると何がうれしいのでしょうか。それは、スケーラビリティが高くなるという点です。スケールさせること自体は仮想マシンでも可能ですが、コンテナはその起動の速さから、より柔軟にスケールすることができます。Kubernetesなどのコンテナオーケストレーションツールを用いれば、比較的簡単にスケール管理も行うことができます。

## 少し注意が必要な点
コンテナは仮想マシンと違って、ホストOSのカーネルを利用するというお話をしました。それゆえに軽量なわけですが、注意すべき点があります。それは、**前提とするカーネルが異なるコンテナは動かせない**という点です。基本的にはLinuxカーネルを前提とするコンテナを使うことが多いかと思いますが、例えばWindowsのカーネルを前提とするアプリケーションをコンテナにする場合、ホストOSもWindowsのカーネルである必要があります。ですので、「なんでもとりあえずコンテナにしちゃえ！」とはいかないということには注意が必要です。

# ここまでのまとめ
最後に、第一回から第四回までで出てきたコマンドなどを整理しておきたいと思います。
## Dockerの基本コマンド
|  コマンド |説明  |
|:-|:-:|
| docker **container** run \<image-name> | 新しいコンテナを作成して実行  |
| docker **container** ls | 起動・停止しているコンテナの一覧を確認 |
| docker **container** start \<container-name>| 停止しているコンテナを起動|
| docker **container** stop \<container-name>| 起動しているコンテナを停止 |
| docker **container** rm  \<container-name>| コンテナを削除（停止させてから実行する）  |
| docker **container** exec \<container-name> \<command>| 起動しているコンテナで指定したコマンドを実行 |
| docker **image** build -t \<image-name> .| カレントディレクトリのDockerfileからコンテナイメージをビルドする |
| docker **image** ls | コンテナイメージの一覧を確認  |
| docker **image** rm \<image-name>| コンテナイメージを削除  |

## Dockerfileの基本コマンド
| コマンド      | 説明                                                                                        | 使用例                                                      |
|---------------|---------------------------------------------------------------------------------------------|-------------------------------------------------------------|
| `FROM`        | ベースとなるイメージを指定します。                                                            | `FROM ubuntu:20.04`                                         |
| `RUN`         | イメージのビルド時に実行するコマンドを指定します。                                            | `RUN apt-get update && apt-get install -y nginx`            |
| `CMD`         | コンテナ起動時に実行するデフォルトのコマンドを指定します。                                     | `CMD ["nginx", "-g", "daemon off;"]`                        |
| `ENTRYPOINT`  | コンテナ起動時に実行するメインのコマンドを指定します。                                         | `ENTRYPOINT ["docker-entrypoint.sh"]`                       |
| `COPY`        | ホストシステムからコンテナにファイルまたはディレクトリをコピーします。                         | `COPY myapp/ /usr/src/myapp/`                               |
| `ADD`         | `COPY` と似ていますが、URLからのダウンロードやアーカイブの自動解凍もサポートします。           | `ADD myapp.tar.gz /usr/src/myapp/`                          |
| `ENV`         | 環境変数を設定します。ビルド時と実行時に使用されます。                                         | `ENV APP_ENV=production`                                    |
| `EXPOSE`      | コンテナがリッスンするネットワークポートを指定します。メタデータの一種で、実際に何か操作を行うわけではなく、コンテナがリッスンするポートを分かりやすくしています。                                        | `EXPOSE 80`                                                 |
| `WORKDIR`     | 作業ディレクトリを設定します。この命令以降の、`RUN`コマンド等のコマンドが実行されるディレクトリを指定します。                                                                 | `WORKDIR /usr/src/myapp`                                    |
| `USER`        | コンテナ内でコマンドを実行するユーザーを指定します。                                           | `USER appuser`                                              |
| `VOLUME`      | ホストとコンテナ間でマウントされるボリュームを指定します。                                     | `VOLUME /var/lib/mysql`                                     |
| `ARG`         | ビルド時に渡される引数を指定します。                                                           | `ARG build_env=production`                                  |
| `LABEL`       | メタデータをイメージに追加します。バージョン情報やメンテナンス情報を含めるのに便利です。       | `LABEL version="1.0" description="A simple example"`        |
| `ONBUILD`     | このイメージが他のイメージのベースとして使用されたときに実行するコマンドを指定します。         | `ONBUILD ADD . /app/src`                                    |

## カレントディレクトリのDockerfileからビルドしてローカルで動かすまで
```bash
docker image build -t <image-name> .
docker run [option] <image-name>
```
以下は例
```bash
$ docker image build -t simple-knowledge-sharing-platform .
$ docker run -d -p 8080:5000 --network flask-net -v $(pwd)/uploads:/app/uploads simple-knowledge-sharing-platform
```

## カレントディレクトリのDockerfileからビルドしてリモートレジストリにプッシュするまで
```bash
docker image build -t <image-name> .
docker image ls # ビルドしたイメージを確認
docker tag <ビルドしたイメージ名> <リモートレジストリのレポジトリ名とタグ>
docker push <リモートレジストリのレポジトリ名とタグ>
```
例は以下
```bash
$ docker image build -t simple-knowledge-sharing-platform .
$ docker image ls
REPOSITORY                                                TAG         IMAGE ID      CREATED       SIZE
localhost/simple-knowledge-sharing-platform               latest      fe705099a994  5 hours ago   238 MB
yyz.ocir.io/orasejapan/simple-knowledge-sharing-platform  latest      fe705099a994  5 hours ago   238 MB
<none>                                                    <none>      ff639a5aac72  5 hours ago   238 MB
<none>                                                    <none>      7ddb674174a7  4 days ago    238 MB
docker.io/library/mysql                                   8.0         1eba4c9bcaa8  6 weeks ago   583 MB
docker.io/library/python                                  3.9-slim    4602238ffbdc  2 months ago  131 MB

$ docker tag localhost/simple-knowledge-sharing-platform:latest yyz.ocir.io/orasejapan/simple-knowledge-sharing-platform:latest
$ docker push yyz.ocir.io/orasejapan/simple-knowledge-sharing-platform:latest
```
# 本記事のまとめ
ここまでで、基本的なDockerの使い方については分かったと思います。次回からは、Docker Composeによる複数コンテナの管理について説明していきたいと思います。