NGINX Plus 로 백엔드 업그레이드, 2부 개별 서버
이것은 NGINX Plus를 사용하여 중단 시간 없이 서버의 백엔드 업그레이드 하는 방법에 대한 시리즈의 세 포스트 중 두 번째 포스트입니다. 첫 번째 포스트에서는 다운타임 없이 백엔드 업그레이드에 사용할 수 있는 두 가지 NGINX Plus 기능(NGINX Plus API 및 애플리케이션 상태 확인)에 대해 설명하고 각 방법의 이점에 대해 설명합니다.
이 두 번째 포스트에서는 서버를 오프라인으로 전환하는 가장 일반적인 이유 중 하나인 개별 서버에서 소프트웨어 또는 하드웨어를 업그레이드 하는 것과 관련된 사용 사례를 살펴봅니다. 준비 없이 서버를 오프라인으로 전환하는 것은 최선의 방법이 아닙니다. 그러면 모든 현재 클라이언트 연결이 끊어지고 사용자 경험이 나빠지기 때문입니다. 우리가 원하는 것은 서버에 새로운 요청이나 연결을 보내는 것을 중지하고 미해결 작업을 끝내도록 하는 것입니다. 그런 다음 클라이언트에 영향을 주지 않고 안전하게 오프라인으로 전환할 수 있습니다. 이 포스트에서는 다음 NGINX Plus 기능을 사용하여 이러한 결과를 얻는 방법을 설명합니다.
[참고 – 언급된 경우를 제외하고 이 포스트는 upstream 그룹의 실시간 활동 모니터링 및 동적 구성에 NGINX Plus API를 사용하여 원래 사용되었던 별도의 상태 및 upstream Conf API를 대체하도록 업데이트되었습니다.]
목차
1. 사용 사례의 기본 구성
2. API를 사용하여 개별 서버 업그레이드
3. API를 사용하여 세션 지속성이 구성된 개별 서버 업그레이드
4. Health Checks를 사용하여 개별서버 업그레이드
5. 결론
upstream 서버 그룹에서 애플리케이션 버전 업그레이드 에 대한 사용 사례는 세 번째 포스트 NGINX Plus 로 백엔드 업그레이드, 3부 앱 버전을 참조하세요.
1. 사용 사례의 기본 구성
아래 예에서는 NGINX Plus 인스턴스에서 API 호출을 수행하므로 localhost
로 전송됩니다.
사용 사례의 기본 구성은 demoapp이라는 단일 upstream 구성 블록에 있는 두 개의 서버로 시작합니다. 첫 번째 server 구성 블록에서는 demoapp upstream 그룹에 대한 모든 요청의 부하를 분산하는 포트 80에서 수신 대기하는 가상 서버를 구성합니다.
백엔드 서버 오류가 사용자 경험에 미치는 영향을 줄이고 모니터링을 개선하기 위한 모범 사례인 애플리케이션 상태 확인을 구성하고 있습니다. 여기서는 서버가 HTTP 2xx 또는 3xx 응답 코드(상태 확인의 기본 성공 기준)와 함께 healthcheck.html 파일을 반환하는 경우 성공하도록 상태 확인을 구성합니다.
기본 상태 확인에 꼭 필요한 것은 아니지만 health_check 지시문을 자체 location 블록에 넣습니다. 이는 Health Check와 일반 트래픽에 대해 시간 제한 및 헤더와 같은 다른 설정을 구성할 수 있으므로 좋은 방법입니다. health_check
지시문에 대한 별도의 location 필요한 사용 사례는 세 번째 포스트의 카나리아 릴리스 수행을 참조하십시오.
# In the HTTP context
upstream demoapp {
zone demoapp 64k;
server 172.16.210.81:80;
server 172.16.210.82:80;
}
server {
listen 80;
status_zone demoapp;
location / {
proxy_pass http://demoapp;
}
location @healthcheck {
internal;
proxy_pass http://demoapp;
health_check uri=/healthcheck.html;
}
}
또한 NGINX Plus API(/api) 및 NGINX Plus 라이브 활동 모니터링 대시보드(/dashboard.html)에 해당하는 location에 대한 요청에 대해 포트 8080에서 수신 대기하는 두 번째 가상 서버를 구성합니다. 이러한 location 이름은 일반적인 이름이지만 원하는 경우 다른 이름을 선택할 수 있습니다.
NGINX Plus API 및 대시보드에 대한 모든 트래픽을 보호하는 것이 가장 좋습니다. 여기서는 192.168.100.0에서 192.168.100.255 범위의 내부 IP 주소에 있는 사용자에게만 액세스 권한을 부여합니다. 더 강력한 보안을 위해 클라이언트 인증서, HTTP 기본 인증 또는 인증 요청 모듈을 사용하여 LDAP와 같은 외부 인증 시스템과 통합하십시오.
# In the HTTP context
server {
listen 8080;
allow 192.168.100.0/24;
deny all;
location /api {
api write=on;
}
location = /dashboard.html {
root /usr/share/nginx/html;
}
# Redirect requests made to the pre-NGINX Plus R14 dashboard
location = /status.html {
return 301 /dashboard.html;
}
}
이 구성을 사용하면 이 포스트의 API 명령에 대한 기본 URL은 다음과 같습니다.
http://localhost:8080/api/3/http/upstreams/demoapp/servers
2. API를 사용하여 개별 서버 업그레이드
demoapp upstream 그룹(이전 섹션에서 구성)의 두 서버가 활성 상태인지 확인하기 위해 대시보드의 Upstreams 탭을 확인합니다. Requests 및 Conns 열의 0이 아닌 값은 서버가 트래픽을 처리하고 있음을 확인합니다.

