01 引言
声明:本文为《Kubernetes权威指南:从Docker到Kubernetes实践全接触(第5版)》的读书笔记
在前面,我们知道Service的表现形式为IP地址和端口号(ClusterIP:Port
),即工作在TCP/IP
层。而对于基于HTTP
的服务来说,不同的URL
地址经常对应到不同的后端服务或者虚拟服务器(Virtual Host
),这些应用层的转发机制仅通过Kubernetes
的Service
机制是无法实现的。
所以Kubernetes从1.1版本开始引入Ingress资源对象,用于将Kubernetes集群外的客户端请求路由到集群内部的服务上,同时提供7层(HTTP和HTTPS)路由功能。
02 ingress概念
Kubernetes 使用了一个Ingress策略定义和一个具体提供转发服务的Ingress Controller,两者结合,实现了基于灵活Ingress策略定义的服务路由功能。
如果是对Kubernetes集群外部的客户端提供服务,那么Ingress Controller实现的是类似于边缘路由器(Edge Router)的功能。需要注意的是,Ingress
只能以HTTP
和 HTTPS
提供服务,对于使用其他网络协议的服务,可以通过设置Service
的类型 type
为NodePort
或LoadBalancer
对集群外部的客户端提供服务。
2.1 简单例子
使用Ingress进行服务路由时,Ingress Controller基于Ingress规则将客户端请求直接转发到Service对应的后端Endpoint(Pod)上,这样会跳过kube-proxy设置的路由转发规则,以提高网络转发效率,下图是一个典型的HTTP层路由的例子:
其中:
- 对http:/mywebsite.com/api的访问将被路由到后端名为api的Service上;
- 对http:/mywebsite.com/web的访问将被路由到后端名为web的Service上;
- 对http:/mywebsite.com/docs的访问将被路由到后端名为docs的Service上。
03 完整案例
下面先通过一个完整的例子对Ingress Controller
的部署、Ingress
策略的配置,以及客户端如何通过Ingress Controller
访问服务对Ingress
的原理和应用进行说明。
3.1 部署ingress controller
Ingress Controller
需要实现基于不同HTTP URL向后转发的负载分发规则, 并可以灵活设置7层负载分发策略。目前Ingress Controller
已经有许多实现方案, 包括Nginx
、HAProxy
、Kong
、Traefik
、Skipper
、Istio
等开源软件的实现,以及公有云GCE
、Azure
、AWS
等提供的Ingress
应用网关,用户可以参考官方网站根据业务需求选择适合的Ingress Controller
。
本例基于Nginx
提供的Ingress Controller进行说明。
在Kubernetes中,Ingress Controller 会持续监控 API Server 的 /ingress 接口 (即用户定义的到后端服务的转发规则)的变化。当/ingress接口后端的服务信息发生变化时,Ingress Controller会自动更新其转发规则。
Nginx Ingress Controller 可以以Daemonset
或Deployment
模式进行部署,通常可以考虑通过设置 nodeSelector
或 亲和性调度策略将其调度到固定的几个Node
上提供服务。
对于客户端应用如何通过网络访问Ingress Controller
:
- 通过在容器级别设置hostPort,将80和443端口号映射到宿主机上,这样客户端应用可以通过 URL地址“
http://<NodeIP>:80
”或“https://<NodeIP>:443
”访问Ingress Controller
(本例演示); - 可以配置
Pod
使用hostNetwork模式直接监听宿主机网卡的IP地址和端口号; - 使用Service的NodePort将端口号映射到宿主机上。
下面是Nginx Ingress Controller的YAML
定义,其中将Pod创建在namespace“nginx-ingress”
中,通过nodeSelector“role=ingress-nginx-controller”
设置了调度的目标Node,并设置了hostPort
将端口号映射到宿主机上供集群外部的客户端访问。该配置文件包含了Namespace、ServiceAccount、RBAC、 Secret、ConfigMap和Deployment
等资源对象的配置。
namespace的定义如下:
# nginx-ingress-controller.yaml apiVersion: v1 kind: Namespace metadata: name: nginx-ingress
ServiceAccount的定义如下:
apiVersion: v1 kind: ServiceAccount metadata: name: nginx-ingress namespace: nginx-ingress
RBAC相关资源的定义如下:
kind: ClusterRole apiVersion: rbac.authorization.k8s.io/v1 metadata: name: nginx-ingress rules: - apiGroups: - "" resources: - services - endpoints verbs: - get - list - watch - apiGroups: - "" resources: - secrets verbs: - get - list - watch - apiGroups: - "" resources: - configmaps verbs: - get - list - watch - update - create - apiGroups: - "" resources: - pods verbs: - list - watch - apiGroups: - "" resources: - events verbs: - create - patch - list - apiGroups: - extensions resources: - ingresses verbs: - list - watch - get - apiGroups: - "extensions" resources: - ingresses/status verbs: - update - apiGroups: - k8s.nginx.org resources: - virtualservers - virtualserverroutes - globalconfigurations - transportservers - policies verbs: - list - watch - get - apiGroups: - k8s.nginx.org resources: - virtualservers/status - virtualserverroutes/status verbs: - update --- kind: ClusterRoleBinding apiversion: rbac.authorization.k8s.io/v1 metadata: name: nginx-ingress subjects: - kind: ServiceAccount name:nginx-ingress namespace: nginx-ingress roleRef: kind: ClusterRole name: nginx-ingress apiGroup: rbac.authorization.k8s.io
Secret的定义如下:
apiVersion: v1 kind: Secret metadata: name: default-server-secret namespace: nginx-ingress type: Opaque data: tls.secret: xxx... tls.key: xxxx...
ConfigMap的定义如下:
kind: ConfigMap apiVersion: v1 metadata: name: nginx-config namespace: nginx-ingress data:
Deployment的定义如下:
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-ingress namespace: nginx-ingress spec: replicas: 1 selector: matchLabels: app: nginx-ingress template: metadata: labels: app: nginx-ingress spec: nodeSelector: role: ingress-nginx-controller serviceAccountName: nginx-ingress containers: - image: nginx/nginx-ingress:1.7.2 imagePullPolicy: IfNotPresent name: nginx-ingress ports: - name: http containerPort: 80 hostPort: 80 - name: https containerPort: 443 hostPort: 443 securityContext: allowPrivilegeEscalation: true runAsUser: 101 #nginx capabilities: drop: - ALL add: - NET_BIND_SERVICE env: - name: POD_NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace - name: POD_NAME valueFrom: fieldRef: fieldPath: metadata.name args: - -nginx-configmaps=$(POD NAMESPACE)/nginx-config - -default-server-tls-secret=$(POD NAMESPACE)/default-server-secret
通过kubectl create命令创建nginx-ingress-controller:
查看nginx-ingress-controller容器,确认其正常运行:
用curl访问Nginx Ingress Controller
所在宿主机的80端口,验证其服务是否正常,在没有配置后端服务时Nginx会返回404应答:
3.2 创建ingress策略
本例对域名mywebsite.com
的访问设置Ingress
策略,定义对其/demo
路径的访问转发到后端webapp Service
的规则:
# mywebsite-ingress.yaml apiversion: networking.k8s.io/v1 kind: Ingress metadata: name: mywebsite-ingress spec: rules: - host: mywebsite.com http: paths: - path: /demo pathType: ImplementationSpecific backend: service: name: webapp port: number: 8080
通过该Ingress定义设置的效果:客户端对目标地址 http://mywebsite.com/demo的访问将被转发到集群内的服务“webapp”上,完整的URL为“http://webapp:8080/demo”。
在
Ingress
策略生效之前,需要先确保webapp
服务正确运行。同时注意Ingress
中对路径的定义需要与后端webapp
服务提供的访问路径一致,否则将被转发到一个不存在的路径上,引发错误。
创建:
一旦Ingress
资源成功创建,Ingress Controller
就会监控到其配置的路由策略,并更新到Nginx
的配置文件中生效。
以本例中的Nginx Controller
为例,它将更新其配置文件的内容为在Ingress
中设定的路由策略。
登录一个nginx-ingress-controller Pod
,在/etc/nginx/conf.d
目录下可以看到
Nginx Ingress Controller
自动生成的配置文件default-mywebsite-ingress.conf
,查看其内容,可以看到对mywebsite.com/demo
的转发规则的正确配置:
3.3 客户端通过Ingress Controller访问后端webapp服务
由于Ingress Controller容器通过hostPort
将服务端口号80映射到了宿主机上,所以客户端可以通过Ingress Controller
所在的Node
访问mywebsite.com
提供的服务。
需要说明的是,客户端只能通过域名
mywebsite.com
访问服务,这时要求客户端或者DNS
将mywebsite.com
域名解析到node
的真实IP
地址上。
通过curl
访问mywebsite.com
提供的服务(可以用--resolve
参数模拟DNS
解析,目标地址为域名;也可以用-H'Host:mywebsite.com'
参数设置在HTTP
头中要访问的域名,目标地址为IP
地址),可以正确访问到myweb
服务/demo/
的页面内容。
或
04 ingress资源对象配置
4.1 定义
一个ingress资源对象的定义如下:
apiversion: networking.k8s.io/v1 kind: Ingress metadata: name: mywebsite-ingress spec: rules: - host: mywebsite.com http: paths: - path: /demo pathType: ImplementationSpecific backend: service: name: webapp port: number: 8080
Ingress资源主要用于定义路由转发规则,可以包含多条转发规则的定义,通spec.rules
进行设置。下面对其中的关键配置进行说明。
4.2 规则 (rules)相关设置
规则 (rules)相关设置如下:
配置 | 描述 |
host(可选配置) | 基于域名的访问,客户端请求将作用于指定域名的客户端请求 |
http.paths | 一组根据路径进行转发的规则设置,每个路径都应配置相应的后端服务信息(服务名称和服务端口号)。只有客户端请求中的host和path都匹配之后,才会进行转发。 |
backend | 目标后端服务,包括服务的名称和端口号。 |
Ingress Controller将根据每条rule中path定义的URL路径将客户端请求转发到backend定义的后端服务上。
如果一个请求同时被在Ingress中设置的多个URL路径匹配,则系统将以最长的匹配路径为优先。如果有两条同等长度的匹配路径,则精确匹配类型(Exct) 优先于前缀匹配类型(Prefix)。
4.3 后端(Backend)设置
后端通常被设置为目标服务(Service),通常还应该为不匹配任何路由规则 (rule)的请求设置一个默认的后端,以返回HTTP 404响应码来表示没有匹配的规则。
默认的后端服务可以由Ingress Controller
提供,也可以在Ingress
资源对象中设置。
另外,如果后端不是以Kubernetes
的Service
提供的,则也可以设置为提供服务的资源对象,在这种情况下使用resource
字段进行设置。例如,下例中的Ingress
设置的后端地址为通过CRD“StorageBucket”
定义的某个服务,同时设置为默认的后端:
apiversion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-resource-backend spec: defaultBackend: resource: apiGroup: k8s.example.com kind: StorageBucket name: static-assets rules: - http: paths: - path: /icons pathType: ImplementationSpecific backend: resource: apiGroup: k8s.example.com kind: StorageBucket name: icon-assets
通过这个Ingress的定义,客户端对路径/icons
的访问将会被路由转发到后端名为“icon-assets
”的StorageBucket
服务上。不匹配任何规则的请求则侧被路由转发到默认的后端(defaultBackend
)上。