8.基于 Ingress-nginx-controller 实现 k8s 七层代理

负载均衡是什么?

bash 复制代码
负载均衡(Load Balancing)是指将计算机或网络资源分配给多个任务或请求,以便有效地处理负
载,提高系统性能和可靠性的技术或方法。在计算机网络中,负载均衡可以应用于各种场景,如服务器负
载均衡、网络负载均衡和数据库负载均衡等。
负载均衡的主要目标是通过分配和管理资源,避免某个节点或服务过载,从而提高整个系统的性能和
可用性。它可以通过以下几种方式来实现:
1、请求分发:将来自用户或客户端的请求分发到多个服务器或节点上。这可以确保每个服务器都能
够处理适量的请求,避免单个服务器过载。
2、资源调度:根据服务器或节点的负载情况,动态地将请求分配到最空闲或最合适的服务器上。这
样可以平衡负载,确保每个服务器都得到合理的负载。
3、故障处理:当一个服务器或节点发生故障时,负载均衡系统可以自动将请求重新分配到其他正常
工作的服务器上,以确保服务的连续性和可用性。
4、扩展性和可伸缩性:通过添加更多的服务器或节点,负载均衡系统可以实现水平扩展,从而提高
系统的吞吐量和容量。

在 k8s 中为什么要做负载均衡?

bash 复制代码
1、高可用性:负载均衡可以确保应用程序的高可用性。在 K8s 集群中,应用程序通常由多个副本
(Pod)组成,这些副本运行在不同的节点上。通过负载均衡,流量可以均匀地分发到这些副本上,即使
一个节点或副本出现故障,负载均衡仍然可以将流量重定向到其他健康的副本,从而保持应用程序的可用
性。
2、水平扩展:负载均衡可以支持应用程序的水平扩展。当应用程序的负载增加时,可以通过增加副
本数量来扩展应用程序的容量。负载均衡器可以自动将流量分发到这些新创建的副本上,从而实现应用程
序的扩展性。
3、流量管理:负载均衡器能够管理流量的分发和控制。它可以根据不同的负载均衡算法,如轮询、
最小连接数或基于权重等,将流量分发到不同的副本上。这样可以确保每个副本都能够平均地处理请求,
并避免某些副本被过载。
4、服务发现:K8s 中的负载均衡器还可以提供服务发现功能。负载均衡器可以为应用程序提供一个
固定的访问入口(通常是一个虚拟 IP 地址),而不必直接暴露每个副本的 IP 地址。这样,当副本的 IP 地
址发生变化时,客户端仍然可以通过负载均衡器访问应用程序。



扩展: 在 k8s 为什么要引入七层负载均衡?
1、应用层路由和转发:七层负载均衡能够在应用层进行路由和转发决策。与四层负载均衡(基于传
输层的负载均衡)相比,七层负载均衡可以根据应用协议(如 HTTP、HTTPS)的特定属性进行更精细
的流量分发,例如基于 URL、HTTP 头、Cookie 等信息。这使得负载均衡器能够更好地理解应用程序的
行为,并根据需要进行灵活的流量控制。
2、HTTP/HTTPS 负载均衡:Kubernetes 中的大部分应用程序都使用 HTTP 或 HTTPS 协议进行
通信。七层负载均衡器可以在应用层进行 HTTP/HTTPS 的负载均衡,具有更深入的应用层理解和更高级
的功能,如 HTTP 请求重写、URL 重定向、会话保持等。这使得负载均衡器能够提供更强大和灵活的
HTTP/HTTPS 流量管理能力。
3、请求级别的负载均衡:七层负载均衡器可以实现请求级别的负载均衡。它可以根据请求的特性和
需求,将请求分发到不同的后端服务或副本。例如,可以根据请求的 URL 路径将特定类型的请求发送到
专门的处理服务,或者根据请求的 Cookie 信息将请求发送到特定的会话保持副本。这种细粒度的负载均
衡可以根据应用程序的需求进行定制和优化。
4、应用程序性能和可用性优化:七层负载均衡器能够提供一系列应用层的性能优化和安全功能,如
SSL 加速、Gzip 压缩、请求缓存等。它还可以通过健康检查和故障检测来监控后端服务的可用性,并自
动将流量从故障的服务转移到健康的服务,从而提高应用程序的可用性和可靠性。

Ingress 和 Ingress Controller 深度解读

