暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

通过traceID实例讲解 Nginx Ingress 参数配置

3237


01

写在之前


今天记录一下Nginx Ingress的常用参数配置,如果你还没有安装过,可以参考之前学习记录的文档链接:同一kubernetes部署多个Nginx Ingress Controller


众所周知,Nginx 参数很多,但在Nginx Ingress上面如何配置呢,安装完后,都是使用的默认参数,这些参数如果想修改,应该如何修改呢?这里整理下如何修改Nginx Ingress默认参数配置,清晰并快速掌握配置Nginx Ingress的整体脉络,记录一下。


其实Ingress存在的本质原因,是不想让我们直接修改Nginx Ingress Controller,或者说只能通过Ingress规则去修改,但往往事与愿违,很多默认的参数不能满足我们的需求。


02

实例需求


手机APP上面访问服务时,每次请求都带有一个traceID,如果请求Header中没有traceID信息的话,在APP网关(APP接入层 Nginx)上面通过lua或第三方插件自动生成,说到这里,大家应该都清楚了,这是为链路追踪而设计的,之前我们在Nginx服务器上面,通过获取Header头信息,然后再proxy_set_header到上游服务器,一层一层的传递下去,在kubernetes上面,应该如何实现呢?


默认情况下Nginx Ingress配置不支持自定义的Heaer,需要简单配置,然后把此信息以proxy_set_header的形式传递到上游服务器,最近通过实验,做下记录;


03

实例架构图

从上面图中,我们可以看出,Nginx Ingress Controller工作原理,它是以deployment资源类型部署的,主动监听ingress 资源的变化,ingress发现变化后,他立即生成若干server片段,每个server片段反向代理到ingress规则对应service后面的Pod上面 ,所有配置最终生成到nginx.conf并自动加载,不需要人为重启(主要是因为nginx ingress甚于openresty开发的)。


04

Nginx Ingress 参数说明


下面是nginx ingress controller的部分配置

containers:
  - args:
    - nginx-ingress-controller
    - --default-backend-service=kubeops/outroute-nginx-ingress-default-backend
    - --election-id=ingress-controller-leader
    - --ingress-class=outroute
    - --configmap=kubeops/outroute-nginx-ingress-controller
    env:
    - name: POD_NAME
      valueFrom:
        fieldRef:
          apiVersion: v1
          fieldPath: metadata.name
    - name: POD_NAMESPACE
      valueFrom:
        fieldRef:
          apiVersion: v1
          fieldPath: metadata.namespace
    image: hub.k8s.vip/kubernetes/nginx-ingress-controller-timezone8:0.28.0
    imagePullPolicy: IfNotPresent


–-configmap:kubeops/outroute-nginx-ingress-controller,这是官方还有很多网上文档说的,使用configmap的方式配置nginx,这里要注意一下,这里只是允许配置http段的各种配置项,configmap配置应用后,就会覆盖默认的参数值;官方参数链接:https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/configmap.md,如日志格式、worker数目、keepalive参数等等;

--ingress-class=outroute,不同的nginx-ingress就是通过此参数进行隔离的,这个是kubernetes的内置资源,或者说是集群资源,同一集群部署多个隔离的nginx ingress controller就是通过此参数区分;


默认情况下nginx ingress只是提供http/https反向代理的功能,但是我们知道nginx目前已经支持了tcp/udp代理,那么nginx ingress应该如何支持呢?其实也是通过configmap的形式,

–tcp-services-configmap、–udp-services-configmap,具体配置可参考官网:https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/exposing-tcp-udp-services.md


还有很多默认参数,比如–-annotations-prefix=nginx.ingress.kubernetes.io,这个参数大家需要了解一下,刚才简单提到了nginx ingress controller工作原理,ingress规则把定义的配置生成到server段中,如果我们想修改server段的内容怎么办呢?就需要在定义ingress时通过配置annotations来修改各种配置,它们必须遵循这个前缀才能被nginx-ingress识别;


