k8s ingress学习和部署

理解ingress

ingress简单来讲,就是一个利用负载均衡的玩意,其主要用来解决使用NodePort暴露Service的端口时Node IP会漂移的问题。同时,若大量使用NodePort暴露主机端口,管理会非常混乱。
好的解决方案就是让外界通过域名去访问Service,而无需关心其Node IP及Port。那为什么不直接使用Nginx?这是因为在K8S集群中,如果每加入一个服务,我们都在Nginx中添加一个配置,其实是一个重复性的体力活,只要是重复性的体力活,我们都应该通过技术将它干掉

ingress的特性

Pod与Ingress的关系
通过label-selector相关联
通过Ingress Controller实现Pod的负载均衡
支持TCP/UDP 4层和HTTP 7层

Kubernetes提供了两种负载均衡机制,一种是工作与传输层的Service资源,实现“TCP负载均衡器”,另一种是Ingress资源,实现“HTTP(S)负载均衡器”

在Kubernetes中,服务和Pod的IP地址仅可以在集群网络内部使用,对于集群外的应用是不可见的。
为了使外部的应用能够访问集群内的服务,Kubernetes目前提供了以下几种方案:

NodePort: 先访问Service,Service可以直接通过集群内部负载均衡至pod中的应用,而外部访问集群中的Service可以通过在Service中定义NodePort实现;这种方式在集群中的每台主机上开放一个随机的指定的端口,且每个端口只能提供一个服务,它是通过端口不同来区分不同应用,而不是通过域名,缺点是管理不便,不适合在大规模集群中部署。

LoadBalancer:通过LoadBlancer Service访问Service,这个需要接入云服务,每个服务都会由云服务提供一个IP作为入口,转发相应的流量,但每个LoadBlancer Service都会产生费用,成本比较高。

Ingress:可以作为k8s集群的前端调度器,可以基于域名的方式将请求反向给集群中的service去处理。

Ingress 组成

ingress controller
将新加入的Ingress转化成Nginx的配置文件并使之生效
ingress服务
将Nginx的配置抽象成一个Ingress对象,每添加一个新的服务只需写一个新的Ingress的yaml文件即可

Ingress 工作原理

1.ingress controller通过和kubernetes api交互,动态的去感知集群中ingress规则变化,
2.然后读取它,按照自定义的规则,规则就是写明了哪个域名对应哪个service,生成一段nginx配置,
3.再写到nginx-ingress-control的pod里,这个Ingress controller的pod里运行着一个Nginx服务,控制器会把生成的nginx配置写入/etc/nginx.conf文件中,
4.然后reload一下使配置生效。以此达到域名分配置和动态更新的问题

Ingress 可以解决什么问题

1.动态配置服务
  如果按照传统方式, 当新增加一个服务时, 我们可能需要在流量入口加一个反向代理指向我们新的k8s服务. 而如果用了Ingress, 只需要配置好这个服务, 当服务启动时, 会自动注册到Ingress的中, 不需要而外的操作.
2.减少不必要的端口暴露
  配置过k8s的都清楚, 第一步是要关闭防火墙的, 主要原因是k8s的很多服务会以NodePort方式映射出去, 这样就相当于给宿主机打了很多孔, 既不安全也不优雅. 而Ingress可以避免这个问题, 除了Ingress自身服务可能需要映射出去, 其他服务都不要用NodePort方式

部署配置Ingress

下载nginx-ingress-controller配置文件
(如果下载的该版本不适用于你的k8s版本,可以下载其他的版本,要理解配置文件的各项参数配置才能更好的学习)

wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.21.0/deploy/mandatory.yaml

修改镜像路径

#替换镜像路径
#image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.21.0
          image: willdockerhub/nginx-ingress-controller:0.21.0
执行yaml文件部署 	
kubectl apply -f mandatory.yaml 

nodeport方式对外提供服务:
通过ingress-controller对外提供服务,现在还需要手动给ingress-controller建立一个servcie,接收集群外部流量。这里要理解为什么要用nodeport把ingress-controller代理到外部,因为我们需要把ingress-controller服务的默认端口映射到宿主机的端口上,外部才能访问到ingress,然后ingress通过域名转发到自己的各种服务上,如同nginx,你需要先把nginx的80端口映射到公网80上,外部通过公网80端口找到nginx的80端口,才能通过nginx定义的规则找到你的其他服务