bash 复制代码
当我们在日常生活中想要去不同的商店购物时,我们需要找到正确的入口并按照商店的规则进入。类
似地,Ingress 和 Ingress-Nginx Controller 在 Kubernetes 中提供了类似的功能。
1. Ingress:在 Kubernetes 中,Ingress 是一个 API 对象,它充当着一个入口点的角色,帮助我
们将外部的请求引导到正确的服务上。就像商店的入口指示我们如何进入商店一样,Ingress 定
义了一组规则,指定了如何将外部的请求流量路由到 Kubernetes 集群内部的服务。
2. Ingress-Nginx Controller:Ingress-Nginx Controller 是一个特定类型的 Ingress 
Controller,它使用 Nginx 作为负载均衡器来实现 Ingress 规则定义的流量转发。类比于商店
的入口,Ingress-Nginx Controller 就像是一个管理商店入口的工作人员,根据 Ingress 规则
将客户引导到正确的服务上。


举个例子,想象你是一个在线购物平台,你有多个商家在平台上销售商品。每个商家都有自己的店铺(服
务)在 Kubernetes 集群中运行。现在你需要为每个商家提供一个独立的 URL 来访问他们的店铺,同时
确保访问流量能够正确地转发到相应的店铺。这时,你可以使用 Ingress 来定义规则,比如为每个商家指
定一个独特的 URL 路径(如/shop1、/shop2),然后使用 Ingress-Nginx Controller 将来自外部的
请求根据这些规则转发到对应的商家店铺

使用 Ingress Controller 代理 k8s 内部应用的流程

bash 复制代码
(1)部署 Ingress controller,我们 ingress controller 使用的是 nginx
(2)创建 Pod 应用,可以通过控制器创建 pod
(3)创建 Service,用来分组 pod
(4)创建 Ingress http,测试通过 http 访问应用
(5)创建 Ingress https,测试通过 https 访问应用
客户端通过七层调度器访问后端 pod 的方式



备注:跨域啥意思?
跨域(Cross-Origin)是一个安全机制,用于限制来自不同域名的资源之间的交互。当一个网页的
脚本尝试从一个源(域、协议和端口的组合)获取数据时,浏览器会执行跨域检查,以确保该请求的目标
源具有适当的访问权限。
Nginx 是一个流行的 Web 服务器软件,它也可以用作反向代理服务器。在 Nginx 中,跨域问题通
常与浏览器的同源策略(Same-Origin Policy)有关。同源策略要求网页中的 JavaScript 只能访问与
其来源具有相同域名、协议和端口的资源。
当你的网页上的 JavaScript 尝试从一个不同域名的资源请求数据时,浏览器会发出跨域请求,并且
会在控制台上报告跨域错误。为了解决这个问题,你可以在 Nginx 服务器上进行跨域配置,允许特定的
跨域请求。
在 Nginx 中配置跨域可以通过添加 HTTP 头字段来实现。以下是一个示例配置,允许来自
example.com 域名的跨域请求:
location / {
 add_header 'Access-Control-Allow-Origin' 'http://example.com';
 add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
 add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept';
}
上述配置将在每个响应中添加跨域相关的 HTTP 头字段,允许来自 example.com 域的 GET、
POST 和 OPTIONS 请求,并允许一些常见的请求头。

安装 Nginx Ingress Controller

bash 复制代码
Ingress-controller 和 k8s 版本对照:
Ingress-controller 官网: https://github.com/kubernetes/ingress-nginx/


传镜像
root@ubuntu0:~/matedata/volumes# ansible all -m copy  -a "src=nginx-ingress-controller_v1.1.1.tar.gz dest=/root"
 root@ubuntu0:~/matedata/volumes# ansible all -m copy  -a "src=kube-webhook-certgen_1.1.1.tar.gz dest=/root"

导入镜像
root@ubuntu0:~/matedata/volumes# ansible all -m shell -a "ctr -n=k8s.io images import kube-webhook-certgen_1.1.1.tar.gz"
root@ubuntu0:~/matedata/volumes# ansible all -m shell -a "ctr -n=k8s.io images import nginx-ingress-controller_v1.1.1.tar.gz"


安装 Ingress conrtroller 需要的 yaml 所在的 github 地址:
https://github.com/kubernetes/ingressnginx/blob/main/deploy/static/provider/baremetal/deploy.yaml
更改了镜像名称以及
root@ubuntu0:~# grep hostNetwork deploy.yaml 
      hostNetwork: true  #运行在主机上



root@ubuntu0:~/matedata/ingress# kubectl apply -f deploy.yaml 

