ダーク/ライト切り替え

Docker × logrotate × bind mount で発生する uid/gid 地獄とその解決法

投稿日 2025-12-25T11:03:03.512717+09:00

Docker × logrotate × bind mount で発生する uid/gid 地獄とその解決法

目次

目次を読み込み中...

― コンテナ内ログローテーション時の権限トラブル完全整理 ―

はじめに

Docker コンテナでアプリを運用していると、ログはホストに bind mount したいケースがほとんどだと思います。
その際に避けて通れないのが uid / gid とファイル権限の問題です。

今回は以下の構成で発生したトラブルを題材に、

  • logrotate は正常に動いているのに
  • ローテート後にアプリが起動不能になる
  • create 0644 root root が原因に見えるが、それだけではない

という問題を 原因分析 → 正しい設計 → 再発防止策 の順で整理します。

構成概要

前提構成

  • ホスト Linux(debian系 Ubuntu等)
  • Docker + docker-compose
  • Django + Gunicorn
  • ログは ホストの ./log を /app/log に bind mount
  • コンテナ内アプリは 非 root ユーザーで実行
  • logrotate は ホスト側で実行

発生した現象

logrotate 設定

ローテート後の状態

問題点

新しく生成された access.log / error.log

  • owner: root
  • permission: 0644

コンテナ内のアプリユーザーが 書き込み不可

結果として:

  • Gunicorn / Django 起動時にログファイルを open できず
  • コンテナが起動しない

表面的な原因

一見すると原因はこれです。

確かに、

  • root:root
  • 書き込みは owner のみ

なので、非 root ユーザーで動くアプリは書けない。

しかし本質的な原因は別にある

問題の本質

ホストとコンテナで uid / gid の整合性が取れていない

これに尽きます。

uid / gid は固定値か?

結論

  • 数値(uid/gid)は固定値
  • 意図的な操作をしない限り勝手に変わらない

ただし…

「いつのまにかズレる」ケース

以下はよくある罠です。

  1. Dockerfile で useradd / groupadd をミスる

⬇ エラー

原因:

  • groupadd と useradd を 1行で連結
  • -m は useradd のオプション

正しくは:

  1. ホスト側の log ディレクトリが root 所有のまま

bind mount は 権限を変換しない。

ホスト root:root (0644)

コンテナでも root:root (0644)

Docker が気を利かせてくれることはない。

「create 0755 にすればいい?」問題

結論

推奨しない

これをすると:

  • root 所有のまま
  • world-writable に近い状態
  • セキュリティ的に雑
  • 問題の根本(uid/gid不一致)は未解決

正しい解決アプローチ(推奨)

方針

ホストとコンテナで uid / gid を揃える

手順① ホスト側の uid/gid を確認

手順② Dockerfile で同じ uid/gid を作る

手順③ docker-compose.yml で build args を指定

手順④ ホスト側 log ディレクトリの所有者を変更

手順⑤ logrotate の create を修正

なぜこれで解決するのか

  • logrotate は ホスト側で root として動作
  • しかし 所有者を appuser に指定
  • bind mount 経由でコンテナ内 appuser(uid=1001) がそのまま書き込み可能

つまり:

Host uid=1001
↓ bind mount
Container uid=1001

が成立する。

よくある勘違いまとめ

勘違い実際
`Docker` が `uid` を変換してくれる❌ しない
`create` のパーミッションだけで解決❌ 一時しのぎ
`uid/gid` は勝手に変わる❌ 意図しない限り固定
`root` で作れば安全❌ むしろ事故る

再発防止チェックリスト

  • bind mount するディレクトリの uid/gid を把握している
  • Dockerfile の useradd / groupadd を分けて書いている
  • logrotate の create で owner/group を明示している
  • world-writable(777/775)で逃げていない

おわりに

Docker + logrotate + bind mount は
「動いているように見えて、ある日突然死ぬ」構成になりがちです。

今回のポイントはただ一つ。

uid/gid を数値で揃えろ。権限は後から考えろ。

この原則を守れば、同様のトラブルにはほぼ遭遇しません。

将来また詰まった時は、まずここを疑う。
それだけでデバッグ時間は大幅に減ります。


準備中

このサイトをシェアする

Docker × logrotate × bind mount で発生する uid/gid 地獄とその解決法