service-nodeport配置文件:
wget   https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.30.0/deploy/static/provider/baremetal/service-nodeport.yaml
kubectl apply -f service-nodeport.yaml
查看ingress-nginx组件状态
kubectl get pod  svc -n ingress-nginx 
[centos@k8s-master ~]$ kubectl get pod -n ingress-nginx 
NAME                                        READY   STATUS    RESTARTS   AGE
nginx-ingress-controller-6bdcbbdfdc-wd2bn   1/1     Running   0          24s
[centos@k8s-master ~]$ kubectl get svc -n ingress-nginx 
NAME            TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx   NodePort   10.104.138.113   <none>        80:30737/TCP,443:31952/TCP   13s

可以看到,ingress中的80端口何443端口分别映射到了主机的30737和31952端口,提供给一会的服务使用

如此ingress组件就创建好了,我们可以开始学习使用它
Ingress资源的类型
(你可以看作是nginx配置文件中的转发规则,这样好理解)

1)单service资源型ingress

暴露单个服务的方法可以使用service的NodePort、LoadBalancer类型;也可使用Ingress,使用Ingress时,只需指定ingress的default backend即可。

# 定义一个单Service资源型的ingres

[root@master01 test03]# cat test05.yaml 
apiVersion: extensions/v1beat1
kind: Ingress
metadata:
  name: test-ingress02
spec:
  backend:
    serviceName: nginx-svc
    serviceName: 80

2)基于URL路径进行流量分发的ingress

基于URL路径转发是根据客户端请求不同的URL路径转发到不同的后端服务中
# 定义一个多路径的ingress资源

[root@master01 test03]# cat test06.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata: 
  name: test-ingress05
  annotations:
    kubernetes.io/ingress: “nginx test path”
spec:
  rules:
  - host: www.dayi123.com
    http:
      paths: 
      - path: /nginx
        backend:
          serviceName: nginx-svc
          servicePort: 80
      - path: /tomcat
        backend:
          serviceName: test-svc
          servicePort: 80

3)基于主机名称的ingress虚拟主机
基于主机名的ingress虚拟主机是将每个应用分别以独立的FQDN主机名进行输出。

# 定义一个基于主机名的service

[root@master01 test03]# cat test07.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata: 
  name: test-ingress06
spec:
  rules:
  - host: blog.dayi123.com
    http:
      paths:
      - backend:
          serviceName: nginx-svc
          servicePort: 80
  - host: doc.dayi123.com
    http:
      paths:
      - backend:
          serviceName: test-svc
          servicePort: 80

4)TLS类型的Ingress资源
TLS类型的Ingress资源用于以HTTPS发布Service资源,基于一个含有私钥和证书的Secret对象即可配置TLS协议的Ingress资源。Ingress资源目前仅支持单TLS端口,并且还会卸载TLS会话

做个实验实战讲解:
使用ingress发布Tomcat

在这里插入图片描述前提:已经部署好ingress服务,没有部署的照着上面的部署即可。
部署一个tomcat后端服务
(1)创建名称空间
# 定义名称空间的资源配置清单

[root@master01 ingress-tomcat]# cat ingress-tomcat.yaml
apiVersion: v1
kind: Namespace
metadata:
name: test-ingress
labels:
env: test-ingress

创建名称空间

[root@master01 ingress-tomcat]# kubectl apply -f ingress-tomcat.yaml
namespace/test-ingress created

(2)部署tomcat实例

定义基于deployment的tomcat资源配置清单

 [root@master01 ingress-tomcat]# cat tomcat-deployment.yaml 
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: tomcat-deployment
      namespace: test-ingress
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: ingress-tomcat
      template:
        metadata:
          labels:
            app: ingress-tomcat
        spec:
          containers:
          - name: tomcat
            image: tomcat
            ports:
            - name: httport
              containerPort: 8080
            - name: ajpport
              containerPort: 8009
    # 创建tomcat的pod控制器
    [root@master01 ingress-tomcat]# kubectl apply -f tomcat-deployment.yaml 
    deployment.apps/tomcat-deployment created
    # 查看创建的tomcat pod
    [root@master01 ingress-tomcat]# kubectl get pods -n test-ingress
    NAME                                 READY   STATUS    RESTARTS   AGE
    tomcat-deployment-67f5dcbdb4-7mmhz   1/1     Running   0          96s
    tomcat-deployment-67f5dcbdb4-km5q8   1/1     Running   0          96s

