@Wylaroren

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

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

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

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

CpeKL.png

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

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

lb9tb.png

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

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

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

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

xDbXN.png

Данный вариант не предполагает добавления новых образов и контейнеров, а вот насчёт 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-а.

P. S.

В течение месяца данный вопрос не получил ни одного ответа на русскоязычном Stack Overflow, что надеюсь на Вас, дорогие пользователи Хабра.
  • Вопрос задан
  • 64 просмотра
Пригласить эксперта
Ответы на вопрос 2
SignFinder
@SignFinder
Wintel\Unix Engineer\DevOps
S3 бакет\бакеты. Например на базе Minio
Ответ написан
saboteur_kiev
@saboteur_kiev
software engineer
Странные рассуждения.

например Nginx. Так как в случае с Docker это не означает покупку ещё одного сервера,

И без докера, это не обязательно означает покупку еще одного сервера.

Вы юзаете докер не очень обособленно. Видимо просто чтобы запускать каждое приложение в контейнере без установки его на целевом VPS. Но если вы оперируете именно понятием VPS, то можно и без докера.

На сегодня Docker чаще это просто промежуточный кирпичик по пути в оркестрацию контейнерами кубером или опенщифтом. А в этом плане, гораздо лучше все-таки отталкиваьтся от бест практик, а именно S3 бакет.
Можно рамдиск для аплоад папки из которой отдельный процесс будет перекладывать в s3 с какими-то промежуточными действиями (регистрация в базе, проверка антивирусом, проверка формата файлов, чтобы не битый был)

Собственно именно использование сервисов (s3/nexus/artifactory), а не дисков/волумом и позволяет не ковыряться в настройках виртуалки/инфраструктуры, потому что вы для всего пользуетесь именно сервисами, а не кусками инфраструктуры и железа.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы