NGINX 로드 밸런서와 Consul 템플릿

NGINX 로드 밸런서와 Consul 템플릿 (NGINX Load Balancer with Consul Template)

이 튜토리얼은 Consul과 Consul template을 사용해 최신 백엔드 서버 목록으로 NGINX 구성 파일을 자동 업데이트하는 방법을 설명해요. 서비스 등록, 템플릿 구성, 스케일링과 헬스 체크 테스트까지 실습해 볼게요.

출처: 문서

본문

이 튜토리얼은 Consul의 서비스 디스커버리를 사용해 최신 백엔드 서버 목록으로 NGINX 구성 파일을 자동으로 업데이트하는 데 Consul과 Consul template을 사용하는 방법을 설명합니다.

이 튜토리얼을 따르면서 다음을 하게 됩니다:

  • 예제 서비스를 Consul에 등록
  • Consul template 구성
  • NGINX 로드 밸런서 구성 템플릿 생성
  • Consul template 실행
  • 서버 스케일링
  • Consul 헬스 체크 테스트

이 튜토리얼을 완료하면 아래 다이어그램과 같은 아키텍처가 완성됩니다. NGINX는 Consul template을 통해 Consul 서비스 디스커버리에서 정상(healthy) 서버 목록을 받아 자체 구성에 따라 인터넷 트래픽을 그 서버들로 분산합니다.

선행 요구 사항 (Prerequisites)

이 튜토리얼을 완료하려면 다음이 필요합니다:

  • Consul 클러스터. Consul 서버 노드 3개를 권장합니다.
  • 노드에 Consul 클라이언트 에이전트가 실행 중이고 Consul 서비스 디스커버리에 등록된 애플리케이션 서버 최소 2개(다음 예제에서는 HTTP 포트 80에서 수신하는 표준 웹 서버를 가정합니다)
  • NGINX가 실행되는 노드
  • NGINX 노드의 Consul 클라이언트 에이전트
  • NGINX 구성 파일을 최신 상태로 유지하기 위한 NGINX 노드의 Consul-template

팁

이 튜토리얼의 내용은 HashiCorp Cloud (HCP)에 호스팅된 Consul 클러스터에도 적용됩니다.

웹 서버를 Consul에 등록 (Register your web servers to Consul)

아직 Consul 서비스 레지스트리에 웹 서버를 등록하지 않았다면 Consul의 구성 디렉터리 /etc/consul.d/에 웹 서비스용 서비스 정의를 만드세요.

다음 내용으로 web 서비스용 서비스 등록 파일을 만듭니다.

HCL

JSON

web-service.hcl:

service {
  name = "web"
  port = 80
  check {
    args = ["curl", "localhost"]
    interval = "3s"
  }
}

web-service.json:

{
  "service": {
    "Name": "web",
    "Port": 80,
    "check": {
      "args": ["curl", "localhost"],
      "interval": "3s"
    }
  }
}

이 서비스 정의에는 웹 서버용 기본 "curl" 헬스 체크가 포함되어 있으므로 웹 서버가 실행되는 Consul 에이전트의 구성에서 enable_local_script_checks를 true로 설정해야 합니다.

새 서비스 정의를 읽도록 로컬 Consul 에이전트를 리로드합니다.

$ consul reload

서비스를 등록하면 Consul 서비스 레지스트리에 나타납니다.

모든 웹 서버 인스턴스에 대해 등록 단계를 반복하면 모든 인스턴스가 "web" 서비스의 인스턴스 보기에 나타납니다.

Consul template 구성 (Configure Consul template)

Consul template 구성 파일은 사용할 입력 템플릿, 생성할 출력 파일, 그리고 새 구성으로 Consul template의 대상 애플리케이션(이 튜토리얼에서는 NGINX)을 리로드할 명령을 지정합니다.

다음 내용으로 consul-template-config.hcl이라는 구성 파일을 만드세요.

consul-template-config.hcl:

consul {
  address = "localhost:8500"

  retry {
    enabled  = true
    attempts = 12
    backoff  = "250ms"
  }
}
template {
  source      = "/etc/nginx/conf.d/load-balancer.conf.ctmpl"
  destination = "/etc/nginx/conf.d/load-balancer.conf"
  perms       = 0600
  command     = "service nginx reload"
}

consul 스탠자는 consul-template에 Consul API를 어디서 찾을지 알려줍니다. 우리는 NGINX 인스턴스와 같은 노드에서 Consul 클라이언트 에이전트를 실행하므로 localhost에 있습니다.