授权
root@ubuntu0:~/matedata/ingress# kubectl create clusterrolebinding clusterrolebinding-user-3 --clusterrole=cluster-admin --user=system:serviceaccount:ingress-nginx:ingress-nginx
clusterrolebinding.rbac.authorization.k8s.io/clusterrolebinding-user-3 created
root@ubuntu0:~/matedata/ingress# kubectl get pods -n ingress-nginx
NAME                                        READY   STATUS      RESTARTS   AGE
ingress-nginx-admission-create-9hztd        0/1     Completed   0          60s
ingress-nginx-admission-patch-5wdz4         0/1     Completed   2          60s
ingress-nginx-controller-56dc9c69b9-656fg   0/1     Running     0          60s
这两个 Completed 状态的 Pod 是 Ingress-Nginx 控制器的准入控制 Webhook 的 Job Pod。这是正常现象

这两个 Pod 的作用
1. ingress-nginx-admission-create
功能: 创建 TLS 证书和密钥,用于验证 Ingress 资源的有效性

作用: 为准入控制 Webhook 生成必要的安全凭证

2. ingress-nginx-admission-patch
功能: 将 Webhook 配置更新到 Kubernetes API 服务器

作用: 注册验证 Webhook,确保创建的 Ingress 资源符合规范
工作流程
root@ubuntu0:~/matedata/ingress# kubectl get jobs -n ingress-nginx
NAME                             COMPLETIONS   DURATION   AGE
ingress-nginx-admission-create   1/1           17s        4m10s
ingress-nginx-admission-patch    1/1           31s        4m10s
为什么是 Completed 状态?
Job 类型: 这两个是 Kubernetes Job,不是 Deployment

一次性任务: Job 执行完成后就会处于 Completed 状态

正常行为: 这是设计如此,不需要持续运行

测试 Ingress HTTP 代理 k8s 内部站点

bash 复制代码
步骤:
(1)部署 Ingress controller,我们 ingress controller 使用的是 nginx
(2)创建 Pod 应用,可以通过控制器创建 pod
(3)创建 Service,用来分组 pod
(4)创建 Ingress http,测试通过 http 访问应用
(5)创建 Ingress https,测试通过 https 访问应用

部署后端 tomcat 服务
root@ubuntu0:~/matedata/ingress# cat ingress-demo.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat-deploy
  namespace: default
spec: 
  replicas: 2
  selector:
    matchLabels:
      app: tomcat
      release: canary
  template:
    metadata:
      labels:
        app: tomcat
        release: canary
    spec:
      containers:
      - name: tomcat
        image: docker.io/library/tomcat:8.5.34-jre8-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 8080
        - name: ajp
          containerPort: 8009
---
apiVersion: v1
kind: Service
metadata:
  name: tomcat
  namespace: default
spec:
  selector:
    app: tomcat
    release: canary
  ports:
  - name: http
    targetPort: 8080
    port: 8080
  - name: ajp
    targetPort: 8009
    port: 8009
root@ubuntu0:~/matedata/ingress# kubectl apply -f ingress-demo.yaml 
deployment.apps/tomcat-deploy created
service/tomcat created
root@ubuntu0:~/matedata/ingress# kubectl get pods -owide
NAME                             READY   STATUS    RESTARTS   AGE     IP               NODE      NOMINATED NODE   READINESS GATES
pod-pvc                          1/1     Running   0          7h48m   10.244.152.105   ubuntu2   <none>           <none>
read-pod                         1/1     Running   0          6h43m   10.244.25.174    ubuntu1   <none>           <none>
tomcat-deploy-7455769b96-b9z4r   1/1     Running   0          9s      10.244.25.191    ubuntu1   <none>           <none>
tomcat-deploy-7455769b96-rlfs8   1/1     Running   0          9s      10.244.152.121   ubuntu2   <none>           <none>
xpp-c44d68dcf-fkxkk              1/1     Running   0          6h56m   10.244.25.173    ubuntu1   <none>           <none>

编写 ingress 规则

bash 复制代码
root@ubuntu0:~/matedata/ingress# cat ingress-myapp.yaml 
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-myapp
  namespace: default
spec:
  ingressClassName: nginx
  rules: #定义后端转发的规则
  - host: tomcat.lucky.com #通过域名进行转发  
    http:
      paths:
      - path: / #配置访问路径,如果通过 url 进行转发,需要修改;空默认为访问的路径为"/"
        pathType: Prefix
        backend: #配置后端服务
          service:
            name: tomcat
            port:
              number: 8080

备注:pathType: Prefix?
指定了路径前缀匹配方式
http:
 paths:
 - path: /
 pathType: Prefix
 backend:
 service:
 name: tomcat
 port: 8080
