kubernetes-Ingress

目录

    • Ingress
      • Ingress是什么
          • 安装Ingress
          • 案例1、简单的来实现一个Ingress
          • 案例2、基于URL路由多个服务
          • 案例3、基于名称的虚拟主机
      • Ingress:HTTPS
          • 生成ssl证书
    • Ingress Controller
          • Ingress Controller高可用
    • Ingress:个性化配置
    • Ingress优化

Ingress

NodePort存在的不足

  • 一个端口只能一个服务使用,端口需提前规划
  • 只支持4层负载均衡
    所以衍生出来了Ingress

Ingress是什么

  • Ingress:K8S中的一个抽象资源,给管理员提供一个暴露应用的入口定义方法
  • Ingress Controller:根据Ingress生成具体的路由规则,并对Pod负载均衡

Ingress Controller有很多实现方法,我们这里采用官方维护的基于nginx实现的控制器

项目地址:http://github.com/kubernetes/ingress-nginx
文档:https://kubernetes.github.io/ingress-nginx/deploy
其他控制器:https://kubenetes.io/docs/concepts/services-networking/ingress-controllers

kubernetes-Ingress_第1张图片

安装Ingress

我用的是0.49这个版本安装的,以下是对应支持版本
我这里用的是0.49的
kubernetes-Ingress_第2张图片

[root@k8s-master ~]# ls
anaconda-ks.cfg  calico.yaml.bak  ingress-controller-0.49.yaml  pod.yaml
calico.yaml      deployment.yaml  pod-nodeaffinity.yaml         services.yaml
# 直接构建即可,这个文件中所需的镜像在国外,所以修改了下镜像的获取地址,其他的没变
[root@k8s-master ~]# kubectl apply -f ingress-controller-0.49.yaml
# 运行后他有两个是job
[root@k8s-master ~]# kubectl get job -A
NAMESPACE       NAME                             COMPLETIONS   DURATION   AGE
ingress-nginx   ingress-nginx-admission-create   1/1           48s        32m
ingress-nginx   ingress-nginx-admission-patch    1/1           73s        32m
# controller运行即可,其他两个是job
[root@k8s-master ~]# kubectl get pods -n ingress-nginx
NAME                                        READY   STATUS      RESTARTS   AGE
ingress-nginx-admission-create-vq9hb        0/1     Completed   0          32m
ingress-nginx-admission-patch-b52mc         0/1     Completed   0          32m
ingress-nginx-controller-78b4958f8f-5plrv   1/1     Running     0          32m
案例1、简单的来实现一个Ingress

将web服务由Ingress代理出去,使用之前创建的3个nginx的pod测试即可

[root@k8s-master ~]# kubectl get pods 
NAME                   READY   STATUS    RESTARTS   AGE
web-586db47859-5vqr4   1/1     Running   0          21h
web-586db47859-ljvm4   1/1     Running   0          21h
web-586db47859-tkp2k   1/1     Running   0          21h
# 创建一个Ingress
[root@k8s-master ingress]# vim ingress.yaml 
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  # 设置名称
  name: web1
spec:
  rules:
  # 设置域名
  - host: web1.aaa.cn
    http:
      paths:
      - pathType: Prefix
        # 设置的访问路径为/,也就是说在访问"web1.aaa.cn"域名时直接访问的是对应Service的/路径
        path: "/"
        backend:
          # 与service关联,这里与service的name为web的相关联
          service:
            name: web
            port:
              number: 80
            
# 创建好之后查看svc,可以看到80这个端口被映射为31636了,等等访问域名的时候就加入这个端口
[root@k8s-master ingress]# kubectl get svc -n ingress-nginx
NAME                                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             NodePort    10.106.183.203   <none>        80:31636/TCP,443:32389/TCP   63m
ingress-nginx-controller-admission   ClusterIP   10.100.222.247   <none>        443/TCP                      63m
# 查看ingress
[root@k8s-master ingress]# kubectl get ingress
NAME   CLASS    HOSTS         ADDRESS           PORTS   AGE
web1   <none>   web1.aaa.cn   192.168.113.146   80      13m

在自己本地的hossts文件下加入主机映射,就可以访问了
kubernetes-Ingress_第3张图片
kubernetes-Ingress_第4张图片

案例2、基于URL路由多个服务

kubernetes-Ingress_第5张图片
创建测试环境

# 在创建一个用来测试的Pod
[root@k8s-master ingress]# kubectl create deployment java-demo --image=lizhenliang/java-demo
deployment.apps/java-demo created
# 创建Pod对应的service
[root@k8s-master ingress]# kubectl expose deployment java-demo --port=8088 --target-port=8080 --type=NodePort
service/java-demo exposed
# PORT中前面的8088是service的IP,后面的30939是容器中8080对外暴露的IP
[root@k8s-master ingress]# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
java-demo    NodePort    10.104.210.67   <none>        8088:30939/TCP   3s

