[Docker][Web] Nginx의 Reverse Proxy를 이용한 분산처리(2)

이수진·2022년 2월 12일
0

저번시간에 이어서 이번에도 Nginx의 Reverse Proxy를 이용한 분산처리입니다.
이번에는 경로(URL)로 구분하여 내부 서버들을 라우팅해보도록 하겠습니다.

먼저 구성한 아키텍처부터 소개하겠습니다.

1. 아키텍처

과장해서 구성해보았는데,
총 4개의 서비스(app1, app2, app3, app4)가 있고 이 서비스들을 각각 독립적인 서버(nginx1, nginx2, apache1, apache2)에서 실행하고 있는 것입니다.

앞단의 웹 서버인 nginx_proxy는 80포트만 개방을 했구요, 기본인 80:80으로 설정하였습니다.

그리고 뒷 단의 서버들을 모두 경로로 구분하였습니다.

앞단의 nginx_proxy서버와 뒷 단의 4개의 서버를 모두 독립적인 컨테이너로 만들어 실행시켰습니다.

2. 파일 구조

파일 구조는 다음과 같습니다.

  • 파일구조
root
│
└───docker-compose.yml
│
└───nginx
    └───nginx.conf

3. docker-compose.yml , nginx.conf 설정

  • docker-compose.yml
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
  • 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/ {
            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;
        }
    }

}

4. 도커 컨테이너 생성 및 실행

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을 설치한 후에 위의 작업을 수행해야 합니당❗️

5. 각 내부 서버 접속 확인

  • ip주소/app1 -> app1서버(docker-nginx1 컨테이너)에 접속
  • ip주소/app2 -> app2서버(docker-nginx2 컨테이너)에 접속
  • ip주소/app3 -> app3서버(docker-apache1 컨테이너)에 접속
  • ip주소/app4 -> app4서버(docker-apache2 컨테이너)에 접속

이를 확인하면 다음과 같습니다.

  • /app1 -> app1 서버에 연결(docker-nginx1 컨테이너)
  • /app2 -> app2 서버에 연결(docker-nginx2 컨테이너)
  • /app3 -> app3 서버에 연결(docker-apache1 컨테이너)
  • /app4 -> app4 서버에 연결(docker-apache2 컨테이너)

6. rewrite옵션으로 보완해서 -> URL별로 라우팅하기

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 파일은 다음과 같습니다.

  • nginx/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파일이 뜰 것입니다.

이를 확인해보면 다음과 같습니다.

  • /app1 -> app1 서버에 연결(docker-nginx1 컨테이너)

  • /app2 -> app2 서버에 연결(docker-nginx2 컨테이너)

  • /app3 -> app3 서버에 연결(docker-apache1 컨테이너)

  • /app4 -> app4 서버에 연결(docker-apache2 컨테이너)

profile
꾸준히, 열심히, 그리고 잘하자

0개의 댓글