Ingress介绍

ingress主要解决k8s集群中东西流量的访问也就是外部客户端访问k8s内部服务的流量,具体架构图如下
ingress-1
k8s如果使用Ingress功能,需要安装Ingress控制器,直接创建Ingress规则是没有任何效果的,官方维护的Ingress控制器有:

  • AWS
  • GCE
  • nginx Ingress 控制器

Ingress控制器安装

安装Ingress nginx

可参考之前博客k8s部署ingress-nginxk8s部署ingress-nginx,本文通过Helm部署,需要首先安装helm管理工具:https://github.com/helm/helm
Ingress nginx控制器官方:https://kubernetes.github.io/ingress-nginx/deploy/#using-helm

安装Helm

[root@k8s01 ~]# ls
helm-v3.7.2-linux-amd64.tar.gz 
[root@k8s01 ~]# tar xf helm-v3.7.2-linux-amd64.tar.gz 
[root@k8s01 ~]# cp linux-amd64/helm /usr/bin/
#可以执行以下命令表示安装完成
[root@k8s01 ~]# helm version
version.BuildInfo{Version:"v3.7.2", GitCommit:"663a896f4a815053445eec4153677ddc24a0a361", GitTreeState:"clean", GoVersion:"go1.16.10"}

安装ingress控制器

由于Ingress资源的api版本进行了很多次调整,所以如果k8s集群版本低于1.19,请安装3.X版本或较低版本的ingress控制器,创建ingress时api版本也要正确填写
官方说明:https://kubernetes.github.io/ingress-nginx/deploy/#running-on-kubernetes-versions-older-than-119

#添加官方仓库
[root@k8s01 ~]# helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
"ingress-nginx" has been added to your repositories

#由于我的k8s是1.18的版本所以需要调整控制器的版本
,下载4版本以下的包
[root@k8s01 ~]# helm pull ingress-nginx/ingress-nginx --version='<4'

#解压下载的压缩包
[root@k8s01 ~]# tar xf ingress-nginx-3.40.0.tgz -C /tmp/

#修改配置
[root@k8s01 ~]# cd /tmp/ingress-nginx/

dnsPolicy: ClusterFirstWithHostNet  #修改dns策略
hostNetwork: true                   #使用hostnetwork,使用宿主机网络
kind: DaemonSet                     #部署方式使用ds控制器
nodeSelector:
     kubernetes.io/os: linux
     ingress-nginx: true            #添加一个nodeselector的标签
type: ClusterIP                     #svc类型改为ClusterIP 


#创建一个命名空间
[root@k8s01 ~]# kubectl  create ns ingress-nginx
#创建ingress控制
[root@k8s01 ~]# helm install ingress-nginx -n ingress-nginx .

#验证
[root@k8s01 ~]# kubectl  get po -n ingress-nginx 
NAME                             READY   STATUS    RESTARTS   AGE
ingress-nginx-controller-8742l   1/1     Running   1          46h

ingress使用

ingress的api版本历经过多次变化他们的配置项也不太一样分别是

ingress版本区别

如果Kubernetes版本低于1.19 ,可以使用networking.k8s.io/v1beta1替代,配置可以参考下述的networking.k8s.io/v1beta1,只有backend配置不一样

v1beta1基本使用

示例文件:

apiVersion: networking.k8s.io/v1beta1  # api版本号
kind: Ingress                          # 资源类型
metadata:
  annotations:                         #一般一些nginx特性在此定义
    kubernetes.io/ingress.class: "nginx"  #使用那个ingress控制器,集群有多个可以选择
    nginx.ingress.kubernetes.io/rewrite-target: "/$1"  #nginx的rewrite功能
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"   #后端如果是https协议需要说明,默认http
  name: nginx                             #名称
spec:
  rules:   #一个Ingress可以配置多个rules
  - host: www.test.com  #域名配置,可以不写,匹配*, *.bar.com
    http:
      paths:   #相当于nginx的location配合,同一个host可以配置多个path / /abc
      - backend:    #后端svc定义
          serviceName: nginx-a  #svc名称
          servicePort: 80       #svc端口
        path: "/a/(.*)"         #匹配的路径
      - backend:
          serviceName: nginx-b
          servicePort: 80
        path: "/b/(.*)"
  tls:    #需要https加密
  - hosts:  #主机域名列表,可以配置多个
    - www.test.com
    - www.dev.com
    secretName: tls #secret证书文件,可以写多个
    secretName: tls1

