웹 애플리케이션을 만들고 나면 항상 웹 서버를 구축하여 웹 서버 + 웹 애플리케이션의 구성으로 운영을 하라고 강하게 권고한다.
웹 서버는 웹 애플리케이션의 앞단에서 로드 밸런싱, 캐싱, 리버스 프록시 등의 기능을 제공해주어서 시스템의 안정성을 높여주는 역할을 한다. 때문에 Production level에서는 웹 서버를 꼭 사용하게 된다. 그 중 널리 사용되고 있는 nginx를 알아보자.
NGINX는 웹 서비스, 리버스 프록시, 캐싱, 로드 밸런싱, 미디어 스트리밍 등을 위한 오픈 소스 소프트웨어이다. HTTP 서버 기능 외에도 NGINX는 이메일(IMAP, POP3, SMTP)의 프록시 서버 역할과 HTTP, TCP, UDP 서버의 역방향 프록시 및 로드 밸런서 역할도 할 수 있다.
nginx 는 크게 4가지 프로세스로 구성된다.
1. 마스터 프로세스
2. 캐시 로더 프로세스
3. 캐시 관리자 프로세스
4. 작업자 프로세스
마스터 프로세스는 configuration 파일을 읽기, 포트 바인딩, 그리고 cache loader, cache manager, worker 와 같은 자식 프로세스를 만든다.
캐시 로더 프로세스는 시작 시 실행되어 디스크 기반 캐시를 메모리에 로드한 다음 종료된다.
캐시 관리자 프로세스는 주기적으로 실행되며 디스크 캐시에서 항목을 정리하여 구성된 크기 내에서 유지한다.
작업자 프로세스가 모든 일을 한다. 네트워크 연결을 처리하고, 디스크를 읽고 쓰고, 업스트림 서버와 통신한다.
nginx는 모든 연결에 대해 프로세스나 스레드를 만들지 않는다. Worker process는 공유 listen 소켓으로 부터 새로운 요청을 받고 이를 각 worker 별로 run-loop를 돌며 각 worker 당 수천개 이상의 connection을 맺고 처리할 수 있다. worker 별 request 분배는 OS kernel의 메커니즘에 따라서 결정된다.
한 마디로 비동기적으로 요청들을 처리하기 때문에 blocking이 없이 실행이 된다.
master process 가 읽는 configuration 의 default path 는 /usr/local/nginx/conf, /etc/nginx, or /usr/local/etc/nginx 이다.
nginx 의 configuration 은 두 가지의 지시어 (directives) 로 이루어져 있다.
이름, 값으로 정의하고 세미콜론으로 끝을 낸다.
worker_process 2;
user www-data;
worker_processes auto;
worker_rlimit_nofile 60000;
pid /run/nginx.pid;
include [path]
user: linux 시스템의 어떤 사용자가 NGINX 서버를 동작시킬지 설정한다.
worker_processes: 몇 개의 thread가 사용될지 정의한다. CPU 코어 수에 맞추는 것이 권장된다. auto 로 설정하면 자동으로 cpu 개수에 맞게 설정됨.
pid: NGINX pid가 적혀있는 파일.
include: 외부 configuration 내용을 가져온다.
worker_rlimit_nofile: worker프로세스가 최대 열수 있는 파일 수 제한
구조는 똑같으나 세미콜론 대신 중괄호를 사용한다. block directive 안에 또 다른 directives를 갖을 수 있는데 다른 block directive를 포함하는 block directive를 context라고 부른다. ( events, http, server, location )
http {
server {
}
}
location / {
root /data/www;
}
1. events block
events 블록은 네트워크의 작동 환경을 설정하는 지시어를 제공합니다. 이벤트 블록의 지시어는 이벤트 블록에서만 사용할 수 있고, http, server, local 블록과는 상속 관계를 갖지 않습니다. 아래의 지시어들은 반드시 events 블록 안에서만 사용해야 합니다.
events {
use epoll;
multi_accept on;
worker_connections 1024;
}
2. http block
http 블록은 HTTP 부분과 관련된 모듈의 지시어와 블록을 정의하며, server와 location의 루트 블록이라고 할 수 있습니다. http, server, location 블록은 계층 구조를 가지고 있습니다. 많은 지시어가 각 블록에서 동시에 사용될 수 있는데, http 블록의 내용은 server 블록의 기본값이 되고, server 블록의 내용은 location 블록의 기본값이 됩니다. 만약 상위 블록에서 선언된 지시어를 하위 블록에서 다시 선언하면 상위의 지시어는 무시됩니다. http 블록 안에 한 개 이상의 server 블록을 선언할 수 있습니다.
include /etc/nginx/mime.types;
default_type application/octet-stream;
keepalive_timeout 10s;
keepalive_requests 100;
reset_timedout_connection on;
client_max_body_size 50m;
client_body_timeout 10s;
client_header_timeout 10s;
send_timeout 10s;
resolver_timeout 10s;
3. server block
server 블록은 하나의 호스트를 선언하는데 사용하며, http 블록 안에서만 사용할 수 있습니다. server 블록에는 한 개 이상의 location 블록을 선언할 수 있습니다.
listen 80 default_server;
server_name _;
# 아래 설정은 WebSocket 통신을 위한 설정법으로 WebSocket통신을 하고 싶다면 아래와 같이 설정해주면 된다.
# 1. HTTP/1.1 버전에서 지원하는 프로토콜 전환 메커니즘을 사용한다
proxy_http_version 1.1;
# 2. hop-by-hop 헤더를 사용한다
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
# 3. 받는 대상 서버(WAS)
proxy_set_header Host $host;
proxy_set_header X-Forwarded_For $proxy_add_x_forwarded_for;
proxy_cache_bypass $http_upgrade;
4. location block
location 블록에는 server 블록 안에 정의되며, 특정 URL을 처리하는 방법을 정의합니다. 예를 들면 http://example.com/hello/1 과 http://example.com/world/1 접근하는 요청을 다르게 처리하고 싶을 때 사용합니다.
upstream app_upstream {
server IP:8080; ( if dns 설정이 돼있다면 server app:8080)
}
location ~* ^/app {
access_log off;
proxy_pass http://app_upstream;
}
location 패턴
- location /: 해당 path 아래 sub path 까지 모두
- location ~: 대문자/소문자 정확히 일치
- location ~*: 대문자/소문자 구별하지 않음
- location ^$: ^시작과 $끝을 의미함 e.g. location ~ ^/admin 대/소문자 구별하고 /admin으로 시작해야함.
Directives를 정의해놓은 공식 홈페이지를 참고해서 필요한 configuration을 정의할 수 있다.
http://nginx.org/en/docs/http/ngx_http_core_module.html#http
nginx cli 를 이용해서 nginx를 컨트롤 할 수 있다.
nginx -s signal
과 같은 방식으로 사용할 수 있고 signal에는
Docker 를 통해서 nginx 를 실행하기 위해서는 우선 Dockerfile 을 작성해줘야한다. 다양한 방식으로 nginx 를 실행할 수 있겠지만 DockerHub에서 공식 nginx image를 받아서 적용하도록 해봤고, 실제 사용하면서 설정했던 값들을 토대로 example Dockerfile을 만들었다.
FROM nginx:{version}
# Working directory 설정.
WORKDIR /usr/app
RUN apk update && apk add --no-cache logrotate curl ( nginx 의 Log를 rotate 시키기 위해서 logrotate를 설치 )
# custom config 파일을 덮어쓰기.
COPY ./nginx.conf /etc/nginx/nginx.conf
# Nginx log rotate 정보를 넣고 crontab 에 등록
COPY ./nginx-logrotate /etc/logrotate.d
RUN chown root /etc/logrotate.d/nginx-logrotate && echo "0 */1 * * * /usr/sbin/logrotate -f /etc/logrotate.d/nginx-logrotate" >> /etc/crontabs/root
# boot script 적용.
COPY ./bootstrap.sh /usr/app
RUN chmod -x /usr/app/bootstrap.sh
# Port 열기 ( HTTP, HTTPS )
EXPOSE 80
EXPOSE 443
# boot script 실행
CMD ["sh", "/usr/app/bootstrap.sh"]
https://www.nginx.com/resources/glossary/nginx/
https://nginx.org/en/docs/
http://www.aosabook.org/en/nginx.html