定义ingress规则时annotations可以修改的参数有哪些呢?官方链接:https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/annotations.md,你可以定义proxy-connect-timeout、proxy-send-timeout、proxy-set-header等等;


通过分析nginx ingress配置,我们得出一个结论,如果你想修改的是http段的默认参数,你可以通过configmap的形式修改,如果你修改的是server段的默认参数,你需要通过定义ingress规则时,通过annotations配置;


05

traceID配置


 配置Nginx Ingress

这里简单修改下 nginx ingress 日志格式,根据上面的结论,nginx日志格式需要定义在http段,所以我们需要修改--configmap=kubeops/outroute-nginx-ingress-controller这里的configmap,我们定义一个outroute_log.yaml,内容如下

apiVersion: v1
data:
  worker-processes: 'auto'
  log-format-upstream: '$time_iso8601 $remote_addr $http_host $scheme $request_method $uri $request_id $status $upstream_addr $upstream_status $request_time $upstream_response_time $upstream_connect_time $upstream_header_time $req_id '
  http-snippet: |
    map $http_trace_header_id $req_id {
      default $http_trace_header_id;
      ""        $request_id;
    }
kind: ConfigMap
metadata:
  name: 'outroute-nginx-ingress-controller'
  namespace: 'kubeops'


这里我们除了修改了下日志格式,我们还定义了一个http-snippet片段,主要功能是把trace_header_id取到,如果为空,使用request_id,熟悉nginx的同学,这个很简单;


应用配置

[root@master01 modiy_logformat]# kubectl apply -f outroute_log.yaml
configmap/outroute-nginx-ingress-controller unchanged
[root@master01 modiy_logformat]#


验证配置

...

log_format upstreaminfo '$time_iso8601 $remote_addr $http_host $scheme $request_method $uri $request_id $status $upstream_addr $upstream_status $request_time $upstream_response_time $upstream_connect_time $upstream_header_time $req_id ';
...

map $http_trace_header_id $req_id {
        default   $http_trace_header_id;
        ""        $request_id;
    }

....


定义Ingress规则

我们创建一个Demo,这个Demo是使用nginx,方便打出header信息,日志格式的最后加上'$http_trace_header_id';

apiVersion: apps/v1
kind: Deployment
metadata:
  name: test3-deployment-nginx
  namespace: test
spec:
  replicas: 1
  selector:
    matchLabels:
      run: test3-deployment-nginx
  template:
    metadata:
      labels:
        run: test3-deployment-nginx
    spec:
      containers:
      - name: test3-deployment-nginx
        image: hub.k8s.vip/kubernetes/nginx-header-test:v1
        ports:
        - containerPort: 80
        command: ["/bin/sh","-c","/data/nginx/sbin/nginx && tail -f dev/null"]
---
apiVersion: v1
kind: Service
metadata:
  name: test3-svc-nginx
  namespace: test
spec:
  selector:
    run: test3-deployment-nginx
  type: ClusterIP
  ports:
    - name: svc-nginx-port
      port: 80
      targetPort: 80

---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: default-ingress-nginx5
  namespace: test
  annotations:
    kubernetes.io/ingress.class: "outroute"
    nginx.ingress.kubernetes.io/proxy-body-size: 1000m
    nginx.ingress.kubernetes.io/rewrite-target:
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/configuration-snippet: |
      add_header trace-header-id $req_id;
      proxy_set_header trace-header-id $req_id;
spec:
  rules:
  - host: e.k8s.vip
    http:
      paths:
      - path:
        backend:
          serviceName: test3-svc-nginx
          servicePort: svc-nginx-port


上面创建的deployment、service、ingress,配置都很简单,不做说明,这里重点说下

nginx.ingress.kubernetes.io/configuration-snippet: |

  add_header trace-header-id $req_id;

  proxy_set_header trace-header-id $req_id;


根据前面的总结,知道server块中的配置,需要在Ingress规则中配置,这里我们定义了add_header(向客户端Header中添加 trace-header-id),也定义了proxy_set_header(向上游服务中添加trace-header-id);


