【初心者にやさしい】Dockerというスゴイ奴をしっかりと理解する

# 本記事の目的
　Dockerを勉強したいしたいと思いながら中々勉強できずでいましたが、偶然にもDockerを開発環境として利用するアプリ開発にアサインしていただけたので、そこでの経験も踏まえてDockerのことをしっかりと理解できるような内容を他の人にも共有したいと思うようになりました。

　そこで本記事では、「__これからDockerを使った開発をしてみたいが、そもそもDockerとは何なんだ__」という疑問を持っている方に向けて、「__Dockerというものをしっかりと頭の中でイメージしながらスムーズに開発を進めていけるようになる__」ことを目的としております。

# 本記事の内容
　本記事の内容は以下の通りです。

+ Dockerとは
+ Dockerのメリット
+ Dockerはどう動くのか
+ 今回のまとめ

# Dockerとは
　Dockerとは一体何者なのでしょうか。
　一言で言うと、「__いくつものデータやプログラムを隔離した状態で安全に扱える技術__」です。これにより、 __自分のPC上で複数のシステムをそれぞれ隔離した状態で構築していくことが可能__ になります。これがなぜ安全なのかというと、理由は様々ですが、私が一番感じているのは、「__隔離していることによってバージョンの違いによる不具合がない__」ということです。
![Dockerとそれ以外の環境.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/c5e9d594-8dce-90ab-7c78-a6e35bdcfacb.png)
　上の図で考えてみましょう。左図は自分のPC上にPHPをインストールしてある状態です。この時、初めはシステムAのみを使用していたが、途中からシステムBもPHPで作ろうとなったとします。もしシステムBがPHPバージョン8以降でしか動かないとしたらバージョンを上げたくなりますよね。でもシステムAはPHPバージョン8以降では動かないとしたらどうでしょう。バージョンの違いによる不具合が発生するとはこのことです。
　無論、バージョン管理システムを利用すればそのような不具合も解消できるでしょうが、 __Dockerならばもっと簡単__ です。

　Dockerでは「__コンテナ__」という隔離空間を使用して、それぞれのコンテナに必要なものを入れて使用していきます。今回で言えば、システムA用のコンテナには「PHPバージョン7」を入れておき、システムB用のコンテナには「PHPバージョン8」を入れておけば良いということになります。__それぞれのコンテナは隔離されている__ ので、バージョンが違っていても大丈夫です。

 「__それぞれのシステムに必要なものだけそれぞれに合わせてコンテナに入れて使う__」という考え方を覚えておきましょう。

# Dockerのメリット
　「Dockerとはこういうもの」というのがある程度分かったところで、次は「__Dockerを使うメリット__」についてです。メリットは主に以下の3つです。

　①複数のサーバー機能をコンテナごとに分けて、Docker上に同居させることができる。
　②イメージ化(設計図化)できるから持ち運び可能
　③動作がとても軽量

## メリット① 複数のサーバー機能をコンテナごとに分けて同居OK
　例えばアプリケーション開発において、Webサーバーを用意する時のことを考えてみましょう。Webサーバーとして「Apache」を入れたいとして、Dockerならば一つのコンテナに一つのApacheを入れて他からは隔離して使用することができるため、 __同じApacheを複数使用することができます。__
　通常サーバーマシンには一つのWebサーバーしか入れられないため、今回の例の場合、普通であればApacheを一つしか導入できません。しかし、Dockerを使うと、「__コンテナ__」という隔離技術のおかげで、Apacheを複数用意できるのです。これにより、それぞれのシステムに一つの専用のWebサーバーを用意できるため、安全な開発が期待できるというわけですね。
　
　これにより、「__物理的にはApacheという一つのWebサーバーしかない__」が、「__機能的には複数のApacheが存在する__」という状況を作ることができるのです。
![Dockerメリット①：サーバー同居.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/36594e8b-fc94-95d8-1ea6-58641fb6bb7f.png)
　ちなみに、上の図で「__Docker Engine__」というものがありますが、これはDockerのソフトであると考えてください。

## メリット② イメージ化(設計図化)できるから持ち運び可能
　Dockerは一つのコンテナに一つのサーバーを入れて使用するのが基本です。例えば、PHPとMySQLを使用したWebアプリケーションの開発をDocker環境下で行う場合、「__PHPを入れるコンテナ(フレームワークを使うならフレームワークも一緒に)__」、「__WebサーバーとしてApacheを入れるコンテナ__」、「__MySQLを入れるコンテナ__」、「__phpMyAdminを入れるコンテナ__」といった具合でしょうか。
　この時、それぞれのコンテナはどうやって作られているのでしょうか。
　
　答えは「__設計図をもとにコンテナを作っている__」です。

　コンテナを作るための設計図のことを「__イメージ__」と呼びます。このイメージを元にして一つ一つのコンテナを作っていくという仕組みになっています。
![Dockerメリット②イメージ化.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/f69aaae8-ed0d-3206-f5bc-670b0c31700b.png)
　コンテナはそれぞれを隔離して簡単にかつ安全に開発環境を構築できるものでした。そして、それぞれのコンテナは設計図である「__イメージ__」をもとに作られることも説明しました。このイメージは __簡単に配布__ することができます。そして他の人がそのイメージを使用してコンテナを同じように作成すれば、開発環境があっという間に完成してしまいます。これがDocker2つ目のメリットです。

