【Kubernetes】七层代理Ingress

七层代理Ingress

  • 一、回顾四层代理Service
    • 1.1、在k8s中为什么要做负载均衡?
    • 1.2、Service存在的问题
    • 1.3、四层负载和七层负载的区别
  • 二、Ingress和Ingress Controller介绍
    • 2.1、Ingress
    • 2.2、Ingress Controller
    • 2.3、使用Ingress Controller代理k8s内部pod流程
    • 2.4、总结
  • 四、Ingress Controller高可用
    • 4.1、部署ingress-nginx-controller
    • 4.2、基于keepalive和nginx实现ingress-nginx-controller高可用
      • 【1】nginx主备安装
      • 【2】keepalive配置
      • 【3】判断nginx是否存活
      • 【4】启动服务
      • 【5】测试vip是否绑定成功
      • 【6】测试keepalived
    • 4.3、测试Ingress HTTP 代理k8s内部pod
      • 【1】部署后端tomcat服务
      • 【2】编写ingress规则
      • 【3】测试访问
    • 4.4、测试Ingress HTTPS代理k8s内部pod
      • 【1】构建TLS站点
      • 【2】创建Ingress
      • 【3】修改电脑的hosts文件
  • 五、同一个k8s搭建多套Ingress-controller

一、回顾四层代理Service

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

pod漂移问题,可以理解成pod ip是变化的。
k8s具有强大的副本控制能力,能保证再任意副本pod挂掉时,自动从其他机器启动一个新的,还可以动态库容。通俗地说,这个pod可能任何时刻出现在任何节点上,也可能在任何时刻死在任何节点上。那么自然随着pod的创建和销毁,pod ip是变化的,如何把这个动态的pod ip暴露出去?
这里借助k8s的色弱ice机制,service可以以标签形式选定一组带指定标签的pod,并监控和自动负载他们的pod ip,那么我们向外暴露只暴露了service ip就行了。
这里就是NodePort模式:即在每个节点上开启一个端口,然后转发到内部pod ip上。

svc域名组成:svc名称.svc所在名称空间.svc.cluster.local
这个只能在集群内部访问,即只能在pod里面去访问这个域名,因为svc域名是由cordns解析的,物理机用的dns可以通过cat /etc/resolv.conf查看,这俩个dns不是同一个网段的。

1.2、Service存在的问题

Service可以通过标签选择器找到它所关联的pod,但是属于四层代理,只能基于ip和端口代理。

# svc创建后,会对应创建endpoint
# ENDPOINTS 存的就是这个service对应的后端pod所对应的ip+port
[root@master ~]# k get ep -n kube-system
NAME             ENDPOINTS                                                        AGE
kube-dns         10.244.140.72:53,10.244.140.75:53,10.244.140.72:53 + 3 more...   43d
metrics-server   10.244.140.71:4443                                               42d
# 这里svc和pod的ip怎么保存到防火墙规则里面?  通过kube-proxy实现,保存到ipvs规则里面
# 通过ipvsadm -Ln可以看到

Service的type类型有很多,如NodePort、ClusterIp、LoadBalancer、Externalname,如果Service想要被k8s集群外部访问,需要用NodePort类型,但这有以下几个问题:
+++++++++++++++
1、nodeport会在物理机映射一个端口,绑定到物理机上,导致每个服务都要映射一个端口,端口过多,维护困难。
2、service底层使用的是iptables或者ipvs,仅支持四层代理,无法基于https协议做代理。
+++++++++++++++

1.3、四层负载和七层负载的区别

  • 四层负载:基于ip和端口的负载均衡。在三层负载基础上通过发布三层的ip地址(VIP)然后加上四层的端口号,来决定哪些流量需要做负载均衡;
    对需要处理的流量进行NAT处理,然后转发至后台服务器,并记录 下这个TCP或者UDP的流量是由那台服务器处理的,后续这个连接的所有流量都同样转发到同一台服务器处理。

  • 七层负载: 基于虚拟的URL或主机IP的负载均衡,在四层的基础上,再考虑应用层的特征,比如同一个web服务器的负载均衡,除了根据VIP加80端口辨别是否需要处理的流量,还可以根据七层的URL、浏览器类别、语言来决定是否需要进行负载均衡。
    举个例子,如果你的Web服务器分成两组,一组是中文语言的,一组是英文语言的,那么七层负载均衡就可以当用户来访问你的域名时,自动辨别用户语言,然后选择对应的语言服务器组进行负载均衡处理。

