Файловая система, права, дескрипторы

↑ 1.2 ОС и Linux для разработчика · ← Предыдущая · → Следующая

Желательно~5 мин чтенияУровень: junior

Зачем это на собесе

Сервис пишет логи, временные файлы, читает конфиги и сертификаты, монтирует volumes в Docker. Ошибки «Permission denied» и «Too many open files» — классика продакшена.

Подтемы

  • Файловая система Linux, inode, ссылки
  • Права доступа, chmod/chown, umask, особые биты
  • Файловые дескрипторы, ulimit
  • Работа с файлами в .NET
  • Файлы в Docker

Объяснение

Файловая система Linux

  • Единое дерево от /. Важные каталоги: /etc (конфиги), /var/log (логи), /tmp (временные), /home, /app (обычно приложение в контейнере), /proc (виртуальная ФС с информацией о процессах).
  • «Всё есть файл»: устройства, сокеты, пайпы тоже представлены файлами.
  • inode хранит метаданные файла (права, владельца, размер, блоки). Имя — ссылка на inode.
  • Жёсткая ссылка — ещё одно имя того же inode. Символическая (ln -s) — файл-указатель на путь.

Права доступа

Пример вывода ls -l: -rwxr-x--- 1 app app 4096 appsettings.json

СимволыКомуЧто значит
-типобычный файл (d каталог, l символическая ссылка)
rwxвладелец (user)чтение, запись, выполнение
r-xгруппа (group)чтение и выполнение
---остальные (other)нет прав
  • r (4) чтение, w (2) запись, x (1) выполнение. Для каталога x — право войти.
  • chmod 640 file → rw-r-----. chown app:app file — сменить владельца.
  • umask — маска прав по умолчанию для новых файлов.
  • Особые биты: setuid, setgid, sticky (на /tmp — удалять можно только свои файлы).

Файловые дескрипторы

Процесс обращается к открытым файлам, сокетам и пайпам через целые числа — дескрипторы (0 stdin, 1 stdout, 2 stderr).

  • Лимит на процесс: ulimit -n (часто 1024 по умолчанию, в контейнерах выше).
  • Каждое TCP-соединение — дескриптор. Утечка соединений или файлов (не вызван Dispose) → Too many open files.
ls -l /proc/<pid>/fd | wc -l      # сколько дескрипторов открыто
lsof -p <pid>                     # какие именно

В .NET

// всегда освобождать файловые ресурсы
await using var stream = File.OpenRead(path);
using var reader = new StreamReader(stream);
 
// кроссплатформенные пути
var logPath = Path.Combine(AppContext.BaseDirectory, "logs", "app.log");
var tmp = Path.GetTempFileName();
 
// права (Unix)
File.SetUnixFileMode(path, UnixFileMode.UserRead | UnixFileMode.UserWrite);

В Docker

  • Контейнер лучше запускать не от root (USER app в Dockerfile). Тогда volume, смонтированный с хоста, должен быть доступен этому UID, иначе «Permission denied».
  • Логи пишите в stdout/stderr, а не в файлы внутри контейнера: их собирает Docker или агент.
  • Файловая система контейнера эфемерна: всё, что нужно сохранить, — в volume или объектное хранилище (MinIO).

Нюансы и подводные камни

  • Windows и Linux: регистр в именах файлов (Config.json ≠ config.json в Linux), разделители путей. Используйте Path.Combine.
  • Удалённый, но открытый процессом файл продолжает занимать место (частая загадка «диск заполнен, а файлов нет» — ротация логов без переоткрытия).
  • Запись больших временных файлов в слой контейнера раздувает его и замедляет. Используйте volume или tmpfs.
  • Права 777 «чтобы заработало» — дыра в безопасности.

Вопросы с ответами

Связанные темы