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

上一节中我们学习了Service以及对应的负载均衡,但是这些负载均衡都是基于IP和端口的四层负载均衡。那么如果想要实现七层负载均衡,也就是根据请求的内容来,有没有办法实现呢?这就需要用到本节即将学习的Ingress了。

我是T型人小付,一位坚持终身学习的互联网从业者。喜欢我的博客欢迎在csdn上关注我,如果有问题欢迎在底下的评论区交流,谢谢。

文章目录

    • 什么是Ingress
    • Ingress vs NodePort
    • Ingress-Nginx
      • 安装
      • 实际操作
        • HTTP代理
        • HTTPS代理
        • BasicAuth
        • Nginx重写
    • 总结

什么是Ingress

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

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

Ingress vs NodePort

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

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

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

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

Ingress-Nginx

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

需要注意几点:

  • 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           80:31958/TCP,443:30265/TCP   54m
ingress-nginx-controller-admission   ClusterIP   10.109.76.229           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               443/TCP    10d
mynginx-service   ClusterIP   10.97.205.233           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               
mynginx-deployment-b66f59f66-vfvsw   1/1     Running   0          14s   10.244.1.76   k8s-node1               
mynginx-deployment-b66f59f66-xtk4c   1/1     Running   0          14s   10.244.0.15   k8s-master              

下面需要将上述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 010】Ingress作用及Ingress-Nginx实际操作详解_第4张图片

这样就成功完成了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 010】Ingress作用及Ingress-Nginx实际操作详解_第5张图片
因为是我们自己签名的证书,所以需要用户认证一下
【Kubernetes 010】Ingress作用及Ingress-Nginx实际操作详解_第6张图片
之后就可以正常访问了
【Kubernetes 010】Ingress作用及Ingress-Nginx实际操作详解_第7张图片

更多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 010】Ingress作用及Ingress-Nginx实际操作详解_第8张图片
输入刚才创建的用户和密码即可成功访问。

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。

你可能感兴趣的:(Devops,-,Kubernetes)