目录
2.3 部署Ingress NGINX Controller
一、介绍
在Kubernetes中Service是工作在第四层(既网络模型中的第四层,既TCP/UDP层)。而HTTP和HTTPS是在网络模型中第七层,Ingress就是工作在第七层的路由机制。
Open Systems Interconnection Model (OSI Model):
- 第四层L4 refer to layer 4 (Transport Layer; TCP, UDP)
- 第七层L7 refer to layer 7 (Application Layer; HTTP)
在Kubernetes中已经有了Service,为什么还需要Ingress呢?
- 由于Ingress工作在第七层,所以不再局限于在IP和端口层面控制。而是可以基于HTTP/HTTPS进行分发。比如根据URL中包含特定的字符进行分发,比如根据HTTP请求头的内容进行分发,比如基于Cookie的回话亲和性等规则。
- 为多个不同Service提供统一代理和分发。例如:对于type=LoadBalancer类型的Service,在云厂商托管情况会自动创建云负载均衡器。所以每个Service都会有一个负载均衡器,这种做法既浪费资源,也难以管理,更合理的做法是Kubernetes提供相对统一的负载均衡器。因此这种统一的、为不同Service提供代理和分发就是Ingress。例如对外由Ingress统一暴露某个域名http://www.zyp.com,其中访问http://www.zyp.com/coffee域名分发至后端的Coffee服务,访问http://www.zyp.com/tea域名分发至后端的Tea服务。
所以Ingress本身就是Service及Pod等各类资源,可以说Ingress是“Service”的“Service”。
Ingress示意图如下::

在Ingress中分为:
- Ingress Resource 就是定义的HTTP或HTTPS分发规则Rules。比如通过yaml清单文件创建kind为Ingress的Kubernetes资源定义。
- Ingress Controller 对资源定义的rules进行具体处理的实现体。在Kubernetes中几十种Ingress Controller,列表见官网https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/。
二、安装Ingress控制器Controller
下面选择比较常用的Ingress NGINX Controller进行演示。安装部署Ingress NGINX Controller可以有多种方式,下面通过yaml清单文件方式部署。
官网网站:https://kubernetes.github.io/ingress-nginx/
Github地址:https://github.com/kubernetes/ingress-nginx 有与Kubernetes版本对应关系表。
2.1 下载清单文件
安装部署Ingress NGINX Controller可以有多种方式,比如Helm方式,比如yaml清单文件方式。下面通过yaml清单文件方式部署。该清单文件创建如下类型的资源:
- 1个Namespace,名为“ingress-nginx”的。 (以下资源在该Namespace下创建)
- 2个ServiceAccount,名为“ingress-nginx”、“ingress-nginx-admission”
- 2个Role,名为“ingress-nginx”、“ingress-nginx-admission”
- 2个ClusterRole,名为“ingress-nginx”、“ingress-nginx-admission”
- 2个RoleBinding
- 2个ClusterRoleBinding
- 1个ConfigMap,名为“ingress-nginx-controller”
- 2个Service,type=LoadBalancer名为“ingress-nginx-controller”、type=ClusterIP名为“ingress-nginx-controller-admission”。 type=LoadBalancer的Service用途是把“Ingress NGINX Controller”作为统一入口对外暴露(端口80与443),由其接收流量后,再根据分发规则Rules分发至后端各Service。
- 1个Deployment,使用镜像“registry.k8s.io/ingress-nginx/controller”
- 2个Job,名为“ingress-nginx-admission-create”、“ingress-nginx-admission-patch”
- 1个IngressClass,名为“nginx”,并且controller指定关联到具体实现的Deployment中Pod。
- 1个ValidatingWebhookConfiguration
在Kubernetes的Control控制平面上:
# 下载yaml清单文件并重命名
curl -o ingress-nginx-controller.yaml https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.13.3/deploy/static/provider/cloud/deploy.yaml
# 查看该yaml文件中有哪些资源类型
grep "^kind" ingress-nginx-controller.yaml
#若国内无法直接访问registry.k8s.io,则替换为国内源
sed -i 's#registry.k8s.io#k8s.nju.edu.cn#' ingress-nginx-controller.yaml
2.2 外部负载均衡器
在该yaml清单文件中,type=LoadBalancer名为“ingress-nginx-controller”的Service用途是作为统一入口对外暴露,由其接收流量。如果是云厂商托管的Kubernetes(如Amazon的EKS、阿里云的ACK)会自动检测到type=LoadBalancer的Service,并通过云控制器管理器调用云厂商的 API(如 AWS EC2 API、阿里云 SLB API)自动创建一个云负载均衡器,并将云负载均衡器IP自动注入到“ingress-nginx-controller”的Service中。
但本文演示环境不属于云上托管,是本地自行搭建的私有环境,因此没有云会自动创建负载均衡器,也不能将IP自动注入Service。此处为了简易起见,通过手工配置一个IP来模拟外部负载均衡器。模块方式具体为:
- 在Kubernetes集群找其中任意一台节点机器,对该节点增加配置一个IP地址作为外部负载均衡器IP。要求该IP地址能被集群外部直接访问。在本文中增加配置IP为192.168.43.50
- 在yaml清单文件里,“ingress-nginx-controller”的Service配置下手工增加externelIPs,模拟云厂商托管场景下自动注入外部负载均衡器IP。
注:type=LoadBalancer的Service相关知识可参见:https://blog.csdn.net/zyplanke/article/details/151224929
针对模拟方式第1步,在一台Kubernetes节点机器上,以root用户执行以下命令增加IP:
#在已有的网卡设备(以下为ens33为例)上增加配置一个IP,并设定别名为“ens33:2”
#以下命令仅当前临时有效。若希望Linux重启后仍有效,则还应配置在网卡配置文件中
sudo ip addr add 192.168.43.50 dev ens33 label ens33:2
#以上命令执行成功后,则可以ping通该IP。可对该IP再进一步配置域名(本文略)
针对模拟方式第2步,在yaml清单文件中对“ingress-nginx-controller”的Service配置下,新增externalIPs、调整externalTrafficPolicy配置:

2.3 部署Ingress NGINX Controller
Kubernetes的Control控制平面上:
# 根据修改后的清单文件部署
kubectl apply -f ingress-nginx-controller.yaml
# 查看该命名空间下的资源
kubectl get all -n ingress-nginx
根据该namespace查看已创建的资源如下(注意输出展示Service的EXTERNAL-IP、PORT):

查看Pod并访问该Pod,可以看到Nginx的应答。由于此时还为配置Ingress的分发规则,因此HTTP返回的是Nginx自身,而不是后端服务(更准确说Pod中容器)返回的应答。

自此,Ingress Controller已安装部署完毕,但还没有配置分发规则。下一步以示例来展示。
三、完整示例
3.1 准备后端应用
分别准备两个后端应用如下:
- coffee服务:1个的Service(端口11110)、两个Pod副本(端口1111)
- tea服务:1个的Service(端口22220)、两个Pod副本(端口2222)
为便于演示,Pod中容器使用alpine镜像并通过nc命令启动简易HTTP服务端。
1、创建coffee服务。准备demo-coffee.yaml文件如下:
apiVersion: v1
kind: Service
metadata:
name: svc-coffee
spec:
selector: # 标签选择器,选择满足条件的后端Pod
app: http-coffee
type: ClusterIP
ports:
- port: 11110 # Service在clusterIP上的监听端口
targetPort: 1111 # 转发至后端Pod上的端口,若未指定则等于port
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: p-alpine-coffee
spec:
replicas: 2 # 期望的副本数,默认为1
selector: # 标签选择器。若多个matchLabels则为AND关系;还可以用matchExpressions来表达复杂选择关系
matchLabels:
app: http-coffee # 需与.spec.template.metadata.labels一致
template: # Pod模版定义
metadata:
labels:
app: http-coffee
spec:
containers:
- name: c-alpine #容器名(需符合RFC 1123,不能有下划线)
image: alpine #镜像名
command: #容器启动时执行命令,通过nc命令启动简易HTTP服务端
- sh
- -c
- |
while : ;
do
(echo "HTTP/1.1 200 OK";
echo "";
echo "Demo HTTP Server by nc! "
echo "HTTP serverHostname=`hostname` serverIP=`hostname -i` serverTime=`date`";
) | nc -v -l -p 1111;
done
ports:
- containerPort: 1111 #展示性申明容器对外暴露的端口,可多个
2、创建后,可以看到直接通过其Service访问,其应答分别是由不同的Pod(容器)返回的:

3、创建tea服务。准备demo-tea.yaml文件如下:
apiVersion: v1
kind: Service
metadata:
name: svc-tea
spec:
selector: # 标签选择器,选择满足条件的后端Pod
app: http-tea
type: ClusterIP
ports:
- port: 22220 # Service在clusterIP上的监听端口
targetPort: 2222 # 转发至后端Pod上的端口,若未指定则等于port
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: p-alpine-tea
spec:
replicas: 2 # 期望的副本数,默认为1
selector: # 标签选择器。若多个matchLabels则为AND关系;还可以用matchExpressions来表达复杂选择关系
matchLabels:
app: http-tea # 需与.spec.template.metadata.labels一致
template: # Pod模版定义
metadata:
labels:
app: http-tea
spec:
containers:
- name: c-alpine #容器名(需符合RFC 1123,不能有下划线)
image: alpine #镜像名
command: #容器启动时执行命令,通过nc命令启动简易HTTP服务端
- sh
- -c
- |
while : ;
do
(echo "HTTP/1.1 200 OK";
echo "";
echo "Demo HTTP Server by nc! "
echo "HTTP serverHostname=`hostname` serverIP=`hostname -i` serverTime=`date`";
) | nc -v -l -p 2222;
done
ports:
- containerPort: 2222 #展示性申明容器对外暴露的端口,可多个
4、创建后,可以看到直接通过其Service访问,应答分别是由不同的Pod(容器)返回的:

3.2 定义Ingress规则(单Host多Path)
这里对外提供一个域名,每个域名后分别两个子Path分别对应后端coffee与tea两个应用服务。对此将Ingress Resource(既规则)写成yaml清单文件one-host-ingress.yaml,内容如下:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: one-host-ingress
spec:
ingressClassName: nginx #指定本规则由哪种Ingress Controller实现
rules:
- host: "*.zyp.com" #与HTTP请求头中Host对应(可带通配符)。不能为IP格式
http:
paths:
- path: /coffee #HTTP请求中URL,必须以“/” 开头
pathType: Prefix #path匹配类型:Exact完全精准匹配;按“/”拆分URL路径前缀匹配
backend:
service: #后端服务需与本Ingress同属一个namespace
name: svc-coffee #流量分发至后端服务名
port: #流量分发至后端服务中哪个端口(可以为name端口名 或 number数字端口号)
number: 11110
- path: /tea #HTTP请求中URL,必须以“/” 开头
pathType: Prefix #path匹配类型:Exact完全精准匹配;按“/”拆分URL路径前缀匹配
backend:
service: #后端服务需与本Ingress同属一个namespace
name: svc-tea #流量分发至后端服务名
port: #流量分发至后端服务中哪个端口(可以为name端口名 或 number数字端口号)
number: 22220
Kubernetes的Control控制平面上:
# 部署Ingress清单文件部署
kubectl apply -f one-host-ingress.yaml
# 查看Ingress资源(注意输出展示的Address刚开始可能无值,需等几十秒后才自动有值)
kubectl describe ingress/one-host-ingress

注意输出展示的Rules中,Ingress通过服务已直接获得后端Pod的IP与端口,因此通过Ingress分发时可直接一步到位分发至Pod。
然后再Kubernetes集群之外,找台机器通过访问外部负载均衡器:
# 设置HTTP请求头
curl -H "Host: www.zyp.com" http://192.168.43.50/coffee
curl -H "Host: www.zyp.com" http://192.168.43.50/tea
注1:Ingress规则中Host是与HTTP请求头中Host匹配,不是与URL。
注2:curl或者浏览器默认会根据请求URL中内容自动设置Host请求头。但由于本环境中没有对外部负载均衡器配置DNS域名,因此在URL中只能写IP,对此需要手工设置HTTP请求头以便通过Host与Ingress规则匹配。

