고성능 웹 서버 분야에서 NGINX는 가볍고 효율적인 아키텍처를 바탕으로 대규모 트래픽을 처리할 수 있어 널리 사용됩니다. 공유 딕셔너리 기능이 NGINX JavaScript 모듈(njs)의 일부로 도입되면서 NGINX의 성능은 한 단계 더 향상되었습니다.
이 블로그 게시물에서는 njs 공유 사전의 기능과 이점을 살펴보고, SSL/TLS 인증서를 교체할 때 재시작할 필요가 없도록 NGINX Open Source를 설정하는 방법을 소개합니다.
공유 딕셔너리의 기본 개념과 이점
새로운 js_shared_dict_zone 지시문을 사용하면 NGINX Open Source 사용자가 공유 메모리 영역을 활성화하여 워커 프로세스 간에 데이터를 효율적으로 교환할 수 있습니다. 이러한 공유 메모리 영역은 키-값 딕셔너리로 작동하며, 실시간으로 액세스하고 수정할 수 있는 동적 구성 설정을 저장합니다.
공유 딕셔너리의 주요 이점은 다음과 같습니다:
- 오버헤드가 적고 사용이 간편함 – njs에 직접 내장되어 있어 직관적인 API와 간단한 구현 방식으로 손쉽게 프로비저닝하고 활용할 수 있습니다. 또한 워커 프로세스 간 데이터 관리 및 공유 절차를 간소화하는 데 도움이 됩니다.
- 가볍고 효율적 – NGINX와 원활하게 통합되며, 이벤트 기반의 논블로킹 I/O 모델을 활용합니다. 이 방식은 메모리 사용량을 줄이고 동시 처리 성능을 향상시켜 NGINX가 다수의 동시 연결을 효율적으로 처리할 수 있도록 합니다.
- 확장성 – NGINX의 여러 워커 프로세스에 걸친 수평 확장 기능을 활용하므로, 복잡한 프로세스 간 통신 메커니즘 없이도 해당 프로세스 간에 데이터를 공유하고 동기화할 수 있습니다. TTL(Time-to-Live) 설정을 사용하면 비활성 상태인 공유 딕셔너리 항목을 영역에서 제거하여 레코드를 관리할 수 있습니다.
evict매개변수는 새 항목을 위한 공간을 확보하기 위해 가장 오래된 키-값 쌍을 제거합니다.
공유 사전을 사용한 SSL 인증서 교체
공유 딕셔너리의 가장 효과적인 활용 사례 중 하나는 SSL/TLS 인증서 교체입니다. js_shared_dict_zone을 사용하면 SSL/TLS 인증서나 키가 업데이트되어도 NGINX를 다시 시작할 필요가 없습니다. 또한 NGINX에서 인증서를 관리할 수 있는 REST 형식의 API를 제공합니다.
다음은 js_set 및 ssl_certificate 지시어를 사용하여 HTTPS 서버를 설정하는 NGINX 구성 파일의 예입니다. JavaScript 핸들러는 js_set을 사용하여 파일에서 SSL/TLS 인증서 또는 키를 읽습니다.
이 구성 스니펫은 공유 사전을 사용하여 인증서와 키를 공유 메모리에 캐시로 저장합니다. 키가 없으면 디스크에서 인증서 또는 키를 읽어 캐시에 저장합니다.
캐시를 지우는 location을 노출할 수도 있습니다. 디스크의 파일이 업데이트되면(예: 인증서와 키가 갱신된 경우) 공유 딕셔너리가 디스크에서 파일을 다시 읽도록 강제할 수 있습니다. 이렇게 하면 NGINX 프로세스를 다시 시작하지 않고도 인증서와 키를 교체할 수 있습니다.
http { ...
js_shared_dict_zone zone=kv:1m;
server {
…
# Sets an njs function for the variable. Returns a value of cert/key
js_set $dynamic_ssl_cert main.js_cert;
js_set $dynamic_ssl_key main.js_key;
# use variable's data
ssl_certificate data:$dynamic_ssl_cert;
ssl_certificate_key data:$dynamic_ssl_key;
# a location to clear cache
location = /clear {
js_content main.clear_cache;
# allow 127.0.0.1;
# deny all;
}
...
}다음은 js_shared_dict_zone을 사용하여 SSL/TLS 인증서와 키를 교체하는 JavaScript 구현입니다:
function js_cert(r) { if (r.variables['ssl_server_name']) {
return read_cert_or_key(r, '.cert.pem');
} else {
return '';
}
}
function js_key(r) {
if (r.variables['ssl_server_name']) {
return read_cert_or_key(r, '.key.pem');
} else {
return '';
}
}
/**
* Retrieves the key/cert value from Shared memory or fallback to disk
*/
function read_cert_or_key(r, fileExtension) {
let data = '';
let path = '';
const zone = 'kv';
let certName = r.variables.ssl_server_name;
let prefix = '/etc/nginx/certs/';
path = prefix + certName + fileExtension;
r.log('Resolving ${path}');
const key = ['certs', path].join(':');
const cache = zone && ngx.shared && ngx.shared[zone];
if (cache) {
data = cache.get(key) || '';
if (data) {
r.log(`Read ${key} from cache`);
return data;
}
}
try {
data = fs.readFileSync(path, 'utf8');
r.log('Read from cache');
} catch (e) {
data = '';
r.log(`Error reading from file:${path}. Error=${e}`);
}
if (cache && data) {
try {
cache.set(key, data);
r.log('Persisted in cache');
} catch (e) {
const errMsg = `Error writing to shared dict zone: ${zone}. Error=${e}`;
r.log(errMsg);
}
}
return data
}
By sending the /clear 요청을 보내면 캐시가 무효화되고, 다음 SSL/TLS 핸드셰이크 시 NGINX가 디스크에서 SSL/TLS 인증서 또는 키를 로드합니다. 또한 요청에서 SSL/TLS 인증서 또는 키를 가져오는 동시에 캐시를 유지하고 업데이트하는 js_content를 구현할 수도 있습니다.
이 예제의 전체 코드는 njs GitHub 저장소에서 확인할 수 있습니다.
지금 시작하세요
공유 딕셔너리 기능은 애플리케이션의 프로그래밍 기능을 강화하는 강력한 도구로, 간소화와 확장성 측면에서 상당한 이점을 제공합니다. js_shared_dict_zone의 기능을 활용하면 새로운 성장 기회를 창출하고 증가하는 트래픽 수요를 효율적으로 처리할 수 있습니다.
NGINX 배포 환경을 js_shared_dict_zone으로 한층 강화할 준비가 되셨나요? NGINX 배포 환경에 js_shared_dict_zone을 도입하여 새로운 사용 사례를 구현하고, 이 기능에 대한 자세한 내용을 문서에서 확인해 보세요. 또한 최근 공개된 njs-acme 프로젝트에서 공유 사전 기능의 전체 예제를 확인할 수 있습니다. 이 프로젝트를 사용하면 njs 모듈 런타임이 ACME 공급자와 연동할 수 있습니다.
NGINX Open Source를 시작하는 데 관심이 있거나 궁금한 점이 있다면 NGINX 커뮤니티 Slack에 참여하세요 – 자신을 소개하고 NGINX 사용자 커뮤니티와 친해져 보세요!
관련 블로그 게시물
시청하기: KubeCon North America 2023에서의 NGINX Gateway Fabric
이 영상에서는 KubeCon의 NGINX 부스를 찾아가, 저희가 공개한 Kubernetes Gateway API 구현을 살펴봅니다.
F5 NGINX로 대규모 WAF 플릿을 확인하고 관리하는 2가지 방법
앱 보안을 강화하는 두 가지 방법을 소개합니다. NGINX Management Suite를 통해 WAF 운영에 대한 가시성을 높이고, NGINX App Protect WAF를 활용해 코드형 보안을 구현하는 것입니다.
Ingress 컨트롤러 선택 가이드, 4부: NGINX Ingress Controller 옵션
개발 주체, 개발 철학, 프로덕션 환경 준비도, 보안 및 지원을 기준으로 어떤 NGINX Ingress 컨트롤러가 가장 적합한지 알아보세요.
진화하는 공격 환경에 NGINX App Protect Denial of Service가 적응하는 방법
NGINX App Protect Denial of Service(DoS)가 계층 7 DoS 공격을 방어하기 위해 완화 방법을 실시간으로 조정하는 방식을 설명합니다. 정상적인 사용자 행동과 서버 상태에 대한 모델을 생성하여 공격을 나타내는 이상 징후를 감지하고 맞춤형 완화 시그니처를 적용할 수 있습니다.
NGINX Instance Manager를 활용한 대규모 구성 업데이트 및 인증서 관리
NGINX Instance Manager 버전 1.0에는 두 가지 새로운 기능이 도입되었습니다. NGINX 인스턴스에 태그와 사용자 역할을 지정하면 전체 그룹에 구성을 한 번에 적용할 수 있습니다. 인증서 검사는 만료 예정인 인증서를 감지하여 서비스 중단을 방지할 수 있도록 인증서를 교체할 수 있게 해줍니다.
Netflix가 자사 CDN의 핵심으로 NGINX를 선택한 이유
Netflix가 글로벌 콘텐츠 전송 네트워크인 Open Connect의 스트리밍 미디어 기술로 NGINX를 선택한 이유를 NGINX 개발자 Gleb Smirnoff에게서 알아보세요.