ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • NGINX 5: 프로그래머빌리티 & 자동화
    DevOps 2023. 3. 18. 00:54
    반응형

     

    먼저 글의 제목인 프로그래머빌리티와 자동화가 Nginx와 어떤 관련이 있는지 설명합니다. 

     

    프로그래머빌리티(Programmability)란 프로그래밍을 통해 상호 작용하는 능력을 말합니다. Nginx Plus는 엔지니어가 Ningx의 설정과 상호작용 하고 동작을 제어할 수 있도록 API를 제공하는데 이것도 프로그래머빌리티의 맥락으로 볼 수 있습니다.

     

    또한 현대의 대규모 웹 애플리케이션을 다루는 엔지니어는 직접 서버 설정을 만지지 않고 설정 관리 도구(Cheif, Ansible, Consul 등..)를 선택해 자동화할 수 있습니다. 도구를 통해 한 번 작성된 설정과 코드를 수많은 서버에 반복적으로 적용할 수 있으며 모듈화된 방식으로 배포할 수 있습니다.

     

     

    1. Nginx Plus API


    Nginx Plus가 제공하는 API를 호출해 서버를 추가하거나 삭제할 수 있습니다.

    upstream backend {
    	zone http_backend 64k;
    }
    
    server {
    	location /api {
    		api [write= on];
    	}
    	
    	location /dashboard.html {
    		root /usr/share/nginx/html;
    	}
    }
    • 공유 메모리 영역을 사용하는 업스트림 서버를 생성합니다.
    • /api 경로에 대한 location 블록을 통해 API를 활성화하며 Nginx Plus 대시보드 접근을 위한 location 블록을 구성합니다.
    • 설정을 완료하면 다음과 같은 API를 호출할 수 있습니다.

     

    업스트림 서버 추가

    • POST /api/{version}/http/upstreams/{httpUpstreamName}/servers
    • Request Body: {"server": "[upstream server ip]"}

     

    업스트림 서버 목록 조회

    • GET /api/{version}/http/upstreams/{httpUpstreamName}/servers
    • URI에 작성된 업스트림 서버 풀에 포함된 모든 서버 목록을 가져옵니다.

     

    업스트림 서버 커넥션 드레이닝

    • PATCH /api/{version}/http/upstreams/{httpUpstreamName}/servers/{serverId}
    • Request Body: {"drain": true}
    • 서버가 제거되려면 해당 서버의 연결이 모두 종료돼야 하기 때문에 drain 옵션을 통해 연결이 점진적으로 감소하도록 한다.

     

    업스트림 서버 제거

    • DELETE /api/{version}/http/upstreams/{httpUpstreamName}/servers/{serverId}

     

     

    2. 키-값 저장소 사용하기 (엔진엑스 플러스)


    Nginx는 API 호출을 통해 공유 메모리 영역에 동적으로 데이터를 추가할 수 있습니다. 해당 API를 사용하여 사용자 IP를 차단하는 기능을 만들어 봅니다.

    keyval_zone zone=blocklist:1M;
    keyval $remote_addr $blocked zone=blocklist;
    
    server {
    	location / {
    		if ($blocked) {
    			return 403 'Forbidden';
    		}
    		return 200 'OK';
    	}
    
    	server {
    		location /api {
    			api write=on;
    		}
    	}
    }
    • keyval_zone 지시자를 사용해 blocklist라는 공유 메모리 영역을 만들고 용량 제한을 1MB로 제한합니다.
    • keyval 지시자는 공유 메모리에 $remote_addr 값과 일치하는 키가 있으면 키값을 $blocked 변수에 저장합니다.
    • 값이 할당된 $blocked 변수는 Nginx가 요청에 대해 403을 반환할지 정상적인 리소스를 반환할지 결정하는데 사용됩니다.

     

    blocklist 저장소에 로컬 호스트 주소르 1로 저장

    • POST /api/{version}/http/keyvals/{httpKeyvalZoneName}
    • Request Body: {"127.0.0.1": "1"}
    • 해당 API를 호출한 후에 Nginx에 요청을 보내면 403 Forbidden 응답 코드를 받게됩니다.

     

    blocklist 저장소에 저장된 정보 변경

    • PATCH /api/{version}/http/keyvals/{httpKeyvalZoneName}
    • Request Body: {"127.0.0.1": null}
    • 값을 null로 변경하면 해당 IP의 요청은 200 OK 응답 코드를 받게됩니다.

     

     

    3. NJS 모듈로 엔진엑스 자바스크립트 기능 활용하기


    Nginx는 NJS모듈을 통해 Javascript를 사용해서 사용자의 요청이나 응답을 처리할 때 사용자 정의된 로직을 수행할 수 있습니다.

     

    먼저 NJS 모듈을 설치합니다. (데비안/우분투)

    apt-get install nginx-module-njs

     

    Nginx 설정 파일 경로 내에 자바스크립트 리소스를 위한 디렉터리를 생성합니다.

    mkdir -p /etc/nginx/njs

     

    만들어진 디렉터리에 jwt.js라는 파일을 생성합니다.

    function jwt(data) {
    	var parts = data.split('.').slice(0, 2)
    			.map(v=>Buffer.from(v, 'base64url').toString()
    			.map(JSON.parse);
    	return { headers:parts[0], payload: parts[1] };
    }
    
    function jwt_payload_subject(r) {
    	return jwt(r.headersIn.Authorization.slice(7)).payload.sub;
    }
    
    function jwt_payload_issuer(r) {
    	return jwt(r.headersIn.Authorization.slice(7)).payload.iss;
    }
    
    export default {jwt_payload_subject, jwt_payload_issuer}
    • 위 함수는 JWT를 디코딩하는 함수와 디코딩된 JWT payload의 subject와 issuer 값을 획득합니다.
    • Nginx에서 두 함수를 사용할 수 있도록 export 명령으로 추출합니다.

     

    Nginx 기본 설정 파일에서 설치한 NJS 모듈을 로드하고 http 블록 내에서 사용할 자바스크립트 파일을 임포트할 수 있습니다.

    load_module /etc/nginx/modules/ngx_http_js_module.so;
    
    http {
    	js_path "/etc/nginx/njs/";
    	js_import main from jwt.js;
    	js_set $jwt_payload_subject main.jwt_payload_subject;
    	js_set $jwt_payload_issuer main.jwt_payload_issuer;
        
    	...
    }
    • js_set 지시자는 자바스크립트 함수가 반환한 값을 Nginx 변수에 설정합니다.
    • 이 변수들을 활용해서 자바스크립트 로직을 검증할 수 있습니다.

     

    위 변수들을 응답에 포함하여 반환하는 server 블록을 정의합니다.

    server {
        listen 80 default_server;
        listen [::] 80 default_server;
        server_name _;
        
        location / {
        	return 200 "$jwt_payload_subject $jwt_payload_issuer";
        }
    }
    • 설정이 적용되면 클라이언트가 권한 헤더로 보낸 값에서 추출한 subject와 issuer 값을 응답으로 반환합니다.

     

    JWT를 요청 헤더에 포함시켜 테스트할 수 있습니다.

    JWT payload
    {
      "iss":"nginx",
      "sub":"alice",
      "foo":123
    }

    curl 'http://127.0.0.1/' -H \
    "Authorizaton: Bearer [JWT]"

    alice nginx
    • subject인 "alice"와 issuer인 "nginx"가 응답에 포함되어 반환된걸 확인할 수 있습니다.
    • NJS 모듈은 요청이 수신됐을 때뿐만 아니라 Nginx가 클라이언트로 응답을 보낼 때도 로직을 주입할 수 있습니다.

     

     

    4. 상용 프로그래밍 언어로 엔진엑스 확장하기


    Nginx가 자바스크립트 기반으로 작성한 NJS 모듈처럼 사용자는 C나 Lua, Perl 언어를 이용해서 커스텀한 모듈을 작성할 수 있습니다.

     

    작성한 모듈을 통해 코드가 작성된 파일을 불러오거나 Nginx 설정 내부에 직접 코드블록을 작성할 수도 있습니다.

     

    load_module modules/ndk_http_modile.so;
    load_module modules/ndx_http_lua_module.so;
    
    http {	
        server {
        	listen 8080;
            
            location / {
                default_type text/html;
                content_by_lua_block {
                	ngx.say("hello, world")
                }
            }
        }
    }
    • 루아로 만들어진 모듈은 ngx라는 이름으로 제공되는 내장 객체를 가지며, 이를 통해 Nginx API를 다룹니다.
    • ngx 객체는 NJS의 요청 객체와 마찬가지로 Nginx가 수신한 요청을 다루는 여러 속성과 메서드가 있고 응답을 만드는데 사용됩니다.
    • 모듈을 작성하는 방식으로 Nginx의 기능을 무한대로 확장할 수 있다는 장점을 가집니다.

     

     

    5. 셰프로 엔진엑스 설치하기

    6. 앤서블로 엔진엑스 설치하기

    7. 콘술 템플릿 기능으로 설정 자동화하기

     

    반응형

    'DevOps' 카테고리의 다른 글

    [Github] Branch protection rule 의미 분석  (0) 2023.03.29
    NGINX 6: 인증  (0) 2023.03.19
    NGINX 4: 콘텐츠 캐싱하기  (0) 2023.03.15
    NGINX 3: 트래픽 관리하기  (0) 2023.03.12
    NGINX 2: 고성능으로 부하 분산하기  (2) 2023.03.11
Designed by Tistory.