Dockerについてざっくり把握しよう

# はじめに
<font color="blue">上司</font>「おう、ちびまろ。おつかれ！今度の案件でDocker使うから勉強しといて」

<font color="red">ちびまろ</font>「イエッサー！！」

と二つ返事でDockerの勉強をすることが決まったので自分なりに落とし込んだ内容をアウトプットしたいと思います。

私もまだまだ初学者なので、何か間違えていることを記載してしまっていた場合はコメント頂けると嬉しいです！

# Dockerとは
>Dockerはコンテナ仮想化を用いたOSレベルの仮想化によりアプリケーションを開発・実行環境から隔離し、アプリケーションの素早い提供を可能にする。かつその環境自体をアプリケーションと同じようにコード（イメージ）として管理可能にする。Dockerを開発・テスト・デプロイに用いることで「コードを書く」と「コードが製品として実行される」間の時間的ギャップを大きく短縮できる。

[Wikipediaより引用](https://ja.wikipedia.org/wiki/Docker)

Dockerとは、Docker社が開発している<INS>**コンテナ型仮想環境を構築・配布・実行するための[プラットフォーム](https://www.idcf.jp/words/platform.html)**</INS>です。

ホスト型（後述）では実現できなかった環境自体をコードで管理できるということが個人的には相当に魅力的でした。

とにかく今は以下のメリットがあることを頭の片隅に覚えておいて欲しいです。

1. 環境をコードで管理できる
2. 設定次第でコマンド1回環境構築が可能
   例：nginx(Webサーバー)、Laravel、MySQLといった3つの環境が1回のコマンドで完成する
3. コードを別メンバーと共有すると、環境の違いによるエラーなどが発生せず、スムーズに環境構築ができる

## 仮想化のアーキテクチャ(仮想環境構築時の構造の種類)
先ほど出てきた「コンテナ型」や「ホスト型」について簡単に説明します。
絶対にこの概念を理解しないとDockerを使えないということはないので、一旦飛ばして後から読み返すなどでも大丈夫です。

一昔前までは、PCの中にもう一つ仮想のPC環境を作成し、その中でLinuxなどのOSをインストールし動かしていました。

上記の方法で行う構造をホスト型と言います。

本当は他にもいくつかありますが、その中からホスト型と、Dockerのコンテナ型について説明します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431046/f7da76de-2faf-5123-c81e-f033bd0ab9b5.png" alt="ホスト型とコンテナ型の違い">

### ホスト型
１番下の土台であるハードウェアの上にホストOS、さらに仮想化ソフトと専門用語が飛び交っていますが全く難しくありません！
１つずつ説明すると

#### ハードウェア
<font color="red">パソコンその物</font>です。

#### ホストOS
OS(Operations System)は基本ソフトウェアとも呼ばれており、**ハードウェアやアプリケーションソフトウェアを管理・制御するソフトウェア**です。

そこまで難しく考えずに、WindowsOS | MacOS | Linux | など聞いたことあるかと思います。あぁ、聞いたことある！となればそれでOKです。
PCより身近なスマホOSだと、IOS | AndroidOS | などですかね！

#### 仮想化ソフト
今あなたが使っているPCの中に、仮想的に別のPCを作成するためのソフトです。

有名どころで言えば、Oracle製の[VirtualBox](https://www.virtualbox.org/)やVMware社の[VMware](https://www.vmware.com/jp.html)などがあります。

これらのいずれかのソフトをインストールして使います。

#### ゲストOS
仮想化ソフト上にインストールするOSのことです。   
あくまで個人的にですが、私は`ホストOS = 親玉`、`ゲストOS = 居候`という感じでざっくり覚えています笑

ちなみに、WindowsOSの購入は必要ですが、MacPCに仮想化ソフトをインストールし、仮想化ソフトの中にWindowsOSをインストールすることも可能です。

#### アプリ
これはそのままですね。ゲストOS内でインストールしたアプリのことです。
ホストOSの上で動くソフトウェアと何ら変わらないです。

### コンテナ型
さぁ今回の本題とも言えるコンテナ型の説明です。
コンテナ型とは、ホストOS上に直接インストールされた**コンテナエンジン**によって運用・管理されています。
コンテナ型の最大の特徴は、先ほどホスト型で説明した「ゲストOS」がいらないことです。
そのため、コンテナは仮想マシン(仮想ソフト)より相当に軽量だと言われています。

また、仮想マシンは完全に独立したOSのインストールが必要になりますが、コンテナはホストOSのカーネルを共有しているため、リソース使用量が少なく、起動が迅速です。

#### コンテナエンジン
ざっくり、Dockerのことだと考えてください。
今回はDockerの環境構築は省きますが、**Docker for Desktop**を起動させると、**Docker Engine** が起動して、コンテナエンジンが立ち上がります。
このイメージを持っていれば、最初の入りは大丈夫かと思います。

コンテナエンジンが立ち上がると、その上でWebサーバーやアプリケーションサーバーなどが起動します。
画像で言うアプリに当たる部分です。

## イメージ（Image）
Dockerを触っていると、よく聞く単語「<font color="red">**イメージ**</font>」は覚えてください。
コンテナを起動させるためには、このイメージが必須です。

イメージはコンテナを作成するための元です。ざっくりCDなどのディスクだと考えてください。
このディスクイメージを共有することで、他のマシン上でも同じ環境を構築することが可能となります。

## Tag
Dockerイメージには<font color="red">**Tag**</font>という概念があり、イメージのバージョンを表記するために利用されます。
[docker hub - nginx](https://hub.docker.com/_/nginx/tags)にアクセスすると、以下画面のようにTagsに「latest」や「stable-perl」などが存在し、どのバージョンを使うかを選択できます。
デフォルトはlatestです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/431046/e4b059e6-99ea-d99c-e103-6f38031d5317.png">

# Docker Compose
複数のコンテナを定義してコマンドを実行するDockerのためのツールです。
「.yml」の拡張子がついたファイルを使ってサービスを設定します。
簡単に言うと、「PHPのアプリ」「NGINXのサーバー」「MYSQLのDBサーバ」

Laravelを使っている方は是非[@ucan-lab](https://github.com/ucan-lab)さんのリポジトリを覗いてみてください。
色々得られるものがあるかと思います。

そんなucan-labさんが公開している[docker-laravel](https://github.com/ucan-lab/docker-laravel)の環境を使って勉強しました。

## コード全文
```yml:compose.yml
volumes:
  db-store:
  psysh-store:


configs:
  db-config:
    file: ./infra/docker/mysql/my.cnf


services:
  app:
    build:
      context: .
      dockerfile: ./infra/docker/php/Dockerfile
      target: ${APP_BUILD_TARGET:-development}
    volumes:
      - type: bind
        source: ./src
        target: /workspace
      - type: volume
        source: psysh-store
        target: /root/.config/psysh
        volume:
          nocopy: true
    environment:
      # Please remove this environment variable, after created the Laravel project. Please write in .env
      - DB_CONNECTION=${DB_CONNECTION:-mysql}
      - DB_HOST=${DB_HOST:-db}
      - DB_PORT=${DB_PORT:-3306}
      - DB_DATABASE=${DB_DATABASE:-laravel}
      - DB_USERNAME=${DB_USERNAME:-phper}
      - DB_PASSWORD=${DB_PASSWORD:-secret}

  web:
    build:
      context: .
      dockerfile: ./infra/docker/nginx/Dockerfile
    ports:
      - target: 80
        published: ${WEB_PUBLISHED_PORT:-80}
        protocol: tcp
        mode: host
    volumes:
      - type: bind
        source: ./src
        target: /workspace

  db:
    build:
      context: .
      dockerfile: ./infra/docker/mysql/Dockerfile
    ports:
      - target: 3306
        published: ${DB_PUBLISHED_PORT:-3306}
        protocol: tcp
        mode: host
    configs:
      - source: db-config
        target: /etc/my.cnf
    volumes:
      - type: volume
        source: db-store
        target: /var/lib/mysql
        volume:
          nocopy: true
    environment:
      - MYSQL_DATABASE=${DB_DATABASE:-laravel}
      - MYSQL_USER=${DB_USERNAME:-phper}
      - MYSQL_PASSWORD=${DB_PASSWORD:-secret}
      - MYSQL_ROOT_PASSWORD=${DB_PASSWORD:-secret}

  mailpit:
    image: axllent/mailpit
    ports:
      - target: 8025
        published: ${MAILPIT_PUBLISHED_PORT:-8025}
        protocol: tcp
        mode: host
```

## volumes

volumesはDockerコンテナをマウントするボリュームを指定します。
マウントする/しないでかなり変わることが分かりました。

マウントしないと、コンテナを削除したりするとDBのデータも一緒に削除されてしまいます。
テストデータとしてまとめて登録できるデータならまだしも、消えてはいけないデータまで完全に消えてしまうため、マウントは必須だと思います。
DBデータを残したいなら絶対です！！
コンテナ内の記憶領域のデータは削除されますが、別でDataVolumeという領域にデータのバックアップが保管されているイメージです。
volumesを設定することで、このDataVolumeという領域が使えるようになるとイメージすればOKかな？
```yml
volumes:
  db-store:
  psysh-store:
```

# 参考サイト
 - [Docker公式サイト](https://www.docker.com/resources/wha$$t-container/)
 - [Docker入門（第一回）～Dockerとは何か、何が良いのか～](https://knowledge.sakura.ad.jp/13265/)
 - [Docker Wikipedia](https://ja.wikipedia.org/wiki/Docker)