-
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