(3)创建Service资源

Ingress资源仅能通过Service资源识别相应的Pod资源,获取其IP地址和端口,然后Ingress控制器即可直接使用各Pod对象的IP地址与Pod内的服务直接进行通信,不经过Service的代理和调度,因此Service资源的ClusterIP对Ingress控制器来说存不存在无所谓。
# 定义service的资源配置清单文件

  [root@master01 ingress-tomcat]# cat tomcat-service.yaml 
    apiVersion: v1
    kind: Service
    metadata:
      name: tomcat-svc
      namespace: test-ingress
      labels:
        app: tomcat-svc
    spec:
      selector:
        app: ingress-tomcat
      ports:
      - name: http
        port: 80
        targetPort: 8080
        protocol: TCP
    # 创建并查看service
    [root@master01 ingress-tomcat]# kubectl apply -f tomcat-service.yaml 
    service/tomcat-svc created
    [root@master01 ingress-tomcat]# kubectl get svc -n test-ingress
    NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
    tomcat-svc   ClusterIP   10.106.153.248   <none>        80/TCP    15s

(4)创建Ingress资源

 # 定义ingress资源配置清单
    [root@master01 ingress-tomcat]# cat tomcat-ingress.yaml 
    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: tomcat
      namespace: test-ingress
      annotations:
        kubernetes.io/ingress: "nginx"
    spec:
      rules:
      - host: tomcat.dayi123.com
        http:
          paths:
          - path:
            backend:
              serviceName: tomcat-svc
              servicePort: 80
    # 创建并查看Ingress
    [root@master01 ingress-tomcat]# kubectl apply -f tomcat-ingress.yaml 
    ingress.extensions/tomcat created
    [root@master01 ingress-tomcat]# kubectl get ingress -n test-ingress
    NAME     HOSTS                ADDRESS   PORTS   AGE
    tomcat   tomcat.dayi123.com             80      14s

上面的配置完成后,在宿主机的/etc/hosts中添加tomcat.dayi123.com对应node节点的解析后,就可在本地通过http://tomcat.dayi123.com:30737去访问tomcat服务。这个node节点的30737端口就是在前面为nginx类型的ingress控制器创建的service中定义的

(5)配置TLS Ingress资源
互联网中的服务基本都是以https的方式提供服务的,如果希望ingress控制器接受客户端的请求时又希望它能够提供https服务,就应该配置tls类型的ingress资源

# 生成用于测试的私钥和自签证书

[root@master01 ingress-tomcat]# openssl genrsa -out tls.key 2048
[root@master01 ingress-tomcat]# openssl req -new -x509 -key tomcat.key -out tomcat.crt -subj /C=CN/ST=Shanghai/L=Shanghai/O/dev/CN=tomcat.dayi123.com -days 736

在ingress控制器上配置HTTPS主机时,是不能直接使用私钥和证书文件的,而是要使用Secret资源对象来传递相关的数据。

   # 创建一个TLS类型名为tomcat-ingress-secret的secret资源
    [root@master01 ingress-tomcat]# kubectl create secret tls tomcat-ingress-secret --cert=tomcat.crt --key=tomcat.key -n test-ingress
    secret/tomcat-ingress-secret created
    # 查看创建的secret资源
    [root@master01 ingress-tomcat]# kubectl get secrets tomcat-ingress-secret -n test-ingress
    NAME                    TYPE                DATA   AGE
    tomcat-ingress-secret   kubernetes.io/tls   2      109s

secret资源创建完成后,就可以将创建的secret应用到ingress资源的配置清单中。

   # 定义TLS类型的Ingress资源的配置清单
    [root@master01 ingress-tomcat]# cat tomcat-ingress-tls.yaml 
    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      name: tomcat-ingress-tls
      namespace: test-ingress
      annotations:
        kubernetes.io/ingress: "nginx"
    spec:
      tls:
      - hosts:
        - tomcat.dayi123.com
        secretName: tomcat-ingress-secret
      rules:
      - host: tomcat.dayi123.com
        http:
          paths:
          - path:
            backend:
              serviceName: tomcat-svc
              servicePort: 80
    # 创建并查看tls类型的ingress资源
    [root@master01 ingress-tomcat]# kubectl apply -f tomcat-ingress-tls.yaml 
    ingress.extensions/tomcat-ingress-tls created
    [root@master01 ingress-tomcat]# kubectl get ingress tomcat-ingress-tls -n test-ingress
    NAME                 HOSTS                ADDRESS   PORTS     AGE
    tomcat-ingress-tls   tomcat.dayi123.com             80, 443   3m35s