## メリット③ 動作がとても軽量
　Dockerはとても動作が軽量であるという特徴を持ちます。なぜ、軽量なのでしょうか。それは、Dockerのコンテナには「__Linuxカーネルがないから__」です。どういうことかを理解するために、まず「__OS__」というものについて考えてみましょう。
 OSは「__ソフトウェアからの命令をハードウェアに伝えて操作する__」という役割を持ちます。この時実際にハードウェアに対して命令を伝えて操作するのがOSの中核部分に存在する「__カーネル__」という存在になります。このカーネルとその __周辺部分__ によってOSはできています。
![カーネルと周辺部分.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/df6f47bf-f50e-fcbc-4172-890b411e9fdb.png)
ここで、Dockerのコンテナの構造を見てみましょう。以下の図のような構造になっています。
![Dockerコンテナの構造.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/643f83bc-f29f-a2bf-0aca-f376ca700935.png)
　コンテナにも「__OSっぽいもの__」が入っています。しかし、実態はOSの周辺部分としての機能のみであり、肝心なカーネル部分はハードウェアに任せているのです。これにより、Dockerでは軽量な動作を実現しているのです。「__カーネルがないから動作が軽量__」というのはこういうことなのです。

# Dockerはどう動くのか

## Dockerが動くための前提条件
　Dockerのメリットが分かったところで、実際にDockerはどのようにして動いているのかを見ていきましょう。

　まず、Dockerが動くためには、 __土台のOSがLinuxである必要があります。__ これはコンテナ内のOSっぽいものがLinuxで動いているからであります。デフォルトでハードウェアのOSがLinuxであるならいいですが、WindowsOSやMacOSの場合はどうすればいいのでしょうか。

　心配は要りません。何とかしてLinuxの環境を構築すればいいのです。やり方は大きく2つあり、「__仮想環境を用意して、Linux環境を作り、その上にDockerを置く__」という方法と、「__Docker for Desktopというパッケージをインストールして使用する__」方法です。詳しい方法は割愛しますが、どちらにせよ「__Linux環境が必要__」ということを覚えておきましょう。

## Dockerコンテナの作成から起動まで
　ここからは __Dockerのコンテナを作成し、起動する方法__ を見ていきましょう。基本的にコマンドを使用して作成、起動していきます。コンテナは設計図であるイメージから作られることはすでに説明しましたが、そのイメージはどこにあるのでしょうか？これは「__Docker Hub__」と呼ばれるサービス上で多くのイメージが公開されています。
　Docker Hubは以下から確認してみてください。
　(https://hub.docker.com/)

　このDocker Hub上にあるイメージをダウンロードし、コンテナを作成、起動するところまでを見ていきましょう。
```docker
#今回はApacheのイメージである「httpd」を使用してApacheコンテナを作成していきます。

#まず、httpdをダウンロードします。特にオプションを指定しなければ最新版がダウンロードされます。
docker pull httpd

#次にイメージを元にコンテナを作成します。
docker create httpd

#コンテナが作成されたかどうか確認します。
docker ps -a

CONTAINER ID   IMAGE                         COMMAND                  CREATED          STATUS      PORTS                               NAMES
3f27359ca42c   httpd                         "httpd-foreground"       10 seconds ago   Created                                         hungry_shockley

#次にコンテナを起動します。起動したいコンテナIDを指定します。
docker start 3f27359ca42c

3f27359ca42c

#コンテナを停止します。
docker stop 3f27359ca42c

#最後にコンテナを削除します。
docker rm 3f27359ca42c

#イメージも削除しておきます。
docker image rm httpd 
```

## Dockerのコンテナへのアクセス方法
　次に起動したコンテナにアクセスする方法を紹介します。「__ブラウザからApacheコンテナにアクセスする場合__」を考えてみましょう。ApacheコンテナはWebサーバーとして機能しているので勿論ポートを開いて外からのアクセスが来るのを待っています。HTTP通信であれば基本80番ポートなので、Apacheコンテナは80番ポートを開いてアクセスが来るのを待っている状態です。
　しかし、普通のままアクセスしようとしても、アクセスできません。なぜならコンテナは外部とは繋がっていないからです。そこで、「__物理マシンにポートを開いてもらい、そのポートへアクセスし経由してApacheコンテナへアクセス__」という方法を取ります。
![Dockerコンテナへのアクセス.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/764f32ca-5656-6305-9272-e9226ce8fef9.png)
　それでは、ポートも指定した上で再度コンテナを作成、起動しましょう。
```docker
#ここでは、「イメージのダウンロード、コンテナの作成、起動」を一括で行える「run」コマンドを使用します。
#docker run --name コンテナ名 -d -p ホストポート:コンテナポート イメージ名　でコマンド入力します。
docker run --name apache1 -d -p 8080:80 httpd
```
　本当にApacheコンテナにアクセスできるのかどうかを確かめるために、ブラウザ上で「localhost:8080」と入力してみましょう。すると以下のようなデフォルト画面が出てくればOKです。
![apacheデフォルト画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2375287/2d17758c-15f1-ec13-be69-e5cd1c2460dc.png)

::: note warn
　物理マシンのポート番号は一意である必要があります。一方、コンテナ側のポート番号は重複していても大丈夫となります。気をつけて使いましょう。
:::

# 今回のまとめ
　今回は本当にdockerの基礎的な部分に留めておきました。次回の記事では、より実践的な使い方として、「Dockerfie」や「docker-compose」をテーマにしてお送りしたいと思います。また、 __私自身が実業務の中で出くわしたエラーなども共有していきたいと思っています。__