template 스탠자는 Consul template에 다음을 알려줍니다:

  • source(입력) 템플릿 파일이 위치할 곳(이 경우 /etc/nginx/conf.d/load-balancer.conf.ctmpl)
  • destination(출력) 파일이 위치해야 할 곳(이 경우 /etc/nginx/conf.d/load-balancer.conf. 이것은 NGINX가 구성을 읽는 기본 경로입니다. NGINX 배포판에 따라 이 경로나 /usr/local/nginx/conf/를 사용합니다.)
  • destination 파일에 필요한 permissions
  • destination 파일을 렌더링한 후 실행할 명령. 이 경우 service nginx reload는 NGINX가 구성을 리로드하도록 트리거합니다.

Consul template의 모든 사용 가능한 구성 옵션은 GitHub 저장소를 참조하세요.

입력 템플릿 생성 (Create an input template)

이제 Consul template이 NGINX 로드 밸런서 인스턴스의 최종 load-balancer.conf를 렌더링하는 데 사용할 기본 NGINX 로드 밸런서 구성 템플릿을 만듭니다.

source로 지정한 위치(이 예제에서는 /etc/nginx/conf.d/)에 다음 내용으로 load-balancer.conf.ctmpl이라는 템플릿 파일을 만듭니다:

/etc/nginx/conf.d/load-balancer.conf.ctmpl:

upstream backend {
{{- range service "web" }}
  server {{ .Address }}:{{ .Port }};
{{- end }}
}

server {
   listen 80;

   location / {
      proxy_pass http://backend;
   }
}

로드 밸런서 구성 파일에 백엔드 서버 IP 주소를 직접 명시하는 대신, Consul template의 템플릿 언어를 사용해 이 파일에 일부 변수를 지정합니다. 그러면 최종 값이 Consul 서비스 레지스트리에서 자동으로 가져와져 최종 로드 밸런서 구성 파일이 렌더링됩니다.

구체적으로 위 템플릿 파일의 아래 스니펫은 Consul template이 현재 데이터센터의 "web" 서비스의 모든 정상 노드를 Consul 서비스 레지스트리에서 조회하고, 그 엔드포인트의 IP 주소와 서비스 포트를 생성된 출력 구성 파일에 넣도록 지시합니다.

{{- range service "web" }}
  server {{ .Address }}:{{ .Port }};
{{- end }}

Consul template과 함께 사용할 템플릿 파일을 만드는 방법의 모든 옵션은 GitHub 저장소를 참조하세요.

NGINX 기본 사이트 구성 정리 (Clean up NGINX default sites config)

NGINX 인스턴스가 웹 서버가 아닌 로드 밸런서로 동작하도록 하려면 다음 파일이 존재하면 삭제하세요.

/etc/nginx/sites-enabled/default

그런 다음 NGINX 서비스를 리로드합니다.

$ service nginx reload

이제 NGINX 로드 밸런서에는 어떤 구성도 없으며 NGINX IP 주소로 브라우징하면 웹 페이지가 보이지 않아야 합니다.

Consul template 실행 (Run Consul template)

앞서 생성한 구성 파일로 Consul template을 시작합니다.

$ consul-template -config=consul-template-config.hcl

이렇게 하면 프로세스를 중지할 때까지 Consul template이 포그라운드에서 실행됩니다. 자동으로 Consul API에 연결하고 NGINX 구성을 렌더링하며 NGINX 서비스를 리로드합니다.

이제 NGINX 로드 밸런서는 트래픽을 제공하고 등록된 정상 "web" 서버 인스턴스들 사이에서 간단한 라운드 로빈 로드 밸런싱을 수행해야 합니다.

/etc/nginx/conf.d/load-balancer.conf에 위치한 결과 로드 밸런서 구성은 다음과 같아야 합니다:

/etc/nginx/conf.d/load-balancer.conf:

upstream backend {
  server 192.168.43.101:80;
  server 192.168.43.102:80;
}

server {
   listen 80;

   location / {
      proxy_pass http://backend;
   }
}

Consul template이 템플릿 파일의 변수를 "web" 서버의 실제 IP 주소와 포트로 채운 것을 확인하세요.

구현 검증 (Verify your implementation)

이제 모든 것이 설정되고 실행 중이므로, 서비스를 스케일하거나 중지할 때 어떤 일이 일어나는지 지켜보며 구현을 테스트합니다. 두 경우 모두 Consul template이 NGINX 구성을 최신 상태로 유지해야 합니다.

백엔드 서비스 스케일링 (Scale your backend services)

Consul template은 Consul API에 대한 장기 실행 HTTP 쿼리(블로킹 쿼리)를 사용하며, 요청한 서비스 "web"의 업데이트에 대한 즉각적인 알림을 받습니다.

