目 录CONTENT

文章目录

服务发布Ingress

简中仙
2023-06-30 / 0 评论 / 0 点赞 / 138 阅读 / 0 字 / 正在检测是否收录...
温馨提示:
本文最后更新于2024-01-14,若内容或图片失效,请留言反馈。 本文如有错误或者侵权的地方,欢迎您批评指正!

这篇学习笔记是基于杜宽老师在51CTO上发布的视频课程制作的。在此,感谢杜宽老师的分享和教学。如有侵权,请及时联系我。版权归原作者所有,未经允许不得转载或使用。

一、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 的镜像地址,需要将公网镜像同步至公司内网镜像仓库

2、镜像的 digest 值注释

3、hostNetwork 设置为 true

4、dnsPolicy 设置为 ClusterFirstWithHostNet

5、NodeSelector 添加 ingress: "true"部署至指定节点

6、类型更改为 kind: DaemonSet

7、将 ingress nginx 设置为默认的 ingressClass

ingressclassResource:
  name: nginx
  enabled: true
  default: true
  controllerValue: "k8s.io/ingress-nginx"

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: 
  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

创建该 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: 
  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

defaultBackend:
##
  enabled: true
  name: defaultbackend
  image:
	registry: registry.cn-beijing.aliyuncs.com
	image: dotbalo/defaultbackend-amd64
tag: "1.5"

更新 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"
# 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 字段即可

  • hosts:证书所授权的域名列表
  • secretName:证书的 Secret 名字
  • 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: 
  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
  • nginx.ingress.kubernetes.io/auth-type:认证类型,可以是 basic 和 digest
  • nginx.ingress.kubernetes.io/auth-secret:密码文件的 Secret 名称
  • 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: 
  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: 
  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}
0

评论区