おは代々木ダイアリー

いろいろ試したメモを書きます

nodeなどのコンテナイメージでdevcontainerを使うとuidが変わらなくて困る問題への対処

Visual Studio CodeのRemote Containers機能(Dev Containers)には、VSCodeの実行ユーザーのUIDでコンテナ内のユーザーのUIDを更新してくれる便利な機能があります。

例えば、UIDが1002のユーザーでVSCodeを立ち上げていて、コンテナ内で作成したユーザー devuser を使用したとき、コンテナ内の devuser のUIDは1002に上書きされるといった挙動になります。これは、手元のディレクトリをコンテナ内にマウントしていて、それをVSCodeでいじる場合に、UIDが異なってしまうという問題を回避することができるのでとても便利。

使い方

使い方は簡単で、devcontainer.json に以下のように remoteUserupdateRemoteUserUID を指定するだけ。remoteUser にコンテナイメージ内に存在するユーザー名を指定することでコンテナを開いたときに使用されるユーザーを指定でき、かつ updateRemoteUserUID を有効にすると 指定したユーザーのUIDが現在のログインユーザーのUIDになってくれます

{
  "remoteUser": "devuser",
  "updateRemoteUserUID": true,
}

説明のためupdateRemoteUserUID も念のため指定していますが、このオプションはデフォルトで有効になっているので明示的な設定は省略可能です。

DevContainersに使用するコンテナイメージには、以下のようなDockerfileを考えてみます。

FROM ubuntu:20.04

ARG USERNAME=devuser
ARG USER_UID=1234
ARG USER_GID=$USER_UID

# Create the user
RUN groupadd --gid $USER_GID $USERNAME \
    && useradd --uid $USER_UID --gid $USER_GID -m -s /bin/bash $USERNAME 

Dockerfile では UID 1234 で devuser というユーザーが作成されていますが、Dev Containersで開いてみると、見事IDなどが変わっていることがわかります。

devuser@cbb03f77d869:/workspaces/devcontainer_example$ id
uid=1000(devuser) gid=1000(devuser) groups=1000(devuser)

devuser@cbb03f77d869:/workspaces/devcontainer_example$ ls /home/devuser -la
total 28
drwxr-xr-x 1 devuser devuser 4096 Jan 12 04:17 .
drwxr-xr-x 1 root    root    4096 Jan 12 04:17 ..
-rw-r--r-- 1 devuser devuser  220 Feb 25  2020 .bash_logout
-rw-r--r-- 1 devuser devuser 3771 Feb 25  2020 .bashrc
-rw-r--r-- 1 devuser devuser  807 Feb 25  2020 .profile
drwxr-xr-x 6 devuser devuser 4096 Jan 12 04:17 .vscode-server

ちゃんと HOME のパーミッションも変わっていてとてもGOODですね。

問題点

「指定したユーザーのUIDが現在のログインユーザーのUIDになってくれます」と書きましたが、これが効かないケースもありました。

というのも、変更先のUID(つまりログインユーザーのUID)がコンテナイメージ内ですでに使われていた場合、このオプションは有効に働かず、コンテナイメージ内のUIDがそのまま使われてしまいます。

例えば、「node」のコンテナイメージはデフォルトで node というユーザーがUIDが1000で作成されているので、VSCodeを起動しているユーザーのUIDが1000だった時にバッティングしてしまい、devuser は作成した時点の UID 1234 の状態のままでDev Containersが立ち上がってしまいました。

解決方法

ここで、この問題を解決できる方法を考えてみました。

1. そのユーザーをそのまま開発にも使う

すでに使いたいUIDが使用されてしまっているのであれば、remoteUser にそのUIDが割り当てられているユーザーを指定してしまうのも手です。

ただ、これだとユーザー名が自由に選べませんし、意図した通りにセットアップされているかはDockerfileを読み解いていくしかありません。そもそも、Dev Contaienrsで乗り込むコンテナにユーザーがあったとしても、そのユーザーをそのまま活用するケースに出会ったことがありませんし、こういうユーザーは封印前提で次に示す解決策2を取るのがいいのかなと思います。

2. そのユーザーのUIDを変えてしまう

1でも書きましたが、これはこのユーザーがDockerfile作者の想定した通りに使えなくなる可能性があるので、「封印前提」で考えるべきでしょう。

RUN groupmod -g 12345 node && \
    usermod -u 12345 -g 12345 node

上記のように、node ユーザーがすでに使いたいUIDを使っていて邪魔なのであれば、そのユーザーのUIDを使わない値にしてしまえという発想です。(消しちゃってもいいのかもしれない)

このようにすることで、uid 1000がすでに使われていたとしてもログインユーザーのUIDに合わせてDevContainers内のUIDを上書きすることができるようになりました。

終わりに

以上、ゴリゴリっと書いてしまいましたが、DevContainersのremoteUser の問題と対処でした。

(読み返すとUID, VSCode, DevContainersと表現が揺れまくっているのが気になる…)