DDoS разрушает мой сайт, который использует Gunicorn в контейнере docker, nginx выбрасывает ошибки отказа в подключении, но Gunicorn все еще работает?
Я запускаю Django сайт с Gunicorn внутри контейнера docker. Запросы направляются в этот контейнер с помощью nginx, который работает без докеризации как обычный сервис Ubuntu.
Мой сайт иногда подвергается сильным DDoS-атакам, которые невозможно предотвратить. Я принял ряд мер, включая Cloudflare, ограничения скорости nginx, ограничения скорости gunicorn, а также fail2ban. В конечном счете, эти атаки удается преодолеть из-за огромного количества IP-адресов, которые, похоже, находятся в ботнете.
Сейчас у меня нет ничего сверхкритичного, и позже я рассмотрю балансировку нагрузки и другие варианты. Однако моя главная проблема заключается в том, что DDoS-атаки не просто выводят из строя мой сайт - сайт не восстанавливает доступность после завершения атаки.
Каким-то образом огромное количество запросов что-то ломает, и я не могу понять, что именно. Единственный способ вернуть сайт обратно - перезапустить контейнер. Служба Nginx работает нормально и каждый раз показывает в журнале ошибок следующее:
2022/08/02 18:03:07 [error] 2115246#2115246: *72 connect() failed (111: Connection refused) while connecting to upstream, client: 172.104.109.161, server: examplesite.com, request: "GET / HTTP/2.0", upstream: "http://127.0.0.1:8000/", host: "examplesite.com"
После этого я подумал, что DDoS каким-то образом разрушает docker-контейнер с gunicorn и приложением django. Поэтому я реализовал проверку здоровья в Dockerfile:
HEALTHCHECK --interval=60s --timeout=5s --start-period=5s --retries=3 \
CMD curl -I --fail http://localhost:8000/ || exit 1
Я использовал Docker Autoheal для мониторинга здоровья контейнера, однако контейнер никогда не становится "нездоровым". Ручное выполнение команды curl http://localhost:8000/
возвращает домашнюю страницу сайта, поэтому контейнер никогда не становится нездоровым.
Несмотря на это, контейнер, похоже, больше не принимает запросы от nginx, поскольку это единственный вывод от gunicorn (указывающий на то, что он получает healthcheck curl, но ничего больше):
172.17.0.1 - - [02/Aug/2022:15:34:49 +0000] "GET / HTTP/1.0" 403 135 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3599.0 Safari/537.36"
[2022-08-02 15:34:49 +0000] [1344] [INFO] Autorestarting worker after current request.
[2022-08-02 15:34:49 +0000] [1344] [INFO] Worker exiting (pid: 1344)
172.17.0.1 - - [02/Aug/2022:15:34:49 +0000] "GET / HTTP/1.0" 403 135 "-" "Mozilla/5.0 (iPad; CPU OS 8_1_1 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B435 Safari/600.1.4"
[2022-08-02 15:34:50 +0000] [1447] [INFO] Booting worker with pid: 1447
[2022-08-02 15:34:50 +0000] [1448] [INFO] Booting worker with pid: 1448
[2022-08-02 15:34:51 +0000] [1449] [INFO] Booting worker with pid: 1449
127.0.0.1 - - [02/Aug/2022:15:35:31 +0000] "HEAD / HTTP/1.1" 200 87301 "-" "curl/7.74.0"
127.0.0.1 - - [02/Aug/2022:15:36:31 +0000] "HEAD / HTTP/1.1" 200 87301 "-" "curl/7.74.0"
127.0.0.1 - - [02/Aug/2022:15:37:31 +0000] "HEAD / HTTP/1.1" 200 87301 "-" "curl/7.74.0"
127.0.0.1 - - [02/Aug/2022:15:51:33 +0000] "HEAD / HTTP/1.1" 200 87301 "-" "curl/7.74.0"
[2022-08-02 15:51:54 +0000] [1] [CRITICAL] WORKER TIMEOUT (pid:1449)
[2022-08-02 15:51:54 +0000] [1449] [INFO] Worker exiting (pid: 1449)
127.0.0.1 - - [02/Aug/2022:15:52:33 +0000] "HEAD / HTTP/1.1" 200 87301 "-" "curl/7.74.0"
127.0.0.1 - - [02/Aug/2022:15:53:34 +0000] "HEAD / HTTP/1.1" 200 87301 "-" "curl/7.74.0"
Как вы видите, после 15:34:49 gunicorn больше не получает никаких неurl-запросов. Nginx продолжает показывать ошибку Upstream connection refused. Что я могу с этим сделать? Ручной перезапуск докер-контейнера просто невозможен - проверка работоспособности должна сработать, но по какой-то причине сайт продолжает работать внутри, но докер-контейнер не получает внешних запросов от nginx.
Я пробовал варьировать количество рабочих gunicorn и количество запросов на одного рабочего, но ничего не помогает. Сайт работает совершенно нормально, я просто полностью застрял на где ddos что-то ломает. По моим наблюдениям, nginx работает нормально, и проблема где-то в докеризованном экземпляре gunicorn, но я не знаю, как, учитывая, что он прекрасно отвечает на внутренние команды curl - если бы он был сломан, проверка здоровья не смогла бы получить доступ к сайту!