Ingress


1、介绍

在前面文章中已经提到,Service对集群之外暴露服务的主要方式有两种:NotePort和LoadBalancer,但是这两种方式,都有一定的缺点:

NodePort方式的缺点是会占用很多集群机器的端口,那么当集群服务变多的时候,这个缺点就愈发明显。

LB方式的缺点是每个service需要一个LB,浪费、麻烦,并且需要kubernetes之外设备的支持。

基于这种现状,kubernetes提供了Ingress资源对象,Ingress只需要一个NodePort或者一个LB就可以满足暴露多个Service的需求。工作机制大致如下图表示:

图片

在Kubernetes中,Ingress是管理Kubernetes集群内部服务的外部访问的API对象。

实际上,Ingress相当于一个7层的负载均衡器,是kubernetes对反向代理的一个抽象,它的工作原理类似于Nginx,可以理解成在Ingress里建立诸多映射规则,Ingress Controller通过监听这些配置规则并转化成Nginx的反向代理配置 , 然后对外部提供服务。在这里有两个核心概念:

  • ingress:kubernetes中的一个对象,作用是定义请求如何转发到service的规则

  • ingress controller:具体实现反向代理及负载均衡的程序,对ingress定义的规则进行解析,根据配置的规则来实现请求转发,实现方式有很多,比如Nginx, Contour, Haproxy等等

87.png

88.png

Ingress-Nginx github 地址:https://github.com/kubernetes/ingress-nginx

Ingress-Nginx 官方网站:https://kubernetes.github.io/ingress-nginx

版本与k8s对照表

Supported Ingress-NGINX version k8s supported version Alpine Version Nginx Version Helm Chart Version
🔄 v1.10.1 1.29, 1.28, 1.27, 1.26 3.19.1 1.25.3 4.10.1*
🔄 v1.10.0 1.29, 1.28, 1.27, 1.26 3.19.1 1.25.3 4.10.0*
🔄 v1.9.6 1.29, 1.28, 1.27, 1.26, 1.25 3.19.0 1.21.6 4.9.1*
🔄 v1.9.5 1.28, 1.27, 1.26, 1.25 3.18.4 1.21.6 4.9.0*
🔄 v1.9.4 1.28, 1.27, 1.26, 1.25 3.18.4 1.21.6 4.8.3
🔄 v1.9.3 1.28, 1.27, 1.26, 1.25 3.18.4 1.21.6 4.8.*
🔄 v1.9.1 1.28, 1.27, 1.26, 1.25 3.18.4 1.21.6 4.8.*
🔄 v1.9.0 1.28, 1.27, 1.26, 1.25 3.18.2 1.21.6 4.8.*
v1.8.4 1.27, 1.26, 1.25, 1.24 3.18.2 1.21.6 4.7.*
v1.7.1 1.27, 1.26, 1.25, 1.24 3.17.2 1.21.6 4.6.*
v1.6.4 1.26, 1.25, 1.24, 1.23 3.17.0 1.21.6 4.5.*
v1.5.1 1.25, 1.24, 1.23 3.16.2 1.21.6 4.4.*
v1.4.0 1.25, 1.24, 1.23, 1.22 3.16.2 1.19.10† 4.3.0
v1.3.1 1.24, 1.23, 1.22, 1.21, 1.20 3.16.2 1.19.10† 4.2.5

部署 Ingress-Nginx

# https://kubernetes.github.io/ingress-nginx/deploy/
# 下载部署用yaml文件,大家根据自己的k8s版本更换版本号
wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.6.4/deploy/static/provider/cloud/deploy.yaml

# 修改镜像地址为国内镜像地址,否则镜像拉取会失败
vim deploy.yaml

# -----------------------------------------------------------------
# 在第439行
# 将image改为registry.cn-hangzhou.aliyuncs.com/google_containers/nginx-ingress-controller:v1.6.3
# 教室局域网可以使用:192.168.3.200:8099/ingress-nginx/controller:v1.6.3
# 第536行和第585行
# 将registry.k8s.io/ingress-nginx/替换为registry.aliyuncs.com/google_containers/
# 教室局域网可以使用:192.168.3.200:8099/ingress-nginx/kube-webhook-certgen:v20220916-gd32f8c343
# -----------------------------------------------------------------

kubectl apply -f deploy.yaml
# 教室局域网专用版本,针对无法使用外网的情况。(已安装,可忽略)
# wget http://192.168.3.200/Software/ingress-nginx-v1.6.3-deploy.yaml
# kubectl apply -f ingress-nginx-v1.6.3-deploy.yaml
[root@k8s-master ~]# kubectl get pod -n ingress-nginx
NAME                                        READY   STATUS      RESTARTS   AGE
ingress-nginx-admission-create-db6jl        0/1     Completed   0          5h6m
ingress-nginx-admission-patch-m6rvd         0/1     Completed   0          5h6m
ingress-nginx-controller-7998c976fc-ln7z9   1/1     Running     0          5h6m

# 查看ingress-nginx-controller svc 注意: 80:30577/TCP,443:32667/TCP 此处 30577和32667 后续需要使用到  
[root@k8s-master ~]# kubectl get svc -n ingress-nginx
NAME                                 TYPE           CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             LoadBalancer   10.68.155.84   <pending>     80:30577/TC,443:32667/TCP   5h6m
ingress-nginx-controller-admission   ClusterIP      10.68.89.135   <none>        443/TCP                      5h6m

2、准备Service、Pod

为了后面的实验比较方便,创建如下图所示的模型

图片

安装上述图片模型,我们创建3个Nginx Pod和3个Tomcat Pod,并分别为他们创建servce ,yaml文件名叫tomcat-nginx.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx-pod
  template:
    metadata:
      labels:
        app: nginx-pod
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80

---

apiVersion: apps/v1
kind: Deployment
metadata:
  name: tomcat-deployment
  namespace: dev
spec:
  replicas: 3
  selector:
    matchLabels:
      app: tomcat-pod
  template:
    metadata:
      labels:
        app: tomcat-pod
    spec:
      containers:
      - name: tomcat
        image: tomcat:8.0
        ports:
        - containerPort: 8080

---

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: dev
spec:
  selector:
    app: nginx-pod
  clusterIP: None
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 80

---

apiVersion: v1
kind: Service
metadata:
  name: tomcat-service
  namespace: dev
spec:
  selector:
    app: tomcat-pod
  clusterIP: None
  type: ClusterIP
  ports:
  - port: 8080
    targetPort: 8080

执行文件并查看创建结果

# 1.先创建dev命令空间
[root@k8s-master ~]# kubectl create ns dev
# 2.创建nginx-deployment和tomcat-deployment
[root@k8s-master ~]# kubectl apply -f tomcat-nginx.yaml
deployment.apps/nginx-deployment created
deployment.apps/tomcat-deployment created
service/nginx-service created
service/tomcat-service created
[root@k8s-master ~]#
# 3.查看 deploy
[root@k8s-master ~]# kubectl get deploy -n dev
NAME                READY   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment    2/3     3            2           7s
tomcat-deployment   3/3     3            3           7s
[root@k8s-master ~]#
# 4.查看pod
[root@k8s-master ~]# kubectl get pod -n dev
NAME                                 READY   STATUS              RESTARTS   AGE
nginx-deployment-69cbb4f6b6-2nwkd    1/1     Running             0          13s
nginx-deployment-69cbb4f6b6-lsqcp    1/1     Running             0          13s
nginx-deployment-69cbb4f6b6-rmfzc    0/1     ContainerCreating   0          13s
tomcat-deployment-798c966d9d-cg59r   1/1     Running             0          13s
tomcat-deployment-798c966d9d-s5blw   1/1     Running             0          13s
tomcat-deployment-798c966d9d-zrjdf   1/1     Running             0          13s
# 5.查看svc
[root@k8s-master ~]# kubectl get svc -n dev
NAME             TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)    AGE
nginx-service    ClusterIP   None         <none>        80/TCP     17s
tomcat-service   ClusterIP   None         <none>        8080/TCP   17s

3.在本机配置host

更改本机host,模拟两个域名
# 我的master IP 为192.168.8.201 模拟 nginx域名为 nginx.lz.com
[root@k8s-master ~]# echo "192.168.8.201 nginx.lz.com" >> /etc/hosts
# 我的master IP 为192.168.8.201 模拟 tomcat域名为 tomcat.lz.com
[root@k8s-master ~]# echo "192.168.8.201 tomcat.lz.com" >> /etc/hosts
# 查看已添加hosts
[root@k8s-master ~]# cat /etc/hosts
192.168.8.201 nginx.lz.com
192.168.8.201 tomcat.lz.com

4、Http代理

创建ingress-http.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-http
  namespace: dev
spec:
  # 这个很关键,如果写错会导致访问404
  ingressClassName: nginx
  rules:
    - host: nginx.lz.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx-service
                port:
                  number: 80
    - host: tomcat.lz.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: tomcat-service
                port:
                  number: 8080

ingressClassName 如果忘记自己设置的是什么,可以通过以下方式查询

命令:

kubectl describe deploy ingress-nginx-controller -n ingress-nginx

图片

实际操作

# 创建
[root@k8s-master ~]# kubectl apply -f ingress-http.yaml
ingress.networking.k8s.io/ingress-http created

# 查看ingress
[root@k8s-master ~]# kubectl get ing ingress-http -n dev
NAME           CLASS     HOSTS                        ADDRESS   PORTS   AGE
ingress-http   nginx   nginx.lz.com,tomcat.lz.com             80      64s

