文章目录
- ingress
- 外部访问
- externalIP
- 组成
- Ingress-Nginx
- 部署 nginx-ingress-controller
- DaemonSet+HostNetwork
- 创建 ingress控制器
- 创建ingress资源
- Deployment+NodePort模式
- Ingress HTTPS 代理访问
- 生成证书和私钥
- 创建secret资源
- 创建Ingress资源
- Nginx 进行 BasicAuth
- nginx进行重写
- 总结
ingress
外部访问
在Kubernetes中,Pod的IP地址和service的ClusterIP仅可以在集群网络内部使用,对于集群外的应用是不可见的。为了使外部的应用能够访问集群内的服务,Kubernetes目前提供了以下几种方案:
- NodePort:将service暴露在节点网络上,NodePort背后就是Kube-Proxy,Kube-Proxy是沟通service网络、Pod网络和节点网络的桥梁。
- 测试环境使用还行,当有几十上百的服务在集群中运行时,NodePort的端口管理就是个灾难。因为每个端口只能是一种服务,默认端口范围只能是 30000-32767。
- LoadBalancer:通过设置LoadBalancer映射到云服务商提供的LoadBalancer地址。这种用法仅用于在公有云服务提供商的云平台上设置 Service 的场景。
- 受限于云平台,且通常在云平台部署LoadBalancer还需要额外的费用。
在service提交后,Kubernetes就会调用CloudProvider在公有云上为你创建一个负载均衡服务,并且把被代理的Pod的IP地址配置给负载均衡服务做后端。
- 受限于云平台,且通常在云平台部署LoadBalancer还需要额外的费用。
- externalIPs:service允许为其分配外部IP,如果外部IP路由到集群中一个或多个Node上,Service会被暴露给这些externalIPs。
- 通过外部IP进入到集群的流量,将会被路由到Service的Endpoint上。
- Ingress:只需一个或者少量的公网IP和LB,即可同时将多个HTTP服务暴露到外网,七层反向代理。
- 可以简单理解为service的service,它其实就是一组基于域名和URL路径,把用户的请求转发到一个或多个service的规则
externalIP
- 实现外部网络访问node内部
##创建deployment
kubectl create deployment deploy-demo1 --image=nginx:1.14 --port=80 --replicas=3
##创建 service
kubectl expose deployment deploy-demo1 --port=80 --target-port=80
apiVersion: v1
kind: Service
metadata:
labels:
app: deploy-demo1
name: deploy-demo1
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: deploy-demo1
externalIPs: ##设置 externalIP
- 192.168.10.22
status:
loadBalancer: {}
组成
-
ingress
- ingress是一个API对象,通过yaml文件来配置,ingress对象的作用是定义请求如何转发到service的规则,可以理解为配置模板。
- ingress通过http或https暴露集群内部service,给service提供外部URL、负载均衡、SSL/TLS能力以及基于域名的反向代理。ingress要依靠 ingress-controller 来具体实现以上功能。
-
ingress-controller:
- ingress-controller是具体实现反向代理及负载均衡的程序,对ingress定义的规则进行解析,根据配置的规则来实现请求转发。
- 一般来说,ingress-controller的形式都是一个pod,里面跑着daemon程序和反向代理程序。daemon负责不断监控集群的变化,根据 ingress对象生成配置并应用新配置到反向代理,比如ingress-nginx就是动态生成nginx配置,动态更新upstream,并在需要的时候reload程序应用新配置
-
Ingress-Nginx github 地址:https://github.com/kubernetes/ingress-nginx
-
Ingress-Nginx 官方网站:https://kubernetes.github.io/ingress-nginx/
-
总结
- ingress-controller才是负责具体转发的组件,通过各种方式将它暴露在集群入口,外部对集群的请求流量会先到 ingress-controller, 而ingress对象是用来告诉ingress-controller该如何转发请求,比如哪些域名、哪些URL要转发到哪些service等等。
Ingress-Nginx
- Ingress-Nginx 工作原理
- ingress-controller通过和 kubernetes APIServer 交互,动态的去感知集群中ingress规则变化,
- 然后读取它,按照自定义的规则,规则就是写明了哪个域名对应哪个service,生成一段nginx配置,
- 再写到nginx-ingress-controller的pod里,这个ingress-controller的pod里运行着一个Nginx服务,控制器会把生成的 nginx配置写入 /etc/nginx.conf文件中,
- 然后reload一下使配置生效。以此达到域名区分配置和动态更新的作用
部署 nginx-ingress-controller
###在线下载ingress-controller Pod及相关资源
wget https://gitee.com/mirrors/ingress-nginx/raw/controller-v1.3.0/deploy/static/provider/cloud/deploy.yaml
##修改镜像地址
修改镜像地址为:
image: registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.3.0@sha256:d1707ca76d3b044ab8a28277a2466a02100ee9f58a86af1535a3edf9323ea1b5
image: registry.cn-hangzhou.aliyuncs.com/google_containers/kube-webhook-certgen:v1.1.1@sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660
DaemonSet+HostNetwork
- 用DaemonSet结合nodeselector来部署ingress-controller到特定的node上,然后使用HostNetwork直接把该pod与宿主机node的网络打通,直接使用宿主机的80/433端口就能访问服务。
- 这时,ingress-controller所在的node机器就很类似传统架构的边缘节点,比如机房入口的nginx服务器。该方式整个请求链路最简单,性能相对NodePort模式更好。缺点是由于直接利用宿主机节点的网络和端口,一个node只能部署一个ingress-controller pod。
- 比较适合大并发的生产环境使用。
创建 ingress控制器
##修改 Deployment 为 DaemonSet ,指定节点运行,并开启 hostNetwork 网络
vim deploy.yaml
...
apiVersion: apps/v1
# 修改 kind
#kind: Deployment
kind: DaemonSet
......
spec:
......
template:
......
spec:
# 使用宿主机网络
hostNetwork: true
# 修改选择节点选择器
nodeSelector:
ingress: "true"
......
##创建
kubectl apply -f deploy.yaml
##在随便一个 node节点中查看
netstat -lntp | grep nginx
由于配置了 hostnetwork,nginx 已经在 node 主机本地监听 80/443/8181 端口。
其中 8181 是 nginx-controller 默认配置的一个 default backend(Ingress 资源没有匹配的 rule 对象时,流量就会被导向这个 default backend)。
这样,只要访问 node 主机有公网 IP,就可以直接映射域名来对外网暴露服务了
创建ingress资源
##创建pod资源
kubectl create deployment deploy-demo1 --image=nginx:1.14 --port=80 --replicas=3
##为pod节点创建service资源
kubectl expose deployment deploy-demo1 --port=8080 --target-port=80
##创建ingress
kubectl create ingress ingress-demo1 --class=nginx --rule="www.a.com/=deploy-demo1:8080" --dry-run=client -o yaml > ingress-demo1.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-demo1
spec:
ingressClassName: nginx
rules:
- host: www.a.com
http:
paths:
- backend:
service:
name: deploy-demo1
port:
number: 8080
path: /
pathType: Prefix
status:
loadBalancer: {}
ingressClassName 指定 IngressClass,用来指定选择的 Ingress Controller
host 主机名可以是精确匹配,或者使用通配符来匹配,但通配符仅覆盖一个 DNS 标签(例如 *.foo.com 不匹配 baz.bar.foo.com)。
pathType 支持的路径类型有三种:
Exact:精确匹配 URL 路径,且区分大小写。
Prefix:基于以 / 分隔的 URL 路径前缀匹配。匹配区分大小写。如果路径的最后一个元素是请求路径中最后一个元素的子字符串,则不会匹配 (例如:/foo/bar 匹配 /foo/bar/baz, 但不匹配 /foo/barbaz)。
ImplementationSpecific:对于这种路径类型,匹配方法取决于 IngressClass。具体实现可以将其作为单独的 pathType 处理或者与 Prefix 或 Exact 类型作相同处理。
具体可详见:https://kubernetes.io/zh-cn/docs/concepts/services-networking/ingress/#the-ingress-resource
##在另外一台主机上
##修改host
vim /etc/hosts
192.168.10.20 www.a.com
##访问网址查看
curl http://www.a.com
###在创建一个 deployment和servoce
kubectl create deployment deploy-demo2 --image=nginx:1.15 --port=80 --replicas=3
kubectl expose deployment deploy-demo2 --port=9090 --target-port=80
##创建ingress
kubectl create ingress ingress-demo1 --class=nginx --rule="www.b.com/=deploy-demo2:9090" --dry-run=client -o yaml > ingress-demo2.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-demo2
spec:
ingressClassName: nginx
rules:
- host: www.b.com
http:
paths:
- backend:
service:
name: deploy-demo2
port:
number: 9090
path: /
pathType: Prefix
status:
loadBalancer: {}
Deployment+NodePort模式
- 同样用deployment模式部署ingress-controller,并创建对应的service,但是type为NodePort。这样,ingress就会暴露在集群节点ip的特定端口上。
- 由于nodeport暴露的端口是随机端口,一般会在前面再搭建一套负载均衡器来转发请求。该方式一般用于宿主机是相对固定的环境ip地址不变的场景。
- NodePort方式暴露ingress虽然简单方便,但是NodePort多了一层NAT,在请求量级很大时可能对性能会有一定影响
##修改配置文件
vim deploy.yaml
kind: Deployment
type: NodePort
externalTrafficPolicy: Cluster
##创建ingress资源
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-demo1
spec:
ingressClassName: nginx
rules:
- host: www.a.com
http:
paths:
- backend:
service:
name: deploy-demo1
port:
number: 8080
path: /
pathType: Prefix
- host: www.b.com
http:
paths:
- backend:
service:
name: deploy-demo2
port:
number: 9090
path: /
pathType: Prefix
status:
loadBalancer: {}
##访问验证
curl http://www.a.com:30080
curl http://www.b.com:30080
Ingress HTTPS 代理访问
生成证书和私钥
openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginxsvc/O=nginxsvc"
创建secret资源
kubectl create secret tls tls-secret --key tls.key --cert tls.crt
创建Ingress资源
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-https
spec:
ingressClassName: nginx
tls:
- hosts:
- www.a.com
secretName: tls-secret
rules:
- host: www.a.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: deploy-demo1
port:
number: 8080
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-http
spec:
ingressClassName: nginx
rules:
- host: www.b.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: deploy-demo2
port:
number: 9090
Nginx 进行 BasicAuth
yum -y install httpd-tools
htpasswd -c auth zhangsan
New password: 123
Re-type new password: 123
Adding password for user zhangsan
kubectl create secret generic basic-auth --from-file=auth
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-http
annotations:
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: basic-auth
nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - zhangsan'
spec:
ingressClassName: nginx
rules:
- host: www.b.com
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: deploy-demo2
port:
number: 9090
nginx进行重写
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: rewrite
namespace: default
spec:
ingressClassName: nginx
rules:
- host: www.a.com
http:
paths:
- path: /something(/|$)(.*)
pathType: Prefix
backend:
service:
name: deply-demo1
port:
number: 8080
总结
-
K8S集群外的客户端应用访问K8S集群内部服务的方案
- Service:NodePort LoadBalancer externalIPs 只支持四层反向代理,端口数量有限,如果业务服务应用很多时端口的管理成本会比较高
- Ingress:支持七层反向代理,可自定义规则根据用户请求的 域名 或 URL路径 转发给指定的 Service
-
ingress 的组成:
- ingress资源对象:设置转发规则,告诉 ingress控制器应该根据什么域名或URL路径转发给相应的 Service 资源
- ingress控制器(ingress-controller):根据 ingress 资源配置的转发规则转发用户请求的组件,以 Pod 形式运行的
-
ingress 的使用:
- DaemonSet + Host网络模式 部署 ingress-controller
- 数据流向:
- 客户端 -> 防火墙、前端负载均衡器 -> Node节点的80/443端口进入ingress-controller -> 根据转发规则 -> 业务Pod的Service -> 业务Pod
- Deployment + NodePort/LoadBalancer类型的Service 部署 ingress-controller
- 数据流向:
- 客户端 -> 防火墙、前端负载均衡器 -> ingress-controller的Service(NodeIP:NodePort)-> ingress-controller -> 根据转发规则 -> 业务Pod的Service -> 业务Pod
ingress 的配置:
kubectl create ingress <资源名称> --rule=<域名>/<URL路径>=<Service名称>:<Service端口> --class=<ingress控制器类>
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: 资源名称
spec:
ingressClassName: 指定ingress控制器类
rules:
- host: 目标域名(可以精确匹配或通配符匹配,比如 *.kgc.com 可以匹配www.kgc.com或mail.kgc.com等,但不能匹配ky22.www.kgc.com)
http:
paths:
- path: 目标域名后的URL路径(比如 / 代表网页根路径,或者 /test)
pathType: Prefix|Exact(Exact用于精确匹配URL路径;Prefix用于前缀匹配,且只能匹配完整的字符串,/abc能匹配/abc/123,但不能匹配/abc123)
backend:
service:
name: 目标Service资源的名称
port:
number: 目标Service的端口
#基于不同的 URL路径 的代理转发
- path: URL路径2
....
#基于不同的 域名 的代理转发
- host: 域名2
http:
....
#基于 https 代理转发
1)先获取 tls 证书和私钥文件
2)创建 tls 类型的 Secret资源 kubectl create secret tls <资源名称> --cert=证书文件路径 --key=私钥文件路径
3)创建 ingress 资源,引用 tls 类型的 Secret资源
spec:
tls:
- hosts:
- 指定使用 https 访问的目标域名
secretName: 指定tls类型的Secret资源
#基于 basic-auth 访问认证
1)使用 htpasswd 创建用户数据文件,固定文件名为 auth
2)创建 Secret资源 kubectl create secret generic <资源名称> --from-file=auth
3)创建 ingress 资源,在 annotations 注释字段中添加配置信息
metadata:
annotations:
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: Secret资源名称
nginx.ingress.kubernetes.io/auth-realm: '窗口提示信息'
#基于 rewrite 重写访问路径
创建 ingress 资源,在 annotations 注释字段中添加配置信息
metadata:
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$2
....
spec:
rules:
- host: "www.kgc.com"
http:
paths:
- pathType: Prefix
path: /something(/|$)(.*)
backend:
service:
name: myapp-ky29
port:
number: 9090
捕获的正则表达式 任何字符(.*) 将其分配给占位符 $2,然后将其用作注释中的参数 rewrite-target
www.kgc.com[:端口]/something 重写为 www.kgc.com[:端口]/
www.kgc.com[:端口]/something/ 重写为 www.kgc.com[:端口]/
www.kgc.com[:端口]/something/new 重写为 www.kgc.com[:端口]/new
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: https://www.accp.com:30443
spec:
rules:
- host: "www.kgc.com"
将任何使用 www.kgc.com 作域名的访问请求,都重写成 https://www.accp.com:30443
metadata:
annotations:
nginx.ingress.kubernetes.io/app-root: /app1
spec:
rules:
- host: "www.kgc.com"
http:
paths:
- pathType: Prefix
path: /
将访问 www.kgc.com[:端口]/ 的请求,都重写成 www.kgc.com[:端口]/app1