NGINX Plus Sidecar Proxy 배포 및 Prometheus를 통한 메트릭 수집

해당 포스트에서는 NGINX Plus Sidecar Proxy 배포 및 Prometheus를 통해 메트릭을 수집하는 방법에 대해 다룹니다.

DevOps 및 Cloud Native 환경에서 마이크로서비스를 관리하고 모니터링하는 것은 매우 중요합니다. NGINX Plus를 Sidecar Proxy 형태로 배포하고 Prometheus를 통해 성능 Metrics를 수집할 수 있습니다.

이 포스트에서는 Sidecar Proxy의 기본 개념부터 설정, 그리고 Prometheus와의 연동까지 단계별로 설명합니다.

목차

1. NGINX Plus Sidecar Proxy 소개
 1-1. Sidecar Proxy란?
 1-2. NGINX Plus의 주요 기능
 1-3. NGINX Plus Sidecar Proxy의 이점
2. NGINX Plus Sidecar Proxy 배포
 2-1. Sidecar Proxy 아키텍처
 2-2. 배포를 위한 요구 사항
 2-3. NGINX Plus Sidecar Proxy 설정 방법
3. Prometheus를 통한 NGINX Plus Sidecar Proxy 메트릭 수집
 3-1. Prometheus란?
 3-2. NGINX Plus Sidecar Proxy와 Prometheus 통합
  3-2-1. NGINX Plus Prometheus-njs 모듈을 통한 Prometheus 통합
  3-2-2. NGINX Exporter를 통한 Prometheus 통합
 3-3. 메트릭 수집 및 Dashboard 설정 가이드
4. 결론

1. NGINX Plus Sidecar Proxy 소개

NGINX Plus는 고급 기능과 더불어 Sidecar Proxy로서도 뛰어난 성능을 발휘합니다.
NGINX Plus Sidecar Proxy는 마이크로서비스 아키텍처에서 서비스 간 통신을 관리하고 최적화하는 강력한 도구입니다. Sidecar Proxy 패턴은 주로 Service Mesh 아키텍처에서 사용되며, 각 마이크로서비스 옆에 배치되어 트래픽을 관리하고 보안을 강화합니다.

1-1. Sidecar Proxy란?

NGINX Plus Sidecar Proxy Architecture 2

Sidecar Proxy는 마이크로서비스 아키텍처에서 개별 서비스에 부속되어 동작하는 프록시입니다.

이 프록시는 서비스 간 통신을 처리하고, 로깅, 모니터링, 보안과 같은 부가 기능을 제공합니다.
Sidecar Proxy는 네트워크 트래픽을 관찰하고 제어할 수 있어 서비스의 안정성과 성능을 향상시킵니다.

1-2. NGINX Plus의 주요 기능

NGINX Plus는 오픈소스 버전인 NGINX의 상업용 (Enterprise) 버전으로, Load Balancing, Content Caching, SSL/TLS Termination, 동적 재구성 등의 기능을 제공합니다. 또한, 모니터링 및 관리 기능이 추가되어 Cloud Native 환경에서의 운영 효율성을 크게 높여줍니다.

1-3. NGINX Plus Sidecar Proxy의 이점

NGINX Plus Sidecar Proxy Architecture 3

NGINX Plus를 Sidecar Proxy로 사용하면, 서비스 간 통신의 보안이 강화되고, 성능 최적화가 가능합니다. 또한, NGINX Plus의 Advanced Load Balancing과 세션 지속성 관리 기능을 통해 마이크로서비스의 가용성과 신뢰성을 높일 수 있습니다. Prometheus와 같은 모니터링 툴과의 통합을 통해 실시간 메트릭 수집 및 분석이 용이합니다.

2. NGINX Plus Sidecar Proxy 배포

NGINX Plus Sidecar Proxy 배포는 서비스 간 통신을 최적화하고 보안을 강화하는 데 중요한 역할을 합니다. 이 목차에서는 Sidecar Proxy 아키텍처의 구성 요소와 배포 절차를 자세히 설명합니다.

2-1. Sidecar Proxy 아키텍처

Sidecar Proxy 아키텍처는 각 마이크로서비스와 함께 배치된 프록시 인스턴스로 구성됩니다. 이 프록시는 서비스로 들어오고 나가는 트래픽을 제어하며, 중앙 집중식 Service Mesh 관리와 달리 개별 서비스에 맞춤형 설정을 적용할 수 있습니다. 아키텍처의 주요 구성 요소로는 프록시 서버, 서비스 인스턴스, 그리고 Control Plane이 있습니다.

2-2. 배포를 위한 요구 사항

