저번시간에 이어서 이번에도 Nginx의 Reverse Proxy를 이용한 분산처리입니다.
이번에는 경로(URL)로 구분하여 내부 서버들을 라우팅해보도록 하겠습니다.
먼저 구성한 아키텍처부터 소개하겠습니다.
과장해서 구성해보았는데,
총 4개의 서비스(app1, app2, app3, app4)가 있고 이 서비스들을 각각 독립적인 서버(nginx1, nginx2, apache1, apache2)에서 실행하고 있는 것입니다.
앞단의 웹 서버인 nginx_proxy는 80포트만 개방을 했구요, 기본인 80:80으로 설정하였습니다.
그리고 뒷 단의 서버들을 모두 경로로 구분하였습니다.
앞단의 nginx_proxy서버와 뒷 단의 4개의 서버를 모두 독립적인 컨테이너로 만들어 실행시켰습니다.
파일 구조는 다음과 같습니다.
root
│
└───docker-compose.yml
│
└───nginx
└───nginx.conf
version: "3"
services:
nginx_proxy: # 컨테이너 1
image: nginx:1.18.0
ports:
- "80:80"
restart: always
volumes:
- "./nginx/nginx.conf:/etc/nginx/nginx.conf" # 직접 설정한 nginx.conf로 기존 default nginx.conf를 대체
nginx1: # 컨테이너 2
depends_on:
- nginx_proxy
image: nginx:1.18.0
restart: always
nginx2: # 컨테이너 3
depends_on:
- nginx_proxy
image: nginx:1.18.0
restart: always
apache1: # 컨테이너 4
depends_on:
- nginx_proxy
image: httpd:2.4.46
restart: always
apache2: # 컨테이너 5
depends_on:
- nginx_proxy
image: httpd:2.4.46
restart: always
제가 추가적으로 설정한 부분은 다음과 같습니다.
.
.
.
upstream docker-nginx1 {
server nginx1:80;
}
upstream docker-nginx2 {
server nginx2:80;
}
upstream docker-apache1 {
server apache1:80;
}
upstream docker-apache2 {
server apache2:80;
}
server {
listen 80;
location /app1/ {
proxy_pass http://docker-nginx1;
proxy_redirect off;
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-Host $server_name;
}
location /app2/ {
proxy_pass http://docker-nginx2;
proxy_redirect off;
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-Host $server_name;
}
location /app3/ {
proxy_pass http://docker-apache1;
proxy_redirect off;
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-Host $server_name;
}
location /app4/ {
proxy_pass http://docker-apache2;
proxy_redirect off;
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-Host $server_name;
}
}
}
docker-compose up -d 명령어를 통해 컨테이너를 생성하고,
docker ps 명령어를 통해 현재 실행중인 컨테이너를 확인해보면 다음과 같습니다.
ubuntu@ip-172-31-38-68:~$ docker-compose up -d
Building with native build. Learn about native build in Compose here: https://docs.docker.com/go/compose-native-build/
Creating nginx_proxy_1 ... done
Creating nginx1_1 ... done
Creating apache2_1 ... done
Creating apache1_1 ... done
Creating nginx2_1 ... done
ubuntu@ip-172-31-38-68:~/04_NGINX_PROXY_PATH$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
25ee28f263ff nginx:1.18.0 "/docker-entrypoint.…" 6 seconds ago Up 2 seconds 80/tcp nginx2_1
e3b0a849eb67 httpd:2.4.46 "httpd-foreground" 6 seconds ago Up 3 seconds 80/tcp apache1_1
040166b29057 nginx:1.18.0 "/docker-entrypoint.…" 6 seconds ago Up 3 seconds 80/tcp nginx1_1
2b56cf6141e6 httpd:2.4.46 "httpd-foreground" 6 seconds ago Up 4 seconds 80/tcp apache2_1
814127e654ad nginx:1.18.0 "/docker-entrypoint.…" 7 seconds ago Up 3 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp nginx_proxy_1
❗️중요한 건, reverse proxy에서 경로로 서비스들을 구분하긴 했지만,
경로가 그대로 http request로 따라들어오는것이기 때문에
❗️각각의 내부서버에서도 이 경로로 맞춰주어야❗️ 서비스를 제공할 수 있습니다.
이는 즉 경로를 reverse proxy에서도 바꾸면 각 내부서버의 루트부터해서 파일 경로도 다 바뀌어야한다는 것입니다.
(이 다음번에는 nginx.conf에서 rewrite옵션을 이용하여 이를 보완할 예정입니다)
먼저, nginx와 apache의 default html경로는 다음과 같습니다.
- nginx: /usr/share/nginx/html
- apache: /usr/local/apache2/htdocs
귀찮겠지만, 내부 4개의 서버에서 각각의 루트 html경로에
해당하는 경로(ex, /app1)를 추가한 후 index.html을 만들어 이를 확인해보도록 하겠습니다.
index.html 간단하게 각 내부 서버를 확인할 수 있게만 적어놓았습니다.
❗️주의: 해당 컨테이너 접속 후, apt-get update와 vim을 설치한 후에 위의 작업을 수행해야 합니당❗️
- ip주소/app1 -> app1서버(docker-nginx1 컨테이너)에 접속
- ip주소/app2 -> app2서버(docker-nginx2 컨테이너)에 접속
- ip주소/app3 -> app3서버(docker-apache1 컨테이너)에 접속
- ip주소/app4 -> app4서버(docker-apache2 컨테이너)에 접속
이를 확인하면 다음과 같습니다.
reverse proxy에서 경로로 서비스들을 구분하긴 했지만,
경로가 그대로 http request로 따라들어오는것이기 때문에
각각의 내부서버에서도 이 경로로 맞춰주어야 서비스를 제공할 수 있었습니다.
이번에는 ❗️내부 서버에 요청하는 경로는 변경되도록❗️ 이를 수정하겠습니다.
예를 들어, 서버ip주소/app1/index.html 과 같이 proxy에 요청했을 때,
내부 서버에서는 서버ip주소/index.html 을 요청한 것처럼 경로를 변경해보도록 하겠습니다.
- proxy 요청: 서버ip주소/app1/index.html
- 내부 서버 요청: 서버ip주소/index.html
이렇게 경로 변경을 위해서는, nginx.conf 파일에서 rewrite옵션만 추가해주면 됩니다.
변경한 nginx.conf 파일은 다음과 같습니다.
.
.
.
upstream docker-nginx1 {
server nginx1:80;
}
upstream docker-nginx2 {
server nginx2:80;
}
upstream docker-apache1 {
server apache1:80;
}
upstream docker-apache2 {
server apache2:80;
}
server {
listen 80;
location /app1/ {
rewrite ^/app1(.*)$ $1 break;
proxy_pass http://docker-nginx1;
proxy_redirect off;
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-Host $server_name;
}
location /app2/ {
rewrite ^/app2(.*)$ $1 break;
proxy_pass http://docker-nginx2;
proxy_redirect off;
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-Host $server_name;
}
location /app3/ {
rewrite ^/app3(.*)$ $1 break;
proxy_pass http://docker-apache1;
proxy_redirect off;
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-Host $server_name;
}
location /app4/ {
rewrite ^/app4(.*)$ $1 break;
proxy_pass http://docker-apache2;
proxy_redirect off;
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-Host $server_name;
}
}
}
app1으로 들어오는 요청을 예로 들어 설명하면 다음과 같습니다.
location /app1/ {
rewrite ^/app1(.*)$ $1 break;
proxy_pass http://docker-nginx1;
proxy_redirect off;
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-Host $server_name;
}
ip주소/app1/index.html 로 요청이 들어온다고 가정해봅시다.
그러면 app1(.*)$ 에서 $1은 index.html이 됩니다.
(자세한 정규표현식에 대한 문법은 따로 설명하지 않겠습니다.)
그래서 아까는 app1의 루트 html 디렉토리 아래에 app1/index.html을 만들었지만,
이제는 내부 서버에서 들어오는 요청이 index.html 이 됩니다.
4개의 서비스 모두 작동 원리는 같습니다.
그러면 아까와 같이 url로 구분하여 요청을 보냈을 때,
nginx서버와 apache서버가 default로 제공하는 html파일이 뜰 것입니다.
이를 확인해보면 다음과 같습니다.