美文网首页云原生
十九 服务发布Ingress

十九 服务发布Ingress

作者: 負笈在线 | 来源:发表于2022-06-11 09:48 被阅读0次

    (一) Ingress Nginx Controller安装

    首先安装Helm

    # wget https://get.helm.sh/helm-v3.6.3-linux-amd64.tar.gz
    # tar -zxvf helm-v3.0.0-linux-amd64.tar.gz
    # mv linux-amd64/helm /usr/local/bin/helm
    

    下载 Ingress Nginx Controller安装包

    # helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
    # helm repo update
    # helm pull ingress-nginx/ingress-nginx --version 4.0.1
    

    更改对应的配置

    # tar xf ingress-nginx-4.0.1.tgz
    #cd ingress-nginx
    #vim values.yaml
    

    需要修改的位置

    1. Controller和admissionWebhook的镜像地址,需要将公网镜像同步至公司内网镜像仓库(和课程不一致的版本,需要自行同步gcr镜像,一样的版本可以直接用registry.cn-beijing.aliyuncs.com/dotbalo/kube-webhook-certgen:v1.0和registry.cn-beijing.aliyuncs.com/dotbalo/controller:v1.0.0)
    2. 镜像的digest值注释
    3. hostNetwork设置为true
    4. dnsPolicy设置为 ClusterFirstWithHostNet
    5. NodeSelector添加ingress: "true"部署至指定节点
    6. 类型更改为kind: DaemonSet
    7. 将ingress nginx设置为默认的ingressClass


    8. 部署ingress,给需要部署ingress的节点上打标签
    # kubectl label node k8s-node02 ingress=true
    # kubectl create ns ingress-nginx
    # helm install ingress-nginx -n ingress-nginx .
    

    (二) Ingress Nginx入门使用

    创建一个用于学习Ingress的Namespace,之后所有的操作都在此Namespace进行:

    # kubectl create ns study-ingress
    namespace/study-ingress created
    

    创建一个简单的Nginx模拟Web服务:

    # kubectl create deploy nginx --image=registry.cn-beijing.aliyuncs.com/dotbalo/nginx:1.15.12 -n study-ingress
    

    然后创建该Web容器的Service:

    # kubectl expose deploy nginx --port 80 -n study-ingress
    

    之后创建Ingress指向上面创建的Service:

    # vim web-ingress.yaml 
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: nginx-ingress
      namespace: study-ingress
    spec:
      ingressClassName: nginx # for k8s >= 1.22+
      rules:
      - host: nginx.test.com
        http:
          paths:
          - backend:
              service:
                name: nginx
                port:
                  number: 80
            path: /
            pathType: ImplementationSpecific 
    

    如果apiVersion是networking.k8s.io/v1beta1,对应的配置如下:

    apiVersion: networking.k8s.io/v1beta1
    kind: Ingress
    metadata:
      name: nginx-ingress
      namespace: study-ingress
    spec:
      rules:
      - host: nginx.test.com
        http:
          paths:
          - backend:
              serviceName: nginx
              servicePort: 80
            path: /
            pathType: ImplementationSpecific
    

    提示:本章内容均采用networking.k8s.io/v1版本创建Ingress资源,如果Kubernetes版本低于1.19,可以使用networking.k8s.io/v1beta1替代,配置可以参考上述的networking.k8s.io/v1beta1,只有backend配置不一样。

    创建该Ingress:

    # kubectl create -f web-ingress.yaml
    

    将域名nginx.test.com即可访问Web服务器,如下图所示:


    (三) Ingress Nginx域名重定向Redirect

    在Nginx作为代理服务器时,Redirect可用于域名的重定向,比如访问old.com被重定向到new.com。Ingress可以更简单的实现Redirect功能,接下来用nginx.redirect.com作为旧域名,baidu.com作为新域名进行演示:

    # vim redirect.yaml 
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        nginx.ingress.kubernetes.io/permanent-redirect: https://www.baidu.com
      name: nginx-redirect
      namespace: study-ingress
    spec:
      rules:
      - host: nginx.redirect.com
        http:
          paths:
          - backend:
              service:
                name: nginx
                port:
                  number: 80
            path: /
            pathType: ImplementationSpecific
    

    使用curl访问域名nginx.redirect.com,可以看到301(请求被重定向的返回值):

    # curl -I  nginx.redirect.com
    HTTP/1.1 301 Moved Permanently
    ...
    Location: https://www.baidu.com
    

    (四) Ingress Nginx前后端分离Rewrite

    创建一个应用模拟后端服务:

    # kubectl create deploy backend-api --image=registry.cn-beijing.aliyuncs.com/dotbalo/nginx:backend-api -n study-ingress
    deployment.apps/backend-api created
    

    创建Service暴露该应用

    # kubectl expose deploy backend-api --port 80 -n study-ingress
    

    查看该Service的地址,并且通过/api-a访问测试:

    # kubectl get svc -n study-ingress
    NAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
    backend-api   ClusterIP   192.168.60.190   <none>        80/TCP    5s
    nginx         ClusterIP   192.168.170.24   <none>        80/TCP    3h27m
    # curl 192.168.60.190/api-a
    <html>
    <head><title>404 Not Found</title></head>
    <body>
    <center><h1>404 Not Found</h1></center>
    <hr><center>nginx/1.15.12</center>
    </body>
    </html>
    

    直接访问根路径是可以的:

    # curl 192.168.60.190
    <h1> backend for ingress rewrite </h1>
    <h2> **Path: /api-a** </h2>
    

    通过Ingress Nginx的Rewrite功能,将/api-a重写为“/”,配置示例如下:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /$2
      name: backend-api
      namespace: study-ingress
    spec:
      ingressClassName: nginx # for k8s >= 1.22+
      rules:
      - host: nginx.test.com
        http:
          paths:
          - backend:
              service:
                name: backend-api
                port:
                  number: 80
            path: /api-a(/|$)(.*)
            pathType: ImplementationSpecific
    

    再次访问nginx.test.com/api-a即可访问到后端服务:


    (五) Ingress Nginx错误代码重定向

    1.通过Helm进行更改

    修改values.yaml如下图所示位置:



    更新ConfigMap:

      config: 
        apiVersion: v1
        client_max_body_size: 20m
        custom-http-errors: "404,415,503"
    

    更新Release:

    # helm upgrade ingress-nginx -n ingress-nginx .
    

    更新后Pod会自动重启,并且会创建一个defaultbackend:

    # kubectl get po -n ingress-nginx
    NAME READY STATUS RESTARTS AGE
    ingress-nginx-controller-pdjvh 1/1 Running 0 95s
    ingress-nginx-defaultbackend-79d64fb85f-kxlnc 1/1 Running 0         109s
    

    更新完成以后访问一个不存在的页面,比如之前定义的nginx.test.com。 访问一个不存在的页面123,就会跳转到Error Server中的页面:

    # curl nginx.test.com/123
    default backend - 404
    

    使用浏览器访问,会出现如下图所示的页面:


    (六) Ingress Nginx SSL

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

    # openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/CN=nginx.test.com"
    Generating a 2048 bit RSA private key
    .....+++
    ............................+++
    writing new private key to 'tls.key'
    -----
    # kubectl create secret tls ca-secret --cert=tls.crt --key=tls.key  -n study-ingress
    secret/ca-secret created
    

    配置Ingress添加TLS配置:

    # vim ingress-ssl.yaml 
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      creationTimestamp: null
      name: nginx-ingress
      namespace: study-ingress
      # annotations:
        # kubernetes.io/ingress.class: nginx
    spec:
      ingressClassName: nginx # for k8s >= 1.22+
      rules:
      - host: nginx.test.com
        http:
          paths:
          - backend:
              service:
                name: nginx
                port:
                  number: 80
            path: /
            pathType: ImplementationSpecific
      tls:
      - hosts:
        - nginx.test.com
        secretName: ca-secret
    

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

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

    接下来更新该Ingress即可:

    # kubectl apply -f ingress-ssl.yaml
    ingress.networking.k8s.io/nginx-ingress configured
    

    使用curl进行测试,域名已经被重定向到https:

    # curl http://nginx.test.com -I
    HTTP/1.1 308 Permanent Redirect
    ...
    Location: https://nginx.test.com
    

    使用浏览器访问,会自动跳转到https,如下图所示:


    (七) Ingress Nginx匹配请求头

    首先部署移动端应用:

    # kubectl create deploy phone --image=registry.cn-beijing.aliyuncs.com/dotbalo/nginx:phone -n study-ingress
    # kubectl expose deploy phone --port 80 -n study-ingress
    

    Ingress实例也可以通过kubectl create进行创建,只需要一条命令即可:

    # kubectl create ingress phone --rule=m.test.com/*=phone:80 -n study-ingress
    

    部署电脑端应用:

    # kubectl create deploy laptop --image=registry.cn-beijing.aliyuncs.com/dotbalo/nginx:laptop -n study-ingress
    deployment.apps/laptop created
    # kubectl expose deploy laptop --port 80 -n study-ingress
    service/laptop exposed
    # kubectl get po -n study-ingress -l app=laptop
    NAME                          READY   STATUS    RESTARTS   AGE
    laptop-664b565969-hpxlh   1/1     Running   0          3m22s
    

    之后创建电脑端的Ingress,注意Ingress annotations的 nginx.ingress.kubernetes.io/server-snippet配置。Snippet配置是专门用于一些复杂的Nginx配置,和Nginx配置通用。匹配移动端实例如下:

    # vim laptop-ingress.yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        kubernetes.io/ingress.class: nginx
        nginx.ingress.kubernetes.io/server-snippet: |
          set $agentflag 0;
                  if ($http_user_agent ~* "(Android|iPhone|Windows Phone|UC|Kindle)" ){
                    set $agentflag 1;
                  }
                  if ( $agentflag = 1 ) {
                    return 301 http://m.test.com;
                  }
      name: laptop
      namespace: study-ingress
    spec:
      ingressClassName: nginx # for k8s >= 1.22+
      rules:
      - host: test.com
        http:
          paths:
          - backend:
              service:
                name: laptop
                port:
                  number: 80
            path: /
            pathType: ImplementationSpecific
    

    首先通过浏览器访问test.com,可以看到页面是Laptop:



    接下来使用浏览器的开发者工具将终端类型改为iPhone,或者直接用iPhone手机访问(线上业务一般配置的都有DNS,可以直接解析域名,测试环境可能需要自己单独配置),如下图所示:



    刷新页面会自动跳转至m.test.com,如下图所示:

    (八) Ingress Nginx基本认证

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

    # yum install httpd -y
    

    使用htpasswd创建foo用户的密码:

    # htpasswd -c auth foo
    New password: 
    Re-type new password: 
    Adding password for user foo
    # cat auth 
    foo:$apr1$okma2fx9$hdTJ.KFmi4pY9T6a2MjeS1
    

    基于之前创建的密码文件创建Secret:

    # kubectl create secret generic basic-auth --from-file=auth -n study-ingress
    secret/basic-auth created
    

    创建包含密码认证的Ingress:

    # vim ingress-with-auth.yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
    # kubernetes.io/ingress.class: nginx
        nginx.ingress.kubernetes.io/auth-realm: Please Input Your Username and Password
        nginx.ingress.kubernetes.io/auth-secret: basic-auth
        nginx.ingress.kubernetes.io/auth-type: basic
      name: ingress-with-auth
      namespace: study-ingress
    spec:
    ingressClassName: nginx # for k8s >= 1.22+
      rules:
      - host: auth.test.com
        http:
          paths:
          - backend:
              service:
                name: nginx
                port:
                  number: 80
            path: /
            pathType: ImplementationSpecific 
    
    1. nginx.ingress.kubernetes.io/auth-type:认证类型,可以是basic和digest
    2. nginx.ingress.kubernetes.io/auth-secret:密码文件的Secret名称
    3. nginx.ingress.kubernetes.io/auth-realm:需要密码认证的消息提醒

    创建该Ingress,并访问测试:



    输入密码后即可进入到页面,在此不再演示。

    (九) Ingress Nginx黑/白名单

    1.黑名单

    配置黑名单禁止某一个或某一段IP,需要在Nginx Ingress的ConfigMap中配置,比如将192.168.10.130(多个配置逗号分隔)添加至黑名单:

    # vim values.yaml
    config:
     block-cidrs: 192.168.10.130
    

    滚动更新Nginx Ingress:

    # helm upgrade ingress-nginx -n ingress-nginx .
    

    使用192.168.10.130主机再次访问,发现该IP已经被禁止:

    # curl auth.test.com -I
    HTTP/1.1 403 Forbidden
    ...
    Connection: keep-alive
    

    2.白名单

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

    # vim auth-whitelist.yaml
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        # kubernetes.io/ingress.class: nginx # K8s >= 1.22+ 使用ingressClassName替代
        nginx.ingress.kubernetes.io/auth-realm: Please Input Your Username and Password
        nginx.ingress.kubernetes.io/auth-secret: basic-auth
        nginx.ingress.kubernetes.io/auth-type: basic
        nginx.ingress.kubernetes.io/whitelist-source-range: 192.168.10.128
      name: ingress-with-auth
      namespace: study-ingress
    spec:
      ingressClassName: nginx # for k8s >= 1.22+
      rules:
      - host: auth.test.com
        http:
          paths:
          - backend:
              service:
                name: nginx
                port:
                  number: 80
            path: /
            pathType: ImplementationSpecific
    

    更新该Ingress:

    # kubectl apply -f test-auth.yaml
    ingress.networking.k8s.io/ingress-with-auth configured
    

    此时192.168.10.128主机是可以访问的:

    # curl auth.test.com -I
    HTTP/1.1 401 Unauthorized
    

    其它IP访问被禁止:

    # curl auth.test.com -I
    HTTP/1.1 403 Forbidden
    

    (十) Ingress Nginx速率限制

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

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

    # ab -c 10 -n 100 http://auth.test.com/ | grep requests
    Complete requests: 100
    Failed requests: 0
    

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

    # vim auth-rate-limit.yaml 
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        kubernetes.io/ingress.class: nginx
        nginx.ingress.kubernetes.io/auth-realm: Please Input Your Username and Password
        nginx.ingress.kubernetes.io/auth-secret: basic-auth
        nginx.ingress.kubernetes.io/auth-type: basic
        nginx.ingress.kubernetes.io/limit-connections: "1"
      name: ingress-with-auth
      namespace: study-ingress
    spec:
      ingressClassName: nginx # for k8s >= 1.22+
      rules:
      - host: auth.test.com
        http:
          paths:
          - backend:
              service:
                name: nginx
                port:
                  number: 80
            path: /
            pathType: ImplementationSpecific
    

    再次使用ab测试,Failed为67:

    [root@k8s-master01 5.10]# ab -c 10 -n 100 http://auth.test.com/ | grep requests:
    Complete requests: 100
    Failed requests: 67
    

    还有很多其它方面的限制,常用的配置如下:

    #限制每秒的连接,单个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
    

    (十一) 使用Nginx实现灰度/金丝雀发布

    1.创建v1版本

    首先创建模拟Production(生产)环境的Namespace和服务:

    # kubectl create ns production
    namespace/production created
    # kubectl create deploy canary-v1 --image=registry.cn-beijing.aliyuncs.com/dotbalo/canary:v1 -n production
    # kubectl expose deploy canary-v1 --port 8080 -n production
    # kubectl create ingress canary-v1 --rule=canary.com/*=canary-v1:8080 -n production
    

    使用浏览器访问该服务,可以看到Canary v1的页面:


    2.创建v2版本

    接下来创建v2版本,充当灰度环境:

    # kubectl create ns canary
    namespace/canary created
    

    创建v2版本的应用和Service:

    # kubectl create deploy canary-v2 --image=registry.cn-beijing.aliyuncs.com/dotbalo/canary:v2 -n canary
    # kubectl expose deploy canary-v2 --port 8080 -n canary
    

    待程序启动完成后,通过Service访问该服务,会返回Canary v2:

    # kubectl get svc -n canary
    NAME        TYPE        CLUSTER-IP        EXTERNAL-IP   PORT(S)    AGE
    canary-v2   ClusterIP   192.168.181.120   <none>        8080/TCP   89s
    # curl 192.168.181.120:8080
    <h1>Canary v2</h1>
    

    接下来通过Ingress控制流量。

    3.Canary版本切入部分流量

    创建v2版本的Ingress时,需要添加两个注释,一个是nginx.ingress.kubernetes.io/canary,表明是灰度环境,nginx.ingress.kubernetes.io/canary-weight表明切多少流量到该环境,本示例为10%:

    # vim canary-v2.yaml 
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      annotations:
        nginx.ingress.kubernetes.io/canary: "true"
        nginx.ingress.kubernetes.io/canary-weight: "10"
      name: canary-v2
      namespace: canary
    spec:
      ingressClassName: nginx # for k8s >=1.22+
      rules:
      - host: canary.com
        http:
          paths:
          - backend:
              service:
                name: canary-v2
                port:
                  number: 8080
            path: /
            pathType: ImplementationSpecific
    

    此时通过nginx.ingress.kubernetes.io/canary-weight: "10"设置的权重是10,即v1:v2为9:1。

    4.测试灰度发布

    接下来使用Ruby脚本进行测试,此脚本会输出v1和v2的访问次数比值:

    # vim  test-canary.rb 
    counts = Hash.new(0)
    
    100.times do
      output = `curl -s canary.com | grep 'Canary' | awk '{print $2}' | awk -F"<" '{print $1}'`
      counts[output.strip.split.last] += 1
    end
    
    puts counts
    

    安装ruby并测试

    # yum install ruby -y
    # ruby test-canary.rb 
    {"v1"=>90, "v2"=>10}
    # ruby test-canary.rb 
    {"v1"=>92, "v2"=>8}
    # ruby test-canary.rb  
    {"v1"=>91, "v2"=>9}
    

    (十二) 环境清理

    测试无误后,可以清理之前的学习数据:

    # kubectl delete deploy,svc,ingress -n production --all
    deployment.apps "canary-v1" deleted
    service "canary-v1" deleted
    ingress.networking.k8s.io "canary-v1" deleted
    # kubectl delete deploy,svc,ingress -n canary --all
    deployment.apps "canary-v2" deleted
    service "canary-v2" deleted
    ingress.networking.k8s.io "canary-v2" deleted
    # kubectl delete deploy,svc,ingress -n study-ingress --all
    deployment.apps "err-page" deleted
    deployment.apps "laptop" deleted
    deployment.apps "nginx" deleted
    deployment.apps "phone" deleted
    service "err-page" deleted
    service "laptop" deleted
    service "nginx" deleted
    service "phone" deleted
    ingress.networking.k8s.io "ingress-with-auth" deleted
    ingress.networking.k8s.io "laptop" deleted
    ingress.networking.k8s.io "nginx-ingress" deleted
    ingress.networking.k8s.io "phone" deleted
    # kubectl delete ns study-ingress production canary
    namespace "study-ingress" deleted
    namespace "production" deleted
    namespace "canary" deleted
    

    相关文章

      网友评论

        本文标题:十九 服务发布Ingress

        本文链接:https://www.haomeiwen.com/subject/iktuurtx.html