创建ingress

# 编写yaml
[root@k8s-master ingress]# vim ingress2.yaml 
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web2
spec:
  rules:
  - host: web2.aaa.cn
    http:
      paths:
      - path: /foo
        pathType: Prefix
        backend:
          service:
            name: web
            port:
              number: 80
      - path: /bar
        pathType: Prefix
        backend:
          service:
            name: java-demo
            port:
              number: 8088
# 这样就创建了一个名称为web2的ingress
[root@k8s-master ingress]# kubectl get ingress
NAME   CLASS    HOSTS         ADDRESS           PORTS   AGE
web1   <none>   web1.aaa.cn   192.168.113.146   80      164m
web2   <none>   web2.aaa.cn   192.168.113.146   80      64s  

# 查看该ingress的信息
[root@k8s-master ingress]# kubectl describe ingress web2
# 其中有这样一条信息,可以看到代理的PodIP
Rules:
  Host         Path  Backends
  ----         ----  --------
  web2.aaa.cn  
               /foo   web:80 (10.244.36.75:80,10.244.36.76:80,10.244.36.77:80)
               /bar   java-demo:80 (10.244.169.140:8080)
         

在本地hosts加入主机映射后访问下试试,当然nginx的需要提前创建一个foo目录并且写入index.html文件,原理就和nginx一样
看到是可以访问的
kubernetes-Ingress_第6张图片
Java-demo这个因为是tomcat,所以添加上页面后使用绝对路径访问
在这里插入图片描述
kubernetes-Ingress_第7张图片

案例3、基于名称的虚拟主机

kubernetes-Ingress_第8张图片

# 有之前创建的web和Java-demo两个Pod,那么直接通过不通的路径去访问
[root@k8s-master ingress]# vim ingress3.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web3
spec:
  rules:
  - host: web3-1.aaa.cn
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: java-demo
            port:
              number: 8088
  - host: web3-2.aaa.cn
    http:
      paths:
      - pathType: Prefix
        path: "/"
        backend:
          service:
            name: web
            port:
              number: 80

设置主机映射之后访问即可kubernetes-Ingress_第9张图片

Ingress:HTTPS

配置HTTPS步骤:
1、准备域名证书文件(来自:openssl/cfssl工具自签或者权威机构颁发)
2、将证书文件保存到Secret
kubectl create secret tls blog-aliangedu-cn --cert=blog.aliangedu.cn.pem --key=blog.aliangedu.cn-key.pem
3、Ingress规则配置tls

# 示例
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: blog-https
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: https://www.baidu.com
spec:
  tls:
  - hosts:
      - blog.aliangedu.cn
    secretName: blog-aliangedu-cn
  rules:
  - host: blog.aliangedu.cn
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx
            port:
              number: 80
生成ssl证书

cfssl方式生成证书

# 先使用cfssl.sh获取cfssl命令
[root@k8s-master ssl]# cat cfssl/cfssl.sh 
# 脚本内容如下
wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
chmod +x cfssl*
mv cfssl_linux-amd64 /usr/bin/cfssl
mv cfssljson_linux-amd64 /usr/bin/cfssljson
mv cfssl-certinfo_linux-amd64 /usr/bin/cfssl-certinfo
# 使用certs.sh生成证书,其中那个"blog.zzz.com"可以修改,为该域名签发一个证书
[root@k8s-master ssl]# cat certs/certs.sh
cat > ca-config.json <<EOF
{
  "signing": {
    "default": {
      "expiry": "87600h"
    },
    "profiles": {
      "kubernetes": {
         "expiry": "87600h",
         "usages": [
            "signing",
            "key encipherment",
            "server auth",
            "client auth"
        ]
      }
    }
  }
}
EOF

cat > ca-csr.json <<EOF
{
    "CN": "kubernetes",
    "key": {
        "algo": "rsa",
        "size": 2048
    },
    "names": [
        {
            "C": "CN",
            "L": "Beijing",
            "ST": "Beijing"
        }
    ]
}
EOF

cfssl gencert -initca ca-csr.json | cfssljson -bare ca -

cat > blog.zzz.com-csr.json <<EOF
{
  "CN": "blog.zzz.com",
  "hosts": [],
  "key": {
    "algo": "rsa",
    "size": 2048
  },
  "names": [
    {
      "C": "CN",
      "L": "BeiJing",
      "ST": "BeiJing"
    }
  ]
}
EOF

cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes blog.zzz.com-csr.json | cfssljson -bare blog.zzz.com

生成证书