NGINX Plus Sidecar Proxy를 배포하기 위해서는 몇 가지 필수 요구 사항을 충족해야 합니다. 먼저 NGINX Plus Sidecar Proxy를 배포하기 위한 NGINX Plus의 상업용 라이선스가 필요하며, Prometheus와의 통합을 위해 적절한 네트워크 및 방화벽 설정과 포트 Mapping이 필요합니다.

NGINX Plus 상업용 라이선스에 대한 자세한 내용은 NGINX STORE를 통해 문의해 보세요.

2-3. NGINX Plus Sidecar Proxy 설정 방법

Deployment를 통해 배포될 NGINX의 프록시 구성을 위한 ConfigMap을 우선적으로 배포합니다.

다음은 Sidecar Proxy 형태로 주입된 NGINX Plus 컨테이너에 삽입될 Proxy 구성 NGINX configmap 입니다.

sidecar-nginx.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx-conf
data:
  nginx.conf: |
    user nginx;
    worker_processes  auto;

    error_log  /var/log/nginx/error.log notice;
    pid        /var/run/nginx.pid;


    events {
        worker_connections  1024;
    }


    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;

        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';

        access_log  /var/log/nginx/access.log  main;

        sendfile        on;
        #tcp_nopush     on;

        keepalive_timeout  65;

        #gzip  on;

        include /etc/nginx/conf.d/*.conf;
    }
  default.conf: |
    upstream nodejs {
      zone nodejs 64k;
      server localhost:3000; # nodejs 컨테이너 프록시
    }
    server {
    listen       80;
    server_name  localhost;

    #access_log  /var/log/nginx/host.access.log  main;

    location / {
      proxy_pass http://nodejs$request_uri;
      status_zone backend;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    }
    server {
      listen 8080; # 대시보드 활성화

      location /api {
        api write=on;
        allow all;
        #deny;
        access_log /dev/null;
      }

      location = /dashboard.html {
          root /usr/share/nginx/html;
      }
    }
#  kubectl get configmaps

NAME               DATA   AGE
nginx-conf         2      7d

NGINX를 Sidecar Proxy를 프록시 인스턴스와 함께 클러스터에 배포하려면, NGINX를 별도의 컨테이너로 정의하고 동일한 Pod 내에서 배포해야 합니다. 이를 위해 Deployment의 spec.template.spec.containers 섹션에 NGINX를 추가해야 합니다.

다음은 Node.js로 작성된 간단한 응답용 Deployment에 NGINX Plus Sidecar Proxy를 Injection 하는 yaml 파일입니다.

nodejs-app-with-nginxplus.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nodejs-app-deployment
  labels:
    app: nodejs-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nodejs-app
  template:
    metadata:
      labels:
        app: nodejs-app
    spec:
      imagePullSecrets:
        - name: <private-registry-secret> # NGINX Plus 이미지가 포함된 개인 이미지 레지스트리 시크릿
      containers:
      - name: nodejs-app-container
        image: nginxstore/example-response-nodejs:latest # NGINX STORE 제공 nodejs 컨테이너 이미지
        ports:
        - containerPort: 3000
        resources:
          limits:
            memory: "128Mi"
            cpu: "500m"
          requests:
            memory: "64Mi"
            cpu: "250m"
      - name: sidecar-nginx
        image: <private.docker.nginxstore.com/nginx-plus/nginx-plus:r32> # NGINX Plus가 포함된 개인 이미지 레지스트리 주소로 변경
        ports:
        - containerPort: 80
        - containerPort: 8080
        volumeMounts:
        - name: nginx-conf
          mountPath: /etc/nginx/nginx.conf
          subPath: nginx.conf
        - name: nginx-conf
          mountPath: /etc/nginx/conf.d/default.conf #컨테이너에 마운트될 경로
          subPath: default.conf
          readOnly: true
      volumes:
        - name: nginx-conf
          configMap:
            name: nginx-conf
# kubectl get deployments.apps

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
nodejs-app-deployment   1/1     1            1           6m28s

# kubectl get pods

NAME                                     READY   STATUS    RESTARTS   AGE
nodejs-app-deployment-75c5b7c797-b8skw   2/2     Running   0          6m24s

Pods 접근을 위한 Service를 배포합니다.

nodejs-app-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: nodejs-service
spec:
  selector:
    app: nodejs-app
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP
      name: nginx
    - port: 8080 # NGINX Plus API 및 Dashboard 접근 포트
      targetPort: 8080
      protocol: TCP
      name: nginx-api
  type: NodePort
# kubectl get services

NAME             TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                       AGE
nodejs-service   NodePort   10.101.51.199   <none>        80:32547/TCP,8080:31716/TCP   7m42s

3. Prometheus를 통한 NGINX Plus Sidecar Proxy 메트릭 수집

Prometheus는 오픈 소스 모니터링 및 경고 도구로, NGINX Plus Sidecar Proxy에서 발생하는 다양한 메트릭을 수집하고 시각화할 수 있습니다. 이 섹션에서는 Prometheus를 사용하여 NGINX Plus의 성능 데이터를 수집하는 방법을 설명합니다.

3-1. Prometheus란?

Prometheus는 시계열 데이터베이스로서, 주기적으로 메트릭을 수집하고 이를 기반으로 대시보드를 구성합니다. 클라우드 네이티브 애플리케이션의 모니터링을 위해 설계되었으며, 다양한 Exporter를 통해 다양한 데이터 소스를 지원합니다. 특히, HTTP 기반 메트릭 수집에 최적화되어 있어 NGINX Plus와의 통합에 적합합니다.

3-2. NGINX Plus Sidecar Proxy와 Prometheus 통합

NGINX Plus와 Prometheus를 통합하려면, NGINX Plus의 stub_status 또는 ngx_http_api_module을 활성화하여 메트릭을 노출시켜야 합니다. Prometheus는 이 엔드포인트를 주기적으로 조회하여 데이터를 수집합니다. 수집된 메트릭은 로드 밸런싱 상태, 요청 처리 시간, 에러율 등 NGINX Plus의 성능을 실시간으로 파악하는 데 사용됩니다.

3-2-1. NGINX Plus Prometheus-njs 모듈을 통한 Prometheus 통합

NGINX Plus의 고유 모듈인 Promtheus-njs 모듈을 통해 NGINX Plus Sidecar Proxy에서 직접 Prometheus 통합을 구현할 수 있습니다.
Prometheus-njs 모듈에 대한 정보는 NGINX STORE의 Prometheus-njs 문서를 확인하세요.

K8s 환경에서 Prometheus-njs 모듈이 포함된 NGINX Plus Sidecar Proxy를 배포하기 위해 Prometheus-njs 모듈이 포함된 NGINX Plus 이미지를 빌드해야 합니다.

다음과 같은 Dockerfile 작성으로 Prometheus-njs 모듈이 포함된 Sidecar Proxy용 NGINX Plus 이미지를 빌드할 수 있습니다.

ARG RELEASE=bookworm
FROM debian:${RELEASE}-slim

LABEL maintainer="NGINX Docker Maintainers <docker-maint@nginx.com>"

RUN --mount=type=secret,id=nginx-crt,dst=nginx-repo.crt \
    --mount=type=secret,id=nginx-key,dst=nginx-repo.key \
    set -x \
    && groupadd --system --gid 101 nginx \
    && useradd --system --gid nginx --no-create-home --home /nonexistent --comment "nginx user" --shell /bin/false --uid 101 nginx \
    && apt-get update \
    && apt-get install --no-install-recommends --no-install-suggests -y ca-certificates gnupg2 lsb-release \
    && \
    NGINX_GPGKEY=573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62; \
    NGINX_GPGKEY_PATH=/usr/share/keyrings/nginx-archive-keyring.gpg; \
    export GNUPGHOME="$(mktemp -d)"; \
    found=''; \
    for server in \
        hkp://keyserver.ubuntu.com:80 \
        pgp.mit.edu \
    ; do \
        echo "Fetching GPG key $NGINX_GPGKEY from $server"; \
        gpg --keyserver "$server" --keyserver-options timeout=10 --recv-keys "$NGINX_GPGKEY" && found=yes && break; \
    done; \
    test -z "$found" && echo >&2 "error: failed to fetch GPG key $NGINX_GPGKEY" && exit 1; \
    gpg --export "$NGINX_GPGKEY" > "$NGINX_GPGKEY_PATH" ; \
    rm -rf "$GNUPGHOME"; \
    apt-get remove --purge --auto-remove -y gnupg2 && rm -rf /var/lib/apt/lists/* \
    && nginxPackages=" \
        nginx-plus \
        nginx-plus-module-njs \
        nginx-plus-module-prometheus\
    " \
    && echo "Acquire::https::pkgs.nginx.com::Verify-Peer \"true\";" > /etc/apt/apt.conf.d/90nginx \
    && echo "Acquire::https::pkgs.nginx.com::Verify-Host \"true\";" >> /etc/apt/apt.conf.d/90nginx \
    && echo "Acquire::https::pkgs.nginx.com::SslCert     \"/etc/ssl/nginx/nginx-repo.crt\";" >> /etc/apt/apt.conf.d/90nginx \
    && echo "Acquire::https::pkgs.nginx.com::SslKey      \"/etc/ssl/nginx/nginx-repo.key\";" >> /etc/apt/apt.conf.d/90nginx \
    && echo "deb [signed-by=$NGINX_GPGKEY_PATH] https://pkgs.nginx.com/plus/debian `lsb_release -cs` nginx-plus\n" > /etc/apt/sources.list.d/nginx-plus.list \
    && mkdir -p /etc/ssl/nginx \
    && cat nginx-repo.crt > /etc/ssl/nginx/nginx-repo.crt \
    && cat nginx-repo.key > /etc/ssl/nginx/nginx-repo.key \
    && apt-get update \
    && apt-get install --no-install-recommends --no-install-suggests -y $nginxPackages curl gettext-base \
    && apt-get install libpcre3-dev libssl-dev zlib1g zlib1g-dev net-tools vim -y \
    && apt-get remove --purge -y lsb-release \
    && apt-get remove --purge --auto-remove -y && rm -rf /var/lib/apt/lists/* /etc/apt/sources.list.d/nginx-plus.list \
    && rm -rf /etc/apt/apt.conf.d/90nginx /etc/ssl/nginx \
    && ln -sf /dev/stdout /var/log/nginx/access.log \
    && ln -sf /dev/stderr /var/log/nginx/error.log

EXPOSE 80

STOPSIGNAL SIGQUIT

CMD ["nginx", "-g", "daemon off;"]

작성한 Dockerfile을 빌드합니다.

docker build --no-cache -t nginxplus --secret id=nginx-crt,src=/path/to/your/nginx-repo.crt --secret id=nginx-key,src=/path/to/your/nginx-repo.key .

생성된 이미지를 NGINX Plus Sidecar Proxy 이미지로 사용합니다.

# docker images

REPOSITORY                                                               TAG       IMAGE ID       CREATED             SIZE
nginxplus                                                                latest    3ca5f6b60383   About an hour ago   267MB

NGINX STORE의 Prometheus-njs 문서를 참고하여 2-3. NGINX Plus Sidecar Proxy 설정 방법 목차의 ConfigMap을 수정합니다.

3-2-2. NGINX Exporter를 통한 Prometheus 통합

2-3. NGINX Plus Sidecar Proxy 설정 방법 목차에서 활성화 한 NGINX Plus API를 수집하기 위해 NGINX Plus API 메트릭을 Prometheus 형식 메트릭으로 변환하는 NGINX Exporter를 배포합니다.

nginx-exporter-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-exporter
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-exporter
  template:
    metadata:
      labels:
        app: nginx-exporter
    spec:
      containers:
      - name: nginx-exporter
        image: nginx/nginx-prometheus-exporter:0.10.0
        env:
        - name: NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        args:
          - -nginx.plus
          - -nginx.scrape-uri=http://nodejs-service.$(NAMESPACE).svc.cluster.local:8080/api
        ports:
        - name: metrics
          containerPort: 9113
# kubectl get pods

NAME                                     READY   STATUS    RESTARTS   AGE
nginx-exporter-75678864d9-blc58          1/1     Running   0          5s

NGINX Exporter 파드를 노출시키기 위해 NodePort Type의 서비스를 배포합니다.

apiVersion: v1
kind: Service
metadata:
  name: nginx-exporter-service
  labels:
    app: nginx-exporter
spec:
  type: NodePort
  ports:
  - port: 9113
    targetPort: 9113
    protocol: TCP
  selector:
    app: nginx-exporter
# kubectl get services

NAME                     TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)                       AGE
nginx-exporter-service   NodePort   10.102.185.225   <none>        9113:30956/TCP                3s

NGINX Exporter의 메트릭을 수집하는 Prometheus를 Pods 형태로 배포합니다. 메트릭 수집 사전 구성을 위한 Prometheus ConfigMap을 우선적으로 배포합니다.

Prometheus 배포는 개별 네임스페이스인 'prometheus' 네임스페이스에 배포를 진행합니다.

prometheus-configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-config
  namespace: prometheus
data:
  prometheus.yml: |
    global:
      scrape_interval: 15s
    scrape_configs:
      - job_name: 'node1'
        static_configs:
          - targets: ['nginx-exporter-service.node1.svc.cluster.local:9113'] #node1은 NGINX Exporter 서비스가 배포된 Namespace로 변경
# kubectl get configmaps

NAME                DATA   AGE
prometheus-config   1      7d

Deployment 파일 작성을 통해 Prometheus를 배포하고 ConfigMap을 통해 Volume을 설정합니다.

prometheus-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: prometheus-deployment
  namespace: prometheus
  labels:
    app: prometheus
spec:
  replicas: 1
  selector:
    matchLabels:
      app: prometheus
  template:
    metadata:
      labels:
        app: prometheus
    spec:
      containers:
      - name: prometheus
        image: prom/prometheus:v2.45.0
        ports:
        - containerPort: 9090
        volumeMounts:
        - name: prometheus-config-volume
          mountPath: /etc/prometheus/
      volumes:
      - name: prometheus-config-volume
        configMap:
          name: prometheus-config
# kubectl get deployments.app

NAME                    READY   UP-TO-DATE   AVAILABLE   AGE
prometheus-deployment   1/1     1            1           7d

# kubectl get pods

NAME                                     READY   STATUS    RESTARTS   AGE
prometheus-deployment-745dd4f674-mmrn2   1/1     Running   0          6d23h

Prometheus 파드의 외부 접근을 위한 NodePort Type의 서비스를 배포합니다.

apiVersion: v1
kind: Service
metadata:
  name: prometheus-service
  labels:
    app: prometheus
spec:
  type: NodePort
  ports:
  - port: 9090
    targetPort: 9090
    protocol: TCP
    nodePort: 30090  # 노드의 포트 설정 (수정 가능)
  selector:
    app: prometheus
# kubectl get services

NAME                 TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
prometheus-service   NodePort   10.104.33.137   <none>        9090:30090/TCP   7d

3-3. 메트릭 수집 및 Dashboard 설정 가이드

NGINX Exporter가 Sidecar Proxy로 배포된 NGINX Plus Pods의 메트릭을 정상적으로 수집하고, Prometheus 형식으로 노출하고 있는지 확인하기 위해 NodePort Type의 서비스로 접근합니다.

$ curl 192.168.200.100:30956/metrics

# HELP nginxexporter_build_info Exporter build information
# TYPE nginxexporter_build_info gauge
nginxexporter_build_info{commit="7a03d0314425793cf4001f0d9b0b2cfd19563433",date="2021-12-21T19:24:34Z",version="0.10.0"} 1
# HELP nginxplus_connections_accepted Accepted client connections
# TYPE nginxplus_connections_accepted counter
nginxplus_connections_accepted 34
. . .
# TYPE nginxplus_location_zone_responses counter
nginxplus_location_zone_responses{code="1xx",location_zone="backend"} 0
nginxplus_location_zone_responses{code="2xx",location_zone="backend"} 56
nginxplus_location_zone_responses{code="3xx",location_zone="backend"} 9
nginxplus_location_zone_responses{code="4xx",location_zone="backend"} 2
nginxplus_location_zone_responses{code="5xx",location_zone="backend"} 0
# HELP nginxplus_location_zone_sent Bytes sent to clients
# TYPE nginxplus_location_zone_sent counter
nginxplus_location_zone_sent{location_zone="backend"} 15748

다른 NameSpace에 배포된 Prometheus가 NGINX Exporter의 메트릭을 정상적으로 수집할 수 있는지 cURL과 브라우저 도구를 통해 확인합니다.

$ curl 192.168.200.100:30090/metrics

# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 6.202e-05
go_gc_duration_seconds{quantile="0.25"} 0.000127171
go_gc_duration_seconds{quantile="0.5"} 0.000191506
go_gc_duration_seconds{quantile="0.75"} 0.000261089
go_gc_duration_seconds{quantile="1"} 0.001693722

. . .

Prometheus가 다른 Namespace에 존재하는 NGINX Plus Sidecar Proxy의 API 메트릭을 NGINX Exporter를 통해 수집할 수 있음을 확인할 수 있습니다.

4. 결론

이번 포스트에서는 NGINX Plus Sidecar Proxy를 배포하고 Prometheus를 통해 메트릭을 수집하는 방법을 다뤘습니다.
NGINX Plus의 강력한 기능과 Sidecar Proxy 패턴을 활용하면 마이크로서비스 간 통신을 효율적으로 관리할 수 있으며, Prometheus를 통해 실시간으로 성능을 모니터링할 수 있습니다.

NGINX Plus와 같은 고급 도구를 활용하여 클라우드 네이티브 환경에서의 운영을 최적화하는 방법을 연구하고 싶으신가요?
NGINX STORE의 Kubernetes 카테고리를 참고하거나 NGINX STORE에 문의하여 사용 사례에 대해 상담 받아보세요.

NGINX 및 NGINX Plus에 대한 상담이 필요하다면 아래 Form을 통해 NGINX STORE에게 연락해주세요.