Nginx와 Flask로 Load Balancing 테스트하기
What is Load-Balancing?
로드 밸런싱이란 트래픽이 급증하거나 여러 사용자가 동시에 접속할 때, 여러 대의 서버에 클라이언트의 요청을 분산시켜 개별 서버의 과부하를 막고, 전체 서비스의 안정성과 성능을 높이는 기술이다.
즉,
1
2
• 하나의 서버에만 요청이 몰려 서버가 느려지거나 다운되는 걸 방지하고,
• 여러 대의 서버가 함께 트래픽을 처리하도록 해 확장성과 가용성을 높여준다.
Nginx
Nginx(엔진엑스)는 웹 서버와 리버스 프록시 서버 역할을 동시에 할 수 있는, 가볍고 빠른 오픈소스 소프트웨어이다.
쉽게 말해 Nginx는 웹 서버이자 로드밸런서로, 빠르고 가볍게 트래픽을 효율적으로 관리하는 소프트웨어이다.
What is Reverse-Proxy?
클라이언트(브라우저)의 요청을 받아 실제 서버(백엔드)에 대신 전달하고, 그 응답도 다시 클라이언트에 돌려주는 중간 서버이다.
Reverse-Proxy는 사용자가 직접 백엔드 서버에 접속하지 못하게 하고, Nginx(혹은 다른 프록시 서버)가 모든 요청을 받아서 내부 서버에 대신 전달한다.
1
• 사용자는 실제로는 프록시 서버만 보게 되고,프록시가 내부적으로 Flask, Spring, Node 등 여러 백엔드 서버들과 통신한다.
Purpose
1
2
3
4
5
• 보안 강화: 직접 백엔드가 노출되지 않으니 보안이 좋아짐
• 로드 밸런싱: 여러 서버에 트래픽 분산 가능
• SSL 종료: SSL 인증서 관리도 프록시에서
• 캐싱: 자주 쓰는 정적 자원(이미지 등)을 프록시가 직접 응답 가능
• 접근 제어: 특정 IP, 경로 등에 대한 제어 가능
Flow Chart
내가 테스트하고자 하는 구조는 다음과 같다. localhost:80 으로 접속하면 서버1,서버2,서버3으로 접속할 수 있게끔 하려고 한다.
Web Client는 Nginx서버 하나만을 바라보고 있다Nginx는Web Client와Flask서버 3개를 바라보고 있다.- 각 서버의
port는 순차적으로5001,5002,5003으로 설정했다.
Local에서 Flask 로 테스트 서버를 3개 띄어놓고 Nginx는 Docker로 띄울 것이다.
Directory Tree
1
2
3
4
.
├── Dockerfile
├── app.py
└── default.conf
Dockerfile:Nginx를 Docker 띄우기 위한 파일app.py: Flask serverdefault.conf:Nginx설정 파일Python Server 띄우기
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
from flask import Flask
import sys
app = Flask(__name__)
@app.route("/")
def hello():
return f"Hello from Flask server {sys.argv[2]} (port {sys.argv[1]})"
if __name__ == "__main__":
port = int(sys.argv[1]) if len(sys.argv) > 1 else 5000
server_id = sys.argv[2] if len(sys.argv) > 2 else "no-id"
app.config["SERVER_ID"] = server_id
app.run(port=port)
sys.argv[1] , sys.argv[2]- 매개변수는 서버가 정상적으로
Load Balancing되었음을 테스트하기 위해 넘겨주도록 만들었다.Command
각기 다른 터미널에서 다음의 명령어를 실행한다.
1 2 3
python3 app.py 5001 one python3 app.py 5002 two python3 app.py 5003 three
예시 실행 결과
Docker
Dockerfile
1
2
3
4
5
FROM nginx:alpine
COPY ./default.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
mount하는 파일명은 커스텀해도 문제 없다.
Nginx config file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
upstream flask_app {
server host.docker.internal:5001;
server host.docker.internal:5002;
server host.docker.internal:5003;
}
server {
listen 80;
location / {
proxy_pass http://flask_app;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
host.docker.internal:Nginx서버는 Docker위에서 실행되기 때문에 Docker 내부에서 바라보는 로컬 환경은host.docker.internal설정하면 된다.localhost로 설정하면 Docker 내부의 주소(즉,nginx 컨테이너 자신)로 mapping되어 엉뚱한 주소를 넘겨주게 된다.
Docker image build
Dockerfile, app.py, default.conf이 같이 존재하는 디렉토리 위에서 다음과 같은 커맨드를 실행시킨다. image를 빌드하는 것이다.
1
docker build -t nginx-test .
Dockerfile를 사용하여 nginx-test라는 이름의 이미지를 생성하는 것이다. 이미지 이름은 원하는대로 설정하면 된다. 위에 명령어 실행 후 이미지가 정상적으로 생성이 되었는지 확인해 보자.
1
docker images
- 실행 결과
1 2
REPOSITORY TAG IMAGE ID CREATED SIZE nginx-test latest 903baa599c27 46 hours ago 80.2MB
본인이 설정한 이름의 image명이 보인다면 성공이다.
Docker container 올리기
1
docker run -d --name nginx-test-container -p 80:80 nginx-test
-d: 백그라운드에서 실행하는 옵션--name: 컨테이너의 이름을 설정하는 옵션-p: 포트 설정하는 옵션nginx-test: 본인이 만들었던 이미지 이름
컨테이너가 올라갔는지 확인해보자
1
docker ps
1
2
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
dd1c05b9f220 nginx-test "/docker-entrypoint.…" 11 minutes ago Up 11 minutes 0.0.0.0:80->80/tcp, [::]:80->80/tcp nginx-test-containe
본인이 설정한 컨테이너 명이 보인다면 성공이다.
Result
이제 모든 설정을 마쳤으니 결과를 확인해보자.
localhost:80으로 접속해보고 게속 새로고침을 눌러보자. 5001,5002,5003 포트로 순차적으로 접속이 됌을 확인할 수 있다.


