🐳

権限問題を解消した .devcontainer のテンプレート

に公開
3

概要

VSCodeのdevcontainerは開発環境をそろえる点からすごく便利だが、UIDなどをホストと揃えないと権限の問題が生じていろいろ面倒くさい。そこで権限問題を解消済みの.devcontainerディレクトリのテンプレートをここにメモしておく。好きに使ってほしい。

内容

.devcontainer/compose.yaml
services:
  devel:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        UID: ${HOST_UID:-20000}
        GID: ${HOST_GID:-20000}
    volumes:
      - ..:/workspace
    working_dir: /workspace
    tty: true
.devcontainer/Dockerfile
FROM ubuntu:latest

RUN apt update && apt-get --no-install-recommends install -y \
    build-essential \
    git wget curl ca-certificates \
    python3


ARG UID=20000
ARG GID=20000
RUN set -eux; \
    # 既存ユーザー・グループを安全に削除
    if getent passwd "${UID}" >/dev/null; then \
        olduser=$(getent passwd "${UID}" | cut -d: -f1); \
        echo "UID ${UID} already used by ${olduser}, deleting..."; \
        userdel -r -f "${olduser}" || true; \
    fi; \
    if getent group "${GID}" >/dev/null; then \
        oldgroup=$(getent group "${GID}" | cut -d: -f1); \
        echo "GID ${GID} already used by ${oldgroup}, deleting..."; \
        groupdel "${oldgroup}" || true; \
    fi; \
    # 新規グループ・ユーザーを作成
    groupadd -g "${GID}" dev; \
    useradd -m -u "${UID}" -g "${GID}" -s /bin/bash dev; \
    # 念のためホーム権限を確認
    chown -R "${UID}:${GID}" /home/dev

USER dev
WORKDIR /workspace
.devcontainer/init_env.sh
#!/bin/bash
set -eu
SCRIPT_FILE="$(cd "$(dirname "$0")"; pwd)/$(basename "$0")"

cd $(dirname $SCRIPT_FILE)

rm -f .env
touch .env
echo "HOST_UID=$(id -u)" >> .env
echo "HOST_GID=$(id -g)" >> .env
.devcontainer/devcontainer.json
{
    "name": "<YOUR_PROJECT_NAME>",
    "dockerComposeFile": "compose.yaml",
    "service": "devel",
    "workspaceFolder": "/workspace",
    "customizations": {
        "vscode": {
            "extensions": [
                "ms-python.python",
                "charliermarsh.ruff"
            ],
            "settings": {
                "python.defaultInterpreterPath": "/workspace/.venv/bin/python",
                "[python]": {
                    "editor.codeActionsOnSave": {
                        "source.fixAll.ruff": "explicit",
                        "source.organizeImports.ruff": "explicit"
                    },
                    "editor.defaultFormatter": "charliermarsh.ruff",
                    "editor.formatOnSave": true,
                    "editor.formatOnType": true
                }
            }
        }
    },
    "initializeCommand": ".devcontainer/init_env.sh",
}

Discussion

たつおたつお

お世話になっております。

Linux(WSL2も含む)はバインドマウントしてる領域は、
ホストとコンテナで所有権やパーミッションが一致するため、当記事のような配慮必要ですよね

さもなくば、rootでログインする前提のコンテナの中で、各種Webフレームワークが用意してる
コマンドなどで、ひな形ソースコード作成した場合、root所有となるファイルやフォルダが作成される。
それが混じった状況で、ホスト側でブランチ切り替えやプルなど
実ファイルの追加、更新、削除を伴うgit操作が途中で、権限エラーとなり不整合となってしまう
そのリカバリー作業がメンドイ。。。
という事態に陥る。これは、とてもメンドイですね

Devcontainersは元のDockerfileの構成に対して、後から、追加対応という形で
当記事のようにホスト側のUID,GIDでのユーザ追加。および、それをコンテナ側でパスワードなしでsudersに登録し
該当のUID,GIDでログイン時でもsudoコマンドを使えるようにカスタマイズできたりします。

それらを自動的に行ってくれるような公式のDevcontainer用のfeatureもあったりします

