はじめに
bind mount の権限エラーを避けるために、users.csv(username,uid,gid)を唯一の管理元にし、コンテナを再起動した後に 1コマンドでCSVを読み込んでユーザーを作成する方法を検証しました。
なぜ手動反映なのか
Dockerfileでユーザーを作成する方法もありますが、以下の理由で「手動反映」を選択しています:
- CSVファイルを編集するだけでユーザー管理が完結
- イメージ再ビルド不要で運用が柔軟
- 既存のコンテナに対して後からユーザーを追加可能
前提条件
- Amazon Linux 2(他のOSでも読み替え可能)
準備
# ============================================================
# Docker(Engine)インストール(Amazon Linux 2)
# ============================================================
# Docker インストール
sudo yum -y update
sudo amazon-linux-extras install -y docker
# Dockerサービス enable + start(OS起動時に自動起動させる)
sudo systemctl enable docker
sudo systemctl start docker
# 動作確認
sudo docker version
sudo systemctl status docker --no-pager
# (任意)sudo無しで docker を叩けるようにする
# ※ 反映には一度ログアウト/ログインが必要
sudo usermod -aG docker "$USER"
# newgrp docker # その場で反映したい場合(シェルが切り替わる)
# ============================================================
# Docker Compose v2(CLIプラグイン)インストール
# ============================================================
# ※ 例として v2.24.5。必要に応じてバージョンを変える
COMPOSE_VERSION="v2.24.5"
sudo mkdir -p /usr/local/lib/docker/cli-plugins
sudo curl -SL "https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-linux-x86_64" \
-o /usr/local/lib/docker/cli-plugins/docker-compose
sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
# Compose 動作確認(v2 なら「docker compose」サブコマンド)
docker compose version
実装手順
1. 作業ディレクトリ作成
mkdir -p csv-user-demo/src
cd csv-user-demo
2. docker-compose.yml 作成
cat > docker-compose.yml << 'EOF'
services:
app:
image: ubuntu:22.04
command: ["bash", "-lc", "sleep infinity"]
volumes:
- ./src:/app/src
- ./users.csv:/app/users.csv:ro
EOF
3. users.csv 作成(最初は1人)
cat > users.csv << 'EOF'
# username,uid,gid
alice,1001,1001
EOF
4. コンテナ起動
docker compose up -d
5. ユーザー反映コマンド(これが核心)
再起動後は毎回このコマンドを実行します。
docker compose exec -u root app bash -lc '
awk -F, "!/^#/ && NF>=3 {print \$1,\$2,\$3}" /app/users.csv \
| while read -r u uid gid; do
getent group "$u" >/dev/null 2>&1 || groupadd -g "$gid" "$u";
id "$u" >/dev/null 2>&1 || useradd -m -u "$uid" -g "$gid" -s /bin/bash "$u";
done
'
このコマンドが何をしているか:
awk: コメント(#)と空行を除外し、3列以上の行だけを取り出すwhile: 行ごとに「グループ無ければ作成」→「ユーザー無ければ作成」- 既存ユーザーはスキップされるため、何度実行しても安全
6. アクセス確認(alice)
docker compose exec -u alice app bash -lc 'id; touch /app/src/alice_ok; ls -l /app/src/alice_ok'
7. ユーザー追加(bob)
# users.csv に追記
echo "bob,1002,1002" >> users.csv
# 再起動
docker compose restart
# 再度、ユーザー反映コマンドを実行
docker compose exec -u root app bash -lc '
awk -F, "!/^#/ && NF>=3 {print \$1,\$2,\$3}" /app/users.csv \
| while read -r u uid gid; do
getent group "$u" >/dev/null 2>&1 || groupadd -g "$gid" "$u";
id "$u" >/dev/null 2>&1 || useradd -m -u "$uid" -g "$gid" -s /bin/bash "$u";
done
'
8. アクセス確認(alice / bob)
# alice確認
docker compose exec -u alice app bash -lc 'id; touch /app/src/alice_ok2; ls -l /app/src/alice_ok2'
# bob確認
docker compose exec -u bob app bash -lc 'id; touch /app/src/bob_ok; ls -l /app/src/bob_ok'
9. 終了(掃除)
docker compose down
動作確認(実行ログ)
実際に上記の手順を実行した結果です。
[root@test ~]#
[root@test ~]# # ============================================================
[root@test ~]# # 1) 作業ディレクトリ作成
[root@test ~]# # ============================================================
[root@test ~]# mkdir -p ~/csv-user-demo/src
[root@test ~]# cd ~/csv-user-demo
[root@test csv-user-demo]#
[root@test csv-user-demo]#
[root@test csv-user-demo]# # ============================================================
[root@test csv-user-demo]# # 2) docker-compose.yml(最小・常駐)
[root@test csv-user-demo]# # - ubuntuを起動しっぱなしにして exec で作業する
[root@test csv-user-demo]# # - src と users.csv をマウント(users.csvはread-only)
[root@test csv-user-demo]# # ============================================================
[root@test csv-user-demo]# cat > docker-compose.yml << 'EOF'
> services:
> app:
> image: ubuntu:22.04
> command: ["bash", "-lc", "sleep infinity"]
> volumes:
> - ./src:/app/src
> - ./users.csv:/app/users.csv:ro
> EOF
[root@test csv-user-demo]#
[root@test csv-user-demo]#
[root@test csv-user-demo]# # ============================================================
[root@test csv-user-demo]# # 3) users.csv(最初は1人だけ:alice)
[root@test csv-user-demo]# # ============================================================
[root@test csv-user-demo]# cat > users.csv << 'EOF'
> # username,uid,gid
> alice,1001,1001
> EOF
[root@test csv-user-demo]#
[root@test csv-user-demo]#
[root@test csv-user-demo]# # ============================================================
[root@test csv-user-demo]# # 4) 作業ディレクトリ(ユーザー別)を用意して所有権を揃える(重要)
[root@test csv-user-demo]# # - これを最初にやることで「Permission denied」を潰す
[root@test csv-user-demo]# # ============================================================
[root@test csv-user-demo]# mkdir -p src/alice
[root@test csv-user-demo]# chown 1001:1001 src/alice
[root@test csv-user-demo]#
[root@test csv-user-demo]# # ============================================================
[root@test csv-user-demo]# # 5) 起動
[root@test csv-user-demo]# # ============================================================
[root@test csv-user-demo]# docker compose up -d
[+] Running 2/2
✔ app 1 layers [⣿] 0B/0B Pulled 5.0s
✔ 7e49dc6156b0 Pull complete 1.1s
[+] Running 1/2
⠇ Network csv-user-demo_default Created 0.8s
✔ Container csv-user-demo-app-1 Started 0.7s
[root@test csv-user-demo]#
[root@test csv-user-demo]# # ============================================================
[root@test csv-user-demo]# # 6) 【反映コマンド】CSVを読み込んでユーザー/グループを作成(毎回これ1発)
[root@test csv-user-demo]# # 何をしてる?
[root@test csv-user-demo]# # - rootでコンテナ内実行(useradd/groupaddに必要)
[root@test csv-user-demo]# # - users.csv から「username uid gid」だけ取り出して、存在しなければ作成
[root@test csv-user-demo]# # ============================================================
[root@test csv-user-demo]# docker compose exec -u root app bash -lc '
> awk -F, "!/^#/ && NF>=3 {print \$1,\$2,\$3}" /app/users.csv \
> | while read -r u uid gid; do
> getent group "$u" >/dev/null 2>&1 || groupadd -g "$gid" "$u";
> id "$u" >/dev/null 2>&1 || useradd -m -u "$uid" -g "$gid" -s /bin/bash "$u";
> done
> '
[root@test csv-user-demo]#
[root@test csv-user-demo]# # ============================================================
[root@test csv-user-demo]# # 7) アクセス確認(alice)
[root@test csv-user-demo]# # - uid/gidが 1001:1001
[root@test csv-user-demo]# # - src/alice に書き込める
[root@test csv-user-demo]# # ============================================================
[root@test csv-user-demo]# docker compose exec -u alice app bash -lc 'id; touch /app/src/alice/alice_ok; ls -l /app/src/alice/alice_ok'
uid=1001(alice) gid=1001(alice) groups=1001(alice)
-rw-r--r-- 1 alice alice 0 Jan 10 00:15 /app/src/alice/alice_ok
[root@test csv-user-demo]#
[root@test csv-user-demo]#
[root@test csv-user-demo]# # ============================================================
[root@test csv-user-demo]# # 追加検証:2人目追加 → 再起動 → 反映 → 両方確認
[root@test csv-user-demo]# # ============================================================
[root@test csv-user-demo]#
[root@test csv-user-demo]# # 8) users.csv に 2人目(bob)を追加
[root@test csv-user-demo]# echo "bob,1002,1002" >> users.csv
[root@test csv-user-demo]#
[root@test csv-user-demo]# # 9) bob用ディレクトリ作成 & 所有権設定(重要)
[root@test csv-user-demo]# mkdir -p src/bob
[root@test csv-user-demo]# chown 1002:1002 src/bob
[root@test csv-user-demo]#
[root@test csv-user-demo]# # 10) 再起動(要件どおり「再起動で読み込み」運用)
[root@test csv-user-demo]# docker compose restart
[+] Restarting 1/1
✔ Container csv-user-demo-app-1 Started 10.8s
[root@test csv-user-demo]#
[root@test csv-user-demo]# # 11) 再起動後に【反映コマンド】をもう一度(bob作成)
[root@test csv-user-demo]# docker compose exec -u root app bash -lc '
> awk -F, "!/^#/ && NF>=3 {print \$1,\$2,\$3}" /app/users.csv \
> | while read -r u uid gid; do
> getent group "$u" >/dev/null 2>&1 || groupadd -g "$gid" "$u";
> id "$u" >/dev/null 2>&1 || useradd -m -u "$uid" -g "$gid" -s /bin/bash "$u";
> done
> '
[root@test csv-user-demo]#
[root@test csv-user-demo]# # 12) アクセス確認(alice / bob)
[root@test csv-user-demo]# docker compose exec -u alice app bash -lc 'id; touch /app/src/alice/alice_ok2; ls -l /app/src/alice/alice_ok2'
uid=1001(alice) gid=1001(alice) groups=1001(alice)
-rw-r--r-- 1 alice alice 0 Jan 10 00:16 /app/src/alice/alice_ok2
[root@test csv-user-demo]#
[root@test csv-user-demo]# docker compose exec -u bob app bash -lc 'id; touch /app/src/bob/bob_ok; ls -l /app/src/bob/bob_ok'
uid=1002(bob) gid=1002(bob) groups=1002(bob)
-rw-r--r-- 1 bob bob 0 Jan 10 00:17 /app/src/bob/bob_ok
[root@test csv-user-demo]#
[root@test csv-user-demo]# # ============================================================
[root@test csv-user-demo]# # 13) 終了(掃除)
[root@test csv-user-demo]# # ============================================================
[root@test csv-user-demo]# docker compose down
[+] Running 2/1
✔ Container csv-user-demo-app-1 Removed 10.2s
✔ Network csv-user-demo_default Removed 0.1s
[root@test csv-user-demo]#
まとめ
users.csv(username,uid,gid)を唯一の管理元にし、コンテナを再起動した後に 1コマンドでCSVを読み込んでユーザーを作成する方法を検証できました。
この方法のメリット:
- CSVファイルの編集だけでユーザー管理が完結
- Dockerイメージの再ビルド不要
- 既存のコンテナに後からユーザーを追加可能
- bind mount の権限エラーを簡単に解決できる