不过这里再次强制一点:ingress的namespace必须与它反向代理service所处的namespace一致。


再次验证配置

进入nginx ingress pod,查看e.k8s.vip片段,发现这两个参数已经修改

add_header trace-header-id $req_id;
proxy_set_header trace-header-id $req_id;


06

验证traceID


[root@master01 ~]# curl -H "Host: e.k8s.vip" -H "trace-header-id: 123456678" http://master01/ -i
HTTP/1.1 200 OK
Server: nginx/1.17.7
Date: Sat, 15 Feb 2020 12:56:51 GMT
Content-Type: application/octet-stream
Content-Length: 10
Connection: keep-alive
trace-header-id: 123456678

BBBBBBBBBB[root@master01 ~]#
[root@master01 ~]#
[root@master01 ~]# curl -H "Host: e.k8s.vip" http://master01/ -i
HTTP/1.1 200 OK
Server: nginx/1.17.7
Date: Sat, 15 Feb 2020 12:57:10 GMT
Content-Type: application/octet-stream
Content-Length: 10
Connection: keep-alive
trace-header-id: 3401f0e4808ed5a12cd0840beb2e9643

BBBBBBBBBB[root@master01 ~]#
[root@master01 ~]#


第一次访问,我们指定了trace-header-id: 123456678,第二次使用了ingress controller自动产生的,现在通过日志查看验证下,日志字段最后一个为trace-header-id

[root@master01 ~]# kubectl logs --tail=2 outroute-nginx-ingress-controller-59f548d7d-g7fwc -n kubeops
2020-02-15T20:56:51+08:00  100.73.16.108  e.k8s.vip http GET a68b2b8e3b770345654de57caf2e2707 200  172.19.184.6:80  200  0.001  0.000  0.000  0.000  123456678 
2020-02-15T20:57:10+08:00  100.73.16.108  e.k8s.vip http GET 3401f0e4808ed5a12cd0840beb2e9643 200  172.19.184.6:80  200  0.001  0.001  0.001  0.001  3401f0e4808ed5a12cd0840beb2e9643
[root@master01 ~]#


通过查看最后两行日志中最后字段是123456678,3401f0e4808ed5a12cd0840beb2e9643,与访问时一致;


现在我们再去查看下应用Pod上面的日志,是否有这两个trace-header-id

[root@master01 ~]# kubectl exec -it test3-deployment-nginx-8ddffb97b-9j87d -n test bin/bash
[root@test3-deployment-nginx-8ddffb97b-9j87d ]# tail -n 2 data/logs/access.log
e.k8s.vip 100.73.16.108 [15/Feb/2020:12:56:51 +0000] "GET HTTP/1.1" 200 10 "-" "curl/7.29.0" "100.73.16.108" "-" 0.000 - - - 123456678
e.k8s.vip 100.73.16.108 [15/Feb/2020:12:57:10 +0000] "GET HTTP/1.1" 200 10 "-" "curl/7.29.0" "100.73.16.108" "-" 0.000 - - - 3401f0e4808ed5a12cd0840beb2e9643
[root@test3-deployment-nginx-8ddffb97b-9j87d /]#


通过查看trace-header-id与客户端一致,说明traceID通过ingress已经正常传到后端(上游)服务器,这样一来,就可以把传统HTTP服务的整个链路串起来。


07

总结


通过以上实例,自定义了日志格式,手机APP上面的header信息经过ingress传到后端应用Pod中,此过程相对简单,这里需要理解Ingress配置的要点,多查官方文档,其实很容易就可以实现。




您的关注是我写作的动力



往期分享


通俗易懂理解Kubernetes核心组件及原理

kubernetes v1.17.x 二进制安装文档 

Harbor镜像仓库高可用配置与使用

同一kubernetes部署多个Nginx Ingress Controller

文章转载自Linux点滴运维实践,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论