Dockerって何？なんのためにあるの？【0から学ぶ】

# Docker

**アプリケーションをコンテナ化する**ためのツール

## 目的

Dockerとは，**アプリケーションをコンテナ化する** ためのツール．
主に以下のような目的で使われる：

1. 環境の統一
  開発環境・テスト環境・本番環境で同じ環境を簡単に再現できるため，「ローカルでは動いたのに本番で動かない」という問題を防げる．

2. アプリケーションの隔離
  コンテナはホストOSとは独立した環境で動作するため，他のアプリケーションに影響を与えずに動作させることができる．

3. 簡単なデプロイとスケーリング
  コンテナは軽量で，すぐに起動できる

4. 依存関係の管理
  アプリケーションとその依存ライブラリをすべてコンテナ内にパッケージできるため，**「バージョンの違いで動かない」** という問題が発生しにくくなる．

5. マルチプラットフォーム対応
  DockerはLinux、Windows、Macで動作し，どの環境でも同じコンテナを動かすことができる．

  例えば，PythonのアプリケーションをDockerで動かす場合，以下のような `Dockerfile` を作成すると，どの環境でも同じPython環境が再現できる．

```dockerfile
FROM python:3.12
WORKDIR /app
COPY . .
RUN pip install -r requirements.txt
CMD ["python", "main.py"]
```

これをもし，`docker build -t my-app .`とした場合，`.`を**ビルドコンテキスト**と呼ぶ．

ここで，`.`はホストのカレントディレクトリ．（例えば，`go`ディレクトリにいて，`docker build`をするなら，`go`ディレクトリのこと．）

- python=3.12環境で実行することを明示
- `/app`ディレクトリで作業をする
- `COPY . .`は，
  - 最初の`.`は**ビルドコンテキスト**内の全てのファイル
  - 二番目の`.`は**コンテナ内の`WORKDIR`（例：`/app/`）
    - Docker の仕様上，`COPY`でビルドコンテキスト外のファイル（`../python` など）を指定することはできない．
- `pip install -r requirements.txt`を実行
- コマンドで，`python main.py`を実行．

という流れと対応する．

## Dockerイメージ・コンテナとは

アプリケーションやその環境（OS, 依存ライブラリ, 設定）をすべてパッケージ化したもの

イメージは**変更できない静的なテンプレート**で，それを実行すると**コンテナ**になる

イメージの構成:

- OS（Ubuntu, Alpine など）
- アプリケーション（Python, Node.js, MySQL など）
- ライブラリ・依存関係
- 設定ファイル（環境変数など）
- 実行コマンド（CMD / ENTRYPOINT）

以下の`Dockerfile`で作るイメージには Pythonとアプリのコードが含まれる

```dockerfile
FROM python:3.12  # OS+Python環境
WORKDIR /app
COPY . .  # ソースコードをコピー
RUN pip install -r requirements.txt  # 必要なライブラリをインストール
CMD ["python", "app.py"]  # 実行コマンド
```

これを**ビルド**すると**イメージ**が作成される：

```sh
docker build -t myapp .
```

そして，実行すると**コンテナ**になる：

```sh
docker run -d --name mycontainer myapp
```

## Dockerレジストリとは

**GitHub やゲーム機** に例えると：

| **Docker** | **GitHub** | **ゲーム機** |
|------------|------------|------------|
| **レジストリ（Registry）** | **リポジトリ（Repository）** | **ゲームソフトを置くストア**（Nintendo eShop など） |
| **イメージ（Image）** | **コミットされたコード（バージョン管理された状態）** | **ゲームカセット（ROMデータ）** |
| **コンテナ（Container）** | **コードをクローンして動かした状態（実行環境）** | **ゲームをプレイしている状態** |

### それぞれの役割

- **レジストリ（Registry） = GitHubのリポジトリ / ゲームストア**
  - Dockerイメージを保存・管理・共有する場所
  - `docker push` でアップロード、`docker pull` でダウンロードできる
  - 例: **Docker Hub, Amazon ECR, GCR**

- **イメージ（Image） = GitHubのコード / ゲームカセット**
  - **変更不可のテンプレート** で、環境・アプリを含んでいる
  - `docker build` で作成し、レジストリにアップロードできる
  - 例: `ubuntu:latest`, `python:3.12`, `myapp:1.0`

- **コンテナ（Container） = GitHubのコードをローカルで実行 / ゲームをプレイ**
  - **イメージを元に動作している実行プロセス**
  - `docker run` で起動、データを保持することも可能
  - 例: `docker run -d myapp`

### 例えを使った流れ

**ゲームの場合:**

1. **ゲームソフトのストア（レジストリ）** からゲームをダウンロード（`docker pull`）
2. **カセット（イメージ）** をゲーム機に差し込む
3. **ゲームをプレイ（コンテナ）** する

**Dockerの場合:**

1. **Docker Hub（レジストリ）** からイメージを `docker pull` する
2. **イメージ** を `docker build` または `docker pull` で用意
3. **コンテナ** を `docker run` で起動し、アプリを実行する

なお，**コンテナはホストマシンとは別の独立した環境**なので，手元のBashから直接操作するのではなく，**コンテナのBashに入って作業する**という流れになる

## Volume（ボリューム）とは

Dockerコンテナがデータを永続的に保存するための仕組み．

通常，Dockerコンテナは一時的なもので，コンテナを削除すると中のデータも消えてしまう．  
しかし，ボリュームを使うとコンテナが削除されてもデータを保持できる．