(6)测试
在前面为基于nginx的ingress控制器创建的service中已将443端口映射到了node节点的31952端口,在本地对域名tomcat.dayi123.com做了解析就可以通过https://tomcat.dayi123.com:31952进行测试。

   # 查看ingress控制器中映射到本地的端口
    [root@master01 ingress-tomcat]# kubectl get svc -n ingress-nginx
    NAME                       TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
    nginx-ingress-controller   NodePort   10.105.134.97   <none>        80:30737/TCP,443:31952/TCP   167m
    # 在linux客户端进行测试(测试前要做hosts解析)
    [root@master01 ingress-tomcat]# curl -k -v https://tomcat.dayi123.com:31952

ingress controller在物理机上的两种部署方式

还记得上面的实验中我们是如何把内网server通过ingress映射到主机外网的吗,我们是通过nodeport,其实实现的方法还有其他几种,我们学习一下

Deployment + LoadBalancer
如果要把 ingress 部署在公有云,那用这种方式比较合适。用 Deployment 部署 ingress-controller,创建一个 type 为 LoadBalancer 的 service 关联这组 pod。大部分公有云,都会为 LoadBalancer 的 service 自动创建一个负载均衡器,通常还绑定了公网地址。只要把域名解析指向该地址,就实现了集群服务的对外暴露。

Deployment + NodePort (刚才实验所用的方法)
同样用 deployment 模式部署 ingress-controller,并创建对应的服务,但是 type 为 NodePort。这样,ingress 就会暴露在集群节点 ip 的特定端口上。由于 nodeport 暴露的端口是随机端口,一般会在前面再搭建一套负载均衡器来转发请求。该方式一般用于宿主机是相对固定的环境 ip 地址不变的场景。NodePort 方式暴露 ingress 虽然简单方便,但是 NodePort 多了一层 NAT,在请求量级很大时可能对性能会有一定影响。

DaemonSet + HostNetwork + nodeSelector(原理就是直接使用宿主机的80端口和443端口,不再进行端口映射)
用 DaemonSet 结合 nodeselector 来部署 ingress-controller 到特定的 node 上,然后使用 HostNetwork 直接把该 pod 与宿主机 node 的网络打通,直接使用宿主机的 80/433 端口就能访问服务。这时,ingress-controller 所在的 node 机器就很类似传统架构的边缘节点,比如机房入口的 nginx 服务器。该方式整个请求链路最简单,性能相对 NodePort 模式更好。缺点是由于直接利用宿主机节点的网络和端口,一个 node 只能部署一个 ingress-controller pod。比较适合大并发的生产环境使用。

两种部署方式的比较
相比较起来,nodePort部署模式中需要部署的ingress-controller容器较少。一个集群可以部署几个就可以了。而hostNetwork模式需要在每个节点部署一个ingress-controller容器,因此总起来消耗资源较多。另外一个比较直观的区别,nodePort模式主要占用的是svc的nodePort端口。而hostNetwork则需要占用物理机的80和443端口。
从网络流转来说,通过nodePort访问时,该node节点不一定部署了ingress-controller容器。因此还需要iptables将其转发到部署有ingress-controller的节点上去,多了一层流转。
另外,通过nodePort访问时,nginx接收到的http请求中的source ip将会被转换为接受该请求的node节点的ip,而非真正的client端ip。
而使用hostNetwork的方式,ingress-controller将会使用的是物理机的DNS域名解析(即物理机的/etc/resolv.conf)。而无法使用内部的比如coredns的域名解析。
因此具体使用哪种部署方式,需要根据实际情况和需求进行选择

现在我们来部署hostNetwork的ingress
为需要部署为边缘节点的 node 打上 labe:

$ kubectl  label   node k8sn91 isIngress="true"

在官方 yaml 配置文件中,相关资源的创建已经包含在内,但是我们需要使用 DaemonSet 的方式部署,就需要修改一小部分内容。下载官方 yaml:

