Kubernetes Ingress作用及Ingress-Nginx实际操作详解

2022年6月8日11:26:40

    什么是Ingress

    在k8s里,Ingress是一个可以允许集群外部访问集群内布服务的控制器。通过配置一条条规则(rules)来规定进来的连接被分配到后端的哪个服务。

    Ingress相当于一个集中的路由中心,例如,可以将xiaofu.com/api/v1/路由到后端的service-v1服务,而将xiaofu.com/api/v2/路由到service-v2服务。

    Ingress vs NodePort

    同样是将集群内部的服务暴露给集群外,很有必要对比下Ingress和上一节学习的NodePort。

    Kubernetes Ingress作用及Ingress-Nginx实际操作详解
    NodePort是Service的一个类型,并没有额外加入组件。其会在每个Node上开一个端口,对应到后端的Service。所有访问集群任意节点IP上该端口都可以访问到后端的Service。这样的优点就是简单快速,但是只是起了简单的Node端口到Service端口的映射功能,功能很单一。

    Kubernetes Ingress作用及Ingress-Nginx实际操作详解
    Ingress是区别于上一节学的那些Service的另一个单独组件,可以被单独声明,创建和销毁。引入Ingress的好处就是有一个集中的路由配置项,同时可实现基于内容的七层负载均衡。小小的麻烦就是引入了额外组件,但是其实创建一个Ingress和创建一个k8s中的其他资源的步骤没什么两样。

    Ingress的实现方式有很多,下面着重学习下官方推荐的基于Nginx的Ingress-Nginx控制器。

    Ingress-Nginx

    可以将上面的Ingress理解为在集群的前端加了一个Nginx,用来提供Nginx所能提供的一切功能,例如基于url的反向代理,https认证,用户鉴权,域名重定向等等
    Kubernetes Ingress作用及Ingress-Nginx实际操作详解

    需要注意几点:

    • Nginx是基于url的,如果没有DNS解析url到集群中任意ip可以考虑hosts文件劫持
    • Nginx的本质也是NodePort的方式暴露给集群外的一个特殊Service
    • Nginx的配置文件根据Ingress的规则自动添加和修改

    更详细的介绍可以查看官方网站

    安装

    直接按照官方文档进行安装即可。官方提供了minikube以及各厂商的云机器上安装的方式,我们是用kubeadm自己搭建的k8s环境,所以选择Bare-metal部分的安装脚本,只有下面一句脚本即可

    kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-0.32.0/deploy/static/provider/baremetal/deploy.yaml

    官方默认采用NodePort的方式安装Nginx,其实还有其余方式,参考https://kubernetes.github.io/ingress-nginx/deploy/baremetal/

    推荐先将上面这个yaml文件下载到本地,因为以后还可以根据这个文件批量删除或者修改ingress-nginx的资源。

    kubectl apply -f xxx.yaml 也可以用来修改资源配置
    kubectl delete -f xxx.yaml 则可以批量删除资源

    [root@k8s-master ~]# kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-0.32.0/deploy/static/provider/baremetal/deploy.yaml
    namespace/ingress-nginx created
    serviceaccount/ingress-nginx created
    configmap/ingress-nginx-controller created
    clusterrole.rbac.authorization.k8s.io/ingress-nginx created
    clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx created
    role.rbac.authorization.k8s.io/ingress-nginx created
    rolebinding.rbac.authorization.k8s.io/ingress-nginx created
    service/ingress-nginx-controller-admission created
    service/ingress-nginx-controller created
    deployment.apps/ingress-nginx-controller created
    validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission created
    clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission created
    clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
    job.batch/ingress-nginx-admission-create created
    job.batch/ingress-nginx-admission-patch created
    role.rbac.authorization.k8s.io/ingress-nginx-admission created
    rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission created
    serviceaccount/ingress-nginx-admission created

    所有的资源都在ingress-nginx这个namespace下

    [root@k8s-master ~]# kubectl get svc  -n ingress-nginx
    NAME                                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
    ingress-nginx-controller             NodePort    10.96.130.237   <none>        80:31958/TCP,443:30265/TCP   54m
    ingress-nginx-controller-admission   ClusterIP   10.109.76.229   <none>        443/TCP                      54m
    [root@k8s-master ~]# kubectl get pod -n ingress-nginx
    NAME                                        READY   STATUS      RESTARTS   AGE
    ingress-nginx-admission-create-g5sfq        0/1     Completed   0          57m
    ingress-nginx-admission-patch-tzv5x         0/1     Completed   0          57m
    ingress-nginx-controller-5575c6cd9d-8xwmt   1/1     Running     0          57m
    [root@k8s-master ~]# kubectl get deployment -n ingress-nginx
    NAME                       READY   UP-TO-DATE   AVAILABLE   AGE
    ingress-nginx-controller   1/1     1            1           57m

    从上面的svc可以看到,有个以NodePort暴露出来的ingress-nginx-controller的service,对外暴露31958端口对应nginx的80端口,暴露30265端口对应nginx的443端口。下面在实际操作的时候会用到这两个外部端口。

    实际操作

    以下所有yaml文件托管在我的Github仓库

    事先删除上一节的所有service和pod,以免引起混淆。

    HTTP代理

    首先用yaml文件http-mynginx.yaml创建mynginx:v2版的deployment的常规的ClusterIP的service

    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
      name: mynginx-deployment
    spec:
      replicas: 3
      template:
        metadata:
          labels:
            app: mynginx
            version: v2
        spec:
          containers:
            - name: mynginx
              image: mynginx:v2
              ports:
                - containerPort: 80
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: mynginx-service
      namespace: default
    spec:
      type: ClusterIP
      selector:
        app: mynginx
        version: v2
      ports:
        - name: http
          port: 8080
          targetPort: 80

    这里其实就是上一节ClusterIP中的两个yaml文件,用---在同一个yaml文件中进行了合并。

    成功创建出pod和service

    [root@k8s-master k8s-ingress]# kubectl apply -f http-mynginx.yaml
    deployment.extensions/mynginx-deployment created
    service/mynginx-service created
    [root@k8s-master k8s-ingress]# kubectl get svc
    NAME              TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
    kubernetes        ClusterIP   10.96.0.1       <none>        443/TCP    10d
    mynginx-service   ClusterIP   10.97.205.233   <none>        8080/TCP   10s
    [root@k8s-master k8s-ingress]# kubectl get pod -o wide
    NAME                                 READY   STATUS    RESTARTS   AGE   IP            NODE         NOMINATED NODE   READINESS GATES
    mynginx-deployment-b66f59f66-bbkgg   1/1     Running   0          14s   10.244.1.77   k8s-node1    <none>           <none>
    mynginx-deployment-b66f59f66-vfvsw   1/1     Running   0          14s   10.244.1.76   k8s-node1    <none>           <none>
    mynginx-deployment-b66f59f66-xtk4c   1/1     Running   0          14s   10.244.0.15   k8s-master   <none>           <none>

    下面需要将上述mynginx-service这个service的8080端口通过nginx暴露出去,用yaml文件http-mynginx-ingress.yaml在nginx中创建一条规则

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: mynginx-http
    spec:
      rules:
        - host: mynginx.xiaofu.com
          http:
            paths:
              - path: /
                backend:
                  serviceName: mynginx-service
                  servicePort: 8080

    这个规则中将域名mynginx.xiaofu.com的根目录映射到后端的mynginx-service。这里用根目录是因为后端pod中只有一个index.html文件,没有别的路径,实际中这个路径可以根据自己需求去灵活指定。

    然后修改本地hosts文件,绑定mynginx.xiaofu.com到k8s集群中任意一个node的外网ip即可。Windows下的hosts文件路径为C:\Windows\System32\drivers\etc\hosts此后访问该域名的31958端口,数据流就会被导到nginx的80端口,然后到后端服务mynginx-service的8080端口,最后走负载均衡到其中一个pod

    效果如下
    Kubernetes Ingress作用及Ingress-Nginx实际操作详解

    这样就成功完成了nginx中的http反向代理功能,对nginx配置感兴趣的话,可以用类似下面的方法进去nginx的pod中看一下配置文件

    [root@k8s-master k8s-ingress]# kubectl get pod -n ingress-nginx
    NAME                                        READY   STATUS      RESTARTS   AGE
    ingress-nginx-admission-create-g5sfq        0/1     Completed   0          4h18m
    ingress-nginx-admission-patch-tzv5x         0/1     Completed   0          4h18m
    ingress-nginx-controller-5575c6cd9d-7b8zt   1/1     Running     0          36m
    [root@k8s-master k8s-ingress]# kubectl exec ingress-nginx-controller-5575c6cd9d-7b8zt -n ingress-nginx -it -- /bin/bash
    bash-5.0$ cat /etc/nginx/nginx.conf

    如果想达到开头时候说的类似访问svc1.mynginx.xiaofu.comsvc2.mynginx.xiaofu.com映射到后端的不同service,只需要将这两个域名都指向集群中node的ip,并在Ingress中添加两条不同规则即可,这里就不演示了。

    HTTPS代理

    如果想要网站访问更安全,可以考虑带加密和认证的https协议。在客户端和nginx之间走https协议,nginx反向代理到后端的时候因为是内网,还是走未加密的http协议即可。Https的工作方式这里不额外介绍了,要完成配置,我们需要服务端的自签名CA证书和私钥文件。

    生成所需的两个文件

    [root@k8s-master ssl]# openssl genrsa -out ca.key 1024
    Generating RSA private key, 1024 bit long modulus
    ..................++++++
    .....................++++++
    e is 65537 (0x10001)
    [root@k8s-master ssl]# openssl req -new -key ca.key -out ca.csr
    You are about to be asked to enter information that will be incorporated
    into your certificate request.
    What you are about to enter is what is called a Distinguished Name or a DN.
    There are quite a few fields but you can leave some blank
    For some fields there will be a default value,
    If you enter '.', the field will be left blank.
    -----
    Country Name (2 letter code) [XX]:SG
    State or Province Name (full name) []:
    Locality Name (eg, city) [Default City]:
    Organization Name (eg, company) [Default Company Ltd]:xiaofu
    Organizational Unit Name (eg, section) []:
    Common Name (eg, your name or your server's hostname) []:
    Email Address []:
    
    Please enter the following 'extra' attributes
    to be sent with your certificate request
    A challenge password []:
    An optional company name []:
    root@k8s-master ssl]# openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt
    Signature ok
    subject=/C=SG/L=Default City/O=xiaofu
    Getting Private key
    [root@k8s-master ssl]# ll
    total 12
    -rw-r--r--. 1 root root 713 May  8 20:07 ca.crt
    -rw-r--r--. 1 root root 582 May  8 20:02 ca.csr
    -rw-r--r--. 1 root root 887 May  8 20:01 ca.key

    将刚才生成的两个文件存储到了k8s的secret里面,这里可以暂时不用管下面的命令具体含义,后面讲到k8s的存储的时候我们再详细学习。

    [root@k8s-master ssl]# kubectl create secret tls tls-secret --key ca.key --cert ca.crt
    secret/tls-secret created

    通过yaml文件https-mynginx.yaml创建一个https加密的域名,采用刚才存储的tls-secret进行认证和加密,映射到后面和刚才一样的service

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: mynginx-https
    spec:
      tls:
        - hosts:
          - secret.xiaofu.com
          secretName: tls-secret
      rules:
        - host: secret.xiaofu.com
          http:
            paths:
              - path: /
                backend:
                  serviceName: mynginx-service
                  servicePort: 8080

    成功创建出来

    [root@k8s-master k8s-ingress]# kubectl apply -f https-mynginx.yaml
    ingress.extensions/mynginx-https created

    之后修改hosts文件,将secret.xiaofu.com绑定到集群中任一node的ip。

    然后就可以用https访问域名了,端口是前面ingress暴露出来的443对用的外网端口
    Kubernetes Ingress作用及Ingress-Nginx实际操作详解
    因为是我们自己签名的证书,所以需要用户认证一下
    Kubernetes Ingress作用及Ingress-Nginx实际操作详解
    之后就可以正常访问了
    Kubernetes Ingress作用及Ingress-Nginx实际操作详解

    更多tls的相关使用参考k8s的官方文档

    BasicAuth

    以下案例参考了k8s官方文档

    因为要通过apache的htpasswd模块去验证,所以要先安装apache,centos7中就是httpd

    yum install httpd

    之后创建用户xiaofu及密码文件auth,并根据auth文件存储到k8s的secret中

    [root@k8s-master ~]# htpasswd -c auth xiaofu
    New password:
    Re-type new password:
    Adding password for user xiaofu
    [root@k8s-master ~]# kubectl create secret generic basic-auth --from-file=auth
    secret/basic-auth created

    通过yaml文件basicauth-mynginx.yaml来添加一条需要认证的域名

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: mynginx-basicauth
      annotations:
        nginx.ingress.kubernetes.io/auth-type: basic
        nginx.ingress.kubernetes.io/auth-secret: basic-auth
        nginx.ingress.kubernetes.io/auth-realm: 'Authentication Required - xiaofu'
    spec:
      rules:
        - host: auth.xiaofu.com
          http:
            paths:
              - path: /
                backend:
                  serviceName: mynginx-service
                  servicePort: 8080

    这里和前面http部分的yaml文件就只是annotations部分。

    成功创建

    [root@k8s-master k8s-ingress]# kubectl apply -f basicauth-mynginx.yaml
    ingress.extensions/mynginx-basicauth created

    同时在hosts文件中将basicauth.xiaofu.com映射到任意node的ip,之后再访问声明了的域名就要密码了
    Kubernetes Ingress作用及Ingress-Nginx实际操作详解
    输入刚才创建的用户和密码即可成功访问。

    Nginx重写

    上面yaml文件中的annotations除了可以声明认证方式外,还有很多重写功能。

    下面的表格取自官方文档

    Name Description Values
    nginx.ingress.kubernetes.io/rewrite-target Target URI where the traffic must be redirected string
    nginx.ingress.kubernetes.io/ssl-redirect Indicates if the location section is accessible SSL only (defaults to True when Ingress contains a Certificate) bool
    nginx.ingress.kubernetes.io/force-ssl-redirect Forces the redirection to HTTPS even if the Ingress is not TLS Enabled bool
    nginx.ingress.kubernetes.io/app-root Defines the Application Root that the Controller must redirect if it’s in ‘/’ context string
    nginx.ingress.kubernetes.io/use-regex Indicates if the paths defined on an Ingress use regular expressions bool

    下面利用重写功能将访问redirect.xiaofu.com的请求都重定向到mynginx.xiaofu.com。yaml文件mynginx-rewrite.yaml如下

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: mynginx-rewrite
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: http://mynginx.xiaofu.com:31958
    spec:
      rules:
        - host: redirect.xiaofu.com
          http:
            paths:
              - path: /
                backend:
                  serviceName: mynginx-service
                  servicePort: 8080

    跳转的目的地址要写完整

    成功创建

    [root@k8s-master k8s-ingress]# kubectl apply -f mynginx-rewrite.yaml
    ingress.extensions/mynginx-rewrite configured

    同时在hosts文件中将redirect.xiaofu.com映射到任意node的ip,此时访问redirect.xiaofu.com:31958/会自动跳转到mynginx.xiaofu.com:31958

    总结

    这一节我们学习了通过Ingress将k8s集群内部服务暴露给集群外的方法,到这里Service的部分就全部结束了,下一节我们开始学习k8s中的存储,其中就会学习到这一节中已经用到了的secret。

    • 作者:T型人小付
    • 原文链接:https://blog.csdn.net/Victor2code/article/details/106007849
      更新时间:2022年6月8日11:26:40 ,共 9803 字。