四层负载均衡工作在传输层,七层负载均衡工作在应用层
OSI七层模型:
【Kubernetes】七层代理Ingress_第1张图片

【Kubernetes】七层代理Ingress_第2张图片

二、Ingress和Ingress Controller介绍

2.1、Ingress

官网定义

Ingress可以把进入到集群内部的请求转发到集群中的一些服务上,从而可以把服务映射到集群外部。
Ingress能把集群内Service配置成外网能够访问的URL、流量负载均衡,提供基于域名访问的虚拟主机等。

简单理解

原来需要修改nginx配置,然后配置各种域名对应哪个service,现在把这个动作抽象出来,变成一个Ingress对象,你可以用yaml创建,每次不要去改nginx了,直接改yaml然后创建/更新就行了。

Ingress总结

Ingress是k8s中的资源,主要是管理ingress-controller这个代理的配置文件。
Ingress Controller解决的是“nginx的处理方式”,它通过与kubernetes api交互,动态感知集群中Ingress规则变化,动态读取,然后按照自己的模板生成一段nginx配置,再写到nginx pod里面,最后reload一下

2.2、Ingress Controller

Ingress Controller是一个七层负载均衡调度器,客户端的请求先到达这个七层负载均衡调度器,由七层负载均衡器在反向代理到后端pod。
常见的七层负载均衡器有nginx、traefik,以我们熟悉的nginx为例,假如请求到达nginx,会通过upstream反向代理到后端pod应用,但是后端pod的ip地址是一直在变化的,因此在后端pod前需要加一个service,这个service只是起到分组的作用,那么我们upstream只需要填写service地址即可。

Ingress-controller里面封装就是nginx,直接在物理机上装个nginx,为啥还弄个Ingress-controller?

Nginx:nginx配置文件一改动,你还需要手动reload一下才可以生效,但是如果用ingress-controller封装的nginx,你ingress维护配置,ingress创建好之后,会自动的把配置文件传到ingress-controller这个pod里,会自动进行reload,然后配置就生效了。
【Kubernetes】七层代理Ingress_第3张图片

2.3、使用Ingress Controller代理k8s内部pod流程

步骤:
【1】部署Ingress Controller,这里ingress controller 使用的是nginx
【2】创建pod应用,可以通过控制器创建pod
【3】创建service,用来分组pod
【4】创建Ingress http,测试通过http访问权限
【5】创建Ingress https,测试通过https访问应用

2.4、总结

1、Ingress Controller结合Ingress 定义的规则生成配置,然后动态更新ingress-controller里的Nginx 或者trafik负载均衡器,并刷新使配置生效,来达到服务自动发现的作用。

2、Ingress 则是定义规则,通过它定义某个域名的请求过来之后转发到集群中指定的 Service。它可以通过 Yaml 文件定义,可以给一个或多个 Service 定义一个或多个 Ingress 规则。

四、Ingress Controller高可用

Ingress Controller 是集群流量的接入层,对它做高可用非常重要,可以基于keepalive实现nginx-ingress-controller高可用:
Ingress-controler根据deployment+nodeselector+pod反亲和性方式部署在k8s指定的俩个work节点,nginx-ingress-controller这个pod共享宿主机ip,然后通过keepalive+nginx实现nginx-ingress-controller高可用。

https://github.com/kubernetes/ingress-nginx

https://github.com/kubernetes/ingress-nginx/tree/main/deploy/static/provider/baremetal

4.1、部署ingress-nginx-controller

【1】在工作节点上传镜像文件,然后解压。

[root@node01 package]# ctr -n=k8s.io images import ingress-nginx-controllerv1.1.0.tar.gz 
[root@node01 package]# ctr -n=k8s.io images import kube-webhook-certgen-v1.1.0.tar.gz
[root@node02 package]# ctr -n=k8s.io images import ingress-nginx-controllerv1.1.0.tar.gz 
[root@node02 package]# ctr -n=k8s.io images import kube-webhook-certgen-v1.1.0.tar.gz