$ wget https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml

修改 Deployment 部分的配置:

……
apiVersion: apps/v1
#kind: Deployment
#修改成 把Deployment改成DaemonSet,DaemonSet 的不同之处在于:每个 Node 上最多只能运行一个副本
kind: DaemonSet
metadata:
  name: nginx-ingress-controller
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
spec:
#注释掉 replicas
#replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: ingress-nginx
      app.kubernetes.io/part-of: ingress-nginx
  template:
    metadata:
      labels:
        app.kubernetes.io/name: ingress-nginx
        app.kubernetes.io/part-of: ingress-nginx
      annotations:
        prometheus.io/port: "10254"
        prometheus.io/scrape: "true"
    spec:
      # wait up to five minutes for the drain of connections
      terminationGracePeriodSeconds: 300
      serviceAccountName: nginx-ingress-serviceaccount
      # 选择打上 isIngress 标签的 node
      nodeSelector:
        isIngress: "true"
      # 暴露服务
      hostNetwork: true
      containers:
        - name: nginx-ingress-controller
          image: quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.26.1
……

部署 nginx-ingress-controller:
$ kubectl apply -f mandatory.yaml
查看:
$ kubectl get ds -n ingress-nginx  查看deamonset
NAME                       DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR    AGE
nginx-ingress-controller   1         1         1       1            1           isIngress=true   10m
$ kubectl get pods -n ingress-nginx
NAME                             READY   STATUS    RESTARTS   AGE
nginx-ingress-controller-prqv5   1/1     Running   0          10m

部署测试 web 服务
为了展示 ingress 路由转发功能,创建两个 web 服务,然后通过 ingress 编写规则来转发相关请求。

apple.yaml
kind: Pod
apiVersion: v1
metadata:
  name: apple-app
  labels:
    app: apple
spec:
  containers:
    - name: apple-app
      image: hashicorp/http-echo
      args:
        - "-text=apple"

---

kind: Service
apiVersion: v1
metadata:
  name: apple-service
spec:
  selector:
    app: apple
  ports:
    - port: 5678 # Default port for image
banana.yaml
kind: Pod
apiVersion: v1
metadata:
  name: banana-app
  labels:
    app: banana
spec:
  containers:
    - name: banana-app
      image: hashicorp/http-echo
      args:
        - "-text=banana"

---

kind: Service
apiVersion: v1
metadata:
  name: banana-service
spec:
  selector:
    app: banana
  ports:
    - port: 5678 # Default port for image
部署 pod
$ kubectl apply -f apple.yaml
$ kubectl apply -f banana.yaml
查看 service、pod:
$ kubectl get svc,po | grep -E "apple|banana"
service/apple-service          ClusterIP   10.106.133.148   <none>        5678/TCP   10m
service/banana-service         ClusterIP   10.108.239.61    <none>        5678/TCP   10m
pod/apple-app                           1/1     Running             0          10m
pod/banana-app                          1/1     Running             0          10m
$ curl 10.106.133.148:5678
apple
$ curl 10.108.239.61:5678
banana

3、部署 Ingress
编写 yaml 文件,指定路由规则

$ vim ingress-nginx.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
  name: nginx-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: nginx.tempdomain.com
    http:
      paths:
      - path: /apple
        backend:
          serviceName: apple-service
          servicePort: 5678
      - path: /banana
        backend:
          serviceName: banana-service
          servicePort: 5678

部署 ingress:
$ kubectl apply -f ingress-nginx.yaml
查看 ingress:
$ kubectl get ingress
NAME            HOSTS               ADDRESS   PORTS   AGE
nginx-ingress   nginx.tempdomain.com             80      10m
$ kubectl describe ingress nginx-ingress
Name:             nginx-ingress
Namespace:        default
Address:
Default backend:  default-http-backend:80 (<none>)
Rules:
  Host               Path  Backends
  ----               ----  --------
  nginx.tempdomain.com
                     /apple    apple-service:5678 (100.93.23.211:5678)
                     /banana   banana-service:5678 (100.107.55.15:5678)
4、在宿主机上检查可用性
$ curl nginx.tempdomain.com/apple
apple
$ curl nginx.tempdomain.com/banana
banana

这样ingress的基础功能就算实现了,其他的今后慢慢深入学习

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值