【備忘録】Docker

# ダウンロード
https://docs.docker.com/get-started/get-docker/

# 動作確認
`docker container run hello-world` -> 実行できたら`Docker daemon`が動いている

# イメージ
コンテナを作る元になる土台のこと

## イメージ図解
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/145340ed-1446-440a-8866-a67dbc5495ed.png)


## ローカルにイメージをダウンロードする
```console
docker image pull {イメージ名:タグ名}
```
- タグ名を省略した場合`イメージ名:latest`を指定する
- 落としたいイメージは`Docker Hub`から探す

## ローカルに存在するイメージ一覧を表示
```console
docker image ls
```

## ローカルのイメージを削除
```console
docker image rm {イメージ名:タグ名}
```

## Dockerfileからイメージを作成する
```console
# 基本的には以下の感覚で良い
docker image build {Dockerfileの存在するディレクトリ}

# 厳密には以下の感覚でいる必要がある
docker image build -f {Dockerfileのパス} {ビルドコンテキストのパス}
```
- `-t {イメージ名:タグ}`を`image build`のオプションに渡すとイメージに命名が出来る
- `-f {Dockerfileのパス}`を`image build`のオプションに渡すと明示的にDockerfileを指定する
- `--target {ビルド対象のステージ}`を`image build`のオプションに渡すと明示的に
**イメージ化するステージ**を指定出来る

- **ビルドコンテキストについては以下の記事を参照する**

https://qiita.com/warabimochi_26/items/5765f479004946194298

- **マルチステージビルドについては以下の記事を参照する**

https://qiita.com/warabimochi_26/items/a4078defbc888a44cf73

## イメージレイヤーを可視化する
```console
docker image history {イメージ名:タグ名}
```
- **イメージレイヤーについては以下の記事を参照する**

https://qiita.com/warabimochi_26/items/4a6b54b2c1367c243dd7


## Dockerfileの書き方
- `FROM {イメージ名:タグ名}`で**ベースイメージ**を決める
- `RUN {コマンド}`は**イメージビルド時**にコマンドを実行する
- `COPY {コピー元ローカル内のファイル コピー先イメージ内のファイル}`は
**イメージビルド時**にローカルからイメージに任意のファイルをコピーする
- `CMD ["コマンド", "オプション1"...]`はデフォルトコマンドを上書きする
- `ENV key="value"`はコンテナで使える環境変数を与える
- `ARG 変数名="デフォルト値"`で**イメージビルド時**にDockerfile内でのみ使う変数を宣言する 
    - `docker image build`に対して`--build-arg {変数名="代入値"}`の
    オプションを与えて代入する
- `WORKDIR {ディレクトリパス}`で
    - **イメージビルド時**に命令が実行されるディレクトリを変更する
    - **コンテナに入った瞬間**のディレクトリを変更する


# コンテナ
ホストOSとは隔離された実行環境のこと

## コンテナ図解
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/63ece4d5-6e9f-47ba-ad0d-537e69351b1c.png)

## イメージからコンテナを起動して実行する
```console
docker container run {イメージ名:タグ名}
```
- タグ名を省略した場合`イメージ名:latest`を指定する
- `image`がローカルに存在しない場合`image pull`から`container run`を直列に行う
- `-it`を`container run`のオプションに渡すと対話モードになる
- `--name`を`container run`のオプションに渡すとコンテナ名を明示的に決定
- `--rm`を`container run`のオプションに渡すと `Exit`状態 -> 破棄 を自動で行う
- `-d`を`container run`のオプションに渡すとコンテナを**バックグラウンド**で実行する

## バッグラウンド起動してるコンテナに接続する
```console
docker container attach {コンテナ名 | コンテナID}
```

## イメージから任意のコマンドでコンテナを起動する
```console
docker container run {イメージ名:タグ名} {任意のコマンド}
```
- `イメージ名`の後にコマンドを入力するとデフォルトコマンドを乗っ取って任意のコマンドを実行出来る 

## 起動しているコンテナに任意のコマンドを実行する
```console
docker container exec {コンテナ名 | コンテナID} {任意のコマンド}
```

## 実行されているコンテナを表示する
```console
docker container ls
```
- `-a`をオプションに付けると`exit`したコンテナも表示される

## Up状態のコンテナをExit状態にする
```console
docker container stop {コンテナ名 | コンテナID}
```

## Exit状態のコンテナをUp状態にする
```console
docker container restart {コンテナ名 | コンテナID}
```

## バックグラウンドで動いてるコンテナのログを見る
```console
docker container logs {コンテナ名 | コンテナID}
```

## Exit状態のコンテナを破棄する
```console
docker container rm {コンテナ名 | コンテナID}
```
- Up状態のコンテナは破棄出来ないので、`container stop`から`container rm`を直列に行う
- `-f`を`container rm`のオプションに渡すと状態問わず破棄する

## Up状態以外のコンテナを全て破棄する
```console
docker container prune
```
- `Created`・`Exit`状態のコンテナを全て破棄する

# ボリューム
`Docker daemon`の管理下で、**コンテナから独立した**データ保存領域
- **ボリュームの実体**はディレクトリ
`windows`なら`\\wsl.localhost\docker-desktop-data\data\docker\volumes`に存在する

## ボリューム図解
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/3384d85c-497f-4089-b8ed-f7b68db54683.png)
    

## ボリュームを作成する
```console
docker volume create {ボリューム名}
```

## ボリューム一覧を表示する
```console
docker volume ls
```

## ボリュームの詳細を表示する
```console
docker volume inspect {ボリューム名}
```

