Какие существуют подходы при организации загружаемых пользователями файлов с использованием Docker, но без сторонних сервисов (таких как AWS Bucket)?

Рейтинг: 0Ответов: 0Опубликовано: 04.06.2023

Подождите писать в комментариях ссылки на bind mounting и volume - эта задача гораздо более многомерная, чем выбор способа хранения данных в Docker. Тут необходимо и на уровне организации Docker-образов поразмыслить, да и при покупке VPS задуматься о дополнительных опциях.

Заранее прошу прощение за длинный вопрос. Длинный он потому, что мне нужно было показать ход моих мыслей, а также что я знаю и чего ещё не знаю.

Что мы имеем изначально? Обычно в проекте серверного приложения у нас есть какая-то папка для хранения загружаемых пользователями файлов. На примере Laravel, это storage/app/public:

введите сюда описание изображения

Иногда полученные от пользователей файлы сохраняют и в public (причём не только в случае PHP и Laravel), но я не уверен, что это хорошая идея - смешивать в одну кучу файлы, подготовленные разработчиками (стили, логотипы, иконки и так далее) и загруженные пользователями.

В отличие от таких языков, как PHP, в моём случае (TypeScript + Node.js) выходной код полностью отделён от исходного, и та структура файлов, что на картинке ниже, на 100% сгенерирована (даже package.json - это не тот, что в корне проекта; из этого сгенерированного package.json полностью исключены зависимости для разработки и те, что подшиты Webpack-ом к скриптам для фронтенда):

введите сюда описание изображения

На данный момент у меня 2 volum-а: один для базы данных и другой - для файлов проекта, который создаётся автоматически командой COPY . /var/www/example.com, прописанной в FrontServer.Dockerfile. Я не говорю, что именно так и делаю, но в теории до тех пор, пока не принималось никаких файлов от пользователей, во время деплоя можно было безопасно удалить volume проекта (потому что данные базы данных хранятся на другом volum-е) и добавленные ранее файлы на картинке выше, и только потом загрузить на сервер файлы собранного проекта заново, установить свежие зависимости и запустить приложение. В реальности я это делаю с помощью rsync, причём с опцией —delete, удаляющей файлы, которых нет в источники. Теперь же планируется начать принимать файлы от пользователей, а потому необходимо внести изменения в процесс деплоя.

Как я уже сказал выше, не думаю, что это хорошая идея - хранить их public. При таком раскладе, как сейчас, добавленные пользователями файлы будут просто потеряны, и хотя их можно хранить в одной из подпапок по отношению к public, исключённой из отслеживания rsync, ошибка может привести к потере данных. Какие ещё варианты мне известны?

Вариант 1: Хранить загружаемые пользователями файлы в отдельной папке + на отдельном volume

Аналогично Laravel, помимо public добавить папку storage для файлов, принимаемых от пользователей.

введите сюда описание изображения

Данный вариант не предполагает добавления новых образов и контейнеров, а вот насчёт Volum-ов надо подумать. Начнём с того, сама папка 06-ProductionBuilding уже соответствует Volume-у, а тут в ней ещё и storage появится, которой должен соответствовать отдельному Volum-у. На данный момент точно не знаю, но не уверен, что так можно.

Затем, возможно для данного случая и bind mounting ничем не хуже. Однако какой бы вариант не был выбран, при деплое новой версии проекта нужно быть осторожным, чтобы не тронуть папку storage, а такой расклад - хорошая почва для гипотетического инцидента потери данных пользователей.

Вариант 2: Создать отдельный образ

Возможно, работу с изображениями и другими мультимедийными файлами следует вообще переложить на отдельные образ и контейнер, а не только volume. Сейчас у меня 2 образа: node.js (front_server) и PostgreSQL:

version: "3.5"

services:

  front_server:

    container_name: Example-Production-FrontServer
    build:
      context: .
      dockerfile: "FrontServer.Dockerfile"
    ports: [ "8080:8080" ]

    environment:
      - DATABASE_HOST=Database

    depends_on: [ Database ]

  Database:

    image: postgres
    container_name: Example-Production-Database
    ports: [ "${DATABASE_PORT}:${DATABASE_PORT}" ]

    environment:
      - POSTGRES_PASSWORD=${DATABASE_PASSWORD}

    volumes:
      - DatabaseData:/data/example.com

volumes:
  DatabaseData: {}

но говорят, что для отдачи файлов лучше организовать отдельных сервер, например Nginx. Так как в случае с Docker это не означает покупку ещё одного сервера, то почему бы и нет: отдельный образ, отдельный контейнер, отдельный volume, лёгкость в резервировании данных. Я даже думаю, что при таком раскладе можно у поставщика VPS и отдельный диск арендовать для хранения на нём только файлов, загруженных пользователями.

Требования конкретно для моей задачи

Если кратко, то начальные требования весьма скромные, на уровне сайта с фотографиями для относительно узкого круга людей, однако ввиду того, что будет вестись блог с загрузкой новых фотографий, нужно чтобы при необходимости было легко расширить начальный объём доступной памяти.

  • Требования к размеру хранилища файлов: Для начала хватит 2-3Гб, но надо, чтобы этот объём было легко увеличить при необходимости
  • Отказоусточивость: На данный момент создавать несколько реплик, чтобы при отказе одного сервера файлы были доступны, не требуется ввиду малого масштаба проекта. Сейчас достаточно иметь возможность извлечь файлы в процессе процедуры восстановления данных без сверхусилий, если что-то случится.
  • Планируется ли использовать хранилище другими сайтами / приложениями: нет
  • Быстродействие: точного приемлемого интервала времени загрузки изображений не назову, но достаточно среднестатистической скорости загрузки картиной - пускай и не мгновенно, но и не как во времена модема. Адаптация сайта для зарубежных посетителей не планируется. Большая часть файлов - изображения; хранить огромные файлы по несколько гигабайт не планируется.
  • Пропуская способность: особых требований нет; расчётный траффик очень далёк до уровня социальных сетей.

Итог

Наверное, есть и друге варианты, но мне известны только эти два. Напомню, что в данном вопросе мы не рассматриваем варианты сторонних сервисов, аналогичных AWS Bucket - сейчас задача понять, чего можно достичь с помощью одного VPS и Docker-а.

Ответы

Ответов пока нет.