pathType: Prefix?
指定了路径前缀匹配方式, 除了精确匹配根路径 / 外,它还会匹配根路径之后的所有子路径。

root@ubuntu0:~/matedata/ingress# kubectl apply -f ingress-myapp.yaml 
ingress.networking.k8s.io/ingress-myapp created
root@ubuntu0:~/matedata/ingress# kubectl get ingress -owide
NAME            CLASS   HOSTS              ADDRESS         PORTS   AGE
ingress-myapp   nginx   tomcat.lucky.com   192.168.23.97   80      65s

访问ip不行,只有域名,因为host: tomcat.lucky.com 写的是域名,写ip别人不认

测试 Ingress HTTPS 代理 tomcat

bash 复制代码
1.构建 TLS 站点
root@ubuntu0:~# openssl genrsa -out tls.key 2048
root@ubuntu0:~# openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=Beijing/L=Beijing/O=DevOps/CN=tomcat.lucky.com
2 生成 secret,
root@ubuntu0:~# kubectl create secret tls tomcat-ingress-secret --cert=tls.crt --key=tls.key
secret/tomcat-ingress-secret created
NAME                          TYPE                                  DATA   AGE
default-token-mnzns           kubernetes.io/service-account-token   3      43d
nfs-provisioner-token-n4w5h   kubernetes.io/service-account-token   3      10h
tomcat-ingress-secret         kubernetes.io/tls                     2      62s
root@ubuntu0:~# kubectl describe secrets tomcat-ingress-secret
Name:         tomcat-ingress-secret
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  kubernetes.io/tls

Data
====
tls.crt:  1310 bytes
tls.key:  1708 bytes

Ingress 规则可以参考官方:
https://kubernetes.io/zh/docs/concepts/services-networking/ingress/
pathType 类型:https://kubernetes.io/zh-cn/docs/concepts/servicesnetworking/ingress/#path-types
root@ubuntu0:~/matedata/ingress# cat ingress-tomcat-tls.yaml 
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-tomcat-tls
  namespace: default
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - tomcat.lucky.com
    secretName: tomcat-ingress-secret
  rules:
  - host: tomcat.lucky.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: tomcat
            port:
              number: 8080
root@ubuntu0:~/matedata/ingress# kubectl apply -f ingress-tomcat-tls.yaml 
Error from server (BadRequest): error when creating "ingress-tomcat-tls.yaml": admission webhook "validate.nginx.ingress.kubernetes.io" denied the request: host "tomcat.lucky.com" and path "/" is already defined in ingress default/ingress-myapp
root@ubuntu0:~/matedata/ingress# kubectl get ingress
NAME            CLASS   HOSTS              ADDRESS         PORTS   AGE
ingress-myapp   nginx   tomcat.lucky.com   192.168.23.97   80      41m
root@ubuntu0:~/matedata/ingress# kubectl delete -f ingress-myapp.yaml 
ingress.networking.k8s.io "ingress-myapp" deleted
root@ubuntu0:~/matedata/ingress# kubectl apply -f ingress-tomcat-tls.yaml 
ingress.networking.k8s.io/ingress-tomcat-tls created
root@ubuntu0:~/matedata/ingress# kubectl get ingress
NAME                 CLASS   HOSTS              ADDRESS         PORTS     AGE
ingress-tomcat-tls   nginx   tomcat.lucky.com   192.168.23.97   80, 443   5m1s
相关推荐
林克爱塞尔达3 小时前
Linux高级技巧之集群部署(七)
linux·运维·php
爱琴孩3 小时前
5年经验,没安装部署过Nginx?
nginx·yum
SunnyJim3 小时前
k8s kubelet 错误 Network plugin returns error: cni plugin not initialized
kubernetes·containerd·kubelet·cri·finnal
企鹅虎4 小时前
黑马高价课程:PHP基础班+就业班 珍藏资源原价19998
php
SunnyJim5 小时前
k8s etcd 运行错误 failed to find plugin “flannel“ in path [/usr/lib/cni]
容器·kubernetes·etcd
熊猫_豆豆6 小时前
MATLAB 九大行星太阳系运行程序
开发语言·nginx·matlab
虫师c6 小时前
GitOps实战:ArgoCD+Tekton打造云原生CI/CD流水线
git·ci/cd·云原生·kubernetes·argocd·tekton
和光同尘20236 小时前
CentOS7搭建ELK日志分析系统
运维·elasticsearch·云原生·kubernetes·centos·kibana·logstash
Ribou6 小时前
不同环境(跨集群和同集群)下的Jenkins与Kubernetes集群连接配置
kubernetes·jenkins