잘못된 정보가 있다면, 꼭 댓글로 알려주세요(비로그인 익명도 가능).
여러분의 피드백이 저와 방문자 모두를 올바른 정보로 인도할 수 있습니다.
감사합니다. -현록
현록의 기록저장소
NGINX 오픈소스 버전에 upstream health check 모듈 추가 본문
[개요]
[설치]
[설정]
[실행]
[개요]
NGINX는 점유율 1위(2022년 5월 기준)의 웹서버로, 비동기식 처리 방식으로 로드밸런싱이 가능하다.
리버스 프록시로 동작하며, 이를 응용하여 무중단 배포 등을 가능하도록 한다.
https://docs.nginx.com/nginx/admin-guide/load-balancer/http-health-check/
들어온 요청을 뒷단(upstream) 중 하나로 전달하고 응답을 받아와서 넘겨주는데,
로직에 따라 서버를 선택하지만, 그 서버가 살아있는지 지속적으로 health check하는 기능은 NGINX Plus(commercial 버전. 구독료 버전)에만 있다.
오픈소스 버전에도 제공하는 옵션은 각 서버에 max_fails(기본값 1회), fail_timeout(기본값 10초) 을 지정하는 것 밖에 없다.
upstream spring-simple-rest {
least_conn;
server nginx-spring-01:8091 max_fails=1 fail_timeout=3s;
server nginx-spring-02:8092 max_fails=1 fail_timeout=3s;
server nginx-spring-03:8093 max_fails=1 fail_timeout=3s;
}
특정 API가 평균 소요시간이 길다면 fail_timeout은 그보다 길어야할 것이다.
설정에 따라 다르지만, 뒷단이 죽어있어도 fail_timeout만큼 기다린 후에야 다른 쪽으로 요청을 넘기기도 한다.
또한 fail_timeout만큼은 해당 쪽으로는 요청을 보내지 않지만, 그 이후로는 다시 해당 쪽으로 요청을 보낼 수 있으며 그 때마다 지연이 발생한다.
요청이 들어올 때 무작정 보내보고 실패하면 다른 쪽으로 넘기는 방식이 아니라,
특정 시간마다 개별적으로 health check를 하고, 뒷단들의 상태를 갖고 있어서
요청이 들어오면 살아있는 쪽들만 후보로 하면, upstream 중 일부에 장애가 있을 때 불필요한 지연을 없앨 수 있다.
그런데 이 기능이 NGINX Plus에만 제공되고 있다.
하지만 오픈소스 모듈을 설치 가능하니, 가장 많이 사용하는 upstream health check 모듈을 설치하여 사용해본다.
https://github.com/yaoweibin/nginx_upstream_check_module
[설치]
위의 오픈소스 모듈 git 프로젝트(https://github.com/yaoweibin/nginx_upstream_check_module)를 내려받는다.
오픈소스 모듈의 버전 업이 NGINX에 비해 원활하지 않은 것 같다.
NGINX가 너무 상위 버전이라면 아직 이 모듈이 적용되는 범위를 벗어날 수 있으니, 이를 참고하여 NGINX 역시 받는다.
NGINX의 압축도 풀어둔다.
patch 명령어로 풀어둔 NGINX들에 패치를 할 것이다.
※ patch 명령어는 Docker 이미지류에는 어디에도 존재하지 않는다.
Docker가 이미 레이어 타입이기 때문.
다른 Linux/Unix에서 패치 후 디렉터리들을 COPY하는 방식으로 사용하자.
~ % cd nginx-1.20.1 nginx-1.20.1 % patch -p1 < ~/Downloads/nginx_upstream_check_module/check_1.20.1+.patch patching file 'src/http/modules/ngx_http_upstream_hash_module.c' patching file 'src/http/modules/ngx_http_upstream_ip_hash_module.c' patching file 'src/http/modules/ngx_http_upstream_least_conn_module.c' patching file 'src/http/ngx_http_upstream_round_robin.c' patching file 'src/http/ngx_http_upstream_round_robin.h' |
nginx 디렉터리 내부에 ./src/http/...에 위 파일들이 수정된 것을 수정된 날짜나 내용등을 통해 확인할 수 있다.
이제 이대로 컴파일 후 빌드할텐데, c로 작성된 프로그램이니 c 컴파일러가 필요하다.
※ 여기서부터의 과정을 Docker 방식으로 하고 싶다면, 과정 아래에 Dockerfile로 간략하게 수록했으니 참고.
nginx-1.20.1 % ./configure --add-module=~/Downloads/nginx_upstream_check_module Configuration summary + using system PCRE library + OpenSSL library is not used + using system zlib library nginx path prefix: "/usr/local/nginx" nginx binary file: "/usr/local/nginx/sbin/nginx" nginx modules path: "/usr/local/nginx/modules" nginx configuration prefix: "/usr/local/nginx/conf" nginx configuration file: "/usr/local/nginx/conf/nginx.conf" nginx pid file: "/usr/local/nginx/logs/nginx.pid" nginx error log file: "/usr/local/nginx/logs/error.log" nginx http access log file: "/usr/local/nginx/logs/access.log" nginx http client request body temporary files: "client_body_temp" nginx http proxy temporary files: "proxy_temp" nginx http fastcgi temporary files: "fastcgi_temp" nginx http uwsgi temporary files: "uwsgi_temp" nginx http scgi temporary files: "scgi_temp" |
우선 nginx/configure에 --add-module 옵션을 주어 실행해보면 컴파일이 가능한지 확인해주며,
빌드할 때 프로그램 설치 경로가 어떨지 설정을 잡아준다.
※ 전체 설치 경로 시작(NGINX_PREFIX)의 기본값은 /usr/local/nginx인데, --prefix=경로 옵션을 주어 전체 설치 경로를 지정할 수 있다.
다른 옵션은 https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-open-source/의 Configuring NGINX Paths에서 확인.
이제 빌드와 설치를 진행한다.
nginx-1.20.1 % make ... ... nginx-1.20.1 % make install ... ... |
오류 없이 설치되었다면 설치 경로를 확인해본다.
% ls -al /usr/local/nginx total 4 drwxr-xr-x 11 root root 352 Jan 31 12:52 . drwxr-xr-x 1 root root 4096 Jan 31 12:27 .. drwx------ 2 nobody root 64 Jan 31 12:52 client_body_temp drwxr-xr-x 18 root root 576 Feb 1 00:49 conf drwx------ 2 nobody root 64 Jan 31 12:52 fastcgi_temp drwxr-xr-x 4 root root 128 Jan 31 12:24 html drwxr-xr-x 5 root root 160 Jan 31 13:10 logs drwx------ 2 nobody root 64 Jan 31 12:52 proxy_temp drwxr-xr-x 3 root root 96 Jan 31 12:24 sbin drwx------ 2 nobody root 64 Jan 31 12:52 scgi_temp drwx------ 2 nobody root 64 Jan 31 12:52 uwsgi_temp |
실행할 프로그램은 ./sbin/nginx 이다.
% /usr/local/nginx/sbin/nginx -V nginx version: nginx/1.20.1 built by gcc 12.2.0 (GCC) configure arguments: --add-module=/nginx_upstream_check_module |
-V 옵션으로 실행시키면 버전 확인과 빌드 설정시 지정했던 옵션 등을 확인할 수 있다.
./configure, make, make install의 Dockerfile 예시를 수록한다.
c 컴파일러로 gcc 이미지를 사용했다.(예시의 이미지는 용량이 무려 1.27 GB이니, 가벼운 c 컴파일러 수록 이미지를 찾아보는 것을 추천)
FROM gcc:12.2.0
COPY --chown=0:0 --chmod=775 ./nginx-1.20.1 /nginx-1.20.1
COPY --chown=0:0 --chmod=775 ./nginx_upstream_check_module /nginx_upstream_check_module
WORKDIR /nginx-1.20.1
RUN [ "./configure", "--add-module=/nginx_upstream_check_module" ]
RUN [ "make" ]
RUN [ "make", "install" ]
WORKDIR /
ENTRYPOINT [ "bin/bash" ]
EXPOSE 8081
[설정]
설치한 nginx의 conf 디렉터리(/usr/local/nginx/conf)를 확인해보자.
% ls -al /usr/local/nginx/conf total 76 drwxr-xr-x 18 root root 576 Feb 1 00:49 . drwxr-xr-x 11 root root 352 Jan 31 12:52 .. -rwxr-xr-x 1 root root 1077 Jan 31 12:24 fastcgi.conf -rwxr-xr-x 1 root root 1077 Jan 31 12:24 fastcgi.conf.default -rwxr-xr-x 1 root root 1007 Jan 31 12:24 fastcgi_params -rwxr-xr-x 1 root root 1007 Jan 31 12:24 fastcgi_params.default -rwxr-xr-x 1 root root 2837 Jan 31 12:24 koi-utf -rwxr-xr-x 1 root root 2223 Jan 31 12:24 koi-win -rwxr-xr-x 1 root root 5231 Jan 31 12:24 mime.types -rwxr-xr-x 1 root root 5231 Jan 31 12:24 mime.types.default -rwxr-xr-x 1 root root 2656 Jan 31 12:24 nginx.conf -rwxr-xr-x 1 root root 2656 Jan 31 12:24 nginx.conf.default -rwxr-xr-x 1 root root 636 Jan 31 12:24 scgi_params -rwxr-xr-x 1 root root 636 Jan 31 12:24 scgi_params.default -rwxr-xr-x 1 root root 664 Jan 31 12:24 uwsgi_params -rwxr-xr-x 1 root root 664 Jan 31 12:24 uwsgi_params.default -rwxr-xr-x 1 root root 3610 Jan 31 12:24 win-utf |
여기서 nginx.conf 파일을 수정해보자.
http {} 블록 내부 맨 아래에 include my.conf; 한 줄만 추가해주자.
그리고 빠져나온 후, my.conf 문서를 생성하여 원하는 옵션을 작성해보자.
아래는 모듈을 설치하지 않은 my.conf 예시이다.
server_tokens off;
upstream spring-simple-rest { least_conn; server nginx-spring-01:8091 max_fails=1 fail_timeout=3s; server nginx-spring-02:8092 max_fails=1 fail_timeout=3s; server nginx-spring-03:8093 max_fails=1 fail_timeout=3s; }
server { listen 8081; # server_name *;
location / { proxy_pass http://spring-simple-rest;
proxy_http_version 1.1; proxy_set_header Host $http_host; # proxy_set_header X-Real-IP $remote_addr; # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off; } } |
아래는 모듈을 설치하여 upstream health check를 하는 my.conf의 예시이다.
server_tokens off;
upstream spring-simple-rest { least_conn; server nginx-spring-01:8091 max_fails=1 fail_timeout=3s; server nginx-spring-02:8092 max_fails=1 fail_timeout=3s; server nginx-spring-03:8093 max_fails=1 fail_timeout=3s;
check interval=1000 rise=1 fall=4 timeout=200 type=http; check_http_send "HEAD /simple/healthcheck HTTP/1.0\r\n\r\n"; check_http_expect_alive http_2xx http_3xx; }
server { listen 8081; # server_name *;
location / { proxy_pass http://spring-simple-rest;
proxy_http_version 1.1; proxy_set_header Host $http_host; # proxy_set_header X-Real-IP $remote_addr; # proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off; }
location = /nginx_status { check_status; } } |
upstream 부분에 check로 시작하는 3줄과
server { ..., location = /nginx_status {} } 부분을 추가한 것이다.
check interval=1000 rise=1 fall=4 timeout=200 type=http; 로
체크 주기, 성공 판단 수, 몇 번 실패해야 최종 실패로 보는지, 요청당 최대 시간, 요청 타입을 지정할 수 있다.
check_http_send "HEAD /simple/healthcheck HTTP/1.0\r\n\r\n"; 로
체크 request method, api 주소 등을 지정할 수 있다. 예시에서는 HEAD 방식으로 http://nginx-spring-01:8091/simple/healthcheck 등으로 API Call로 응답을 확인할 것이다.
check_http_expect_alive http_2xx http_3xx; 로
성공 판단 요청의 http status code를 지정할 수 있다.
server 블록 중 아래 check_status; 부분은 listen 포트(예시에서는 8081)의 해당 경로(예시에서는 ./nginx_status)로 접속하면 upstream 들의 상태를 확인할 수 있다.
더 상세한 설명 및 다른 추가 옵션들은 역시 공식 문서를 보시라.
https://github.com/yaoweibin/nginx_upstream_check_module#readme
[실행]
nginx 서버 실행은 그냥 옵션 없이 실행하면 된다.
% /usr/local/nginx/sbin/nginx |
실행하여 upstream 서버 중 일부를 끄고 켜보면서 확인해본다.
참고로 stop, reload 등은 -s 옵션으로 가능하다.
% /usr/local/nginx/sbin/nginx -s stop|reload|... |
잘못된 정보가 있다면, 꼭 댓글로 알려주세요(비로그인 익명도 가능).
여러분의 피드백이 저와 방문자 모두를 올바른 정보로 인도할 수 있습니다.
감사합니다. -현록