8
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

VSCode Dev Container on WSL2のPermission問題メモ

Posted at

WSL2+VSCode Dev ContainerでFilesharingの警告 - Qiitaで書いた方法でDev Containerを動かすと、一部のイメージでパーミッションに問題が出た。

原因

Windowsファイルシステム上のフォルダをvolumesでバインドマウントしていたときは何の問題もなかった。おそらく、WindowsファイルシステムにLinuxのようなパーミッションがなかったため、よしなにしていてくれたのだと思う。
WSL2を使うとLinuxファイルシステム上のディレクトリをバインドマウントするようになるため、パーミッションが問題になる。

解決方法

  • コンテナ上にWSL2上のディストリビューションで使っているユーザーと同じUID/GIDのユーザーがあれば、保存されるファイルのパーミッションも同じになるのでそれを使う。
  • 該当ユーザーがなかったら、Dockerfileなどでユーザーを作る

まずはWSL2のディストリビューション(今回はUbuntu)でUID/GIDを確認しておく。

WSL上のUbuntuで実行
$ id -u
1000
$ id -g
1000

一般ユーザーが用意されていないイメージ(alpineなど)

もしイメージ内に一般ユーザーが用意されていない(rootしかない)場合は、Dockerfileやスクリプトでユーザーを追加することになる。VSCodeの Advanced Container Configuration のページにやり方が書いてあった。

ただし、上記リンクのサンプルはUIDが決め打ちで、汎用性が低い。Dev Containerとしてプロジェクトに設定をコミットし、チームメンバーと環境を共有することまで想定すると、用意するユーザー名/UID/GIDは各自のマシンに合わせた値になってほしい。

devcontainer.jsonにはinitializeCommandで「イメージがビルドされる前に実行するコマンド」を指定できる。ここでユーザーのUID/GIDを調べて環境変数ファイル.envに保存すれば、docker-compose.ymlを経由してDockerfileやコンテナに渡すことができる。

ソースコード例
init.sh
# .env ファイルを作る
echo "UID=$(id -u $USER)" > .env
echo "GID=$(id -g $USER)" >> .env
echo "USERNAME=$USER" >> .env
devcontainer.json(抜粋)
{
  "initializeCommand": "${localWorkspaceFolder}/.devcontainer/init.sh",
}
docker-compose.yml(抜粋)
version: '3'
  alpine:
    container_name: wsl_example_alpine
    build:
      context: ./docker/alpine/
      args: # ← Dockerfileに渡すにはARGを使う
        USERNAME: $USERNAME
        UID: $UID
        GID: $GID
    tty: true
    volumes:
      - ..:/workspace
FROM alpine:3

RUN apk add --no-cache sudo

ARG USERNAME
ARG UID
ARG GID

RUN apk add --no-cache shadow \
    && groupadd --gid $GID $USERNAME \
    && useradd --uid $UID --gid $GID -m $USERNAME \
    && echo "$USERNAME ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/$USERNAME \
    && chmod 0440 /etc/sudoers.d/$USERNAME \
    && apk del shadow

USER $USERNAME

一般ユーザーが用意されているイメージ(node-alpineなど)

今回使用したnode:14-alpineでは、デフォルトでnodeというnon-rootなユーザーが存在していた。そのユーザーを使う設定をする。

devcontainer.jsonremoteUserで、VSCodeからコンテナへの様々な操作(統合ターミナルを開く、デバッガーを動かす、など)で使用されるユーザーを指定できる。

devcontainer.json(抜粋)
{
  "remoteUser": "node",
}

しかし、使いたいユーザーが1000:1000でないときは困る。前項のようにユーザーを作る処理を入れると今度は逆に、イメージにすでに該当ユーザー名やUIDのユーザーが存在する場合に困る。

これについても先ほどのドキュメント Advanced Container Configuration に方法があった。
イメージ内にユーザーが存在していることはわかっている前提で、そのユーザーのUID/GIDを書き換えてしまおうというものだ。この場合、UID/GIDが元から一致していたとしてもエラーにならない。

ソースコード例
  • init.shjson:devcontainer.jsoninitializeCommandは同じなので省略
docker-compose.yml(抜粋)
version: '3'
  nodealpine:
    container_name: wsl_example_nodealpine
    build:
      context: ./docker/nodealpine/
      args:
        UID: $UID
        GID: $GID
    tty: true
    volumes:
      - ..:/workspace
FROM node:14-alpine

RUN apk add --no-cache sudo

ARG UID
ARG GID

RUN apk add --no-cache shadow \
    && groupmod --gid $GID node \
    && usermod --uid $UID --gid $GID node \
    && chown -R $UID:$GID /home/node \
    && apk del shadow

番外編:postgres公式イメージ

READMEの「Arbitrary --user Notes」セクションにあるが、docker run--userオプションで与えられたユーザーでpostgresを実行できるらしい。
ここに.envで設定した$UID:$GIDを与えてやれば、データディレクトリの中もユーザーのパーミッションにでき、開発環境では便利そうだ。docker-composeの場合はuserオプション。

ソースコード例
  • init.shjson:devcontainer.jsoninitializeCommandは同じなので省略
docker-compose.yml(抜粋)
version: '3'
services:
  postgres:
    container_name: wsl_example_postgres
    user: $UID:$GID # ←これ
    build: ./docker/postgres/
    ports:
      - "5432:5432"
    environment:
      POSTGRES_PASSWORD: tekitou-na-password
    volumes:
      - ./docker/postgres/data:/var/lib/postgresql/data

まとめ

  1. UIDやGIDを含んだ.envファイルを作るためのスクリプトを作成する
  2. devcontainer.jsoninitializeCommandで1のスクリプトを実行し.envファイルを作る
  3. その値をdocker-compose.ymlからARGを使ってDockerfileに渡す
  4. 使用するイメージに合わせてDockerfileや設定ファイルを編集し、ユーザーを操作
  • non-rootユーザーがないイメージの場合、ユーザーを追加し、Dockerfileの最後にUSERでデフォルトユーザーとして設定(alpineサンプル)
  • non-rootユーザーがあるイメージの場合、そのユーザーのUID/GIDのみを変更し、devcontainer.jsonremoteUserに指定(node-alpineサンプル)
  • その他、イメージに応じて設定可能(postgresサンプル)

ソースコード全文: noonworks/vscode-dev-container-example

参考

8
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?