Ingress nginx
svc를 ingress로 외부에 오픈
regex
https://kubernetes.github.io/ingress-nginx/user-guide/ingress-path-matching/
priority
In NGINX, regular expressions follow a first match policy, 그러므로 ingress nginx가 정규식의 길이를 기준으로 역순으로 정렬을 한후 controller에 업데이트합니다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress-1
spec:
rules:
- host: test.com
http:
paths:
- path: /foo/bar
backend:
serviceName: service1
servicePort: 80
- path: /foo/bar/
backend:
serviceName: service2
servicePort: 80
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress-2
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: test.com
http:
paths:
- path: /foo/bar/(.+)
backend:
serviceName: service3
servicePort: 80
이 같은 파일이 두개면 아래와 같이 정렬
location ~* ^/foo/bar/.+ {
...
}
location ~* "^/foo/bar/" {
...
}
location ~* "^/foo/bar" {
...
}
test.com/foo/bar/1 matches ~* ^/foo/bar/.+ and will go to service 3.
test.com/foo/bar/ matches ~* ^/foo/bar/ and will go to service 2.
test.com/foo/bar matches ~* ^/foo/bar and will go to service 1.
테스트를 위해 다음과같은 yaml을 만들어서 적용하엿다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress-1
namespace: default
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: c4.aaaa.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: front
port:
name: http
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress-2
namespace: default
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- host: c4.aaaa.com
http:
paths:
- path: /api(/|$)(.*)/i
pathType: Prefix
backend:
service:
name: api
port:
name: http
결과 생성된 파일이다. 결론부터 이야기하면 ingress에 rewrite를 쓰면 그 인그레스에만 적용이 된다. 아래보면 /api부분에만 rewrite $1 가 적용되어 있다.
## start server c4.aaaa.com
server {
server_name c4.aaaa.com ;
listen 80 ;
listen [::]:80 ;
listen 443 ssl http2 ;
listen [::]:443 ssl http2 ;
set $proxy_upstream_name "-";
ssl_certificate_by_lua_block {
certificate.call()
}
location ~* "^/api(/|$)(.*)" {
set $namespace "default";
set $ingress_name "test-ingress-2";
set $service_name "api";
set $service_port "http";
set $location_path "/api(/|${literal_dollar})(.*)";
set $global_rate_limit_exceeding n;
rewrite_by_lua_block {
lua_ingress.rewrite({
force_ssl_redirect = false,
ssl_redirect = true,
force_no_ssl_redirect = false,
preserve_trailing_slash = false,
use_port_in_redirects = false,
global_throttle = { namespace = "", limit = 0, window_size = 0, key = { }, ignored_cidrs = { } }
})
balancer.rewrite()
plugins.run()
}
...
port_in_redirect off;
set $balancer_ewma_score -1;
set $proxy_upstream_name "default-api-http";
set $proxy_host $proxy_upstream_name;
set $pass_access_scheme $scheme;
set $pass_server_port $server_port;
set $best_http_host $http_host;
set $pass_port $pass_server_port;
set $proxy_alternative_upstream_name "";
client_max_body_size 1m;
proxy_set_header Host $best_http_host;
# Pass the extracted client certificate to the backend
# Allow websocket connections
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Request-ID $req_id;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Host $best_http_host;
proxy_set_header X-Forwarded-Port $pass_port;
proxy_set_header X-Forwarded-Proto $pass_access_scheme;
proxy_set_header X-Forwarded-Scheme $pass_access_scheme;
proxy_set_header X-Scheme $pass_access_scheme;
# Pass the original X-Forwarded-For
proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;
# mitigate HTTPoxy Vulnerability
# https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
proxy_set_header Proxy "";
# Custom headers to proxied server
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffering off;
proxy_buffer_size 4k;
proxy_buffers 4 4k;
proxy_max_temp_file_size 1024m;
proxy_request_buffering on;
proxy_http_version 1.1;
proxy_cookie_domain off;
proxy_cookie_path off;
# In case of errors try the next upstream server before returning an error
proxy_next_upstream error timeout;
proxy_next_upstream_timeout 0;
proxy_next_upstream_tries 3;
rewrite "(?i)/api(/|$)(.*)" /$1 break; # <------------여기
proxy_pass http://upstream_balancer;
proxy_redirect off;
}
location ~* "^/" {
set $namespace "default";
set $ingress_name "test-ingress-1";
set $service_name "front";
set $service_port "http";
set $location_path "/";
set $global_rate_limit_exceeding n;
rewrite_by_lua_block {
lua_ingress.rewrite({
force_ssl_redirect = false,
ssl_redirect = true,
force_no_ssl_redirect = false,
preserve_trailing_slash = false,
use_port_in_redirects = false,
global_throttle = { namespace = "", limit = 0, window_size = 0, key = { }, ignored_cidrs = { } }
})
balancer.rewrite()
plugins.run()
}
port_in_redirect off;
set $balancer_ewma_score -1;
set $proxy_upstream_name "default-front-http";
set $proxy_host $proxy_upstream_name;
set $pass_access_scheme $scheme;
set $pass_server_port $server_port;
set $best_http_host $http_host;
set $pass_port $pass_server_port;
set $proxy_alternative_upstream_name "";
client_max_body_size 1m;
proxy_set_header Host $best_http_host;
# Pass the extracted client certificate to the backend
# Allow websocket connections
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-Request-ID $req_id;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Host $best_http_host;
proxy_set_header X-Forwarded-Port $pass_port;
proxy_set_header X-Forwarded-Proto $pass_access_scheme;
proxy_set_header X-Forwarded-Scheme $pass_access_scheme;
proxy_set_header X-Scheme $pass_access_scheme;
# Pass the original X-Forwarded-For
proxy_set_header X-Original-Forwarded-For $http_x_forwarded_for;
# mitigate HTTPoxy Vulnerability
# https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
proxy_set_header Proxy "";
# Custom headers to proxied server
proxy_connect_timeout 5s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffering off;
proxy_buffer_size 4k;
proxy_buffers 4 4k;
proxy_max_temp_file_size 1024m;
proxy_request_buffering on;
proxy_http_version 1.1;
proxy_cookie_domain off;
proxy_cookie_path off;
# In case of errors try the next upstream server before returning an error
proxy_next_upstream error timeout;
proxy_next_upstream_timeout 0;
proxy_next_upstream_tries 3;
proxy_pass http://upstream_balancer;
proxy_redirect off;
}
}
## end server c4.aaaa.com
주의사항
아래와 같이 만들면 문제가 잇을수 있다.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress-3
annotations:
nginx.ingress.kubernetes.io/use-regex: 'true'
spec:
rules:
- host: test.com
http:
paths:
- path: /foo/bar/bar
backend:
serviceName: test-a
servicePort: 80
- path: /foo/bar/[A-Z0-9]{3}
backend:
serviceName: test-b
servicePort: 80
생성된 결과는 다음과 같다.
location ~* "^/foo/bar/[A-Z0-9]{3}" {
...
}
location ~* "^/foo/bar/bar" {
...
}
test.com/foo/bar/bar 이걸 요청하면 ^/foo/bar/[A-Z0-9]{3} 여기에 걸려버린다. 원하는대로 안된다.
더 알고 싶으면 다음 링크를 읽어보면된다.
log - 2022-09-11
로그를 커스터마이즈 하고 싶은 경우가 있다. 관련 도큐먼트는 다음에서 얻을수 있다.
log-format은 큰 도움이 안되었다. 그래서 2번을 참고해서 진행햇다.
configmap을 추가하면 되는것인데 helm을 사용하다보니 어디에 추가하는지 샘플이 없어서 고생햇다.
heml차트에 보면 다음 부분이 있다.
# Will add custom configuration options to Nginx https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/
# config: {} #이부분
config:
enable-underscores-in-headers: on
log-format-upstream: '$ingress_name "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_length $request_time [$proxy_upstream_name] [$proxy_alternative_upstream_name] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status $req_id'
주석처리후 아래처럼 추가 configmap관련 내용을 추가햇다.
여기서 주의할건 log-format-upstream
을 수정해야된다.
아래 보이는 log-format-stream을 가지고 아무리 해도 적용되지가 않앗다. log-format-upstream
을 사용하는걸 보고 적용해보니 잘 되었다.
기본값은 다음과 같다.
$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_length $request_time [$proxy_upstream_name] [$proxy_alternative_upstream_name] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status $req_id
나의 경우는 로그에 ingress name을 추가로 넣고 싶엇다. 확인해보니 1번 문서에서 추가로 사용할수 있다고 한다.
그래서 다음과 같이 추가햇다.
# Will add custom configuration options to Nginx https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/
config:
enable-underscores-in-headers: on
log-format-upstream: '$ingress_name "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" $request_length $request_time [$proxy_upstream_name] [$proxy_alternative_upstream_name] $upstream_addr $upstream_response_length $upstream_response_time $upstream_status $req_id'
나의 경우는 고객 아이피는 중요한 상황이 아니고 로컬 시간도 중요치 않아서 제거하고 인그레스 이름을 맨 처음에 넣어주고 나머지는 기본값을 사용햇다.
그리고 로그를 확인해보니 다음과 같이 잘 나오는것을 확인햇다.
loki에서 확인해보기
이제 로그를 로키에서 확인해보자.
# 기존
{namespace=~"nginx"} | pattern `<remote_addr> - - <time_local> "<method> <_> <_>" <status> <_> <_> "<_>" <_>` | status="400"
# 수정후
{namespace=~"nginx"} | pattern `<ingress> "<method> <_> <_>" <status> <_> <_> "<_>" <_>` | status=~"[4-5].*" | ingress="IngeressName"
이렇게 하면 ingress name별로 필터가 가능해진다.
grafana dash board
아래처럼 dashboard를 만들어 보앗다.
위에 두 그래프는 프로메테우스에서 메트릭을 가져와서 표현하고 마지막 테이블은 로키에서 로그를 가져와서 뿌려준다.
에러가 발생할때 이제 로그도 함께 볼수가 있어서 좋다.
데시보드 코드는 다음과 같다.
{
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": "-- Grafana --",
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"target": {
"limit": 100,
"matchAny": false,
"tags": [],
"type": "dashboard"
},
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 35,
"iteration": 1662994187189,
"links": [],
"liveNow": false,
"panels": [
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "P1809F7CD0C75ACF3"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 8,
"w": 24,
"x": 0,
"y": 0
},
"hiddenSeries": false,
"id": 6,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": false,
"total": false,
"values": false
},
"lines": true,
"linewidth": 2,
"nullPointMode": "connected",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "8.3.3",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "P1809F7CD0C75ACF3"
},
"exemplar": true,
"expr": "round(sum(irate(nginx_ingress_controller_requests{ingress=~\"$ingress\"}[2m])) by (ingress), 0.001)",
"interval": "",
"legendFormat": "",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Ingress Request Volume",
"tooltip": {
"shared": true,
"sort": 2,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:57",
"format": "reqps",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:58",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"aliasColors": {},
"bars": false,
"dashLength": 10,
"dashes": false,
"datasource": {
"type": "prometheus",
"uid": "P1809F7CD0C75ACF3"
},
"fill": 1,
"fillGradient": 0,
"gridPos": {
"h": 7,
"w": 24,
"x": 0,
"y": 8
},
"hiddenSeries": false,
"id": 4,
"legend": {
"avg": false,
"current": false,
"max": false,
"min": false,
"show": false,
"total": false,
"values": false
},
"lines": true,
"linewidth": 2,
"nullPointMode": "null",
"options": {
"alertThreshold": true
},
"percentage": false,
"pluginVersion": "8.3.3",
"pointradius": 2,
"points": false,
"renderer": "flot",
"seriesOverrides": [],
"spaceLength": 10,
"stack": false,
"steppedLine": false,
"targets": [
{
"datasource": {
"type": "prometheus",
"uid": "P1809F7CD0C75ACF3"
},
"exemplar": true,
"expr": "sum(rate(nginx_ingress_controller_requests{ingress=~\"$ingress\",status!~\"[4-5].*\"}[2m])) by (ingress) / sum(rate(nginx_ingress_controller_requests{ingress=~\"$ingress\"}[2m])) by (ingress)",
"interval": "10",
"legendFormat": "{{ingress}}",
"refId": "A"
}
],
"thresholds": [],
"timeRegions": [],
"title": "Ingress Success Rate (non-4|5xx responses)",
"tooltip": {
"shared": true,
"sort": 0,
"value_type": "individual"
},
"type": "graph",
"xaxis": {
"mode": "time",
"show": true,
"values": []
},
"yaxes": [
{
"$$hashKey": "object:222",
"format": "percentunit",
"logBase": 1,
"show": true
},
{
"$$hashKey": "object:223",
"format": "short",
"logBase": 1,
"show": false
}
],
"yaxis": {
"align": false
}
},
{
"datasource": {
"type": "loki",
"uid": "P982945308D3682D1"
},
"gridPos": {
"h": 14,
"w": 24,
"x": 0,
"y": 15
},
"id": 2,
"options": {
"dedupStrategy": "none",
"enableLogDetails": true,
"prettifyLogMessage": false,
"showCommonLabels": false,
"showLabels": false,
"showTime": false,
"sortOrder": "Descending",
"wrapLogMessage": false
},
"pluginVersion": "8.3.3",
"targets": [
{
"datasource": {
"type": "loki",
"uid": "P982945308D3682D1"
},
"expr": "{namespace=~\"ingress-nginx|ingress-nginx-internal\"} | pattern `<ingress> \"<method> <_> <_>\" <status> <_> <_> \"<_>\" <_>`| status=~\"[4-5].*\" | ingress=\"$ingress\"",
"instant": false,
"range": true,
"refId": "log"
}
],
"title": "Http 4-5xx",
"type": "logs"
}
],
"schemaVersion": 34,
"style": "dark",
"tags": [],
"templating": {
"list": [
{
"current": {
"selected": false,
"text": "shop-ingress",
"value": "shop-ingress"
},
"datasource": {
"type": "prometheus",
"uid": "P1809F7CD0C75ACF3"
},
"definition": "label_values(ingress) ",
"hide": 0,
"includeAll": true,
"label": "ingress",
"multi": false,
"name": "ingress",
"options": [],
"query": {
"query": "label_values(ingress) ",
"refId": "StandardVariableQuery"
},
"refresh": 1,
"regex": "",
"skipUrlSync": false,
"sort": 2,
"type": "query"
}
]
},
"time": {
"from": "now-12h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "Loggging",
"uid": "A-3q5wMVz",
"version": 9,
"weekStart": ""
}
log-format vs log-format-upstream
아직 잘 모르는데 이 다이어그램이 좀 도움이 되는듯.
이걸 한번 잘 읽어봐야겟다. https://www.nginx.com/blog/logging-upstream-nginx-traffic-cdn77/ 그나저나 ingress-nginx는 왜 upstream로그를 기본으로 사용할가? 프록시니까 맞는것도 같고...
helmchart 사용중 configmap설정
helmchart를 사용중에 configmap을 설정해야하는 경우가 있다. 매뉴얼등이 전부 configmap만 나오면 다음처럼 하자.
helm chart 에 config에 설정을 넣으면 된다.
# Will add custom configuration options to Nginx https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/
config:
enable-underscores-in-headers: on
여기에 사용할수 있는 항목들은 다음 페이지에서 확인한다.
꽤 많은 옵션들이 여기에서 처리할수 있다.
values 파일을 변경후 argocd에서 로딩을 하거나 적용을 하면 pod에 자동으로 config가 reload가 된다. 중요한것은 pod가 재시작 되지 않는다. 설정만 자동으로 리로드 된다.
만약 설정이 잘못되면 test fail
나면서 리로딩 하지 않는다.
todo
log-format-upstream 과 log-format의 차이점 파악하기
dashboard를 kube-prometheus에서 넣어줘야한다.
Last updated
Was this helpful?