【AWS EC2】CSVのUID/GIDを使って「再起動後に手動反映」する

はじめに

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 の権限エラーを簡単に解決できる
Last modified: 2026-01-11

Author