k8s入门教程十:Ingress与Ingress controller

简介

在kubernetes中对外暴露服务的方式有两种:service(NodePort或者外部LoadBalancer)和ingress,其中service是提供四层的负载均衡,通过iptables DNAT或lvs nat模式实现后端Pod的代理请求。如需实现http,域名,URI,证书等请求方式,service是无法实现的,需要借助于ingress来来实现,本文将来介绍ingress相关的内容。

ingress是一种通过http协议暴露kubernetes内部服务的api对象,即充当Edge Router边界路由器的角色对外基于七层的负载均衡调度机制,能够提供以下几个功能:

  • 负载均衡,将请求自动负载均衡到后端的Pod上;
  • SSL加密,客户端到Ingress Controller为https加密,到后端Pod为明文的http;
  • 基于名称的虚拟主机,提供基于域名或URI更灵活的路由方式

实现Ingress包含的组件有:

  • Ingress,客户端,负责定义ingress配置,将请求转发给Ingress Controller;
  • Ingress Controller,Ingress控制器,实现七层转发的Edge Router,通过调用k8s的api动态感知集群中Pod的变化而动态更新配置文件并重载, Controller需要部署在k8s集群中以实现和集群中的pod通信,通常以DaemonSets或Deployments的形式部署,并对外暴露80和443端口,对于DaemonSets来说,一般是以hostNetwork或者hostPort的形式暴露,Deployments则以NodePort的方式暴露,控制器的多个节点则借助外部负载均衡ExternalLB以实现统一接入;
  • Ingress配置规则,Controller控制器通过service服务发现机制动态实现后端Pod路由转发规则的实现;
  • Service,kuberntes中四层的负载均衡调度机制,Ingress借助service的服务发现机制实现集群中Pod资源的动态感知;
  • Pod,后端实际负责响应请求容器,由控制器如Deployment创建,通过标签Labels和service关联,服务发现。

简而言之,ingress控制器借助service的服务发现机制实现配置的动态更新以实现Pod的负载均衡机制实现,由于涉及到Ingress Controller的动态更新,目前社区Ingress Controller大体包含两种类型的控制器:

  • 传统的七层负载均衡如Nginx,HAproxy,开发了适应微服务应用的插件,具有成熟,高性能等优点;
  • 新型微服务负载均衡如Traefik,Envoy,Istio,专门适用于微服务+容器化应用场景,具有动态更新特点;
类型 常见类型 优点 缺点
传统负载均衡 nginx,haproxy 成熟,稳定,高性能 动态更新需reload配置文件
微服务负载均衡 Traefik,Envoy,Istio 天生为微服务而生,动态更新 性能还有待提升

Nginx Ingress

Nginx Ingress Controller是实现ingress的具体实现,利用openresty开发,基于deployments部署;其监听ingress资源变化,根据ingress配置生成若干server段,每一个server段对应一个应用的Domain,反向代理到对应service的若干POD,所有配置均生成到nginx.conf并自动热加载。

安装

首先需要安装Nginx Ingress Controller控制器,控制器安装方式包含两种:DaemonSets和Deployments。

  • DaemonSets通过hostPort的方式暴露80和443端口,可通过Node的调度由专门的节点实现部署
  • Deployments则通过NodePort的方式实现控制器端口的暴露,借助外部负载均衡实现高可用负载均衡

打开 https://kubernetes.github.io/ingress-nginx/ ,参考官方文档,以下是快速部署方法:

1
2
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.28.0/deploy/static/mandatory.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.28.0/deploy/static/provider/baremetal/service-nodeport.yaml

注意:镜像 quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.28.0 很慢,可以提前下载好。

部署成功之后,就可以看到以下的nginx-ingress-controller了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@master ingress-nginx]# kubectl get pods -n ingress-nginx nginx-ingress-controller-5556bd798f-dngnv
NAME READY STATUS RESTARTS AGE
nginx-ingress-controller-5556bd798f-dngnv 1/1 Running 0 29s
[root@master ingress-nginx]#
[root@master ingress-nginx]# kubectl get deployments.apps -n ingress-nginx nginx-ingress-controller
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-ingress-controller 1/1 1 1 48s
[root@master ingress-nginx]# kubectl exec -n ingress-nginx -it nginx-ingress-controller-5556bd798f-dngnv -- /nginx-ingress-controller --version
-------------------------------------------------------------------------------
NGINX Ingress controller
Release: 0.28.0
Build: git-1f93cb8f3
Repository: https://github.com/kubernetes/ingress-nginx
nginx version: nginx/1.17.7

-------------------------------------------------------------------------------
[root@master ingress-nginx]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx NodePort 10.96.168.79 <none> 80:31863/TCP,443:30442/TCP 21s

用法简介

Ingress资源时基于HTTP虚拟主机或URL的转发规则,需要强调的是,这是一条转发规则。它在资源配置清单中的spec字段中嵌套了rules、backend和tls等字段进行定义。如下示例中定义了一个Ingress资源,其包含了一个转发规则:将发往myapp.magedu.com的请求,代理给一个名字为myapp的Service资源。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: extensions/v1beta1		
kind: Ingress
metadata:
name: ingress-myapp
namespace: default
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: myapp.magedu.com
http:
paths:
- path:
backend:
serviceName: myapp
servicePort: 80