問題は、Devcontainersを利用しない、普通のdocker compose環境なんですよね
チーム全体が、WSL2ユーザであれば、該当のUID,GIDでログインする環境に寄せられるんですけど

Macユーザが多くチーム内にいるときに問題になります
MacはLinuxではなく、直でDockerを動作できませんので、VMでDockerを動作させて
Mac本体のapfsの領域をバインドマウントするときに、Docker for Macは、virtiofsなどの共有ファイルの仕組みでバインドマウントします。

このときに、コンテナ側がroot所有のファイルや、フォルダでも、
ホスト側で見たときに、作業ユーザが所有者であるように見える 挙動になるです
これが、バグなのか、そういう仕様なのか不明ですが

この仕組みにより、コンテナの中でroot所有のファイル、フォルダが混ざってる状況でも
ホスト側でgitの操作時には、それらは、作業ユーザの所有であるため
権限エラーが発生しないのです

Macユーザは、上記の挙動があるために結果的エラーにならないことをいいことに、
root直でログインするままであるDockerfileをチーム内に連携してくるんです。( 理由は、単に、楽したいから )

その時に、Linux、WSL2ユーザとして、自分のローカル環境だけ、UID,GIDを一致させる状態にするのは、メンドイです。
また、この話をMacユーザにしても、全く話が通じないです

なぜなら、そういう細かい環境のことを考えるのがメンドイからMac使ってますってノリの人間が多いからです

このときに、Linux, WSL2ユーザとして、どうするかの裏技の話ですが

POSIX ACLというものを使って、あるフォルダ配下、末端までについては、
この作業ユーザは、フルで権限を与えます
ということができます。

root所有のファイルや、フォルダも問答無料で、更新、削除できます
これで一気に解決できます。

その裏技については、

https://zenn.dev/tazzae999jp/articles/2c235cc6f0e84d

に書いてます

この記事のシェルスクリプトをコピペしてホームディレクトリに置いて
それを、該当のフォルダのパスを指定して一回実行する

ということを最初にやっとくだけでOKです
( ただし、chmodコマンドを使った場合は再実行したほうがよい。それも記事に書いてます )

綺麗なやり方ではないですが、このような裏技もあります

1
h1de_n_nh1de_n_n

コメントありがとうございます。

POSIX ACL というより細かい単位でファイルのアクセス制御をできる仕組みがあるんですね。。知りませんでした。正攻法ではうまくいかないがsudo権限がある場合(macユーザーが作ったdockerfileを動かす場合など?)に試してみようと思いました!

情報共有ありがとうございました!

1
たつおたつお

>macユーザーが作ったdockerfileを動かす場合など?

動かすというより、macユーザーが作ったdockerfileでも、
Linux、WSL2ユーザが権限問題で困らないようにする対処です。

★追記★
★「動かす」=動作させる の意味でしたか・・・macユーザーが作ったdockerfileで動作させる★

自分のローカル環境だけ、ホスト側の作業ユーザと同じUID,GIDでコンテナにログインできるようにしたり、
環境系の話に疎いなどで、話が通じないMacユーザと、細かいやり取りして、
Gitの資産を「ホスト側の作業ユーザと同じUID,GIDでコンテナにログインできるよう」するのが
しんどい場合が多いです。

Macユーザが作ったrootにログインする前提のDockerfileがGitにあるとき、
そのGitで連携されてきたそのDockerfileそのままで、
Linux、WSL2ユーザが権限問題で困らないようにする対処です。

Macユーザが絡むときって、たいていは、Webアプリの開発です
そうすると、開発中のプログラムの実行は、コンテナ内部で動いてるapcheや、nginxの
実行ユーザの www-data などで、動作してたりするです。

単に、phpや、pythonや、rubyのソースコードに対するReadのパーミッションが
www-dataにあれば事足りる場合が多いです。

ホスト側のUbuntuの作業ユーザ、UID,GID=1000:1000に対して、
ローカルのリポジトリのプロジェクトフォルダ配下に末端までフルの権限をPOSIX ACLで与えて
root所有のファイルや、フォルダであろうが問答無用で、更新や削除ができる状況にして
権限問題を回避しても、
開発中のWebアプリの動作が変わることがない。影響しないわけです。

そこが、担保できてるようなケースで、
この【裏技】は、安心して使えます

1