쿠버네티스 Rate Limit 제한하기 – NGINX Plus Ingress Controller
이 포스트에서는 쿠버테니스 환경에서 가장 많이 사용되는 NGINX Ingress Controller의 프로덕션급인 NGINX Plus Ingress Controller 에서 사용할 수 있는 VirtualServer 리소스에서 쿠버네티스 Rate Limit 을 사용하는 방법에 대해 간략하게 알아봅니다.
해당 테스트에서 전제 조건은 다음과 같습니다.
$ kubectl get svc -n nginx-ingress
NAME TYPE CLUSTER-IP EXTERNAL-IP
PORT(S) AGE
nginx-ingress NodePort 10.111.28.177 <none> 80:30000/TCP,443:32342/TCP,9113:31058/TCP,20001:32211/TCP 5d14h
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy1
namespace: nginx-ingress
spec:
replicas: 2
selector:
matchLabels:
app: deploy1
template:
metadata:
labels:
app: deploy1
spec:
containers:
- name: containerd1
image: nginxdemos/nginx-hello:plain-text
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: svc1
namespace: nginx-ingress
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app: deploy1
목차
1. Policy 리소스를 사용한 Rate Limit
1-1. Policy 리소스 작성
1-2. VirtualServer 리소스 생성
1-3. Rate Limit 테스트
2. Snippet을 사용한 Rate Limit
2-1. Snippet 활성화하기
2-2. VirtualServer 리소스 생성
2-3. Rate Limit 테스트
1. Policy 리소스를 사용한 Rate Limit
Policy 리소스를 사용하면 VirtualServer 및 VirtualServerRoute 리소스에 추가할 수 있는 access control 및 쿠버네티스 rate limit 과 같은 기능을 구성할 수 있습니다.
이 리소스는 Custom Resource로 구현됩니다.
전제 조건:
- Policies는 NGINX Plus Ingress Controller에서 별도로 생성해야 하는 VirtualServer 및 VirtualServerRoute 리소스와 함께 작동합니다.
1-1. Policy 리소스 작성
Policy 리소스를 사용한 쿠버네티스 rate limit을 사용하는 것은 복잡하지 않습니다. 이를 위한 구성은 다음과 같습니다:
apiVersion: k8s.nginx.org/v1
kind: Policy
metadata:
name: rate-limit-policy
namespace: nginx-ingress
spec:
rateLimit:
rate: 1r/s
key: ${binary_remote_addr}
zoneSize: 10M
NGINX 또는 NGINX Plus를 사용하여 쿠버네티스 rate limit 을 사용해 보신 적이 있으시다면, 위 구성이 어딘가 익숙하실 것입니다.
위 구성 내용은 다음과 같습니다:
- rateLimit – 쿠버네티스 Rate limit 정책은 정의된 키당 요청 처리 속도를 제어합니다.
- rate – 허용되는 요청 비율입니다. 속도는 초당 요청(r/s) 또는 분당 요청(r/m)으로 지정됩니다.
- key – 비율 제한이 적용되는 키입니다. 텍스트, 변수 또는 이들의 조합을 포함할 수 있으며, 변수는 ${}로 묶어야 합니다. 예: ${binary_remote_addr}. 허용되는 변수는 ${binary_remote_addr}, ${request_uri}, ${url}, ${http_}, ${args}, ${arg_}, ${cookie_}입니다.
- zoneSize – 공유 메모리 영역의 크기입니다. 양수 값만 허용됩니다. 허용되는 접미사는 k 또는 m이며, default는 k입니다.
이 외의 쿠버네티스 rate limit 옵션은 이 문서를 참조하세요.
1-2. VirtualServer 리소스 생성
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
name: hodevops
namespace: nginx-ingress
spec:
host: example.com
ingressClassName: nginx
policies:
- name: rate-limit-policy
upstreams:
- name: root
service: ho-svc1
port: 80
routes:
- path: /
action:
pass: root
VirtualServer 리소스 또한 위에서 작성한 Policy만 추가해주면 적용이 됩니다.
1-3. 쿠버네티스 Rate Limit 테스트
해당 테스트에서 초당 1개의 요청만 허용하도록 구성되어 있으므로 curl 명령어를 사용하여 확인할 수 있습니다.
$ curl -I example.com:30000
HTTP/1.1 200 OK
Server: nginx/1.25.3
Date: Tue, 16 Apr 2024 02:50:48 GMT
Content-Type: text/plain
Content-Length: 156
Connection: keep-alive
Expires: Tue, 16 Apr 2024 02:50:47 GMT
Cache-Control: no-cache
$ curl -I example.com:30000
HTTP/1.1 503 Service Temporarily Unavailable
Server: nginx/1.25.3
Date: Tue, 16 Apr 2024 02:50:48 GMT
Content-Type: text/html
Content-Length: 197
Connection: keep-alive
$ curl -I example.com:30000
HTTP/1.1 503 Service Temporarily Unavailable
Server: nginx/1.25.3
Date: Tue, 16 Apr 2024 02:50:48 GMT
Content-Type: text/html
Content-Length: 197
Connection: keep-alive
위와 같이 curl 요청을 초당 여러번 실행하면 1개의 요청만 허용되는 것을 확인할 수 있습니다.
2. Snippet을 사용한 쿠버네티스 Rate Limit
Snippet을 사용하면 Ingress Controller가 생성하는 NGINX 구성에 새로운 구성을 삽입할 수 있습니다.
NGINX Plus Ingress Controller는 다음과 같은 사항으로 인해 기본적으로 Snippet이 비활성화되어 있습니다. Annotation 및 ConfigMap 항목으로 구성할 수 없는 경우에 Snippet을 사용하는 것을 권장드립니다.
- 복잡성 – Snippet을 사용하려면 다음 작업이 필요합니다.
- NGINX 구성을 이해하고 올바른 NGINX 구성을 구현해야 합니다.
- Snippet이 구성의 다른 기능을 방해하지 않도록 IC가 NGINX 구성을 생성하는 방법을 이해해야 합니다.
- 견고성 저하 – 잘못된 snippet은 NGINX 구성을 유효하지 않게 만들며, 이로 인해 새로고침 실패가 발생합니다. 이렇게 하면 snippet이 수정될 때까지 다른 Ingress 리소스에 대한 업데이트를 포함한 구성 업데이트가 방지됩니다.
- 보안에 미치는 영향 – Snippet은 NGINX 구성 기본 요소에 대한 액세스를 제공하며, 해당 기본 요소는 Ingress Controller에 의해 검증되지 않습니다. 예를 들어, Snippet은 Ingress 리소스에 대한 TLS Termination에 사용되는 TLS 인증서 및 키를 제공하도록 NGINX를 구성할 수 있습니다.
참고: NGINX 구성에 잘못된 snippet이 포함된 경우 NGINX는 최신 유효 구성으로 작동합니다.
2-1. Snippet 활성화하기
앞서 말했듯이, 기본적으로 snippet은 비활성화 상태입니다. 따라서 Snippet을 활성화합니다. 방법은 NGINX Plus Ingress Controller의 Deployment 리소스 파일에서 “- -enable-snippets”를 추가하여 활성화할 수 있습니다.
...
args:
- -nginx-plus
- -nginx-configmaps=$(POD_NAMESPACE)/nginx-config
- -enable-snippets
...
2-2. VirtualServer 리소스 생성
apiVersion: k8s.nginx.org/v1
kind: VirtualServer
metadata:
name: hodevops
namespace: nginx-ingress
spec:
host: example.com
ingressClassName: nginx
http-snippets: |
limit_req_zone $binary_remote_addr zone=mylimit:10m rate=1r/s;
upstreams:
- name: root
service: svc1
port: 80
routes:
- path: /
location-snippets: |
limit_req zone=mylimit;
action:
pass: root
쿠버네티스 Rate limit 을 정의하는 지시문은 다음과 같습니다.
- http-snippets – http syntax 내에 구성 추가
- limit_req_zone – 공유 메모리 영역 지정
- $binary_remote_addr – 요청한 클라이언트의 IP를 기준으로 요청 수를 관리
- zone – 해당 예시에서는 mylimit이라는 영역을 할당하고 키 상태를 유지할 수 있는 메모리의 크기를 10m로 설정합니다.(여기서 키는 IP를 의미합니다.)
- rate – 해당 테스트에서는 1r/s; 를사용했으며 1request/second; 라는 의미입니다. 즉, 초당 1개의 요청을 처리한다는 의미입니다. 자세한 가이드는 여기를 참조하세요.
- location-snippets – location syntax 내에 구성 추가
- limit_req – 위에서 할당한 영역(mylimit)을 적용
위 VirtualServer 리소스를 배포 및 확인합니다.
$ kubectl apply -f virtualserver.yaml
virtualserver.k8s.nginx.org/hodevops created
$ kubectl get virtualserver -n nginx-ingress
NAME STATE HOST IP PORTS AGE
hodevops Valid example.com 43s
여기서 STATE가 Valid 이어야 정상적으로 적용 및 배포된 상태입니다.
2-3. 쿠버네티스 Rate Limit 테스트
위 구성에서는 초당 1회의 요청을 허용했기 때문에 curl 명령어를 사용하여 쉽게 확인할 수 있습니다.
$ curl -I example.com:30000
HTTP/1.1 200 OK
Server: nginx/1.25.3
Date: Mon, 15 Apr 2024 08:25:05 GMT
Content-Type: text/plain
Content-Length: 156
Connection: keep-alive
Expires: Mon, 15 Apr 2024 08:25:04 GMT
Cache-Control: no-cache
$ curl -I example.com:30000
HTTP/1.1 503 Service Temporarily Unavailable
Server: nginx/1.25.3
Date: Mon, 15 Apr 2024 08:25:06 GMT
Content-Type: text/html
Content-Length: 197
Connection: keep-alive
$ curl -I example.com:30000
HTTP/1.1 503 Service Temporarily Unavailable
Server: nginx/1.25.3
Date: Mon, 15 Apr 2024 08:25:06 GMT
Content-Type: text/html
Content-Length: 197
Connection: keep-alive
위와 같이 curl 요청을 초당 여러번 실행하면 1개의 요청만 허용되는 것을 확인할 수 있습니다.
NGINX Plus를 직접 사용해 보시려면 30일 무료 평가판을 신청하거나 NGINX STORE에 연락하여 논의하십시오.