"web"을 스케일하고 새 인스턴스가 Consul 서비스 레지스트리에 등록되는 즉시 Consul template은 서비스의 변경을 보고 구성 파일의 새 생성을 트리거합니다.

백엔드 서버를 두 개에서 세 개 인스턴스로 스케일한 후 /etc/nginx/conf.d/load-balancer.conf에 위치한 NGINX 인스턴스용 결과 로드 밸런서 구성은 다음과 같아야 합니다:

/etc/nginx/conf.d/load-balancer.conf:

upstream backend {
  server 192.168.43.101:80;
  server 192.168.43.102:80;
  server 192.168.43.103:80;
}

server {
   listen 80;

   location / {
      proxy_pass http://backend;
   }
}

웹 서비스 인스턴스에 오류 발생시키기 (Cause an error in a web service instance)

Consul template은 사용 가능한 서비스 엔드포인트에 따라 백엔드 구성을 자동으로 업데이트할 뿐만 아니라, 최종 구성을 렌더링할 때 정상 엔드포인트만 사용합니다.

서비스 정의에서 Consul이 기본 curl 기반 헬스 체크를 수행하도록 구성했으므로, Consul은 "web" 서버 인스턴스가 비정상(unhealthy) 상태임을 알게 됩니다.

오류를 시뮬레이션하고 Consul 헬스 체크가 어떻게 작동하는지 보려면 웹 프로세스 인스턴스 하나를 중지하세요.

$ service nginx stop

이 노드에서 HTTP 포트 80의 요청에 응답하는 서비스가 없으므로 Consul UI에서 이 서비스 인스턴스의 상태가 "Unhealthy"로 표시됩니다.

Consul API에 대한 블로킹 쿼리 때문에 Consul template은 서비스 엔드포인트 중 하나의 건강 상태가 변경되었다는 알림을 즉시 받고, 비정상 인스턴스를 제외한 새 로드 밸런서 구성 파일을 다시 렌더링합니다:

/etc/nginx/conf.d/load-balancer.conf:

upstream backend {
  server 192.168.43.101:80;
  server 192.168.43.103:80;
}

server {
   listen 80;

   location / {
      proxy_pass http://backend;
   }
}

이제 NGINX 인스턴스는 남은 정상 서비스 엔드포인트들 사이에서만 트래픽을 분산합니다.

중지한 "web" 서버 인스턴스를 다시 시작하고 Consul 헬스 체크가 서비스 엔드포인트를 다시 "Healthy"로 표시하는 즉시 프로세스가 자동으로 다시 시작되어 그 인스턴스가 트래픽 제공을 위해 로드 밸런서 백엔드 구성에 포함됩니다:

/etc/nginx/conf.d/load-balancer.conf:

upstream backend {
  server 192.168.43.101:80;
  server 192.168.43.102:80;
  server 192.168.43.103:80;
}

server {
   listen 80;

   location / {
      proxy_pass http://backend;
   }
}

Consul 헬스 체크는 훨씬 더 정교해질 수 있습니다. 중앙 로드 밸런싱 인스턴스에서 모니터링할 수 없는 CPU 또는 RAM 사용률이나 다른 서비스 메트릭을 체크할 수 있습니다. Consul의 헬스 체크 기능에 대해 더 자세히 알아보려면 여기를 참조하세요.

다음 단계 (Next steps)

이 튜토리얼에서는 Consul template이 Consul 서비스 레지스트리에 등록된 사용 가능하고 정상인 서비스 엔드포인트를 기반으로 NGINX 로드 밸런서의 구성을 생성할 수 있음을 발견했습니다. 새 서비스 엔드포인트가 시작되거나 삭제될 때마다 NGINX 로드 밸런서를 수동으로 재구성하지 않고도 서비스를 스케일 업/다운하는 방법을 배웠습니다.

Consul template이 Consul HTTP API에 대한 블로킹 쿼리를 사용해 서비스 변경에 대한 즉각적인 알림을 받고 필요한 구성 파일을 자동으로 다시 렌더링하는 방법을 배웠습니다.

이 튜토리얼은 consul template을 사용해 NGINX를 구성하는 방법을 설명했지만, 유사한 과정이 다른 로드 밸런서에도 적용됩니다. 다른 로드 밸런서를 사용하려면 NGINX 입력 템플릿, 출력 파일, 리로드 명령, 그리고 NGINX CLI 명령을 교체하면 됩니다.

Consul 서비스 등록 및 발견과 Consul template에 대해 더 알아보세요.

더 알아보기 (Learn more)