Ingress 中的spec字段是Ingress资源的核心组成部分,主要包含以下3个字段:

  • rules:用于定义当前Ingress资源的转发规则列表;由rules定义规则,或没有匹配到规则时,所有的流量会转发到由backend定义的默认后端。
  • backend:默认的后端用于服务那些没有匹配到任何规则的请求;定义Ingress资源时,必须要定义backend或rules两者之一,该字段用于让负载均衡器指定一个全局默认的后端。
  • tls:TLS配置,目前仅支持通过默认端口443提供服务,如果要配置指定的列表成员指向不同的主机,则需要通过SNI TLS扩展机制来支持该功能。

backend对象的定义由2个必要的字段组成:serviceName和servicePort分别用于指定流量转发的后端目标Service资源名称和端口。
rules对象由一系列的配置的Ingress资源的host规则组成,这些host规则用于将一个主机上的某个URL映射到相关后端Service对象,其定义格式如下:

1
2
3
4
5
6
7
8
9
spec:
rules:
- hosts: <string>
http:
paths:
- path:
backend:
serviceName: <string>
servicePort: <string>

实例1:绑定域名

创建一个名为nginx-1.7.9的Deployment,一个名为nginx-svc179的SVC,再创建一个ingress,可以通过域名 179.fdm.com 来访问这个Deployment,yaml全文如下:

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
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-1.7.9
spec:
replicas: 2
selector:
matchLabels:
name: nginx-1.7.9
template:
metadata:
labels:
name: nginx-1.7.9
spec:
containers:
- name: nginx
image: nginx:1.7.9
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
lifecycle:
postStart:
exec:
command: ["/bin/sh","-c","echo nginx 1.7.9 >/usr/share/nginx/html/index.html"]
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc179
spec:
ports:
- port: 80
targetPort: 80
protocol: TCP
selector:
name: nginx-1.7.9
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-test
spec:
rules:
- host: 179.fdm.com
http:
paths:
- path: /
backend:
serviceName: nginx-svc179
servicePort: 80

创建完成之后,查看状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@master ingress-nginx]# kubectl get ingresses,svc,deployment
NAME HOSTS ADDRESS PORTS AGE
ingress.extensions/nginx-ingress179 179.fdm.com 10.96.168.79 80 5m6s

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/nginx-svc179 ClusterIP 10.105.98.53 <none> 80/TCP 5m6s

NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx-1.7.9 2/2 2 2 5m6s

[root@master ingress-nginx]# kubectl get svc -n ingress-nginx
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx NodePort 10.96.168.79 <none> 80:31863/TCP,443:30442/TCP 57d

做好强制解析,就可以使用 http://179.fdm.com:31863/ 了。这里为什么是端口31863呢?这是 ingress-nginx 所使用的端口。

1
2
3
4
5
6
7
8
9
10
[root@master ingress-nginx]# curl -I http://179.fdm.com:31863 --resolve 179.fdm.com:31863:192.168.1.60
HTTP/1.1 200 OK
Server: nginx/1.17.7
Date: Sun, 05 Apr 2020 13:58:09 GMT
Content-Type: text/html
Content-Length: 12
Connection: keep-alive
Last-Modified: Sun, 05 Apr 2020 13:55:00 GMT
ETag: "5e89e334-c"
Accept-Ranges: bytes

我们可以进入 ingress-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
[root@master ingress-nginx]# kubectl exec -n ingress-nginx -it nginx-ingress-controller-5556bd798f-dngnv -- /bin/bash
bash-5.0$ cat nginx.conf
...
# Global filters

## start server 179.fdm.com
server {
server_name 179.fdm.com ;

listen 80 ;
listen 443 ssl http2 ;

set $proxy_upstream_name "-";

ssl_certificate_by_lua_block {
certificate.call()
}

location / {

set $namespace "default";
set $ingress_name "nginx-ingress179";
set $service_name "nginx-svc179";
...

注意,现在的nginx ingress版本是看不到upstream_balancer了,由通过lua动态加载了。

实例2:TLS加密

生成TLS证书

1
2
3
4
5
6
7
8
9
10
11
[root@master ingress-nginx]# openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"
Generating a 2048 bit RSA private key
..............................+++
.........................................................................+++
writing new private key to 'tls.key'
-----
[root@master ingress-nginx]# kubectl create secret tls tls-secret --key tls.key --cert tls.crt
secret/tls-secret created
[root@master ingress-nginx]# kubectl get secrets tls-secret
NAME TYPE DATA AGE
tls-secret kubernetes.io/tls 2 48s

还是使用之前创建好的deployment,再加一个SSL证书,Yaml如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-ingress-auth
spec:
tls:
- hosts:
- auth.fdm.com
secretName: tls-secret
rules:
- host: auth.fdm.com
http:
paths:
- path: /
backend:
serviceName: nginx-svc179
servicePort: 80

这样就可以通过 https//auth.fdm.com:30442 来访问了。

参考链接

  • 本文作者: wumingx
  • 本文链接: https://www.wumingx.com/k8s/kubernetes-Ingress.html
  • 本文主题: k8s入门教程十:Ingress与Ingress controller
  • 版权声明: 本博客所有文章除特别声明外,转载请注明出处!如有侵权,请联系我删除。
0%