Dockerチュートリアルをやったのでまとめる

Dockerのチュートリアルをやってわかったことやハマったことをまとめる。

https://docs.docker.jp/get-started/toc.html

## Dockerコンテナの操作
### Dockerのコンテナイメージ作成
`Dockerfile`の内容に基づき、`docker build`コマンドを使用してコンテナイメージを作成する。
ビルドコンテキストはビルド時に使用するファイルを指定する。
ビルドコンテキストに指定されたファイル群はDockerデーモンに送信され、コンテナ内で利用できる。
`.dockerignore`ファイルに、ビルドコンテキストから除外するファイルを指定できる。
```
docker build -t <image名> <ビルドコンテキスト>

例：
docker built -t getting-started .
```

### Dockerコンテナの起動
`docker run`コマンドを使用する。
コマンド実行後に表示される文字列がコンテナID。
```
docker run <image名>
  -p <HOST>:<CONTAINER PORT>: ポートの関連付け。<CONTAINER PORT>を<HOST>に公開する。
  -d: コンテナに入らずにバックグラウンドで実行する。
  -i: ホストの標準入力とコンテナの標準出力をつなげる。
  -t: コンテナの標準出力とホストの標準出力をつなげる。
  -v <HOSTDIR>:<CONTAINERDIR>: ホストとコンテナ間でファイルを共有する。
  
❯ docker run -dp 127.0.0.1:3000:3000 --mount type=volume,src=todo-db,target=/etc/todos getting-started
28af0df133e953ac9d0a1ea52b8384dbf21227af080e98b1b48e80f521252606
```

### Dockerコンテナの一覧の確認
`docker ps`を使用する。
`docker ps`コマンドで確認できるコンテナIDを各種操作の際に指定する。
```
docker ps

❯ docker ps
CONTAINER ID   IMAGE             COMMAND                   CREATED         STATUS         PORTS                      NAMES
28af0df133e9   getting-started   "docker-entrypoint.s…"   7 seconds ago   Up 7 seconds   127.0.0.1:3000->3000/tcp   flamboyant_wilson
```

### Dockerコンテナの停止・削除
`docker stop`及び`docker rm`を使用する。
コンテナIDの指定は一意に特定できれば全て入力しなくても良い。
```
docker stop <container-id>
docker rm <container-id>

あるいは

docker rm -f <container-id>


❯ docker stop 2
2

❯ docker rm 2
2
```

### Dockerイメージの一覧の確認
`docker image ls`を使用する。
```
docker image ls

❯ docker image ls
REPOSITORY              TAG         IMAGE ID       CREATED         SIZE
getting-started         latest      28dc6354df72   10 hours ago    218MB
```

## データの保持
Dockerホスト側の特定のディレクトリをマウントし、マウントされたディレクトリに保持するデータを格納することで、コンテナ側から参照できる。
### ボリュームマウント
データの保管領域を作成し、Dockerコンテナの特定のディレクトリと紐づける。
データの保管領域はDockerが決定し、ボリューム名を用いて参照する。
データの共有や保持に利用する？

ボリュームは以下のコマンドで予め作成する。
```
docker volume create <volume-name>
```

Dockerコンテナ起動時に`--mount`オプションを用いてマウントを行う。
以下の場合は、`/etc/todos`に作成されたファイルをボリュームに確保する。
```
docker run -dp 127.0.0.1:3000:3000 --mount type=volume,src=todo-db,target=/etc/todos getting-started
```

### バインドマウント
DockerホストとDockerコンテナの特定のディレクトリを紐づける。
紐づけは絶対パスでホスト側・コンテナ側いずれも指定できる。
ソースコードなどの共有などに利用する？

Dockerコンテナ起動時に`--mount`オプションを用いてマウントを行う。
以下の場合は、ホストのカレントディレクトリとコンテナの`/src`を紐づける。
```
docker run -it --mount type=bind,src="$(pwd)",target=/src ubuntu bash
```

## Docker Compose
`docker-compose.yml`に各コンテナをサービスとして定義しておき、
`docker compose up`でサービス単位で一度にコンテナを起動したり、`docker compose down`で一度にコンテナを破棄したりできる。
また、複雑なオプションを都度指定する必要がなくなる。

`docker-compose.yml`の例。
`app`と`mysql`の2つのサービスを定義している。
```
services:
  app:
    image: node:18-alpine
    command: sh -c "yarn install && yarn run dev"
    ports:
      - 127.0.0.1:3000:3000
    working_dir: /app
    volumes:
      - ./:/app
    environment:
      MYSQL_HOST: mysql
      MYSQL_USER: root
      MYSQL_PASSWORD: secret
      MYSQL_DB: todos

  mysql:
    image: mysql:8.0
    volumes:
      - todo-mysql-data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: todos

volumes:
  todo-mysql-data:
```

`docker compose up`でコンテナを一度に起動したり、`docker compose down`でコンテナを一度に破棄したりできる。
```
❯ docker compose up -d
[+] Running 3/3
 ✔ Network app_default    Created                                          0.1s
 ✔ Container app-mysql-1  Started                                          0.4s
 ✔ Container app-app-1    Started                                          0.4s

❯ docker ps
CONTAINER ID   IMAGE            COMMAND                   CREATED          STATUS                    PORTS                      NAMES
254ce5b1d496   mysql:8.0        "docker-entrypoint.s…"   10 seconds ago   Up 10 seconds (healthy)   3306/tcp, 33060/tcp        app-mysql-1
e96e4061ad19   node:18-alpine   "docker-entrypoint.s…"   10 seconds ago   Up 9 seconds              127.0.0.1:3000->3000/tcp   app-app-1

❯ docker logs e9
yarn install v1.22.19
[1/4] Resolving packages...
success Already up-to-date.
Done in 0.48s.
yarn run v1.22.19
$ nodemon src/index.js
[nodemon] 2.0.20
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node src/index.js`
Waiting for mysql:3306.
Connected!
Connected to mysql db at host mysql
Listening on port 3000

❯ docker compose down
[+] Running 3/3
 ✔ Container app-app-1    Removed                                          0.2s
 ✔ Container app-mysql-1  Removed                                          3.6s
 ✔ Network app_default    Removed                                          0.1s
```

## ハマったこと

### `docker`コマンドを初回実行時にpermission denied
`docker`コマンド初回利用時に下記エラーが発生。
```
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
```

下記サイトを参考に、`docker`グループにユーザーを追加後、再起動することで解消された。

https://zenn.dev/botamotch/scraps/43f6b5e560137f

### Part7でブラウザからアクセス不可になった

MySQLコンテナを起動せずに、appコンテナだけを起動していたので、
MySQLへの接続時にタイムアウトしてしまい、appコンテナがクラッシュしていた。
MySQLコンテナ起動後、appコンテナを起動したところブラウザからアクセス可能になった。

### Part8のDockerComposeで起動時、MySQLへの接続がタイムアウトする
色々調べた限りでは、MySQLコンテナの起動より前に、appコンテナからMySQLコンテナへの接続がタイムアウトしている様子。
こちらはいい解決法が見つかっていない。

## 参考にしたサイト
https://zenn.dev/levtech/articles/docker-build