# 执行该命令获取命令
[root@k8s-master ssl]# bash cfssl.sh
# 执行该命令生成证书
[root@k8s-master ssl]# bash certs.sh
[root@k8s-master ssl]# ls
blog.zzz.com.csr       blog.zzz.com-key.pem  ca-config.json  ca-csr.json  ca.pem    cfssl.sh
blog.zzz.com-csr.json  blog.zzz.com.pem      ca.csr          ca-key.pem   certs.sh
# 主要使用以上的"blog.zzz.com-key.pem"和"blog.zzz.com.pem"来去配置域名的

使用证书

# 将生成的证书保存到k8s中
# 保存到k8s中并且名称为blog-zzz-com的证书
[root@k8s-master ssl]# kubectl create secret tls blog-zzz-com --cert=blog.zzz.com.pem --key=blog.zzz.com-key.pem
secret/blog-zzz-com created
# 查看保存到k8s中的证书
[root@k8s-master ssl]# kubectl get secret
NAME                  TYPE                                  DATA   AGE
blog-zzz-com          kubernetes.io/tls                     2      49s
default-token-rmp55   kubernetes.io/service-account-token   3      9d
# 配置Ingress文件
[root@k8s-master ingress]# vim ingress-blog.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: blog
spec:
  tls:
  - hosts:
      # 使用的域名,就是在生成证书时配置的域名,需要与下方rules中的host保持一致
      - blog.zzz.com
    # 创建时设置的secret名称
    secretName: blog-zzz-com
  rules:
  # 需要与上面的的tls中的host保持一致
  - host: blog.zzz.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: java-demo
            port:
              number: 8088
# 查看ingress           
[root@k8s-master ingress]# kubectl get ingress
NAME   CLASS    HOSTS                         ADDRESS           PORTS     AGE
blog   <none>   blog.zzz.com                                    80, 443   18s
# 查看svc
[root@k8s-master ingress]# kubectl get svc -n ingress-nginx
NAME                                 TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             NodePort    10.106.183.203   <none>        80:31636/TCP,443:32389/TCP   20h
ingress-nginx-controller-admission   ClusterIP   10.100.222.247   <none>        443/TCP                      20h

根据以上信息可以知道域名为blog.zzz.com,https的端口为32389,所以访问即可
kubernetes-Ingress_第10张图片
点击"不安全"打开证书,可以看到证书信息
kubernetes-Ingress_第11张图片

这个证书是自己签发的,所以显示"不安全",如果有买下的证书,按照以上流程签发即可

Ingress Controller

Ingress Contronler怎么工作的
  Ingress Contronler通过与Kubernetes API交互,动态的去感知集群中Ingress规则变化,然后读取它,按照自定义的规则,规则就是写明了那个域名对应那个service,生成一段Nginx配置,应用到管理的Nginx服务,然后热加载生成
以此来达到Nginx负载均衡器配置及动态更新的问题

流程包流程:客户端 -> Ingress Controller(Nginx) -> 分布在各节点Pod

Ingress Controller高可用

一般Ingress Controller会以DaemonSet+nodeSelector部署到几台特定的Node,然后将这几台挂载到公网负载均衡器对外提供服务

Ingress:个性化配置

Ingress-Controller这个Pod其实里面运行着的是一个ingress的控制器和nginx,如下

[root@k8s-master ingress]# kubectl exec -it ingress-nginx-controller-78b4958f8f-5plrv -n ingress-nginx -- bash
bash-5.1$ ps -ef 
PID   USER     TIME  COMMAND
    1 www-data  0:00 /usr/bin/dumb-init -- /nginx-ingress-controller --election-id=ingress-controller-leade
    7 www-data  0:22 /nginx-ingress-controller --election-id=ingress-controller-leader --ingress-class=ngin
   26 www-data  0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /etc/nginx/nginx.conf

我们可以在创建Ingress时,加入一些对nginx的配置,如下
配置的这些规则是直接在nginx的配置文件中的server块生效的,配置完成后可以在nginx中查看
更多使用方法

# 以下是一段示例
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web1
  annotations:
     # 使用的控制器的标识,如果时多个控制器的话可以指定使用不同的控制器
     kubernetes.io/ingress.class: "nginx"
     # 增加链接超时
     nginx.ingress.kubernetes.io/proxy-connect-timeout: "600"
     nginx.ingress.kubernetes.io/proxy-send-timeout: "600"
     nginx.ingress.kubernetes.io/proxy-read-timeout: "600"
     # 设置客户端上传文件大小
     nginx.ingress.kubernetes.io/proxy-body-size: "100m"
     # 重定向
     nginx.ingress.kubernetes.io/rewrite-target: https://www.baidu.com
     # 自定义规则
     nginx.ingress.kubernetes.io/server-snippet: |
       if ($http_user_agent ~* '(Android|iPhone)') {
          rewrite ^/(.*) http://m.baidu.com break;
       }
   
