k8s随笔 – nginx-ingress配置原理
如题,今天剖析一下nginx-ingress的配置原理,帮助大家快速搞清楚整体脉络。
几个概念
nginx-ingress作为K8S集群对外的流量入口,充当K8S集群内各个service的反向代理。
- ingress:K8S内置资源类型,用于配置应用Domain与后端service的关联关系,提供给ingress-controller使用。
- nginx-ingress-controller:ingress-controller的其中一种实现,利用openresty开发,基于deployments部署;其监听ingress资源变化,根据ingress配置生成若干server段,每一个server段对应一个应用的Domain,反向代理到对应service的若干POD,所有配置均生成到nginx.conf并自动热加载。
前提
我已经部署了1个项目,并且创建了其service:
1 2 3 4 5 6 7 8 9 10 11 |
kind: Service apiVersion: v1 metadata: name: zhongce-service spec: selector: app: zhongce ports: - protocol: TCP port: 809 targetPort: 809 |
该项目监听在809端口,内部利用nginx提供了5个不同域名的服务。
创建nginx-ingress-controller
1 |
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml |
这个YAML的目的就是创建nginx-ingress-controller的deployment。
我们需要关注nginx-ingress-controller的启动参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
containers: - name: nginx-ingress-controller image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.23.0 args: - /nginx-ingress-controller - --configmap=$(POD_NAMESPACE)/nginx-configuration - --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services - --udp-services-configmap=$(POD_NAMESPACE)/udp-services - --publish-service=$(POD_NAMESPACE)/ingress-nginx - --annotations-prefix=nginx.ingress.kubernetes.io securityContext: allowPrivilegeEscalation: true capabilities: drop: - ALL add: - NET_BIND_SERVICE # www-data -> 33 runAsUser: 33 env: - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace |
这个deployment跑在ingress-nginx namespace。
- –configmap:让其加载ingress-nginx/nginx-configuration这个configmap配置文件,从而允许我们修改nginx的http段的各种配置项覆盖nginx的默认值:https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/,这就是官方说的configmap方式配置nginx。
- –tcp-services-configmap:又是一个configmap,因为ingress只是拿来提供http/https反向代理用的概念,而nginx额外提供了4层TCP反向代理的能力,这需要通过单独的configmap配置,而不是用ingress对象配置,具体参考:https://kubernetes.github.io/ingress-nginx/user-guide/exposing-tcp-udp-services/。
- –udp-services-configmap:nginx提供udp反向代理能力,也是通过独立的configmap配置。
- –publish-service:配置为了ingress-nginx/ingress-nginx对象,意思就是指定ingress-controller对外暴露用的service的名字,我们稍后创建nginx-ingress的service时就得用这个名字,否则nginx-ingress就会因为报错。这个配置的意义在于,在describe ingress对象的时候可以通过查看这个service来打印出nginx-ingress的POD列表。
- –annotations-prefix:刚才说过ingress是配置nginx.conf中的server的,ingress可以配置annotations来修改server段中的各种配置项,但是它们必须遵循这个前缀才能被nginx-ingress识别。
所有的命令行参数在这里查看:https://kubernetes.github.io/ingress-nginx/user-guide/cli-arguments/。
我个人认为值得关注的其他参数包括:
- –ingress-class:默认是nginx,也就是说这个nginx-ingress只会响应annotation中ingress.class=nginx的ingress对象。如果我们部署了不同的nginx-ingress,那么就需要通过class来隔离ingress配置。
创建ingress
接下来就是配置反向代理了,看看就明白了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-zhongce-v2 annotations: # nginx-controller的命令行参数指定加载对应class的ingress规则 kubernetes.io/ingress.class: "nginx" spec: rules: - host: testapi.smzdm.com http: paths: - path: / backend: serviceName: zhongce-service servicePort: 809 - host: test.bgm.smzdm.com http: paths: - path: / backend: serviceName: zhongce-service servicePort: 809 - host: test-api.smzdm.com http: paths: - path: / backend: serviceName: zhongce-service servicePort: 809 - host: test.smzdm.com http: paths: - path: / backend: serviceName: zhongce-service servicePort: 809 - host: test.m.smzdm.com http: paths: - path: / backend: serviceName: zhongce-service servicePort: 809 |
上述ingress对象,配置了5个Domain,全部反向代理到了zhongce-service。
这里我们关注到annotations配置了class,从而归属于之前部署的那个nginx-ingress-controller。
可以通过annotations配置这5个server段的详细参数,比如:proxy_connect_timeout,详细参见:https://github.com/kubernetes/ingress-nginx/blob/master/docs/user-guide/nginx-configuration/annotations.md#custom-timeouts,这些annotations只有使用nginx-ingress-controller启动时指定的前缀nginx.ingress.kubernetes.io才会被nginx-ingress-controller识别。
讲到这里,我们应该做一个总结:
1)ingress的目标就是让我们不需要手动维护nginx配置。
2)修改nginx配置的方法需要区分对待:1,server段(也就是虚拟主机)是通过ingress配置的; 2,非server段(http段以及http段之外的配置项,例如:worker数量)是通过configmap配置的。
如果我们有更多的domain要配置,那么就创建更多的Ingress对象好了,不需要都写在一个yaml中。
特别注意,ingress的命名空间必须与它反向代理的service所处的命名空间一致。
nginx-ingress的service
为了让nginx-ingress暴露到K8S集群外,可以采用nodePort service的方式实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
apiVersion: v1 kind: Service metadata: name: ingress-nginx namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx spec: type: NodePort ports: - name: http port: 80 targetPort: 80 protocol: TCP - name: https port: 443 targetPort: 443 protocol: TCP selector: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx |
这里service的label selector是依据nginx-ingress-controller的label配置的,从而筛选出nginx-ingress-controller的POD。
对外暴露了2个nodePort,一个是http的80端口,一个是https的443端口,流量一旦进入到nginx-ingress就可以proxy到各个内部service完成调用了。
特别注意,这个service必须和nginx-ingress-controller的namespace一致,默认安装就是ingress-nginx。
配置文件
在nginx-ingress的yaml里已经创建了configmap,我们只需要在里面配置key-value对即可对nginx进行配置修改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
--- kind: ConfigMap apiVersion: v1 metadata: name: nginx-configuration namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- kind: ConfigMap apiVersion: v1 metadata: name: tcp-services namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx --- kind: ConfigMap apiVersion: v1 metadata: name: udp-services namespace: ingress-nginx labels: app.kubernetes.io/name: ingress-nginx app.kubernetes.io/part-of: ingress-nginx |
问题
基于nodePort暴露的ingress,其可以通过K8S集群的任意机器的nodePort端口访问到,因此在我尝试执行kubectl get ingress -o wide的时候,address入口地址显式为空:
1 2 |
NAME HOSTS ADDRESS PORTS AGE ingress-zhongce-v2 testapi.smzdm.com,test.bgm.smzdm.com,test-api.smzdm.com + 2 more... 80 175m |
有Issue提到在使用nodePort的情况下就是如此:https://github.com/kubernetes/ingress-nginx/issues/1467。
如果文章帮助您解决了工作难题,您可以帮我点击屏幕上的任意广告,或者赞助少量费用来支持我的持续创作,谢谢~