v1基本使用

示例文件

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx
  annotations:
    kubernetes.io/ingress.class: "nginx"  #使用那个ingress控制器,集群有多个可以选择
    nginx.ingress.kubernetes.io/rewrite-target: "/$1"  #nginx的rewrite功能
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"   #后端如果是https协议
spec:
  rules:    #一个Ingress可以配置多个rules
  - host: www.test.com   #域名配置,可以不写,匹配*, *.bar.com
    http: 
      paths:  #相当于nginx的location配合,同一个host可以配置多个path / /abc
      - pathType: Prefix
        path: "/"
        backend:  #后端svc定义
          service:  #service的定义
            name: nginx  #svc名称
            port:
              number: 80 #svc端口
  tls:    #需要https加密
  - hosts:  #主机域名列表,可以配置多个
    - www.test.com
    - www.dev.com
    secretName: tls #secret证书文件,可以写多个
    secretName: tls1

ingress-nginx使用

ingress-nginx是k8s官方维护的ingress项目,当然nginx官方也维护了一个自己的ingress名称为nginx-ingress
ingress-nginx官方文档:https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/
ingress-nginx有三种配置方式:

  1. ConfigMap:使用Configmap在NGINX中设置全局配置,设置后对所有ingress规则生效。https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/
  2. Annotations:如果您想要特定 Ingress 规则的特定配置,请使用此选项。https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/
  3. 自定义模板:当需要更具体的设置时,例如open_file_cache ,在无法通过 ConfigMap 更改配置时调整监听选项。https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/custom-template/

域名重定向Redirect

官方说明:https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#permanent-redirect
在 Nginx 作为代理服务器时,Redirect 可用于域名的重定向,比如访问 old.com 被重定向到 new.com。Ingress 可以更简单的实现 Redirect 功能,接下来用 www.test.com 作为旧域名, www.baidu.com 作为新域名进行演示:
相关配置项:

  • permanent-redirect:重定向到的域名
  • permanent-redirect-code:重定向代码,不配置默认301(永久重定向,如有其他原因可自行配置)
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: www.test.com
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"  #这里是ingress规则选用的那个ingress控制器,如果设置ingress-nginx为默认控制器可不写
    nginx.ingress.kubernetes.io/permanent-redirect: https://www.baidu.com #重定向后的新域名
    nginx.ingress.kubernetes.io/permanent-redirect-code: '301'  #重定向http状态码
spec:
  rules:   
  - host: www.test.com
    http: 
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          serviceName: service-v1
          servicePort: 80

验证

[root@k8s01 ~]# curl www.test.com -I
HTTP/1.1 301 Moved Permanently  #301重定向
Date: Wed, 12 Oct 2022 08:55:39 GMT
Content-Type: text/html
Content-Length: 277
Connection: keep-alive
Location: https://www.baidu.com  #定向到的新域名

前后端分离Rewrite

官方示例:https://kubernetes.github.io/ingress-nginx/examples/rewrite/
现在有2个服务分别是service-v1与service-v2服务假设一个是后端服务一个是前端服务,访问service-v1需要访问/api-a,访问service-v2需要访问/api-b,俩个服务的请求地址都是/index.html,如果不使用Rewrite则所有请求默认会返回404。
相关配置项:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: www.test.com
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/rewrite-target: "/$2"
spec:
  rules:   
  - host: www.test.com
    http: 
      paths:
      - pathType: Prefix
        path: "/api-a(/|$)(.*)"
        backend:
          serviceName: service-v1
          servicePort: 80
      - pathType: Prefix
        path: "/api-b(/|$)(.*)"
        backend:
          serviceName: service-v2
          servicePort: 80

测试

[root@k8s01 ~]# curl http://www.test.com/api-a
111111111111111
[root@k8s01 ~]# curl http://www.test.com/api-b
222222222222222

