NGINX Unit은 여러 언어와 각 언어의 여러 버전을 지원할 수 있는 완전한 동적 애플리케이션 서버입니다. RESTful JSON API를 사용하여 서비스 중단이나 구성 다시 로드 없이 메모리상의 구성을 변경할 수 있다는 점에서 동적입니다.
지난 10월 NGINX Conf 2018에서 진행한 발표에서는 기존 프로덕션 환경에 새 애플리케이션을 구성하는 방법을 시연했습니다. 구체적으로는 PHP 기반 WordPress가 실행 중인 환경에 Django 프레임워크를 사용하는 Python 애플리케이션을 배포했습니다. 또한 파일에서 구성을 불러오는 방법과 API 호출의 인수로 지정해 구성을 불러오는 방법도 시연했습니다.
이 블로그에는 데모에서 사용한 모든 명령어와 구성 코드가 포함되어 있어, 여러분의 배포 환경에 맞게 쉽게 적용할 수 있습니다.
사전 요구 사항
NGINX Conf에서 데모를 진행하기 위해 다음 소프트웨어를 설치했습니다:
- Ubuntu 16.04
- NGINX Plus. 단, 별도로 명시된 경우를 제외하고 NGINX Open Source를 사용할 수 있습니다.
- NGINX Unit(모든 언어 모듈 설치됨)
- Python 3
- Django (구성되지 않음 – 이 데모와 블로그에서 다루는 내용입니다)
root권한 또는 이에 상응하는sudo액세스 권한(필요한 경우 사용)
기존 애플리케이션으로 PHP와 WordPress도 설치되어 있었습니다.
Django 프로젝트 만들기
- Django 프로젝트를 생성할 디렉터리로 이동합니다:
$ cd /var/www/- 새 프로젝트를 초기화하려면
django-adminstartproject명령을 사용합니다. 프로젝트 이름은 djapp으로 지정하겠습니다.
$ sudo django-admin startproject djapp- 프로젝트 디렉터리로 이동합니다:
$ cd djapp- Use the
manage.py스크립트를 사용하여 프로젝트의 데이터베이스를 마이그레이션합니다. 새로 만든 프로젝트에는 이 작업이 필요합니다. Django는 기본적으로 SQLite를 사용하며 이 데모에서도 기본값을 사용하지만, 프로젝트의 요구 사항에 맞는 데이터베이스라면 무엇이든 사용할 수 있습니다.manage.py스크립트는 2단계에서 실행한django-admin명령으로 설치됩니다. 이 스크립트는django-admin과 동일한 명령을 실행하고 동일한 인수를 허용하지만, 프로젝트별 설정 일부를 자동으로 파악하여 사용하므로 편리합니다. 자세한 내용은 Django 문서를 참조하세요.
$ sudo python3 manage.py migrate- 이와 같은 샘플 프로젝트에서는 반드시 필요한 것은 아니지만, Django 슈퍼유저 계정을 생성하는 것이 좋습니다:
$ sudo python3 manage.py createsuperuser- 2단계에서 django-admin
startproject명령으로 생성된settings.py파일이 있는 하위 디렉터리로 이동합니다.
$ cd /var/www/djapp/djapp- 선호하는 텍스트 편집기를 사용하여 settings.py 파일을 엽니다. 여기서는
nano를 사용합니다:
$ sudo nano settings.py- Find the
ALLOWED_HOSTS줄을 찾아 애플리케이션의 도메인 이름, 호스트 이름 또는 IP 주소를 추가합니다:
ALLOWED_HOSTS = ['domain-name']- 또한 애플리케이션에서 제공하는 모든 정적 콘텐츠가 저장되는 디렉터리를 지정하려면 파일 끝에 다음 줄을 추가합니다(9단계 참조).
STATIC_ROOT = '/var/www/djapp/djapp/static'- 기본 프로젝트 디렉터리(manage.py가 있는 디렉터리)로 다시 이동합니다.
$ cd ..- Django 프로젝트에 있는 모든 정적 파일을 수집하여 7단계에서 정의한
manage.pycollectstatic명령을 실행해STATIC_ROOT위치에 저장합니다.
$ sudo python3 manage.py collectstaticNGINX 구성하기
기본적으로 Django 자체에서 프로젝트의 정적 콘텐츠를 제공하지만, NGINX Open Source와 NGINX Plus를 사용하면 더 뛰어난 성능을 얻을 수 있습니다. 여기서는 NGINX Plus를 구성하지만, 아래에 설명된 한 가지 기능을 제외하면 NGINX Open Source를 사용할 수도 있습니다.
- 디렉터리를 /etc/nginx/conf.d(기능별 또는 이 경우 애플리케이션별) HTTP 구성 파일의 일반적인 위치인 다음 경로로 변경합니다:
$ cd /etc/nginx/conf.d- 다음 이름의 파일을 만듭니다. django.conf(여기서도
nano를 사용합니다):
$ sudo nano django.conf- 캐싱을 활성화하는 다음 구성을 삽입합니다. 이 구성에는 NGINX Plus에서만 제공되는 두 가지 기능도 포함되어 있습니다. NGINX Plus를 사용 중이며 해당 기능을 활용하려면 관련 지시문의 주석을 해제하세요. 한 가지 유의할 점은 NGINX Conf 데모에서 제가 로컬 컴퓨터의 IP 주소를
proxy_set_header지시문의 두 번째 인수로 지정했다는 것입니다. 프로덕션 환경에서는 아래와 같이$host변수를 사용하는 것이 더 적절합니다.
# Upstream group for the backend (NGINX Unit running the Python application)
upstream django_unit {
zone django_unit 64k;
server 127.0.0.1:8000;
}
server {
listen 8080;
# Uncomment to collect metrics if using NGINX Plus and the NGINX Plus API
#status_zone django;
# enable caching
proxy_cache django_cache;
proxy_cache_valid 200 60m;
# root directory for static files
root /var/www/djapp/djapp;
# proxy to the NGINX Unit backend
location / {
proxy_pass http://django_unit;
# Second argument must match your production hostname and the value of
# ALLOWED_HOSTS in settings.py
proxy_set_header Host $host;
# Uncomment to enable active health checks if using NGINX Plus
#health_check;
}
# Location for the static files collected from Django and served by
# NGINX Plus; can be empty (as here), because it inherits the value of the
# 'root' directive from its parent block
location /static {
}
}- 이 가상 서버에 대해 확장 메트릭 수집을 활성화하는
status_zone지시어입니다. NGINX Plus API는 구성의 다른 위치에서 활성화되어 있다고 가정합니다. - 능동 상태 확인,
health_check지시어로 활성화됩니다.
- 구성의 구문이 올바른지 확인합니다:
$ sudo nginx –t- 오류를 모두 수정한 후 구성을 다시 로드합니다:
$ sudo nginx -s reloadNGINX Unit 구성
마지막으로, 애플리케이션에 대한 요청을 처리하도록 NGINX Unit을 구성해야 합니다.
- 다음
curl명령을 실행하여 현재 NGINX Unit 구성을 표시합니다. 이 구성은 PHP에서 실행되는 WordPress용입니다. 여기서는 출력을 표시하지 않지만, 아래 6단계에서 곧 추가할 Python 애플리케이션 구성과 함께 WordPress 구성을 확인할 수 있습니다. 여기서는sudo를 사용하여curl명령을 실행합니다. 대부분의curl명령에서는 이렇게 할 필요가 없을 수도 있습니다. 하지만 여기서는 UNIX 소켓에 액세스하려면root가 해당 소켓에 대해 보유한 읽기-쓰기 권한이 필요하므로 반드시 사용해야 합니다.
$ sudo curl --unix-socket /run/control.unit.sock http://localhost/config/- NGINX Unit 구성 파일이 있는 디렉터리로 이동합니다. 이러한 파일은 선택 사항이며, NGINX Unit API 호출 시 모든 데이터를 인수로 직접 입력하지 않고도 구성 모음을 편리하게 로드하기 위한 수단일 뿐이라는 점에 유의하세요. 파일의 내용은 모든 구성 데이터와 마찬가지로 API를 통해 업로드되므로, NGINX Unit은 파일 위치를 알지 못하며 시작할 때 파일을 자동으로 읽을 수 없습니다(NGINX Open Source 및 NGINX Plus와는 다름). 대신 NGINX Unit은 런타임 상태를 별도의 디렉터리에 저장합니다.
$ cd /etc/unit- 다음 이름의 파일을 만듭니다. django.config(여기서도
nano를 사용합니다):
$ sudo nano django.config- Python 애플리케이션을 나타내는 다음 JSON을 추가합니다.
{
"type": "python",
"processes": 5,
"module": "djapp.wsgi",
"path": "/var/www/djapp"
}- 다음
curl명령을 실행하여 django.config에 포함된 JSON을 NGINX Unit에서 관리할 새 애플리케이션 객체로 로드하고, 이름을 djapp으로 지정합니다:
$ sudo curl -X PUT --data-binary @/etc/unit/django.config --unix-socket /run/control.unit.sock http://localhost/config/applications/djapp- 이 명령에서:
- HTTP
PUT메서드는 마지막 인수(URL)로 지정된 위치에 새 NGINX Unit 구성 객체를 생성합니다. 아래의 마지막 항목을 참조하세요. - The
--data-binary인수는curl에 django.config의 내용을 제공된 그대로 불러오도록 지시하며, 줄 바꿈과 캐리지 리턴을 유지하고 어떠한 처리도 수행하지 않습니다. - The
--unix-socket인수는 NGINX Unit API가 수신 대기하는 위치를 지정합니다. (소켓의 기본 소유자인sudo명령을 사용하는 이유는root를 사용하고 있기 때문입니다.) - 마지막 인수는 JSON 형식의 구성 데이터가 들어 있는 django.config를 사용해 채울 새 애플리케이션 객체의 위치와 이름을 지정합니다.
config는 최상위 NGINX Unit 구성 객체이고,applications는 애플리케이션 객체의 상위 객체이며,djapp는 새 애플리케이션 객체의 이름입니다.
- HTTP
- 애플리케이션의 리스너 객체를 정의합니다. 4단계에서처럼 구성 데이터 파일을 로드하는 대신,
curl명령줄에서 데이터를 직접 정의하여djapp애플리케이션이 포트 8000에서 수신 대기하도록 지정합니다.
$ sudo curl -X PUT --data-binary '{"application":"djapp"}' --unix-socket /run/control.unit.sock 'http://localhost/config/listeners/*:8000'- 1단계의
curl명령을 다시 실행하여 이제 Python 애플리케이션 djapp이 주황색으로 강조되어 포함된 NGINX Unit 구성을 표시합니다:
$ sudo curl --unix-socket /run/control.unit.sock http://localhost/config/{
"listeners": {
"127.0.0.1:8090": {
"application": "script_index_php"
},
"127.0.0.1:8091": {
"application": "direct_php"
},
"*:8000": { "application": "djapp" }
},
"applications": {
"script_index_php": {
"type": "php",
"processes": {
"max": 20,
"spare": 5
},
"user": "www-data",
"group": "www-data",
"root": "/var/www/wordpress",
"script": "index.php"
},
"direct_php": {
"type": "php",
"processes": {
"max": 5,
"spare": 0
},
"user": "www-data",
"group": "www-data",
"root": "/var/www/wordpress",
"index": "index.php"
},
"djapp": { "type": "python", "processes": 5, "module": "djapp.wsgi", "path": "/var/www/djapp" }
}
}요약
이 게시물에서는 먼저 프로덕션 환경에서 WordPress용 PHP 애플리케이션을 실행하는 NGINX Unit을 구성한 다음 Python 애플리케이션을 추가했습니다. 데모에서는 NGINX Plus 대시보드를 사용하여 새 애플리케이션을 추가해도 기존 애플리케이션이 중단되지 않는다는 것을 보여 주지만, 이를 확인하는 데는 ps 명령과 같은 시스템 모니터링 도구를 사용할 수도 있습니다. NGINX Unit 구성의 동적 특성은 실행 중인 애플리케이션의 리소스를 절약하고, 새 배포 시 다운타임을 없애며, 애플리케이션 버전 간의 원활한 전환을 보장합니다.
자세한 내용은 unit.nginx.org에서 확인하세요.
관련 블로그 게시물
시청하기: 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에게서 알아보세요.