コンピュータの主記憶（RAM）と補助記憶（HDD/SSD）の関係と似ている．

### 使い方

1. ボリュームを作成

   ```sh
   docker volume create my_volume
   ```

2. コンテナにボリュームをマウント

   ```sh
   docker run -d --name my_container -v my_volume:/app/data ubuntu
   ```

   - `-d`
     - デタッチドモード（detached mode）コンテナをバックグラウンドで実行する
   - `-v my_volume:/app/data`
     - ボリュームをマウント．`my_volume`をコンテナ内の`/app/data`に接続

3. ボリュームにデータを書き込む

   ```sh
   docker exec -it my_container bash
   echo "Hello, Volume!" > /app/data/test.txt
   exit
   ```

   - `exec`
     - 実行中のコンテナの中でコマンドを実行
   - `-i`
     - インタラクティブモード（interactive mode）．標準入力を受け付ける
   - `-t`
     - 擬似ターミナル（tty）を割り当てる
   - `bash`
     - コンテナ内で`bash`シェルを起動（コンテナにログイン）
  
   このコマンドを実行すると，`my_container`の中に入り，`bash`を使ってコマンドを入力できるようになる．

   `my_container`内で，`"Hello, Volume!"`を`/app/data/test.txt`内に書き込む．

4. 別のコンテナでデータを確認

   ```sh
   docker run --rm -v my_volume:/app/data ubuntu cat /app/data/test.txt
   ```

   - `--rm`
     - コンテナの実行が終わったら、自動で削除（クリーンアップ）
   - `-v my_volume:/app/data`
     - ボリューム`my_volume`を`/app/data`にマウント
   - `cat /app/data/test.txt`
     - コンテナ内で`/app/data/test.txt`の内容を表示

   このコマンドでは，**一時的なコンテナを起動**し，ボリューム内のtest.txtを表示した後，コンテナを削除する

5. ボリュームを削除（使わなくなったら）

  ```sh
  docker volume rm my_volume
  ```

基本的には，ボリュームはコンテナの中からしか見れない．（Linuxでは見れる方法もある．）

## マウントとは

**ホスト側のフォルダやファイルをコンテナの内部で使えるようにする**こと

たとえば，ホストの`./db`フォルダをコンテナの`/app/db`に**マウント** すると，コンテナ内のアプリは`/app/db`を**ローカルの`./db`と同じように扱える** ようになる．

**動作**：

1. **ホスト側 (`./db`) にある SQLite のデータベースファイル (`mercari.sqlite3` など) をコンテナ内の `/app/db` で使える**
2. **コンテナを削除しても `./db` のデータはホストに残る**
3. **別のコンテナを立ち上げても、以前のデータを引き継げる**

---

### なぜマウントが必要なのか

- **データの永続化** → **コンテナを削除しても`SQLite`のデータを保持**
- **開発の利便性** → ホスト側でデータを変更すると，コンテナ側にも即反映
- **データ共有** → バックエンドが`sqlite3`を使うとき，ホストのデータと連携できる

---

これにより，バックエンドのコンテナが`/app/db/mercari.sqlite3`を読んだり書き込んだりすると，ホストの`./db/mercari.sqlite3`も同時に更新される

## レジストリからimageを取得する方法

```sh
docker pull alpine
```

## build方法

```sh
docker build -t リポジトリ名:タグ .
```

## run方法

### `docker run` の基本構文

```sh
docker run [オプション] イメージ名 [コマンド]
```

- `docker run` → 新しいコンテナを作成して実行
- `[オプション]` → `--name` などのオプションを指定できる
- `イメージ名` → どのDockerイメージを使うか指定
- `[コマンド]` → コンテナ内で実行するコマンド（省略するとデフォルトのCMDが実行）

---

### `--name` を使う場合

```sh
docker run --name コンテナ名 イメージ名
```

- `--name` → **コンテナの名前を指定**
- `コンテナ名` → 好きな名前をつけられる（例: `my_container`）
- `イメージ名` → 実行するDockerイメージ（例: `ubuntu`）

#### 例

```sh
docker run --name my_container ubuntu
```

これで，`my_container`という名前のコンテナが作成され．`ubuntu`イメージが実行される．

---

### **よく使うオプション**

| オプション | 説明 |
|-----------|------|
| `-d` | **デタッチドモード**（バックグラウンド実行） |
| `-it` | **インタラクティブモード**（ターミナルを割り当てる） |
| `--rm` | **コンテナ終了後に自動削除** |
| `-v` | **ボリュームをマウント** |
| `-p` | **ポートフォワード**（例: `-p 8080:80`） |

---

### **よくある使い方の例**

#### **1. 通常のコンテナ起動**

```sh
docker run ubuntu
```

- `ubuntu` のイメージでコンテナを起動（名前は自動で割り振られる）

#### **2. 名前をつけてコンテナを起動**

```sh
docker run --name my_container ubuntu
```

- `my_container` という名前のコンテナが作成される

#### **3. インタラクティブモードでBashを開く**

```sh
docker run -it --name my_container ubuntu bash
```

- `-it` をつけることで、Bashを開いた状態でコンテナに入れる

#### **4. バックグラウンドで起動**

```sh
docker run -d --name my_container ubuntu
```

- `-d` をつけると、コンテナがバックグラウンドで実行される

#### **5. コンテナ終了後に自動削除**

```sh
docker run --rm ubuntu
```

- `--rm` をつけると、コンテナ終了時に自動で削除される（不要なコンテナが溜まらない）