NGINX 를 3Scale APITools용 지능형 프록시 및 웹 서버로 사용

NGINX 는 웹 서버뿐만 아니라 리버스 프록시 서버로도 흔히 사용됩니다. 그 외에도 다른 용도로도 사용됩니다.

그러나 동시에 두 가지 역할을 동시에 수행하는 사례는 일반적으로 흔하지 않습니다.

각 APItools 모니터는 자체 JSON API를 가진 웹 인터페이스를 통해 제어할 수 있는 지능형 프록시입니다.
이 모든 것은 Lua를 포함한 NGINX 빌드로 관리됩니다.
해당 예제에서 API와 정적 콘텐츠를 위해 루트 위치를 사용합니다. 웹 애플리케이션 (포트 7071)과 프록시 (포트 10002)에 대해 서로 다른 포트를 사용하여 이 역할 분담을 구현합니다.

목차

1. NGINX 웹 애플리케이션
2. NGINX 프록시
3. 결론

1. NGINX 웹 애플리케이션 (7071 포트)

웹 앱은 일반적인 HTTP 앱입니다. 브라우저 창에서 상호 작용을 처리하기 위해 AngularJS를 많이 사용하므로 애플리케이션은 주로 HTML의 초기 덤프로 구성되며, 이로 인해 일부 CSS와 JavaScript가 로드됩니다.
나머지는 JSON API와의 통신입니다.

(일부 내용이 삭제된) 앱 구성은 다음과 같습니다.

server {
    listen 7071;
 
    location /app {
        try_files $uri /index.html;
    }
 
    location / {
        try_files /../public$uri $uri @app;
        header_filter_by_lua_file 'lua/apps/csrf.lua';
    }
 
    location @app {
        content_by_lua_file "lua/apps/api.lua";
    }
}

첫 번째 위치 블록은 초기 HTML 전송을 처리합니다. 두 번째 블록은 정적 파일(예: CSS 및 JavaScript)을 제공합니다.
또한 Lapis와 유사한 구성 파일을 사용하여 CSRF 보호를 보장합니다.
마지막 위치 블록은 API 요청을 처리하는 곳입니다. 대부분의 무거운 작업은 Lua 파일인 api.lua에서 수행됩니다.

api.lua의 대부분의 작업은 각 요청 URL과 매개변수를 구문 분석하고 적절한 컨트롤러를 호출하기 위해 라우터를 구성하는 것으로 이루어져 있습니다. 다음은 api.lua의 간소화된 예시입니다.

local router        = require 'router'
local error_handler = require 'error_handler'
 
local services      = require 'controllers.services_controller'
 
-- [1] Configure the routes
local r = router.new()
 
r:get( '/api/services'     , services.index)
r:get( '/api/services/:id' , services.show)
r:post('/api/services'     , services.create)
 
...
 
-- [2] Invoke the appropriate controller function
local method = ngx.req.get_method():lower()
 
local ok, route_found = error_handler.execute(function()
  r:execute(method, ngx.var.uri, ngx.req.get_uri_args())
end)
 
if ok and not route_found then
  ngx.status = ngx.HTTP_NOT_FOUND
end

파일의 두 가지 주요 부분은 가능한 모든 API 경로로 라우터를 구성하고 URL과 경로에 따라 컨트롤러 함수를 호출합니다.
예를 들어, NGINX 서비스가 존재하지 않는 경우 서비스 컨트롤러가 오류를 발생시키면 error_handler가 이를 캡처하여 400 상태와 오류 메시지가 포함된 JSON 응답으로 변환합니다.
마지막 조건문은 일치하는 경로를 찾을 수 없을 때 오류를 발생시키지 않고 거짓을 반환하기 때문에 어떤 경로와도 일치하지 않는 요청도 올바르게 처리되도록 보장합니다.

2. NGINX 프록시 (10002 포트)

APItools 모니터의 프록시 부분은 ‘지능형 중개자’ 역할을 합니다. 요청과 응답이 도착하면 이를 저장하고 때로는 수정합니다.

프록시 구성(간결성을 위해 많은 세부 사항이 제거됨) :

server {
    listen 10002;
 
    location / {
        content_by_lua_file 'lua/apps/proxy.lua';
    }
}

lua/apps/proxy.lua 파일은 다음과 같이 구성되어 있습니다 (다시 말하지만, 이는 극도로 단순화된 버전입니다).

local host_parser   = require 'host_parser'
local error_handler = require 'error_handler'
local Service       = require 'service'
 
-- [1] Deduce the service, user and url from the host
local service_name, user = host_parser.get_service_and_user_from_host(ngx.var.host)
local service, url       = Service:find_by_endpoint_code(service_name)
 
error_handler.execute(function()
  assert(service, "no service for ".. ngx.var.host)
 
  -- [2] Execute the middleware pipeline
  service:execute_pipeline(url)
end)
 
ngx.exit(ngx.OK)

프록시는 주로 어떤 서비스, 사용자, URL을 실행해야 하는지 추론하는 구문 분석 단계와 적절한 미들웨어를 실행하는 실행 단계로 구성됩니다. 또한 Lua 오류를 감지하여 4xx HTTP 상태와 오류 메시지가 포함된 ngx 응답으로 변환하는 일부 오류 처리도 있습니다.

3. 결론

프록시와 웹 애플리케이션 모두에 단일 NGINX 서버를 사용하는 것이 구현이 간단하고 요구 사항을 충분히 충족시킬 수 있는 성능을 제공한다는 것을 알게 되었습니다. 각 NGINX 인스턴스는 실행하는 데에 6MB의 서버 메모리가 필요합니다.

아래 뉴스레터를 구독하고 NGINX와 NGINX STORE의 최신 정보들을 빠르게 전달 받아보세요.