[TOC]
0x00 Ingress-Nginx 快速安装配置实践
描述: 此节,作为上一章的扩展补充,主要因为ingress-nginx迭代较快,加入了很多新得特性导致原来某些配置被弃用,当前时间节点【2022年3月8日 17:24:28】针对现有Ingress-nginx版本(v1.1.1)进行快速安装配置,与上一章中的安装是存在一定的不同,安装时都可以作为参考。
知识复习
Q: 什么是Ingress?
A: Ingress 是管理对集群中服务的提供外部访问的 API 对象,Ingress 控制器负责实现 Ingress,通常使用负载均衡器,但它也可以配置边缘路由器或其他前端来帮助处理流量,它可以将来自集群外部的 HTTP 和 HTTPS 路由转发到集群内部的 Service 中。
Ingress 只是一个统称,其由 Ingress 和 Ingress Controller 两部分组成。
- Ingress 用作将原来需要手动配置的规则抽象成一个 Ingress 对象,使用 YAML 格式的文件来创建和管理。
- Ingress Controller 用作通过与 Kubernetes API 交互,动态的去感知集群中 Ingress 规则变化。
使用 Ingress 控制器可以轻松实现外部URL访问集群内部服务、负载均衡、代理转发、支持配置SSL/TLS并提供基于名称的虚拟主机,值得注意的是 Ingress 不会暴露任意端口或协议,通过使用 Service.Type=NodePort
或 Service.Type=LoadBalancer
类型的服务向向 Internet 公开 HTTP 和 HTTPS 的访问服务
Q: 常用 Ingress 控制器有那些? 其它更多适用于Kubernetes的ingress控制器可以参考地址[https://kubernetes.io/zh/docs/concepts/services-networking/ingress-controllers/#%E5%85%B6%E4%BB%96%E6%8E%A7%E5%88%B6%E5%99%A8]
- ingress-Nginx : 用于 Nginx Kubernetes Ingress 控制器能够与 NGINX Web 服务器(作为代理)一起使用 (推荐)
- ingress-Traefik :由 Traefik Kubernetes Ingress 提供程序是一个用于 Traefik 代理的Ingress控制器。
- ingress-istio : Istio Ingress 是一个基于Istio的Ingress控制器。
温馨提示: 理想情况下所有 Ingress 控制器都应符合参考规范。实际上各种 Ingress 控制器的操作略有不同,请参考相应Ingress的控制器官方文档。
如下图所示的一个简单的示例,客户端请求访问外部URL地址, Ingress 将其所有流量发送到一个Service中, 后端 Pod 提供服务端响应通过路由进行返回给客户端。

WeiyiGeek.Ingress
Q: Ingress 规则有哪些?
- host : 虚拟主机名称, 主机名通配符主机可以是精确匹配(例如”foo.bar.com”)或通配符(例如“ *.foo.com”)
- paths : URL访问路径。
- pathType : Ingress 中的每个路径都需要有对应的路径类型(Path Type)
- backend : 是 Service 文档中所述的服务和端口名称的组合与规则的 host 和 path 匹配的对 Ingress 的 HTTP(和 HTTPS )请求将发送到列出的 backend, 一般情况可以单独为路径设置Backend以及未匹配的url默认访问的后端defaultBackend。
Ingress 中的每个路径都需要有对应的路径类型(Path Type),未明确设置 pathType 的路径无法通过合法性检查,当前支持的路径类型有三种:
- Exact:精确匹配 URL 路径,且区分大小写。
- Prefix:基于以
/
分隔的URL路径前缀匹配, 且区分大小写,并且对路径中的元素逐个完成。 - ImplementationSpecific:此路径类型匹配方法取决于 IngressClass, 具体实现可以将其作为单独的 pathType 处理或者与 Prefix 、 Exact 类型作相同处理。
说明: 如果路径的最后一个元素是请求路径中最后一个元素的子字符串,则不会匹配 (例如:/foo/bar 匹配 /foo/bar/baz, 但不匹配 /foo/barbaz)。
温馨提示: defaultBackend 通常在 Ingress 控制器中配置,以服务与规范中的路径不匹配的任何请求。1
2
3
4
5
6
7
8
9
10
11
12
13tee > test.yaml << 'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
spec:
defaultBackend:
service:
name: test
port:
number: 80
EOF
kubectl apply -f
注意, 入口控制器和负载平衡器可能需要一两分钟才能分配 IP 地址。 在此之前,你通常会看到地址字段的值被设定为<pending>
。
1.快速安装
1 | # 1.下载 v1.1.1 版本的ingress YAML资源清单到本地。 |
2.服务验证
描述: 创建使用指定的名称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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63# 方式1,创建一个名为demo-myweb-blog的入口,控制器名称为nginx,规则是将访问demo.weiyigeek.top请求转发到后端myweb-blog:80 服务之上
kubectl create ingress demo-myweb-blog --class=nginx --rule="demo.weiyigeek.top/=web-blog:80" --namespace devtest
# kubectl create ingress test-app -n devtest --rule="test.app.weiyigeek.top/oa(/|\$)(.*)=weiyigeek-oa-prod:8080" --annotation nginx.ingress.kubernetes.io/rewrite-target=/\$2
# 方式2.Ingress资源清单如下所示,其中重点是ingressClassName与rules字段
cat > www-myweb-blog.ingress <<'EOF'
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: www-blog
namespace: devtest
annotations:
kubernetes.io/ingress.class: "nginx" # 方式1.根据该注解指定发现 Ingress
ingressclass.kubernetes.io/is-default-class: true # 如未设置IngressClassName名称则采用默认Ingress
nginx.ingress.kubernetes.io/ssl-redirect : false # 禁用强制跳转
nginx.ingress.kubernetes.io/rewrite-target: /
labels:
app: blog
spec:
ingressClassName: nginx # 方式2.根据该字段指定发现 Ingress
defaultBackend:
service:
name: default-http
port:
number: 80
rules:
- host: "www.weiyigeek.top"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: www-blog
port:
number: 80
- host: "web.weiyigeek.top"
http:
paths:
- pathType: ImplementationSpecific
path: "/"
backend:
service:
name: web-blog
port:
number: 80
tls:
- hosts:
- www.weiyigeek.top
secretName: testsecret-tls
EOF
# 部署资源清单
kubectl apply -f www-myweb-blog.ingress
# 查看上面部署的ingress入口信息及其规则默认后端信息。
kubectl get ingress -n devtest
kubectl describe ingress -n devtest
# 调用修改后的 Ingress yaml 文件。
kubectl replace -f www-myweb-blog.ingress
# 通过本机的hosts文件,手动将www.weiyigeek.top、demo.weiyigeek.top域名绑定到K8S中Node节点IP地址上,即可通过浏览器访问。
192.168.12.222 www.weiyigeek.top demo.weiyigeek.top

WeiyiGeek.describe ingress
3.配置虚拟主机证书
描述: 通过设定包含 TLS 私钥和证书的 Secret 来保护 Ingress, TLS Secret 必须包含名为 tls.crt (证书)
和 tls.key (私钥)
的键名1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24# 方式1.资源清单方式
apiVersion: v1
kind: Secret
metadata:
name: www.weiyigeek.top
namespace: devtest
data:
tls.crt: `base64 编码的 cert`
tls.key: `base64 编码的 key`
type: kubernetes.io/tls
# 方式2.kubectl 命令行方式
kubectl create secret tls www.weiyigeek.top --cert=server.crt --key=server.key -n devtest
# 使用示例:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-example-ingress
spec:
tls:
- hosts:
- www.weiyigeek.top
secretName: testsecret-tls
温馨提示: 在 Ingress 中引用此 Secret 将会告诉 Ingress 控制器使用 TLS 加密从客户端到负载均衡器的通道。
4.使用hostNetwork网络方式
描述: 定义后Ingress-controller
的IP就与宿主机IP一样。
步骤 01.编辑 Ingress-controller 的 deploy 资源控制器内容,添加hostNetWork为true
的键值对,。
1 | $ kubectl edit deployments.apps -n ingress-nginx ingress-nginx-controller |
步骤 02.查看Pod的IP地址,此时你会发现其地址为节点主机地址
。1
2
3
4
5
6
7
8~$ kubectl get pod -n ingress-nginx -o wide | grep "ingress-nginx-controller"
ingress-nginx-controller-6b8bd48548-dfnvc 1/1 Running 0 4m26s 192.168.12.224 weiyigeek-224
ingress-nginx-controller-6b8bd48548-r9kpl 1/1 Running 0 5m 192.168.12.226 weiyigeek-226
ingress-nginx-controller-6b8bd48548-x9w9j 1/1 Running 0 5m33s 192.168.12.225 weiyigeek-225
ingress-nginx-controller-6b8bd48548-xqpcc 1/1 Running 0 5m33s 192.168.12.223 weiyigeek-223
~$ curl 192.168.12.225
Hello ingress-Nginx , Index /
步骤 03.让Pod均衡的分别运行在work节点,我们需要执行以下两步,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# 设置工作节点标签
~$ kubectl label nodes weiyigeek-223 weiyigeek-224 weiyigeek-225 weiyigeek-226 node=work
# node/weiyigeek-223 labeled
# node/weiyigeek-224 labeled
# node/weiyigeek-225 labeled
# node/weiyigeek-226 labeled
# 设置节点硬亲和、pod软亲和
~$ kubectl edit deployments.apps -n ingress-nginx ingress-nginx-controller
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node
operator: In
values:
- work
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
labelSelector:
matchExpressions:
- key: ingress
operator: In
values:
- nginx
topologyKey: kubernetes.io/hostname
weight: 100
5.使用externalIP网络方式
描述: 前面我们使用了 hostNetwork 方式,知道了可以使用 controller.hostNetwork=true
参数进行设置, 此处我们采用采用 externalIP
的方式进行服务暴露。
温馨提示:默认的控制器类型是Deployment,不过为其稳定性建议使用 DaemonSet 类型的控制器, 设置 hostNetwork 为 true、设置 dnsPolicy 为 ClusterFirstWithHostNet,也建议为要部署到的节点上打上ingress标签, 然后使用NodeSelector
添加ingress: "true"
部署至指定节点。
安装部署1
2# 启用 RBAC 支持
$ helm install --name nginx-ingress --set "rbac.create=true,controller.service.externalIPs[0]=192.168.12.211,controller.service.externalIPs[1]=192.168.12.212,controller.service.externalIPs[2]=192.168.12.213" stable/nginx-ingress
部署完成后我们可以看到 Kubernetes 服务中增加了 nginx-ingress-controller
和 nginx-ingress-default-backend
两个服务。nginx-ingress-controller 为 Ingress Controller,主要做为一个七层的负载均衡器来提供 HTTP 路由、粘性会话、SSL 终止、SSL直通、TCP 和 UDP 负载平衡等功能。nginx-ingress-default-backend 为默认的后端,当集群外部的请求通过 Ingress 进入到集群内部时,如果无法负载到相应后端的 Service 上时,这种未知的请求将会被负载到这个默认的后端上。
由于我们采用了 externalIP 方式对外暴露服务, 所以 nginx-ingress-controller 会在 192.168.12.211、192.168.12.212、192.168.12.213 三台节点宿主机上的 暴露 80/443 端口。
1 | $ kubectl get svc | grep "nginx-ingress-controller" |
访问 Nginx Ingress Controller , 我们可以使用以下命令来获取 Nginx 的 HTTP 和 HTTPS 地址。1
$ kubectl --namespace default get services -o wide -w nginx-ingress-controller
访问验证:1
2
3# 返回 200
$ curl -I http://192.168.12.211
$ curl -I --insecure http://192.168.12.211
在几台节点宿主机上查看,我们可以看到 ExternalIP 的 Service 是通过 Kube-Proxy对外暴露的,这里的 192.168.12.211、192.168.12.212、192.168.12.213 是三个内网 IP。 实际生产应用中是需要通过边缘路由器或全局统一接入层的负载均衡器将到达公网 IP 的外网流量转发到这几个内网 IP 上,外部用户再通过域名访问集群中以 Ingress 暴露的所有服务。
1 | $ sudo netstat -tlunp|grep kube-proxy|grep -E '80|443' |
6.对外暴露端口配置
描述: 默认的 Ingress 配置是暴露 http(80) 、https(443) 端口, 但需要注意的是创建的 Ingress 必须要和对外暴露的 Service 在同一命名空间下!
除此之外其实还可通过 Ingress controller 来实现TCP 和 UDP 服务端口的暴露,下面进行一一讲解。
1) http/https端口
描述: 缺少ingress支持http与https协议的后端应用。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22cat '
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: rewrite
namespace: default
spec:
ingressClassName: nginx
rules:
- host: rewrite.weiyigeek.top
http:
paths:
- path: /something(/|$)(.*)
pathType: Prefix
backend:
service:
name: http-svc
port:
number: 80
' | kubectl create -f -
2) 暴露TCP/UDP端口
描述: 我们可以通过 tcp-services-configmap.yaml 设置映射tcp, 通过 udp-services-configmap.yaml 映射udp1
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# tcp-services-configmap.yaml
cat > tcp-services-configmap.yaml <<EOF
apiVersion: v1
kind: ConfigMap
metadata:
name: tcp-services
namespace: ingress-nginx
data:
2181: "kafka/kafka-zookeeper:2181"
50000: "devops/jenkins:50000"
EOF
cat tcp-services-configmap.yaml | kubectl create -f -
# udp-services-configmap.yaml
tee udp-services-configmap.yaml <<'EOF'
apiVersion: v1
kind: ConfigMap
metadata:
name: udp-services
namespace: ingress-nginx
data:
53: "kube-system/kube-dns:53"
EOF
cat udp-services-configmap.yaml | kubectl create -f -
查看 ConfigMap 资源1
2
3~$ kubectl get cm -n ingress-nginx | grep "services"
tcp-services 2 15h
udp-services 1 15h
验证暴露的 TCP/UDP 服务:1
2
3
4
5
6~$ telnet 192.168.12.225 50000
Trying 192.168.12.225...
Connected to 192.168.12.225.
Escape character is '^]'.
~$ dig -x jenkins.devops.svc @192.168.12.225
3) 通过helm更新公开端口
描述: 通过helm chart
图表中的deployment-tcp-udp-values.yaml
或者deployment-tcp-udp-configMapNamespace-values.yaml文件
进行暴露TCP/UDP (如果你使用采用helm方式部署的ingress,此种方式是推荐的。), 注意此种方式1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19# ngress-nginx/ci/deployment-tcp-udp-values.yaml
controller:
image:
repository: ingress-controller/controller
tag: 1.0.0-dev
digest: null
admissionWebhooks:
enabled: false
service:
type: ClusterIP
tcp:
9000: "default/test:8080"
udp:
9001: "default/test:8080"
# 执行更新
helm upgrade nginx-ingress stable/nginx-ingress \
-f ./ci/deployment-tcp-udp-values.yaml
7.节点与Pod亲和性设置
描述: 为 deployments.apps 资源控制器部署的 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
25sepc:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node
operator: In
values:
- app
- ali
- www
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
labelSelector:
matchExpressions:
- key: kubernetes.io/os
operator: In
values:
- linux
topologyKey: kubernetes.io/hostname
weight: 100
nodeSelector:
k8s.io/ingress-nginx: "true"
8.基于 auth-url 模块认证方式实践
1.使用auth-url模块配置ldap登录
描述: 在 K8s 中我们可以使用 nginx Ingress
的 auth-url
模块配置ldap登录验证。
前置需求已经有部署自己的ldap server
, 然后还要在要配置ldap验证的服务ingress 上添加以下annotation:
1 | apiVersion: extensions/v1beta1 |
温馨提示: 此处 {server_domain}
是你的 ldap-auth-server
域名或IP地址, 其实现原理也是非常简单的即用你的程序去ldap server校验用户名密码是否正确即可。
1 | # app.py |
0x01 入坑出坑
问题1.K8s Nginx Ingress Controller 转发 X-Forwarded-Proto 请求头的问题
问题说明: 在 Kubernetes 集群上部署了 Nginx Ingress Controller 最前端用的是阿里云七层负载均衡,部署后发现不能正确转发 X-Forwarded-Proto 请求头,造成 http 重定向到 https 无法正常工作,请问如何解决?
1 | # 问题补充: |
问题解决: 终于在 Nginx Ingress Controller 的官方帮助文档 Advanced Configuration with Annotations 中找到一个注解(annotation)解决了这个问题,它就是 nginx.org/redirect-to-https: "true"
1 | Annotation: nginx.org/redirect-to-https |
操作步骤:
1)在 cnblogs-ingress.yaml 中 annotations 下面添加 nginx.org/redirect-to-https: “true”
1 | apiVersion: extensions/v1beta1 |
2) 更新 ingress 配置
1 | kubectl apply -f cnblogs-ingress.yaml |
3) 更新 nginx-ingress
1 | kubectl rollout restart daemonset/nginx-ingress -n nginx-ingress && \ |
4)查看 inginx 容器中的配置
1 | kubectl exec -it daemonset/nginx-ingress -n nginx-ingress cat /etc/nginx/conf.d/production-cnblogs-ingress.conf |
nginx-ingress 自己完成了基于X-Forwarded-Proto
的 http 重定向到 https 的操作,应用都不需要自己处理了。
Tips :建议采用 kubernetes/ingress-nginx 而非 nginxinc/kubernetes-ingress : https://github.com/kubernetes/ingress-nginx
问题2:extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
解决办法:根据当前 Kubernetes 版本中资源组与版本进行选择即可;
1 | ~/K8s/Day7/demo1$ kubectl api-resources | grep "ingresses" |
问题3.Error from server (InternalError): error when applying patch:
错误信息:
1 | $ kubectl apply -f demo-ingress.yaml |
解决办法: Webhook 删除后重新构建 ingress-nginx-http-v1.yaml 资源清单即可
1 | weiyigeek@ubuntu:~/K8s/Day7/demo2$ kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission |
问题4.查看ingress规则时提示kubernetes之ingress error: endpoints "default-http-backend" not found
警告
- 问题信息:
1 | $ kubectl describe ing |
- 问题原因: 注意:根据您正在使用的Ingress控制器,您可能需要创建一个default-http-backend服务。没有规则的入口将所有流量发送到一个默认后端。默认后端通常是Ingress控制器的一个配置选项,在您的Ingress资源中没有指定。如果Ingress对象中的主机或路径都不匹配HTTP请求,则流量将被路由到默认后端。
- 解决办法:
1 | # Ingress 控制器 |
问题5.设置了ingress无法正常显示页面,由于没有在资源清单中指定设置ingressclass名称
问题描述: 由于没有给ingress规则设置默认的ClassName,此时带有虚拟主机头的响应为默认default-http后端。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
45
46
47
48
49
50
51
52
53
54# 1.查看部署的ingress-nginx控制器名称k8s.io/ingress-nginx。
~$ kubectl get deployments.apps -n ingress-nginx ingress-nginx-controller -o yaml | grep " --controller-class"
- --controller-class=k8s.io/ingress-nginx
# 2.查看ingressclass的Name信息
~$ kubectl get ingressclasses.networking.k8s.io
# NAME CONTROLLER PARAMETERS AGE
# nginx k8s.io/ingress-nginx <none> 12d
# 3.编辑ingressclass
~$ kubectl get ingressclasses.networking.k8s.io
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: nginx
labels:
app.kubernetes.io/component: controller
app.kubernetes.io/instance: ingress-nginx
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/version: 1.1.1
helm.sh/chart: ingress-nginx-4.0.15
spec:
controller: k8s.io/ingress-nginx
parameters:
apiGroup: k8s.example.com
kind: IngressParameters
name: external-lb
namespace: external-configuration
scope: Namespace
# 4.为ingress规则指定默认的ingresclass的名称。
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: blog
namespace: devtest
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
# kubernetes.io/ingress.class: nginx # 当使用多个 Ingress 控制器时进行配置,如果不定义 ingress.class,云提供商可能使用默认的 Ingress 控制器。
ingressclass.kubernetes.io/is-default-class: true
spec:
ingressClassName: nginx # 推荐
rules:
- host: "www.weiyigeek.top"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: myweb-blog
port:
number: 80
温馨提示: ingressclass API 资源对象中, 在 sepc.parameters 字段中有一个 scope 和 namespace 字段,可用来引用特定于名字空间的资源,对 Ingress 类进行配置。(FEATURE STATE: Kubernetes v1.22 [beta]
)
- scope 字段默认为 Cluster,表示默认是集群作用域的资源。
- scope 设置为 Namespace 并设置 namespace 字段就可以引用某特定名字空间中的参数资源。
温馨提示: 当前 ingress 1.1.1 版本中使用 ingressClassName
字段来替代kubernetes.io/ingress.class
注解, 两则区别在于该注解通常用于引用实现该 Ingress 的控制器的名称, 而这个新的字段则是对一个包含额外 Ingress 配置的 IngressClass 资源的引用, 包括 Ingress 控制器的名称。
温馨提示: 我们也可以将一个 IngressClass 资源的 ingressclass.kubernetes.io/is-default-class
注解设置为 true ,以确保在未指定 ingressClassName 字段的情况下,Ingress 也能够分配为这个默认的 IngressClass.