spec:
  rules:
  - host: web1.aliangedu.cn
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx
            port:
              number: 80

Ingress优化

在上诉内容中,我们可以知道Ingress是通过NodePort对外暴露的(在查看命名空间为ingress-nginx的svc时可以看到type类型为NodePort)
这样子会在用户访问时中间的转发在多一层,我们可以使用hostnetwork的方式,将Ingress-Controller使用的网络与宿主机公用,并且通过DaemonSet的方式进行高可用

让Ingress共享宿主机网络

# 修改Ingress-controller的yaml配置文件
# 先拷贝一个yaml文件
root@k8s-master ingress]# cp ingress-controller-0.49.yaml ingress-controller-0.49-1.yaml
# 卸载之前的ingress
[root@k8s-master ingress]# kubectl delete -f ingress-controller-0.49.yaml
# 修改cp后的yaml文件,如下,加入"hostNetwork: True"
[root@k8s-master ingress]# vim ingress-controller-0.49-1.yaml
    spec:
      dnsPolicy: ClusterFirst
      # pod使用宿主机网络
      hostNetwork: True
      containers:
        - name: controller
          image: lizhenliang/ingress-nginx-controller:v0.49.0

[root@k8s-master ingress]# kubectl apply -f ingress-controller-0.49-1.yaml

# 查看ingress在那个节点
[root@k8s-master ingress]# kubectl get pods -n ingress-nginx -o wide
NAME                                        READY   STATUS      RESTARTS   AGE   IP                NODE        NOMINATED NODE   READINESS GATES
ingress-nginx-admission-create-xp5mk        0/1     Completed   0          36m   10.244.36.79      k8s-node1   <none>           <none>
ingress-nginx-admission-patch-lvjf4         0/1     Completed   1          36m   10.244.36.80      k8s-node1   <none>           <none>
ingress-nginx-controller-6dbdc4dcbb-smtgq   1/1     Running     0          36m   192.168.113.149   k8s-node1   <none>           <none>


# 查看该节点的监听端口,可以看到该节点监听80和443端口了
[root@k8s-node1 ~]# netstat -antp |grep 80
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      36992/nginx: master 
tcp        0      0 0.0.0.0:30805           0.0.0.0:*               LISTEN      63547/kube-proxy    
tcp6       0      0 :::80                   :::*                    LISTEN      36992/nginx: master 
[root@k8s-node1 ~]# netstat -antp |grep 443
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      36992/nginx: master 

上诉可知,Ingress已经共享宿主机网络,那么访问的话也直接访问即可,不需要在通过NodePort映射的端口进行访问了

kubernetes-Ingress_第12张图片
先访问http的nginx
kubernetes-Ingress_第13张图片
访问blog的https
kubernetes-Ingress_第14张图片

当然,如果我们去把host映射改为其他的IP是访问不到的,因为他只是在149这个节点上运行的,其他节点没有Ingress-controller也不进行监听,如果想要实现多个节点都可以访问,可以将deployment改为DaemonSet方式部署

# 删除Ingress
[root@k8s-master ingress]# kubectl delete -f ingress-controller-0.49-1.yaml
# 修改Ingress-controller的yaml文件,将控制器Deployment改为DaemonSet
apiVersion: apps/v1
kind: Deployment
metadata:
  ...
#  查看Pod情况,之所以没有在master节点部署是因为master1有污点,可以去掉污点或者是在yaml中加入污点容忍即可
[root@k8s-master ingress]# kubectl get pods -n ingress-nginx -o wide
NAME                                   READY   STATUS      RESTARTS   AGE    IP                NODE        NOMINATED NODE   READINESS GATES
ingress-nginx-admission-create-xhb68   0/1     Completed   0          115s   10.244.36.81      k8s-node1   <none>           <none>
ingress-nginx-admission-patch-nf9mv    0/1     Completed   0          115s   10.244.36.82      k8s-node1   <none>           <none>
ingress-nginx-controller-rk9b7         1/1     Running     0          52s    192.168.113.146   k8s-node2   <none>           <none>
ingress-nginx-controller-smc8h         1/1     Running     0          52s    192.168.113.149   k8s-node1   <none>           <none>

这里在说下用户访问的流程吧,两种方式
1、通过NodePort暴露Ingress controller pod:
  浏览器 -> 负载均衡器 -> 域名:端口 -> service NodePort(HTTP:对应端口,HTTPS:对应端口) -> Ingress-nginx-controller(80,443 /他会基于域名去分流,正如之前的配置) -> 分布在各个节点的Pod
2、通过Hostnetwork让Ingress controller Pod共享宿主机网络
浏览器 -> 负载均衡器 -> 域名:端口 -> Ingress-nginx-controller(80,443 /基于域名分流) -> 分布在各个节点上的Pod

你可能感兴趣的:(kubernetes,kubernetes)