docker composeでvolumeマウントした時のPermission Deniedへの対応

# 私の環境
- Ubuntu 20.04 on WSL2
- Docker 23.0.2（↑のUbuntuにインストール）
- docker-compose 2.17.2
# はじめにやったこと
シンプルに公式のnodeイメージをpullして使うだけのDockerfileで、ホスト側（ubuntu）のディレクトリをコンテナにvolumeとしてマウントしようとしました。
```Dockerfile:Dockerfile
FROM node:19.8

WORKDIR /app
```
```yml:docker-compose.yml
version: '3'
services:
  node-dev:
    build:
      context: .
      dockerfile: Dockerfile
    tty: true
    volumes:
      - .:/app
```
ホスト側のカレントディレクトリをコンテナ側のappディレクトリとしてマウントは問題なくできましたが、コンテナ側で作成したファイルをホスト側で編集しようとすると、Permission Deniedで保存ができませんでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199870/a51f034a-2f98-3ce1-d86c-af2f3a69deac.png)

# 原因
コンテナ実行時のuserを指定していなかったため、ホスト側（UID=1000）とコンテナ側（UID=0）で別ユーザーとなってしまっていた。

ホスト（Ubuntu）側
```bash
$ id
uid=1000(hayato) gid=1000(hayato) groups=1000(hayato),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),116(netdev),1001(docker)
```
コンテナ側
```bash
root@e424e34aa8ce:/app# id
uid=0(root) gid=0(root) groups=0(root)
```

コンテナ側で作成したファイルのownerはUID=0で、
ホスト側だとrootユーザーになる。
```bash
$ ls -la
total 16
drwxr-xr-x 2 hayato hayato 4096 Apr  6 21:30 .
drwxr-xr-x 5 hayato hayato 4096 Apr  4 21:51 ..
-rw-r--r-- 1 root   root      0 Apr  6 21:30 CreatedInContainer.txt
-rw-r--r-- 1 hayato hayato   28 Apr  6 21:29 Dockerfile
-rw-r--r-- 1 hayato hayato  133 Apr  6 21:28 docker-compose.yml
```

一般ユーザーにrootが作ったファイルの更新権限はないのでPermission Deniedとなる。
# 対策
## コンテナにログインするときのデフォルトユーザーをホスト側と合わせる
- .envファイルを作ってホスト側のUID・GID・USERNAMEをdocker-compose.ymlに渡す
- docker-composeのuserオプションで↑を指定する
```bash
$ ls -la
total 20
drwxr-xr-x 2 hayato hayato 4096 Apr  6 21:44 .
drwxr-xr-x 5 hayato hayato 4096 Apr  4 21:51 ..
-rw-r--r-- 1 hayato hayato   34 Apr  6 21:43 .env
-rw-r--r-- 1 hayato hayato   28 Apr  6 21:29 Dockerfile
-rw-r--r-- 1 hayato hayato  133 Apr  6 21:28 docker-compose.yml
```
```.env
UID=1000
GID=1000
USERNAME=hayato
```
```yaml:docker-compose.yml
version: '3'
services:
  node-dev:
    user: $UID:$GID
    build:
      context: .
      args:
        UID: $UID
        GID: $GID
        USERNAME: $USERNAME
      dockerfile: Dockerfile
    tty: true
    volumes:
      - .:/app
```

## コンテナ側に同じUIDがいない場合はこれもやる
- DockerfileにARGコマンドでUID・GID・USERNAMEを渡す
- DockerfileでRUNコマンドを実施してgroupadd、useraddして同じUID/GIDのユーザーを作る
```Dockerfile:Dockerfile
# 同じUIDが存在しないイメージ
FROM ubuntu

WORKDIR /app

ARG UID
ARG GID
ARG USERNAME

ENV UID ${UID}
ENV GID ${GID}
ENV USERNAME ${USERNAME}

RUN groupadd -g ${GID} ${USERNAME}
RUN useradd -u ${UID} -g ${USERNAME} -m ${USERNAME}
```
# 結果
無事に、ユーザーを合わせられました。

ホスト（Ubuntu）側
```bash
$ id
uid=1000(hayato) gid=1000(hayato) groups=1000(hayato),4(adm),20(dialout),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),116(netdev),1001(docker)
```
コンテナ側
```bash
hayato@bd07b1769196:/app$ id
uid=1000(hayato) gid=1000(hayato) groups=1000(hayato)
```
コンテナで作ったファイルのowner
```bash
$ ls -la CreatedInContainer2.txt
-rw-r--r-- 1 hayato hayato 0 Apr  6 22:11 CreatedInContainer2.txt
```
編集もできました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199870/74fdefd9-9991-c9a3-f545-b9eb40e59e06.png)

# 参考
https://docs.docker.jp/compose/environment-variables.html
https://zenn.dev/takitakit/articles/a929a4f64aaae4