## ボリュームを削除する
```console
docker volume rm {ボリューム名}
```

## ボリュームに接続してコンテナを起動する
```docker
# 以下二つは同じ挙動を取る
docker container run -v {ボリューム名}:{コンテナ内絶対パス} {イメージ名}

docker conitaner run --mount type=volume,src={ボリューム名},dst={コンテナ絶対パス} {イメージ}
```
- コンテナ内ディレクトリをボリュームに同期させて起動する

# バインドマウント
ホストOS内ディレクトリとコンテナ内ディレクトリを同期させて起動させる機能

## バインドマウント図解
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/6f5c686d-12b9-4bd5-82b4-c90a5ab2005b.png)

## ホスト側のファイル・ディレクトリをコンテナと同期させてコンテナ起動
```docker
# 以下二つは同じ挙動を取る
docker contianer run -v {ホスト側パス}:{コンテナ内絶対パス} {イメージ名} 

docker conrainer run --mount type=bind,src={ホスト側パス},dist={コンテナ内絶対パス} {イメージ名}
```

# ネットワーク
コンテナ群を**論理的に分割**し**グルーピング**したもの

- 同ネットワーク内のコンテナはコンテナ間通信が可能
- 異ネットワーク内のコンテナはコンテナ間通信が出来ない

## ネットワーク図解
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3348923/96391e05-1c4b-4c34-a6ab-81e62f7dfbed.png)

## ホストOSのポートとコンテナのポートを紐づけて外部からの通信をコンテナへ伝達する
```docker
docker container run -p {ホスト側ポート}:{コンテナ側ポート} {イメージ名}
```

## ネットワーク一覧を表示する
```docker
docker network ls
```

## ネットワークの詳細情報を表示する
```docker
docker network inspect {ネットワーク名}
```
- `Containers`を見るとネットワーク配下のコンテナが分かる

## ネットワークを作成する
```docker
docker network create {ネットワーク名}
```

## コンテナを任意のネットワークに接続して起動する
```docker
docker container run --network {ネットワーク名} {イメージ名}
```
- ``--network``を指定しなかった時、コンテナはデフォルトの`bridge`ネットワーク配下に
配置される
- **ユーザ定義ネットワーク**ではコンテナ名からIPアドレスを自動で**名前解決**出来る

## 指定したネットワークを削除する
```docker
docker network rm {ネットワーク名}
```

# Docker Compose
コンテナ群の起動を**1コマンド**で行えるモノ
- `docker-compose.yml`は`docker compose up`で起動するコンテナ群の`container run`に
渡すオプションを予め記載しておくファイル

## コンテナを起動する
```docker
# docker-compose.ymlに定義された全コンテナを起動する
docker compose up

# docker-compose.ymlに定義された内指定したコンテナを起動する
docker compose up {サービス名}
```
- `--build`を`compose up`のオプションに渡すとイメージが存在しても`image build`を行う


## `docker compose up`で起動した全コンテナを破棄する
```docker
docker compose down
```

## 特定のコンテナで任意のコマンドを実行する
```docker
docker compose exec {サービス名} {コマンド}
```

## ディレクトリ内の`compose up`で起動しているコンテナ一覧を表示する
```docker
docker compose ps
```

## docker-compose.ymlの書き方
- `version: {バージョン}`で**Docker Compose**の解釈されるバージョンを指定する
- `services`配下に入れ子で**サービス名**を記載し、各サービスを定義する

**各サービス**は**dockerリソース**の**コンテナ**と同等

- **各サービス**に対して入れ子で以下のように**起動時のオプション**を記載出来る
    - `build: {ビルドコンテキストパス}`は`image build`時の**ビルドコンテキスト**を指定する
        - `context`と`target`を入れ子にすると`image build`の`--target`オプションを使える
    - `image: {イメージ名:タグ名}`は`image build`時の**Docker Hubのイメージ**を指定する
        - `各サービス`には`build`か`image`のどちらかが必須
    - `ports`は`container run`の`-p`オプション
    - `environment`は`container run`の`-e`オプション
    - `volumes`は`container run`の`-v`オプション
    - `container_name`は`container run`の`--name`オプション
    - `tty: true`は`container run`の`-t`オプション
    - `depends_on`は指定した`サービス群`が起動するまで**自サービスの起動を待つ**オプション

- `volumes`配下に入れ子で**ボリューム名**を記載し、**ボリュームの新規作成**を定義する

以下が`docker-compose.yml`の例
```yml:volumesの例
version: "3.9"

services:
  api:
    build: ./api
    ports:
      - 8080:8080
    depends_on:
      - db
  db:
    image: postgres:15
    ports:
      - 5432:5432
    environment:
      - POSTGRES_PASSWORD=mypassword
      - POSTGRES_USER=postgres
      - POSTGRES_DB=appdb
    volumes:
      - db-storage:/var/lib/postgresql/data
      - ./db/initdb:/docker-entrypoint-initdb.d
volumes:
  db-storage:
```
```yml:ステージ指定でのimage build例
version: "3.9"
services:
  api:
    container_name: api
    build: ./api
    ports:
      - 8080:8080
    tty: true
    volumes:
      - ./api:/workspace:cached
  web:
    container_name: web
    build:
      context: ./web
      target: base
    ports:
      - 3000:3000
    environment:
      - REACT_APP_API_SERVER=http://localhost:8080/api
    tty: true
    # :cached ホスト側での変更を瞬時に同期させないがパフォーマンスを向上させる
    volumes:
      - ./web:/workspace:cached
    depends_on:
      - api
```