Comments 40
Только один вопрос — почему без контейнеров?
Когда у вас VPS даже с парой-тройкой сервисов, изоляция решает. Сегодня у вас джанга с SQLite, завтра сервис с MariaDB, а послезавтра — условный телеграм бот на PHP с Postgre. И что, все это на хост будете ставить? А когда обновите версию джанги в одном из проектов, руками пересоздавать venv на хосте будете? Или будете писать чудесный деплой-скрипт, который ходит по файловой системе, обновляет репо, создает виртуальные окружения, пересоздает все что можно? *картинка с троллейбусом*
Тот же certbot — в чем смысл ставить лишний софт на хост, который вам нужен раз в 3 месяца, запускается в одну строчку из контейнера и абсолютно независим от всего остального, что вы там наставили?
Ну да, я делаю всё именно так. В качестве "скрипта" использую Ansible-плейбук, в нём уже есть модуль для управления venv и прочие радости жизни. В чём проблема?
git pull && docker-compose up -d --build
достигают той же цели, но куда меньшими затратами и намного проще и надежнее. Ну и docker/docker-compose нынче куда более распространены, нежели Ansible.А затраты на написание докерфайлов и организацию взаимодействия между контейнерами вы решили тактично умолчать :) Серьёзно, я как-то пробовал автоматизировать развёртывание одного реального PHP-проекта (хоть я и питонист, ну да ладно) — Ansible-плейбук написался без проблем, а довести докер-контейнеры до пригодного для продашкена состояния у меня так и не получилось
environment: {DB_HOST: db}
и depends_on: db
для зависимых контейнеров? Вот и все «взаимодействие». Ну да, простите великодушно, «тактично умолчал», потому что это три строчки, которые после первых пары раз пишутся на автомате и уже не думаешь даже. Секундное дело. Но зато после этого вы получаете docker-compose файл, который кто угодно может на своей машине запустить, имея из зависимостей лишь, собственно, докер и компоуз. Один клик — и весь сервис поднят. Да, естественно, если вам захочется больше плюшек, health-чеков, определенного порядка запуска контейнеров, дальше будет сложнее, но для описанного в посте уровня простенького проекта ничего этого не нужно.Не говоря уж про то, что написание Dockerfile это как минимум «правило хорошего тона», по которому можно понять, какие у вашего проекта зависимости. Если мы говорим про питон, то каждая вторая нетривильная зависимость из requirements.txt будет требовать какой-нибудь нативной библиотеки, про которую, естественно, автор не упомянет в ридми. А если вы напишете в докерфайле «pip install -r requirements.txt», то это банальный тест — если оно билдится, значит побилдится и у всех остальных. Не раз и не два такое было, что на хосте вроде работает, а пишешь в докерфайл — опа, оказывается, еще десяток нативных зависимостей надо доставлять (которые на хосте были поставлены неизвестно когда и уж все забыли про них).
Кэп подсказывает, что Ansible playbook у вас написался без проблем, потому что у вас есть опыт в написании плэйбуков. А у меня наоборот — я подобные простые 2-3 сервиса быстро и без проблем оберну в Dockerfile+docker-compose, а вот если надо будет Ansible юзать, то я уйду гуглить на неопределенное время.
Я говорю о проекте уровня описанного в статье
Окей, начнём с банального — раздача статических файлов. В какой контейнер их класть? В каком контейнере запустить "manage.py collectstatic" и как при этом не наплодить стопицот лишних докер-слоёв?
Чуть менее банальное — почти любой Django-проект однажды дорастёт до необходимости использовать Celery, где и как запускать его воркеры? Если придётся запускать несколько контейнеров — как им всем обеспечить беспроблемный доступ на запись в media-каталог — возможно, делать chmod 777 и umask 000, или есть что-то более умное?
Ну ладно, если запустить два контейнера из одного образа, у них будут одинаковые uid и проблем с доступом возможно не будет. А что если однажды придётся собрать ещё один образ (из моей личной практики — syncthing, например) и дать ему доступ на запись к тому же общему media-каталогу — как это организовать, чтобы было достаточно безопасно и чтобы при этом не было проблем?
про которую, естественно, автор не упомянет в ридми.
Ага, а контейнеры тут при чём? Пусть автор просто прогонит установку на чистой системе (да хоть в том же контейнере, лол) и в ридми допишет зависимости, да и всё. В плейбуке, кстати, зависимости тоже прописаны.
написание Dockerfile это как минимум «правило хорошего тона», по которому можно понять, какие у вашего проекта зависимости.
То же самое можно сделать через CI/CD — в скрипт установки для условного Travis CI или Github Actions тоже придётся прописать все зависимости.
потому что у вас есть опыт в написании плэйбуков.
Так изначально его не было, у меня знания тоже не из воздуха появились.
а вот если надо будет Ansible юзать, то я уйду гуглить на неопределенное время.
А я до сих пор продолжаю гуглить инфу про докер, но так и не могу собрать что-то пригодное для продакшена ¯\_(ツ)_/¯
Окей, начнём с банального — раздача статических файлов. В какой контейнер их класть? В каком контейнере запустить «manage.py collectstatic» и как при этом не наплодить стопицот лишних докер-слоёв?
Вы намекаете, что мне тоже статью стоит написать? Честно говоря, я понимаю, потому что если гуглить «django docker», то во всех этих хипстерских seo-friendly бложиках ни один чел не идет дальше хелловорлда и тему статических файлов не затрагивает. Я сам довольно долго гуглил и спрашивал в чатиках насчет «правильного» способа.
На сегодняшний день я использую один из следующих вариантов:
— Shared volume лишь между контейнерами (но не с хостом, см. SO). Тогда collectstatic пишется в контейнере с джангой и nginx контейнер просто видит папку со статиками
— Если же volume не вариант (например, в Docker Swarm), то можно сделать multistage билд для nginx контейнера. Ну т.е. что-то подобное:
FROM python:3.9 as builder
RUN pip install Django
COPY . /app
WORKDIR /app
RUN manage.py collectstatic --noinput
FROM nginx
COPY config/nginx.conf /etc/nginx/config
COPY --from=builder /static /static
— Ну и «плохой» вариант, но в общем-то вполне рабочий для небольших проектиков без сотен реквестов в секунду — используйте
manage.py runserver
. Тогда вам даже второй контейнер с nginx не нужен. Есть несколько библиотек типа whitenoise, которые в теории несколько улучшают ситуацию с «runserver не для продакшна».Чуть менее банальное — почти любой Django-проект однажды дорастёт до необходимости использовать Celery, где и как запускать его воркеры?
Не могу ответить, поскольку ни в одном из проектов Celery не использовал, не было нужды. Но есть подозрение, что это может выглядеть как один контейнер, в котором воркеры сами скейлятся как надо (собственно, как uwsgi для того же джанго сам делает).
Ага, а контейнеры тут при чём? Пусть автор просто прогонит установку на чистой системе (да хоть в том же контейнере, лол) и в ридми допишет зависимости, да и всё. В плейбуке, кстати, зависимости тоже прописаны.
Понятно, что хороший автор опишет все, но Dockerfile (как и ваш плейбук, видимо) — это не просто текст, это реальные инструкции, которые должны работать, чтобы проект поднялся. И само средство вынуждает автора описать environment. Лишь один коммент — в каком проценте open source проектов вы видели плейбук (или, например, Vagrantfile?) в репозитории? Сравните с процентом репозиториев, имеющих Dockerfile.
Так изначально его не было, у меня знания тоже не из воздуха появились.
А я до сих пор продолжаю гуглить инфу про докер, но так и не могу собрать что-то пригодное для продакшена ¯\_(ツ)_/¯
Ну видите, мы в одинаковой ситуации, только с разными тулами :) Только в самом начале я пошел гуглить про довер и теперь знаю о докере и применяю его, а вы пошли гуглить про Ansible и применяете его. 1-1 :)
В определённый исторический период сложился такой консенсус, что лучше иметь универсальный механизм изоляции для всего, то есть контейнеризацию через Docker. Предполагалось, что девопс-инженерам не придётся изучать тонкости языков и платформ, они просто будут воспроизводить одинаковую среду на серверах и машинах разработчиков, и все будут счастливы.
Но сегодня стало очевидно, что этот универсальный механизм себя не оправдал, не реализовал обещаний. Для разработчиков затраты на поддержание той же системы контейнеров, что и на серверах, оказались неподъёмны: сложно, требует изучения и поддержки, нужно мощное железо, намного усложнились задачи, которые раньше были простыми, типа отладки. Девопсы так и не смогли обойтись без изучения целевых платформ, просто вместо прямого подхода (прочитать немного про CPython, pip и virtualenv) им приходится начинать погружение в чудесный мир Python с отлаживания необъяснимых багов (почему cryptography не собирается в контейнере с Alpine).
В результате поддержка простых и понятных деплой-скриптов на Fabric оказывается намного практичней, чем монструозная система изоляции всего и вся. Особенно если основа продакшена − Python, который уже имел специфические, весьма развитые и взрослые средства изоляции с отличным уровнем переносимости, когда докера ещё не было в проекте.
Прошу прощения — Вы правда считаете что установкой certbot начинается и заканчивается настройка ssl в nginx ?
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}server {
if ($host = example.com) {
return 301 https://$host$request_uri;
} # managed by Certbot
listen 80;
server_name example.com;
return 404; # managed by Certbot
Сейчас в systemd есть пользовательские юниты. Использовать их очень просто: нужно вместо
/etc/systemd/system
использовать ~/.config/systemd/user
, а к вызову systemctl
добавлять ключ --user
.Когда пользовательских юнитов не было, принято было подменять пользователя для запуска gunicorn/uwsgi/et c. вот таким образом:
[Service]
User=www
Group=www
Пускать Django из-под рута − это варварство.
- «Что угодно aio*» − это плюс один фреймворк, то есть для собственного резюме − здорово, а для предприятия − не то чтобы.
- Лично я, скажу честно, не горю желанием перейти на асинхронное программирование, и не встречал ещё таких питонистов, которые бы мечтали об этом. Я видел, как самые простые вещи с async/await превращаются в инкубатор неотлаживаемых багов, и не хочу быть крайним в разгребании этих авгиевых конюшень.
- Что плохого в API через вебсокеты?
Я видел, как самые простые вещи с async/await превращаются в инкубатор неотлаживаемых багов
Вот все вокруг почему-то об этом говорят, а я сколько ни программировал асинхронщину — почему-то ни разу не сталкивался с какими-то специфическими проблемами
не горю желанием перейти на асинхронное программирование, и не встречал ещё таких питонистов, которые бы мечтали об этом
Так я первый буду, который мечтает. Хотя, верится с трудом.
я конечно не спец в 3й джанге (давно сменил стек), но небольшой эксперимент все же проводил. и производительность джанго под asgi у меня проседала на 30% относительно wsgi варианта. а где обещанные бонусы ?))
А вы уверены, что ваши тесты верны и в них использовалась реальная работа веб приложения, а не простое измерение пропускной способности? Бонусы от асинхронности вы получите в любом современном веб приложении, за исключением простых лендингов и отдельных статичных страницах или даже динамичных но простых. Нужно понимать где применять асинхронность, а где нет. Я уже не буду говорить что при длительном синхронном запросе вы его можете просто потерять и при высокой нагрузке на сервер он у вас просто упадет при синхронных запросах. Плюс к этому, чем вам не бонус еще и сокеты. При этом ASGI обратно совместим с синхронными запросами.
А зачем ставить лишнюю сущность, если systemd и так есть по умолчанию почти в любом линуксе? А ещё supervisord всё равно будет запускаться через тот же самый systemd)
супервизор решает одну оч простую задачу — рестарт приложения при краше. именно про это и был мой вопрос тк конфиг автора для системд этого не делает. и если приложение ляжет — само не поднимется
Символическую ссылку не нужно удалять при изменениях оригинального файла. Текстовым редактором можно открывать сразу ссылку, редактироваться будет оригинальный файл. Ведь на то она и ссылка.
https://ru.m.wikipedia.org/wiki/%D0%A1%D0%B8%D0%BC%D0%B2%D0%BE%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F_%D1%81%D1%81%D1%8B%D0%BB%D0%BA%D0%B0
[Service]
User=root
Ну или я что-то не понял.
Я написал данную статью для новичков, для тех, кто впервые сталкивается с подобной задачей, когда они осилили написать django-проект и умеют только в runserver. Данная статья описывают процесс от самого начала и до конца, чтобы сайт можно было вывести в прод. Также, я собирал информацию со множества источников, форумов и даже личных переписок со специалистами в соц. сетях.
apt get update
apt get-install nginx
Исправьте, пожалуйста:
apt-get update или apt update
apt-get install nginx или apt install nginx
Запуск Django сайта на nginx + Gunicorn + SSL