コンテナーに非 root ユーザーを追加する
多くの Docker images では root がデフォルトのユーザーとして使用されますが、代わりに非 root ユーザーを使用したい場合もあります。そうする場合、知っておくべきローカルファイルシステム(バインド)マウントの癖(特性)がいくつかあります。具体的には以下のとおりです。
-
Docker Desktop for Mac: コンテナー内では、マウントされたファイル/フォルダーは、指定したコンテナーユーザーが所有しているかのように動作します。ローカルでは、すべてのファイルシステム操作で、代わりにローカルユーザーの権限が使用されます。
-
Docker Desktop for Windows: コンテナー内では、マウントされたファイル/フォルダーは
rootが所有しているように見えますが、指定したユーザーは引き続きそれらの読み取り/書き込みを行うことができ、すべてのファイルが実行可能になります。ローカルでは、すべてのファイルシステム操作で代わりにローカルユーザーの権限が使用されます。これは、Windows形式のファイル権限をLinuxに直接マッピングする方法が根本的に存在しないためです。 -
Linux上の Docker CE/EE: コンテナー内では、マウントされたファイル/フォルダーは、所有者のユーザーID (UID) やグループID (GID) を含め、コンテナー外とまったく同じ権限を持ちます。このため、コンテナーユーザーは同じ UID を持つか、同じ GID を持つグループに所属している必要があります。ユーザーやグループの実際の名前は関係ありません。マシーン上の最初のユーザーには通常 UID 1000 が割り当てられるため、この問題を回避するために、ほとんどのコンテナーではこれをユーザーの ID として使用します。
VS Code のユーザーを指定する
使用しているイメージまたは Dockerfile にすでにオプションの非 root ユーザーが用意されているにもかかわらず(node イメージなど)、デフォルトが root のままである場合は、devcontainer.json で remoteUser プロパティを指定することで、Visual Studio Code(サーバー)およびサブプロセス(端末、タスク、デバッグ)にそのユーザーを使用させることができます。
"remoteUser": "user-name-goes-here"
Linux上で、devcontainer.json 内で Dockerfile、イメージ、または Docker Compose を参照している場合、この環境に存在するバインドマウントの権限問題を回避するために、コンテナーユーザーの UID/GID がローカルユーザーと一致するように自動的に更新されます("updateRemoteUserUID": false に設定している場合を除きます)。
この設定は VS Code と関連するサブプロセスにのみ影響するため、設定を有効にするには VS Code を再起動(またはウィンドウをリロード)する必要があります。ただし、UID/GID の更新はコンテナーの作成時にのみ適用されるため、変更するには再ビルドが必要です。
デフォルトのコンテナーユーザーを指定する
場合によっては、VS Code だけでなく、コンテナー内のすべてのプロセスを(起動要件などの理由で)別のユーザーとして実行する必要が生じることがあります。これを行う方法は、Docker Compose を使用しているかどうかに応じて若干異なります。
-
Dockerfile とイメージ: 同じファイルに
containerUserプロパティを追加します。"containerUser": "user-name-goes-here"Linux では、
remoteUserと同様に、この環境に存在するバインドマウントの権限問題を回避するために、コンテナーユーザーの UID/GID がローカルユーザーと一致するように自動的に更新されます("updateRemoteUserUID": falseに設定している場合を除きます)。 -
Docker Compose: 該当するサービスに対して、
docker-compose.ymlを次のように更新(または拡張)します。user: user-name-or-UID-goes-here
非 root ユーザーを作成する
Dev Containers 拡張機能に含まれるイメージや Dockerfile には、UID/GID が 1000 の非 root ユーザー(通常は vscode または node という名前)が含まれていますが、多くのベースイメージや Dockerfile には含まれていません。幸いなことに、コンテナーに非 root ユーザーを追加する Dockerfile を更新または作成することができます。
本番環境であっても、アプリケーションを非 root ユーザーとして実行することが推奨されます(セキュリティが向上するため)。そのため、既存の Dockerfile を再利用する場合でも、これは良い方法です。たとえば、Debian/Ubuntu コンテナー向けのこのスニペットは、user-name-goes-here という名前のユーザーを作成し、sudo を使用する権限を与え、デフォルトとして設定します。
ARG USERNAME=user-name-goes-here
ARG USER_UID=1000
ARG USER_GID=$USER_UID
# Create the user
RUN groupadd --gid $USER_GID $USERNAME \
&& useradd --uid $USER_UID --gid $USER_GID -m $USERNAME \
#
# [Optional] Add sudo support. Omit if you don't need to install software after connecting.
&& apt-get update \
&& apt-get install -y sudo \
&& echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \
&& chmod 0440 /etc/sudoers.d/$USERNAME
# ********************************************************
# * Anything else you want to do like clean up goes here *
# ********************************************************
# [Optional] Set the default user. Omit if you want to keep the default as root.
USER $USERNAME
ヒント: ビルド時に GID または UID がすでに存在するというエラーが発生した場合、選択したイメージにはすでに直接利用できる非 root ユーザーが含まれている可能性が高いです。
どちらの場合でも、すでにコンテナーをビルドして接続している場合は、コマンドパレット(F1)から Dev Containers: Rebuild Container を実行して変更を反映させます。それ以外の場合は、Dev Containers: Open Folder in Container... を実行してコンテナーに接続します。
既存のコンテナーユーザーの UID/GID を変更する
Dockerfile またはイメージを使用している場合、Linux上では remoteUser プロパティによって UID/GID が適切に自動更新されますが、代わりに Dockerfile 内でこのスニペットを使用してユーザーの UID/GID を手動で変更することもできます。必要に応じて ARG の値を更新してください。
ARG USERNAME=user-name-goes-here
ARG USER_UID=1000
ARG USER_GID=$USER_UID
RUN groupmod --gid $USER_GID $USERNAME \
&& usermod --uid $USER_UID --gid $USER_GID $USERNAME \
&& chown -R $USER_UID:$USER_GID /home/$USERNAME
Alpine Linux では、最初に shadow パッケージをインストールする必要があることに注意してください。
RUN apk add --no-cache shadow