【2】运行yaml文件

[root@master 17]# kubectl apply -f ingress-deploy.yaml
[root@master 17]# kubectl get pod -n ingress-nginx -owide
NAME                                        READY   STATUS      RESTARTS   AGE     IP               NODE     NOMINATED NODE   READINESS GATES
ingress-nginx-admission-create-2zhnk        0/1     Completed   0          6m18s   10.244.196.130   node01   <none>           <none>
ingress-nginx-admission-patch-htsrd         0/1     Completed   1          6m18s   10.244.196.129   node01   <none>           <none>
ingress-nginx-controller-64bdc78c96-6c9c6   1/1     Running     0          41s     10.32.1.148      node01   <none>           <none>
ingress-nginx-controller-64bdc78c96-fpvlf   1/1     Running     0          6m18s   10.32.1.149      node02   <none>           <none>
# 如果ingress-nginx-controller-xx的pod出现问题,用kubectl logs -f 或者kubectl describe去排查,我出现问题的原因是节点上的80端口被占用了

ingress-nginx-controller–里面封装的就是nginx七层代理。
这里的pod使用的是宿主机的ip。

4.2、基于keepalive和nginx实现ingress-nginx-controller高可用

【Kubernetes】七层代理Ingress_第4张图片

【1】nginx主备安装

在工作节点执行yum install epel-release nginx keepalived nginx-mod-stream -y

[root@node01 ~]#  yum install  epel-release  nginx keepalived nginx-mod-stream  -y
[root@node02 ~]#  yum install  epel-release  nginx keepalived nginx-mod-stream  -y

修改nginx配置文件。主备一样

[root@node01 ~]# cat /etc/nginx/nginx.conf
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

# 四层负载均衡,为两台Master apiserver组件提供负载均衡
stream {

    log_format  main  '$remote_addr $upstream_addr - [$time_local] $status $upstream_bytes_sent';

    access_log  /var/log/nginx/k8s-access.log  main;

    upstream k8s-ingress-controller {
       server 10.32.1.148:80 weight=5 max_fails=3 fail_timeout=30s;   # 修改成自己工作节点的ip
       server 10.32.1.149:80 weight=5 max_fails=3 fail_timeout=30s;  # 修改成自己工作节点的ip
    }

    server {
       listen 30080;
       proxy_pass k8s-ingress-controller;
    }
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

}

备注:

  • server 反向服务地址和端口
  • weight 权重
  • max_fails 失败多少次,认为主机已挂掉,则踢出
  • fail_timeout 踢出后重新探测时间
  • nginx监听端口变成大于30000的端口,比方说30080,这样访问域名:30080就可以了,必须是满足大于30000以上,才能代理ingress-controller

【2】keepalive配置

主配置

[root@node01 ~]# cat /etc/keepalived/keepalived.conf
global_defs {
   notification_email {
     [email protected]
     [email protected]
     [email protected]
   }
   notification_email_from [email protected]
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id NGINX_MASTER
}

vrrp_script check_nginx {
    script "/etc/keepalived/check_nginx.sh"
}

vrrp_instance VI_1 {
    state MASTER
    interface ens32  # 修改为实际网卡名
    virtual_router_id 51 # VRRP 路由 ID实例,每个实例是唯一的
    priority 100    # 优先级,备服务器设置 90
    advert_int 1    # 指定VRRP 心跳包通告间隔时间,默认1秒
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    # 虚拟IP
    virtual_ipaddress {
        10.32.1.155/24
    }
    track_script {
        check_nginx
    }
}	

备配置 (和主配置的区别就是优先级 priority 和state)

[root@node02 package]# cat /etc/keepalived/keepalived.conf
global_defs {
   notification_email {
     [email protected]
     [email protected]
     [email protected]
   }
   notification_email_from [email protected]
   smtp_server 127.0.0.1
   smtp_connect_timeout 30
   router_id NGINX_MASTER
}

vrrp_script check_nginx {
    script "/etc/keepalived/check_nginx.sh"
}