이제 유지 관리를 위해 서버 172.16.210.82를 오프라인으로 전환합니다. 할당된 ID 번호를 보기 위해 기본 API 명령을 보내고 jq 유틸리티로 출력을 필터링하여 각 서버의 호스트명 또는 IP 주소 및 내부 ID만 표시합니다. 서버의 ID가 1임을 확인하고 다음 명령에서 해당 값을 사용하여 식별합니다.
$ curl -s http://localhost:8080/api/3/http/upstreams/demoapp/servers | jq -c '.peers[] | {server, id}'
{"server":"172.16.210.81:80","id":0}
{"server":"172.16.210.82:80","id":1}
서버를 다운된 것으로 표시하려면 다음 명령을 실행합니다.
$ curl -X PATCH -d '{"down":true}' http://localhost:8080/api/3/http/upstreams/demoapp/servers/1
이제 대시보드에 172.16.210.82의 활성 연결 수가 0(Conns 아래의 A 열)으로 표시되므로 유지 관리를 위해 오프라인으로 전환해도 안전합니다.

유지 관리가 완료되면 다음 명령을 실행하여 서버를 다시 온라인 상태로 만들 수 있습니다.
$ curl -X PATCH -d '{"down":false}' http://localhost:8080/api/3/http/upstreams/demoapp/servers/1
API에 명령을 보내는 대신 대시보드의 Upstreams 탭에 있는 편집 인터페이스를 사용하여 서버 상태를 변경할 수도 있습니다(서버를 가동, 중단 또는 드레이닝으로 표시). 자세한 내용은 NGINX Plus 관리자 가이드를 참조하세요.
3. API를 사용하여 세션 지속성이 구성된 개별 서버 업그레이드
세션 지속성을 활성화하면 클라이언트는 세션 동안 모든 요청에 대해 동일한 백앤드 서버로 연결됩니다. NGINX Plus는 upstream
블록에 대한 고정 지시문을 사용하여 여러 세션 지속성 방법을 지원합니다. 여기에서는 고정 쿠키 방법을 사용합니다.
# In the HTTP context
upstream demoapp {
zone demoapp 64k;
server 172.16.210.81:80;
server 172.16.210.82:80;
sticky cookie srv_id expires=1h domain=.example.com path=/;
}
세션 지속성은 사용자의 상태 정보를 유지하는 모든 애플리케이션(장바구니 등)에 필요하지만 서버를 오프라인으로 전환하기 전에 서버에 대한 활성 연결이 없을 때까지 기다리는 것만으로는 충분하지 않기 때문에 업그레이드 가 복잡해집니다. 지금은 요청을 보내지 않고 있지만 서버와의 세션을 종료하지 않은 클라이언트가 있을 수 있습니다. 최상의 사용자 경험을 위해 우리는 활성 세션을 열린 상태로 유지하려고 합니다. 시간은 애플리케이션에 따라 다르지만 새 세션이 시작되는 것은 원하지 않습니다.
다행스럽게도 NGINX Plus drain
상태는 정확히 이 작업을 수행합니다. 세션 드레이닝은 이전 섹션에서 설명한 프로세스에 한 단계를 더 추가합니다. 서버를 즉시 down
으로 표시하는 대신 다음 명령을 실행하여 서버를 drain
으로 표시합니다.
$ curl -X PATCH -d '{"drain":true}' http://localhost:8080/api/3/http/upstreams/demoapp/servers/1
이 경우 서버를 오프라인으로 전환하기 전에 활성 연결 수가 0이 되기를 원할 뿐만 아니라 모든 세션이 종료되기를 원합니다. 이는 애플리케이션에 따라 일정 시간 동안 서버가 유휴 상태임을 의미합니다. 주기적으로 대시보드를 확인하거나 상태 API를 사용하여 서버가 유휴 상태인지 확인할 수 있지만 서버 소모를 표시하고 표시하기 전에 유휴 상태임을 확인하는 프로세스를 자동화할 수도 있습니다.
예를 들어 server-drain-down.py라는 다음 Python 프로그램을 만들었습니다. upstream 그룹 이름과 서버의 IP 주소 및 포트를 입력으로 사용하고 지정된 서버를 drain으로 표시합니다. 그런 다음 60초 동안 유휴 상태이거나 세션 드레이닝이 시작된 후 5분이 지나면(서버가 유휴 상태가 아닌 경우에도) 서버를 다운 상태로 표시합니다. 프로그램은 상태 API를 사용하여 서버로 전송된 마지막 요청의 타임스탬프와 활성 연결 수를 가져옵니다. 구성 API를 사용하여 서버를 drain
으로 표시한 다음 down
합니다.
[참고 – 다음 스크립트는 NGINX Plus API를 사용하도록 업데이트 되지 않았습니다.]
#!/usr/bin/env python
################################################################################
# Copyright (C) 2016 NGINX
#
# This program is provided for demonstration purposes only and is not covered
# by your NGINX Plus support agreement.
#
# It is a proof of concept for automating the process of taking a server offline
# when it is configured for session persistence.
#
# This program takes two command line-arguments:
# - upstream group name
# - server IP address and port
#
# It uses the NGINX Plus status API to get the server's ID and the
# upstream_conf API to set the state of the server to 'drain'. It then loops,
# waiting to mark the server down until either it has been idle for a
# configured period of time or a configured maximum time has elapsed (even if
# the server is not idle).
################################################################################
import requests
import json
import sys
import time
if len(sys.argv) != 3:
print "Error: Wrong number of arguments. Usage is:"
print " server-drain-down.py "
sys.exit(1)
upstream=sys.argv[1]
server=sys.argv[2]
# The URL for the NGINX Plus status API
statusURL = 'http://localhost:8080/status'
# The URL for the NGINX Plus reconfiguration API
confURL = 'http://localhost:8080/upstream_conf'
# The time the server needs to be idle before being marked down, in seconds
maxIdleTime = 60
# The total elapsed time before marking the server down even if it isn't idle,
# in seconds
maxTime = 300
sleepInterval = 1
client = requests.Session() # Create a session for making HTTP requests
################################################################################
# Function sendRequest
#
# Send an HTTP request. Status 200 is expected for all requests.
################################################################################
def sendRequest(url):
try:
response = client.get(url) # Make an NGINX Plus status API call
if response.status_code == 200:
return response
else:
print ("Error: Response code %d") %(response.status_code)
sys.exit(1)
except requests.exceptions.ConnectionError:
print "Error: Unable to connect to " + url
sys.exit(1)
################################################################################
# Main
################################################################################
url = statusURL + '/upstreams/' + upstream + '/peers'
response = sendRequest(url)
nginxstats = json.loads(response.content) # Convert JSON to dict
id = ""
state = ""
serverFound = False
for stats in nginxstats:
if stats['server'] == server:
serverFound = True
id = stats['id']
state = stats['state']
# The last time a request was sent to this server, converted to seconds
lastSelected = stats['selected'] / 1000
break
if not serverFound:
print("Server %s not found in Upstream Group %s") %(server, upstream)
sys.exit(1)
if state == 'down':
print "The server is already marked as down"
sys.exit(0)
elif state == 'unhealthy' or state == 'unavailable':
# The server is not healthy so it won't be receiving requests and can be
# marked down
url = confURL + '?upstream=' + upstream + '&id=' + str(id) + '&down='
response = sendRequest(url)
print "The server was unhealthy or unavailable and has been marked down"
sys.exit(0)
if state == 'up':
print "Set server to drain"
url = confURL + '?upstream=' + upstream + '&id=' + str(id) + '&drain='
response = sendRequest(url)
startTime = int(time.time())
while True: # Loop forever
now = int(time.time())
totalTime = now - startTime
if totalTime >= maxTime:
print "Max time has expired. Mark server as down"
url = confURL + '?upstream=' + upstream + '&id=' + str(id) + '&down='
response = sendRequest(url)
break
idleTime = now - lastSelected
if idleTime >= maxIdleTime:
if nginxstats['active'] == 0:
print "Idle time has expired. Mark server as down"
url = confURL + '?upstream=' + upstream + '&id=' + str(id) + '&down='
response = sendRequest(url)
break
else:
print("Idle time has expired but there are still active "
"connections. %d max seconds") %(totalTime)
else:
print("Server idle for %d seconds. %d max seconds") %(idleTime, totalTime)
url = statusURL + '/upstreams/' + upstream + '/peers/' + str(id)
response = sendRequest(url)
nginxstats = json.loads(response.content)
lastSelected = nginxstats['selected'] / 1000
time.sleep(sleepInterval)
프로그램을 사용하든 서버가 유휴 상태인지 수동으로 확인하든 관계없이 서버가 다운된 후 이전 섹션에서와 같이 진행합니다.
4. Health Checks를 사용하여 개별 서버 업그레이드
사용 사례에 대한 기본 구성에서 구성한 첫 번째 server
블록에서 health_check
지시문을 사용하여 상태 확인을 설정했음을 기억하십시오. 이제 서버 상태를 제어하는 데 사용합니다. 서버가 HTTP 2xx 또는 3xx 응답 코드와 함께 healthcheck.html 파일을 반환하면 상태 확인이 성공한 것입니다.
# In the first server block
location @healthcheck {
internal;
proxy_pass http://demoapp;
health_check uri=/healthcheck.html;
}
서버를 오프라인으로 전환하려는 경우 파일 이름을 fail-healthcheck.html로 바꾸면 상태 확인이 실패합니다. NGINX Plus는 서버에 대한 새 요청 전송을 중지하지만 기존 요청이 완료되도록 허용합니다(API로 설정된 다운 상태와 동일). 상태 확인이 실패한 후에는 API를 사용하여 서버를 down
표시할 때와 마찬가지로 대시보드 또는 상태 API를 사용하여 서버를 모니터링합니다. 업그레이드 를 수행하기 위해 서버를 오프라인으로 전환하기 전에 연결이 0이 될 때까지 기다립니다. 서버가 서비스로 돌아갈 준비가 되면 파일 이름을 다시 healthcheck.html로 바꾸고 상태 확인이 다시 한 번 성공합니다.
앞서 언급한 바와 같이 상태 확인을 통해 서버가 전체 트래픽 공유를 수신할 준비가 되기 전에 약간의 준비 시간이 필요한 경우 느린 시작 기능(slow_start)을 사용할 수 있습니다. 여기서는 upstream 그룹의 서버를 수정하여 NGINX Plus가 트래픽이 발생한 후 30초 동안 점진적으로 트래픽을 증가시키도록 합니다.
# In the HTTP context
upstream demoapp {
zone demoapp 64K;
server 172.16.210.81:80 slow_start=30s;
server 172.16.210.82:80 slow_start=30s;
sticky cookie srv_id expires=1h domain=.example.com path=/;
}
5. 결론
NGINX Plus는 운영 및 DevOps 엔지니어에게 개별 서버에서 소프트웨어 및 하드웨어 업그레이드 를 관리하는 동시에 다운타임을 방지하여 우수한 고객 경험을 지속적으로 제공하기 위한 여러 옵션을 제공합니다.
이 시리즈의 다른 두 포스트를 확인하십시오.
- 업그레이드 방법 개요
- 트래픽을 완전히 다른 서버 또는 upstream 그룹으로 전환하여 새 버전의 애플리케이션으로 업그레이드
NGINX Plus를 직접 사용해 보고 어떻게 업그레이드 를 더 쉽고 효율적으로 하는 확인하십시오. 오늘 30일 무료 평가판을 시작하거나 당사에 연락하여 사용 사례에 대해 논의하십시오.
사용 사례에 대해 최신 소식을 빠르게 전달받고 싶으시면 아래 뉴스레터를 구독하세요.
댓글을 달려면 로그인해야 합니다.