错误代码重定向

这里的错误代码重定向分为全局设置与某个ingress设置
开启全局ingress示例,错误代码重定向功能需要使用helm重新部署ingress-nginx控制器部署步骤如下:

#修改valume.yml文件
defaultBackend:
  ## 
  enabled: true #开启这个功能                          
  image:
    repository: woshitiancai/defaultbackend-amd64  #配置镜像
    tag: "1.5"
#更新ingress
[root@k8s01 ~]# helm upgrade -n ingress-nginx ingress-nginx .
#验证是否生成一个新Pod
[root@k8s01 ~]# kubectl get pod -n ingress-nginx 
NAME                                            READY   STATUS    RESTARTS   AGE
ingress-nginx-controller-nbxgf                  1/1     Running   0          17s
ingress-nginx-defaultbackend-58d87944cb-jd5tj   1/1     Running   0          30s

更新完成后访问一个不存在的页面会跳转到Error Server中的页面

[root@k8s01 ~]# curl www.test.com/login.html
default backend - 404

设置某个ingress的错误重定向会覆盖全局设置,示例如下

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: test-v1
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/default-backend: 'service-v2'
    nginx.ingress.kubernetes.io/custom-http-errors: "404,415"
spec:
  rules:   
  - host: www.test.com
    http: 
      paths:
      - pathType: Prefix
        path: "/a"
        backend:
          serviceName: service-v1
          servicePort: 80

使用ssl加密

生产环境对外的服务,一般需要配置https协议,使用Ingress也可以非常方便的添加https的证书。 可使用OpenSSL生成一个测试证书。如果是生产环境,证书为在第三方公司购买的证书,无需自行生成

#生成证书
[root@k8s01 ~]# openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout com.key -out com.crt -subj "/CN=www.test.com"
[root@k8s01 ~]# openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout org.key -out org.crt -subj "/CN=www.test.com"
#创建证书secret
[root@k8s01 ~]# kubectl create secret tls www.test.com --cert=com.crt --key=com.key

添加ingress的TLS配置
如果在ingress中设置tls,即默认的http会被强制重定向到https,http即不可访问,如果需要http与https同时可以使用可以设置

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: www.test.com
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
  rules:   
  - host: www.test.com
    http: 
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          serviceName: service-v1
          servicePort: 80
  tls:
  - hosts:
    - www.test.com  #证书所授权的域名列表
    secretName: www.zhangzhuo.com #证书的Secret名字,自己匹配

可以看到Ingress添加TLS配置也非常简单,只需要在spec下添加一个tls字段即可:

  • hosts:证书所授权的域名列表
  • secretName:证书的 Secret 名字
  • ingressClassName: ingress class 的名字,1.22+需要配置

匹配请求头

注意Ingress annotations的nginx.ingress.kubernetes.io/server-snippet配置。Snippet 配置是专门用于一些复杂的Nginx配置,和Nginx配置通用,在这里模拟下移动端与电脑端访问同一个域名转发到不同服务

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: www.test.com
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/server-snippet: |
      set $agentflag 0;
        if ($http_user_agent ~* "(Android|IPhone)" ){ #如果是安卓与IPhone访问会重定向到www.baidu.com的新网站
          set $agentflag 1;
        }
        if ( $agentflag = 1 ) {
          return 302 http://www.baidu.com;
        }
spec:
  rules:   
  - host: www.test.com
    http: 
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          serviceName: service-v1
          servicePort: 80

验证

[root@k8s01 ~]# curl www.test.com -I
HTTP/1.1 200 OK
11111111111
#模拟安卓访问
[root@k8s01 ~]# curl 'www.test.com' -H 'User-Agent: Android'  -I
HTTP/1.1 302 Moved Temporarily
Location: http://www.baidu.com

基本认证使用

有些网站可能需要通过密码来访问,对于这类网站可以使用Nginx的basic-auth设置密码访问,具体方法如下,由于需要使用 htpasswd工具,所以需要安装httpd