vrrp_instance VI_1 {
    state BACKUP
    interface ens32  # 修改为实际网卡名
    virtual_router_id 51 # VRRP 路由 ID实例,每个实例是唯一的
    priority 90    # 优先级,备服务器设置 90
    advert_int 1    # 指定VRRP 心跳包通告间隔时间,默认1秒
    authentication {
        auth_type PASS
        auth_pass 1111
    }
    # 虚拟IP
    virtual_ipaddress {
        10.32.1.155/24
    }
    track_script {
        check_nginx
    }
}

#vrrp_script:指定检查nginx工作状态脚本(根据nginx状态判断是否故障转移)
#virtual_ipaddress:虚拟IP(VIP)

【3】判断nginx是否存活

[root@node01 keepalived]# cat check_nginx.sh
#!/bin/bash
#1、判断Nginx是否存活
counter=$(ps -ef |grep nginx | grep sbin | egrep -cv "grep|$$" )
if [ $counter -eq 0 ]; then
    #2、如果不存活则尝试启动Nginx
    service nginx start
    sleep 2
    #3、等待2秒后再次获取一次Nginx状态
    counter=$(ps -ef |grep nginx | grep sbin | egrep -cv "grep|$$" )
    #4、再次进行判断,如Nginx还不存活则停止Keepalived,让地址进行漂移
    if [ $counter -eq 0 ]; then
        service  keepalived stop
    fi
fi
[root@node01 keepalived]# chmod +x /etc/keepalived/check_nginx.sh
# 注:keepalived根据脚本返回状态码(0为工作正常,非0不正常)判断是否故障转移。

【4】启动服务

node01和node02都要操作

 systemctl daemon-reload
 systemctl enable nginx keepalived 
 systemctl start nginx
 systemctl start keepalived

【5】测试vip是否绑定成功

node01是主,上面会有vip
【Kubernetes】七层代理Ingress_第5张图片

【6】测试keepalived

停掉node01上的keepalived。Vip会漂移到node02上

[root@node01 keepalived]#  service  keepalived stop
Redirecting to /bin/systemctl stop keepalived.service
You have mail in /var/spool/mail/root

【Kubernetes】七层代理Ingress_第6张图片

systemctl status keepalived -l检测keepalived是否正常

4.3、测试Ingress HTTP 代理k8s内部pod

【1】部署后端tomcat服务

[root@master 17]# cat ingress-demo.yaml
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
---
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: tomcat:8.5.34-jre8-alpine
        imagePullPolicy: IfNotPresent
        ports:
        - name: http
          containerPort: 8080
          name: ajp
          containerPort: 8009

# 更新资源清单yaml文件          
[root@master 17]# kubectl apply -f ingress-demo.yaml
service/tomcat created
deployment.apps/tomcat-deploy created
[root@master 17]# k get pod|grep tomcat
tomcat-deploy-64d6489dd9-vmx79    1/1     Running   0              3d1h
tomcat-deploy-64d6489dd9-vngw9    1/1     Running   0              3d1h
[root@master 17]# k get svc|grep tomcat
tomcat       ClusterIP   10.109.171.118   <none>        8080/TCP,8009/TCP   3d1h
[root@master 17]# k describe svc tomcat
Name:              tomcat
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=tomcat,release=canary
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.109.171.118
IPs:               10.109.171.118
Port:              http  8080/TCP
TargetPort:        8080/TCP
Endpoints:         10.244.140.87:8080,10.244.196.166:8080
Port:              ajp  8009/TCP
TargetPort:        8009/TCP
Endpoints:         10.244.140.87:8009,10.244.196.166:8009
Session Affinity:  None
Events:            <none>

【2】编写ingress规则

[root@master 17]# 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:
      - backend:
          service:
            name: tomcat
            port:
              number: 8080
        path: /
        pathType: Prefix

[root@master 17]# kubectl apply -f ingress-myapp.yaml
ingress.networking.k8s.io/ingress-myapp created

如果出现以下报错:
在这里插入图片描述
解决办法:kubectl delete -A ValidatingWebhookConfiguration ingress-nginx-admission

# 查看ingress-myapp的详细信息
[root@master 17]# kubectl describe ingress ingress-myapp
Name:             ingress-myapp
Labels:           <none>
Namespace:        default
Address:          10.32.1.148,10.32.1.149
Ingress Class:    nginx
Default backend:  <default>
Rules:
  Host              Path  Backends
  ----              ----  --------
  tomcat.lucky.com
                    /   tomcat:8080 (10.244.140.87:8080,10.244.196.166:8080)