# 查看ingress详情
[root@k8s-master ~]# kubectl describe ing ingress-http  -n dev
Name:             ingress-http
Labels:           <none>
Namespace:        dev
Address:
Ingress Class:    ingress
Default backend:  <default>
Rules:
  Host           Path  Backends
  ----           ----  --------
  # 可以看出域名  nginx.lz.com 代理了后端 三个nginx pod   访问
  nginx.lz.com
                 /   nginx-service:80 (172.17.169.187:80,172.17.169.190:80,172.17.36.106:80)
  # 可以看出域名  tomcat.lz.com 代理了后端 三个tomcat pod
  tomcat.lz.com
                 /   tomcat-service:8080 (172.17.169.185:8080,172.17.169.188:8080,172.17.36.105:8080)
Annotations:     <none>
Events:          <none>

# 还记得上篇文章中我们 安装完ingree-nginx 后,查看 ingress-nginx-controller service的结果吗
# 在上面我们已经安装完ingress-http 如果想在外部访问则需此处PORTS,这个端口意思是,如果ing代理的是http即80端口,则外部访问需要使用30577(随机生成的,可以自定义)端口访问,如果ing代理的是https即443端口,则外部访问需要使用32667(也是随机生成,当然可以自定义)端口访问
[root@k8s-master ~]# kubectl get svc -n ingress-nginx
NAME                                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             NodePort    10.15.245.169   <none>        80:30577/TCP,443:32667/TCP   41h
ingress-nginx-controller-admission   ClusterIP   10.0.156.229    <none>        443/TCP

# 本次实例我们的tomcat和nginx都是80 端口,所以访问的时候都需要在域名 后面增加 :30577 才可正常访问

本机访问效果

图片

图片

5、Https代理

5.1、创建证书

实际生产我们需要申请https nginx证书,这里我们就模拟创建一个证书

# 创建证书
[root@k8s-master ~]# openssl req -x509 -sha256 -nodes -days 365 -newkey rsa:2048 -keyout tls.key -out tls.crt -subj "/C=CN/ST=BJ/L=BJ/O=nginx/CN=lz.com"
Generating a 2048 bit RSA private key
...........+++
..............................+++
writing new private key to 'tls.key'
-----

# 证书已创建
[root@k8s-master ~]# ls
tls.crt  tls.key

# 创建密钥 这个秘钥创建,如果不会先记着,后续有讲解
[root@k8s-master ~]# kubectl create secret tls tls-secret --key tls.key --cert tls.crt
secret/tls-secret created

# 查看已创建秘钥
[root@k8s-master ~]# kubectl get secret
NAME         TYPE                DATA   AGE
tls-secret   kubernetes.io/tls   2      6s

# 5.2、创建ingress-https.yaml
vim ingress-https.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: ingress-https
  namespace: dev
spec:
  tls:
    - hosts:
        - nginx.lz.com
        - tomcat.lz.com
      secretName: tls-secret # 指定秘钥
  # 这个很关键,如果写错会导致访问404
  ingressClassName: nginx
  rules:
    - host: nginx.lz.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: nginx-service
                port:
                  number: 80
    - host: tomcat.lz.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: tomcat-service
                port:
                  number: 8080

5.3、实例操作效果

# 创建
[root@k8s-master ~]# kubectl apply -f ingress-https.yaml
ingress.networking.k8s.io/ingress-https created
[root@k8s-master ~]#
# 查看ing
[root@k8s-master ~]# kubectl get ing ingress-https -n dev
NAME            CLASS           HOSTS                        ADDRESS   PORTS     AGE
ingress-https   ingress-nginx   nginx.lz.com,tomcat.lz.com             80, 443   7s
# 查看ing 详情
[root@k8s-master ~]# kubectl describe ing ingress-https -n dev
Name:             ingress-https
Labels:           <none>
Namespace:        dev
Address:
Ingress Class:    ingress-nginx
Default backend:  <default>
# TLS已关联
TLS:
  tls-secret terminates nginx.lz.com,tomcat.lz.com
Rules:
  # 规则也已经创建
  Host           Path  Backends
  ----           ----  --------
  nginx.lz.com
                 /   nginx-service:80 (172.17.169.187:80,172.17.169.190:80,172.17.36.106:80)
  tomcat.lz.com
                 /   tomcat-service:8080 (172.17.169.185:8080,172.17.169.188:8080,172.17.36.105:8080)
Annotations:     <none>
Events:          <none>

# 查看访问443 需要什么用什么端口  此处是32667
[root@k8s-master ~]# kubectl get svc -n ingress-nginx
NAME                                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             NodePort    10.15.245.169   <none>        80:30577/TCP,443:32667/TCP   41h
ingress-nginx-controller-admission   ClusterIP   10.0.156.229    <none>        443/TCP

# 在本地访问 https://tomcat.lz.com:32667  和 https://nginx.lz.com:32667  查看效果

图片

图片