[root@k8s01 ~]# yum install httpd
#生成用户名密码
[root@k8s01 ~]# htpasswd -c auth test
[root@k8s01 ~]# cat auth 
test:$apr1$MWrO9I1q$.FXzcU6l.riRUGkKXyvVz1
#创建secret
[root@k8s01 ~]# kubectl create secret generic http-auth --from-file=auth

创建包含密码认证的Ingress:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: www.test.com
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/auth-type: basic  #认证类型
    nginx.ingress.kubernetes.io/auth-secret: http-auth  #认证密码secret资源名称
    nginx.ingress.kubernetes.io/auth-realm: "请输入用户名密码:"  #需要密码认证的消息提醒
spec:
  rules:   
  - host: www.test.com
    http: 
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          serviceName: service-v1
          servicePort: 80

配置黑名单/白名单

黑名单配置详解

配置黑名单禁止某一个或某一段 IP,需要在 Nginx Ingress的ConfigMap中配置,比如将 192.168.200.161(多个配置逗号分隔)添加至黑名单
configmap官方配置文档说明:https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/configmap/

[root@k8s01 ingress-nginx]# vim values.yaml
...
config:
  block-cidrs: 192.168.200.161
...    
#更新验证
[root@k8s01 ingress-nginx]# helm upgrade -n ingress-nginx ingress-nginx .
[root@k8s01 ingress-nginx]# curl www.test.com -I
HTTP/1.1 403 Forbidden  #这里拒绝访问

白名单配置详解

白名单表示只允许某个IP可以访问,直接在yaml文件中配置即可(也可以通过ConfigMap配置),比如只允许192.168.200.161访问,只需要添加一个nginx.ingress.kubernetes.io/whitelist-source-range 注释即可:

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: www.test.com
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/whitelist-source-range: 192.168.200.161 #配置白名单
spec:
  rules:   
  - host: www.test.com
    http: 
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          serviceName: service-v1
          servicePort: 80

速率限制

有时候可能需要限制速率以降低后端压力,或者限制单个IP每秒的访问速率防止攻击。此时可以使用 Nginx的rate limit进行配置,相关的设置如下:

#限制每秒的连接,单个 IP: 
nginx.ingress.kubernetes.io/limit-rps
#限制每分钟的连接,单个 IP: 
nginx.ingress.kubernetes.io/limit-rpm 
#限制客户端每秒传输的字节数,单位为 K,需要开启proxy-buffering: 
nginx.ingress.kubernetes.io/limit-rate 
#速率限制白名单 
nginx.ingress.kubernetes.io/limit-whitelist

首先没有加速率限制,使用ab进行访问,Failed为0:

[root@k8s01 ingress-nginx]# ab -c 10 -n 100 http://www.test.com/ | grep requests
Complete requests:      100
Failed requests:        0

添加速率限制,限制只能有一个连接,只需要添加 nginx.ingress.kubernetes.io/limit-connections 为 1 即可

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: www.test.com
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/limit-connections: "1"
spec:
  rules:   
  - host: www.test.com
    http: 
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          serviceName: service-v1
          servicePort: 80

验证

[root@k8s01 ingress-nginx]# ab -c 10 -n 100 http://www.test.com/ | grep requests
Complete requests:      100
Failed requests:        91

实现灰度或者金丝雀发布

首先创建一个v1版本的ingress

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: test-v1
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  rules:   
  - host: www.test.com
    http: 
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          serviceName: service-v1
          servicePort: 80

创建 v2 版本的 Ingress 时,需要添加两个注释

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: test-v2
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "10"
spec:
  rules:   
  - host: www.test.com
    http: 
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          serviceName: service-v2
          servicePort: 80

验证

[root@k8s01 ingress-nginx]# for i in {1..100};do curl www.test.com >> 1.txt;done
[18:50:26 root@node-1 ingress]#cat 1.txt | sort | uniq -c
89 111111111111111
11 222222222222222
#比例大概为9:1

代理后端https协议服务

如果后端服务是https协议,需要使用nginx.ingress.kubernetes.io/backend-protocols声明后端服务是https。这里代理K8s的web控制台作为示例。代理后访问默认会强制跳转到https协议,返回的证书也是服务本身的证书

apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: kubernetes-dashboard
  namespace: kubernetes-dashboard
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/rewrite-target: "/$1"
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"  #这里声明后端服务是https协议,不写默认http
spec:
  rules:   
  - host: dashboard.k8s.com
    http: 
      paths:
      - pathType: Prefix
        path: "/dashboard/(.*)"
        backend:
          serviceName: kubernetes-dashboard
          servicePort: 443

ingress-nginx四层代理

在新版本的nginx也引入了四层代理的概念,可直接代理TCP与UDP协议,在ingress-nginx也可以通过四层代理实现service的代理,实现方式如下:
官方文档:https://kubernetes.github.io/ingress-nginx/user-guide/exposing-tcp-udp-services/
首先在使用helm部署ingress-nginx之后,需修改nginx启动资源的启动参数添加–tcp-services-configmap、–udp-services-configmap的配置启用四层代理,通过修改配置configmap资源进行四层代理的配置

TCP代理

在ingress-nginx-controller中添加–tcp-services-configmap启动参数

args:
            - /nginx-ingress-controller
            - '--publish-service=$(POD_NAMESPACE)/ingress-nginx-controller'
            - '--tcp-services-configmap=$(POD_NAMESPACE)/tcp-configmap-example'  #主要是这里
            - '--election-id=ingress-controller-leader'
            - '--ingress-class=nginx'
            - '--configmap=ingress-nginx/ingress-nginx-controller'
            - '--validating-webhook=:8443'
            - '--validating-webhook-certificate=/usr/local/certificates/cert'
            - '--validating-webhook-key=/usr/local/certificates/key'
#参数说明如下
--tcp-services-configmap=$(POD_NAMESPACE)/  这里为固定,表示tcp配置选择ingress-nginx安装的命名空间的configmap资源
tcp-configmap-example  为configmap资源的名称

创建configmap配置文件

[root@k8s01 ingress-nginx]# vim tcp-configmap-example.yaml 
apiVersion: v1
kind: ConfigMap
metadata:
  name: tcp-configmap-example
data:
  9000: "default/kubernetes:443"
  9001: "kubernetes-dashboard/kubernetes-dashboard:443"
[root@k8s01 ingress-nginx]# kubectl apply -f tcp-configmap-example.yaml -n ingress-nginx
#主要配置参数介绍
代理k8s内部svc资源
9000 对外暴露的端口
"命名空间/svc名称:svc端口"

所有的TCP代理配置都可以写入到这个configmap资源当中,修改后ingress-nginx会自动更新配置,根据配置暴露相应的端口,如果配置错误则不会进行变更

UDP代理

在ingress-nginx-controller中添加–udp-services-configmap启动参数

args:
            - /nginx-ingress-controller
            - '--publish-service=$(POD_NAMESPACE)/ingress-nginx-controller'
            - '--tcp-services-configmap=$(POD_NAMESPACE)/tcp-configmap-example'  
            - '--udp-services-configmap=$(POD_NAMESPACE)/udp-configmap-example'  #主要是这里
            - '--election-id=ingress-controller-leader'
            - '--ingress-class=nginx'
            - '--configmap=ingress-nginx/ingress-nginx-controller'
            - '--validating-webhook=:8443'
            - '--validating-webhook-certificate=/usr/local/certificates/cert'
            - '--validating-webhook-key=/usr/local/certificates/key'
#参数说明如下
--udp-services-configmap=$(POD_NAMESPACE)/  这里为固定,表示tcp配置选择ingress-nginx安装的命名空间的configmap资源
udp-configmap-example  为configmap资源的名称

创建configmap配置文件

[root@k8s01 ingress-nginx]# vim udp-configmap-example.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: udp-configmap-example
data:
  53: "kube-system/kube-dns:53"
[root@k8s01 ingress-nginx]# kubectl apply -f udp-configmap-example.yaml -n ingress-nginx
#主要配置参数介绍
代理k8s内部svc资源
9000 对外暴露的端口
"命名空间/svc名称:svc端口"
文章作者: 鲜花的主人
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 爱吃可爱多
Kubernetes Kubernetes
喜欢就支持一下吧
打赏
微信 微信
支付宝 支付宝