Annotations:        <none>
Events:
  Type    Reason  Age                    From                      Message
  ----    ------  ----                   ----                      -------
  Normal  Sync    2m23s (x2 over 2m48s)  nginx-ingress-controller  Scheduled for sync
  Normal  Sync    2m23s (x2 over 2m48s)  nginx-ingress-controller  Scheduled for sync

【3】测试访问

修改电脑本地的host文件,增加如下一行,下面的ip是vip
10.32.1.155 tomcat.lucky.com
浏览器访问tomcat.lucky.com:30080,出现如下页面:
【Kubernetes】七层代理Ingress_第7张图片
代理流程:tomcat.lucky.com:30080——>10.32.1.155:30080——>10.32.1.148/149:80——>svc:tomcat:8080——>tomcat-deploy

  • 浏览器访问tomcat.lucky.com:30080,通过域名解析,会访问10.32.1.155:30080
  • 10.32.1.155是VIP,通过虚拟ip访问nginx,此时的vip是在node01主机上,所有走的是node01节点的nginx,即10.32.1.148:30080
  • 根据nginx配置文件规则,会随机转发到 10.32.1.149:80或10.32.1.148:80
  • 根据ingress规则,会将流量转达对应svc(tomcat:8080)
  • svc会将流量转发到后端对应的pod上

4.4、测试Ingress HTTPS代理k8s内部pod

【1】构建TLS站点

1、在控制节点上,创建证书

[root@master ~]#  openssl genrsa -out tls.key 2048
Generating RSA private key, 2048 bit long modulus
....+++
...............................................................................+++
e is 65537 (0x10001)
[root@master ~]# openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=Beijing/L=Beijing/O=DevOps/CN=hejin.lucky.com 

2、在控制节点上,生成secret

[root@master ~]# kubectl create secret tls tomcat-ingress-secret --cert=tls.crt --key=tls.key
secret/tomcat-ingress-secret created

3、查看secret

[root@master ~]# kubectl get secret
NAME                    TYPE                DATA   AGE
mysecret                Opaque              2      22d
mysql-password          Opaque              1      22d
tomcat-ingress-secret   kubernetes.io/tls   2      24s

4、查看tomcat-ingress-secret详细信息

[root@master ~]# kubectl get secret
NAME                    TYPE                DATA   AGE
mysecret                Opaque              2      22d
mysql-password          Opaque              1      22d
tomcat-ingress-secret   kubernetes.io/tls   2      24s
[root@master ~]# kubectl describe secret tomcat-ingress-secret
Name:         tomcat-ingress-secret
Namespace:    default
Labels:       <none>
Annotations:  <none>

Type:  kubernetes.io/tls

Data
====
tls.key:  1679 bytes
tls.crt:  1289 bytes

【2】创建Ingress

Ingress规则可以参考官方:
https://kubernetes.io/zh/docs/concepts/services-networking/ingress/

[root@master 17]#  cat ingress-tomcat-tls.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-tomcat-tls
  namespace: default
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    -  hejin.lucky.com
    secretName: tomcat-ingress-secret
  rules:
  - host: hejin.lucky.com
    http:
      paths:
      - path: /
        pathType:  Prefix
        backend:
         service:
           name: tomcat
           port:
            number: 8080

更新yaml文件

[root@master 17]# kubectl delete -f ingress-myapp.yaml
[root@master 17]# kubectl apply -f ingress-tomcat-tls.yaml

【3】修改电脑的hosts文件

打开C:\Windows\System32\drivers\etc目录,找到hosts文件,如下:

......
10.32.1.155 tomcat.lucky.com 
10.32.1.155 hejin.lucky.com
......

使用浏览器访问:http://hejin.lucky.com/
【Kubernetes】七层代理Ingress_第8张图片
【Kubernetes】七层代理Ingress_第9张图片
【Kubernetes】七层代理Ingress_第10张图片

五、同一个k8s搭建多套Ingress-controller

更新中。。。

你可能感兴趣的:(K8S,kubernetes,容器,云原生)