Dockerコンテナ内で作成したVueプロジェクトをホスト側から編集する

意外と気をつけることが多かったし似たようなことしてる記事が全く見当たらなかったのでアップ。

# ゴール
Dockerコンテナ内で `$ vue create <project>` して作成したVueプロジェクトを、VSCode(ホスト側)から編集する。

# 対象者
自環境に `vue-cli` 入れて汚したくない人

# 環境
on Dockerなので稼働環境はあまり関係無いですが、一応記載。
- CentOS Linux 7
- VPS Server に `mosuke` ユーザーとしてログインしてる状態(VSCodeも同様にリモート接続)

# ゴール達成における課題
`alpine`ベースのDockerコンテナ内に `vuejs` インストールさせてvueプロジェクトを作成する。
作成したプロジェクトのルートフォルダはホスト(VPSサーバ)とvolumeマウントさせているが、
なんの対処もしていないと、**Dockerコンテナ内で作成したファイルは`root`権限となるため、ホスト側(一般ユーザー)から編集する際に権限周りでエラーが発生してしまう。**

# ファイル構成
以下のメンツを組めば、コンテナ内で作成したVueプロジェクトの編集が可能となる。

```bash
.
├── .env                # コンテナに渡す環境変数を定義しているファイル
├── Dockerfile
├── app                 # コンテナとマウントするフォルダ
├── docker-compose.yml
└── entrypoint.sh       # コンテナ起動時に「ユーザー/グループID周りを設定」するためのスクリプト
```

## Dockerfile
```bash
FROM alpine


RUN set -ex; \
    apk add --no-cache \
    # gosu の代わり。こっちのほうが alpine には良さそう(https://qiita.com/ao_log/items/1f4fcf09fb53e4fb7ebd)
    su-exec \
    bash \
    # useradd, usermod とかそういう系
    shadow \
    nodejs \
    npm

RUN npm install -g @vue/cli

# コンテナ内でユーザー/グループID周りをいじるスクリプト
COPY ./entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh

RUN useradd mosuke
WORKDIR /home/mosuke

ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
```

## docker-compose.yml
```yml
version: '3'

services:
  app:
    build: .
    ports:
      - 8080:8080
    env_file:
      # UID, GID って環境変数で ユーザー/グループID定義してます。
      - .env
    volumes:
      - ./app:/home/mosuke/app
    tty: true
    stdin_open: true
    command: /bin/sh
```

## entrypoint.sh
```bash
#!/bin/bash

USER_ID=${UID:-9001}
GROUP_ID=${GID:-9001}

echo "Starting with UID : $USER_ID, GID: $GROUP_ID"
usermod -u $USER_ID -o -d /home/mosuke -m mosuke
groupmod -g $GROUP_ID mosuke
export HOME=/home/mosuke

# usermod で $HOME 配下は user に owner が変更されるが、
# $HOME 自体は root 権限となってしまう。
# このままでは ~/.vuerc や ~/.npm が作成出来ずにエラーとなってしまうため、
# 下記で owner を user に変更しておく。
chown -R $USER_ID:$GROUP_ID $HOME

exec /sbin/su-exec mosuke "$@"
```

# 実行cmd
上記のメンツで下記を実行すると、問題無く**dockerコンテナ内でvueプロジェクトが作成され、一般ユーザーでリモート接続してるVSCodeから編集**が出来た。

```bash
[mosuke@vps-server:~/vue_test]
$ docker-compose up -d --build
$ docker-compose exec --user mosuke app bash

bash-5.1$ pwd
/usr/src/app
bash-5.1$ whoami
mosuke
bash-5.1$ vue create app-10
...
bash-5.1$ ls
app-10
```

# (Appendix)`npm run serve`してもエラーとなる問題への対処

## エラー概要
上記でvueプロジェクトを作成してwebサーバーを立ち上げても、`Invalid Host header` ってエラーメッセージが表示されてしまう。

```bash
...
bash-5.1$ cd app-10/
bash-5.1$ npm run serve
# http://<ip>:8080/ とかでアクセス出来るが、vueお馴染みのあの画面とは謁見出来ず、`Invalid Host header` ってエラー
```

## 対処方法
`<project root>/vue.config.js` に下記の変更を加えた。

```bash
  const { defineConfig } = require('@vue/cli-service')
  module.exports = defineConfig({
-   transpileDependencies: true
+   transpileDependencies: true,
+   devServer: {
+     allowedHosts: "all"
+   }
})
```

## `allowedHosts` オプションについての説明
この `Invalid Host header` の対応として、`disableHostCheck`ってのがよく見かけられるけど、
`Vue CLI v5`以降の場合は `allowedHosts` オプションの利用が必須となっている。
(今回のコンテナで利用しているCLIは `5.0.4`(2022.05.10現在))。
この辺りの変遷は下記にまとめておいた。
1. `npm run serve` で起動する開発環境用webサーバーには、`webpack-dev-server`が利用されている。
2. `Vue Cli v4` から `v5` にアップデートされた際に、内部で利用している `webpack-dev-server` も `v3` から `v4` にアップデートされている。(**破壊的アップデート**)
3. `webpack-dev-server` からは、`disableHostCheck`オプションが廃止され、`allowedHosts`オプションで web server にアクセス出来るホストのホワイトリストを指定することになっている。

# 参考
## 本題 の参考記事
- [dockerでvolumeをマウントしたときのファイルのowner問題](https://qiita.com/yohm/items/047b2e68d008ebb0f001)
  `entrypoint.sh`でユーザー/グループIDいじる方法の参考にした
  (色んな記事から参照されてる。頼りがいがある。)
- [【Vue CLI】Creating a Project](https://cli.vuejs.org/guide/creating-a-project.html#vue-create)
  実はホームディレクトリ`/home/mosuke`のownerを一般ユーザーにしてないとエラーになる。
  この記事で `vue create` 時に `~/.vuerc` が作成されること知った

## Appendix の参考記事
- [AWS Cloud9 で Vue 3 開発環境を整備する](https://poota.net/archives/317)
  なんかリテラシー高そうだし犬好きそう
- [【Vue CLI】Migrate from v4 : Dev Server](https://next.cli.vuejs.org/migrations/migrate-from-v4.html#vue-cli-service)
  Vue Cli v4 -> v5 の変更時に、破壊的変更があるので、それについての説明。英語。