至此,通过同个Host不同子Path均成功访问。
3.3 定义Ingress规则(多Host)
有时需要在同一入口(比如一个入口公网IP)上同时对外提供多个域名(既Host)。虽然是同一入口,但通过不同的域名访问,返回的内容是不同的。
对此,在Ingress中配置多个Host,并将不同Host分发到不同的后端服务上。写成yaml清单文件multi-host-ingress.yaml,内容如下:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: multi-host-ingress
spec:
ingressClassName: nginx #指定本规则由哪种Ingress Controller实现
rules:
- host: "*.coffee.ltd" #与HTTP请求头中Host对应(可带通配符)。不能为IP格式
http:
paths:
- path: /coffee #HTTP请求中URL,必须以“/” 开头
pathType: Prefix #path匹配类型:Exact完全精准匹配;按“/”拆分URL路径前缀匹配
backend:
service: #后端服务需与本Ingress同属一个namespace
name: svc-coffee #流量分发至后端服务名
port: #流量分发至后端服务中哪个端口(可以为name端口名 或 number数字端口号)
number: 11110
- host: "*.tea.ltd" #与HTTP请求头中Host对应(可带通配符)。不能为IP格式
http:
paths:
- path: /tea #HTTP请求中URL,必须以“/” 开头
pathType: Prefix #path匹配类型:Exact完全精准匹配;按“/”拆分URL路径前缀匹配
backend:
service: #后端服务需与本Ingress同属一个namespace
name: svc-tea #流量分发至后端服务名
port: #流量分发至后端服务中哪个端口(可以为name端口名 或 number数字端口号)
number: 22220
Kubernetes的Control控制平面上:
# 部署Ingress清单文件部署
kubectl apply -f multi-host-ingress.yaml
# 查看Ingress资源(注意输出展示的Address刚开始可能无值,需等几十秒后才自动有值)
kubectl describe ingress/multi-host-ingress

注意输出展示的Rules中,Ingress通过服务已直接获得后端Pod的IP与端口,因此通过Ingress分发时可直接一步到位分发至Pod。
然后再Kubernetes集群之外,找台机器通过访问外部负载均衡器:
# 设置HTTP请求头
curl -H "Host: a.coffee.ltd" http://192.168.43.50/coffee
curl -H "Host: b.tea.ltd" http://192.168.43.50/tea
注1:Ingress规则中Host是与HTTP请求头中Host匹配,不是与URL。
注2:curl或者浏览器默认会根据请求URL中内容自动设置Host请求头。但由于本环境中没有对外部负载均衡器配置DNS域名,因此在URL中只能写IP,对此需要手工设置HTTP请求头以便通过Host与Ingress规则匹配。

至此,通过不同Host均成功访问。
3.4 探究访问路径
客户端通过Ingress访问后端应用的路径理论上为:
客户端(curl等)→外部负载均衡器→Ingress(对应Controller实现)→Service→Pod中容器应用
但实际访问路径为:
客户端(curl等)→外部负载均衡器→Ingress(对应Controller实现)→Pod中容器应用
注意1:不同的外部负载均衡器实现方式可能不同,在本例中从“外部负载均衡器”至“Ingress(对应Controller实现)”通过NAT转发完成(通过IPVS或者iptables转发),所以无法看到外部负载均衡器IP上监听LISTEN端口。
注意2:上文实际访问路径中,在Pod前没有Service。因为Ingress通过服务已直接获得后端Pod的IP与端口,因此在Ingress(对应Controller实现)分发时可一步到位直接分发至Pod。
3.5 探究Ingress规则如何生效
Ingress Resource只是规则定义,最终如何生效还是靠Ingress Controller的具体实现,不同的Controller类型有不同的具体实现方式。对于本文选择的“Ingress NGINX Controller”这款,它是对Ingress定义规则是如何具体实现的呢?
在以上Ingress规则定义后,可以进入到NGINX Controller容器内
#先进入容器内
kubectl exec -it pod/ingress-nginx-controller-dcfb8c47-l8msj -n ingress-nginx -- /bin/bash
#再进入容器内部后,查看最新的nginx.conf
vi /etc/nginx/nginx.conf
可以看到根据Ingress中定义的规则,已自动写入到nginx.conf文件中。这就是“Ingress NGINX Controller”这款对Ingress定义规则的具体实现方式。

1214

被折叠的 条评论
为什么被折叠?



