В настоящее время я работаю над приложением на Python, которое разрабатываю на AWS EC2.
Это приложение предоставляет API, который имеет 2 конечные точки:
- test/ -> возвращает status_code=200 & сообщение “test”
- test1/ -> возвращает status_code=200 & сообщение “test1”
Как только оно будет работать и запущено на порту 8000, я написал Dockerfile и файлы docker-compose для развертывания его через docker.
Вот пример моего API docker сервиса:
version: '3.9'
services:
api:
container_name: api
build:
context: ..
dockerfile: ./deploy/Dockerfile.api
image: api-image-name
ports:
- "8000:8000"
На данный момент всё работает, я могу запрашивать мой API после развертывания, используя GET-запрос, например:
curl -X GET http://0.0.0.0:8000/test
Обратите внимание, что мой Dockerfile содержит следующие строки, но, вероятно, здесь есть ошибка:
ENV no_proxy="localhost,127.0.0.1"
ENV http_proxy="http://127.0.0.1:80"
Теперь я хочу поставить NGINX, чтобы он работал как балансировщик нагрузки, направляя 50% запросов на test1. Я хочу сделать AB тестирование
Для этого я разворачиваю docker-сервис под названием nginx, который зависит от api:
nginx:
image: nginx:alpine
container_name: ab_testing
volumes:
- ../nginx.conf:/etc/nginx/nginx.conf
environment:
- TZ=Europe/Paris
- ENV=dev
depends_on:
- api
На данный момент всё работает правильно, я могу развернуть оба сервиса, и API все еще работает на http://0.0.0.0:8000/test или http://0.0.0.0:8000/test1
Вы можете заметить, что я монтирую том под названием nginx.conf, который задает конфигурацию. Вот текущее содержимое этого файла:
events {
}
http {
server {
listen 81;
location / {
proxy_pass http://0.0.0.0:8000/test;
}
}
server {
listen 82;
location / {
proxy_pass http://0.0.0.0:8000/test1;
}
}
upstream app {
server 127.0.0.1:81 weight=50;
server 127.0.0.1:82 weight=50;
}
server {
listen 80;
location / {
proxy_pass http://app/;
}
}
}
В этой конфигурации nginx вы можете заметить, что я создаю 2 сервера на портах 81 и 82. Они будут использоваться для перенаправления запросов на мой API.
Затем я создаю балансировщик нагрузки, который использует мои 2 сервера и распределяет нагрузку. Балансировщик нагрузки обрабатывает нагрузку, разделяя её на 50%.
Наконец, я настраиваю свой основной сервер, слушающий на порту:80.
К сожалению, когда я запрашиваю http://0.0.0.0:80/, это не распределяет нагрузку, а выдает ошибку:
Не удалось подключиться к 127.0.0.1, порт 81, после 0 мс: Не удалось подключиться к серверу
Я хотел бы это исправить.
Более того, эта система работает на ECS, и я не знаю, как заставить её работать должным образом.
Можете помочь мне? 🙂
С уважением,
Ответ
Конечно! Давайте разберёмся с вашей задачей по установке NGINX в качестве балансировщика нагрузки для вашего Python приложения, развернутого с использованием Docker на EC2.
Ошибка в конфигурации NGINX
Во-первых, проблема, с которой вы сталкиваетесь (Failed to connect to 127.0.0.1 port 81
), возникает из-за того, что NGINX, работающий в контейнере, не может обращаться к localhost контейнера. В Docker, localhost внутри контейнера (127.0.0.1) ссылается на сам контейнер, а не на хост-машину или другие контейнеры. Вам нужно использовать api
(имя вашего сервиса), чтобы выполнить проксирование, поскольку это имя вашего контейнера API.
Исправление конфигурации NGINX
Вот исправленная версия вашего nginx.conf
:
events {
}
http {
upstream test1 {
server api:8000; # Ваш API-сервис
}
upstream test {
server api:8000; # Ваш API-сервис
}
server {
listen 80;
location / {
# Осуществляем случайный выбор между test и test1
set $backend "";
# Используем $request_uri для переключения между test и test1
if ($request_uri ~ "^/test") {
set $backend test;
}
if ($request_uri ~ "^/test1") {
set $backend test1;
}
# Если не определен $backend, проксируем на test с помощью случайного выбора
if ($backend = "") {
set $backend $request_uri;
# Если переменная пуста, выбираем наугад
if ($request_uri ~ "/") {
if ($random < 0.5) {
rewrite / /test break;
} else {
rewrite / /test1 break;
}
}
}
proxy_pass http://$backend;
}
}
}
Обратите внимание на следующее:
-
upstream: Мы определяем два
upstream
блока, один для каждого из ваших тестовых маршрутов. Они оба ссылаются на ваш API-сервис по адресуapi:8000
. -
Проверка URI: При получении запросов к порту 80, NGINX проверяет, запрашивается ли
/test
или/test1
, и отправляет запрос на соответствующий конец. - Балансировка нагрузки: Если запрос идет на корень сервера (
/
), NGINX будет случайным образом перенаправлять запросы на/test
или/test1
.
Проверьте ваши файлы Docker и Docker Compose
Убедитесь, что ваши файлы docker-compose.yml
и Dockerfile.api
правильно настроены и все контейнеры могут быть связаны. Вот пример вашего файла Docker Compose с соответствующими изменениями:
version: '3.9'
services:
api:
container_name: api
build:
context: ..
dockerfile: ./deploy/Dockerfile.api
image: api-image-name
expose:
- "8000" # Используем expose, а не ports, если не нужна прямой доступ извне
nginx:
image: nginx:alpine
container_name: ab_testing
volumes:
- ../nginx.conf:/etc/nginx/nginx.conf
depends_on:
- api
ports:
- "80:80" # Прокси на порт 80
Развертывание на ECS
Когда вы будете развертывать подобную архитектуру на AWS ECS, вам нужно будет настроить службы и задачи с учетом параметров, похожих на то, что мы сделали выше. Вы также можете использовать Application Load Balancer (ALB) для обеспечения балансировки нагрузки между различными задачами.
Примеры тестирования
Когда вы завершите настройки, вы сможете протестировать вашу API:
curl -X GET http://<EC2 IP>:80/
Это должно случайным образом выводить "test" или "test1".
Заключение
Эти изменения должны помочь вам справиться с проблемами связи между контейнерами, и настроить NGINX для корректной балансировки нагрузки между вашими тестовыми API. Если у вас возникнут дополнительные вопросы, не стесняйтесь их задавать!