server 有一个问题就是无论哪种类型都只能实现 4 层转发和代理,如果要建立一个 http 的服务,那么每一个 app 都要建立成一个 http 主机,因为 4 层调度本身是无法卸载 http 会话的,事实上 k8s 集群还有一种引入集群外部流量的方式:ingress,ingress 资源是一种七层调度器,但他也脱离不了 server资源 和 web 服务
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-joOEKfYz-1624628357507)(https://raw.githubusercontent.com/ma823956028/image/master/picgo/20200829002221.png)]
图中 ingress-nginx service 可以被 DaemonSet 配合 ingress 共享网络名称空间的方式代替
Ingress
负责k8s中的7层负载均衡。其在物理机中有多种部署方式,而主要则有nodePort和hostNetwork两种部署方式。
-
nodePort:
kubernetes 在内部集群中进行调度时,后端被代理的 pod 资源不会配置 https 的他们就是明文的 http,k8s 使用一个特殊的 pod (ingress) 对于这个 pod 来说她是运行在用户空间的正常的运行程序,如 nginx、haproxy 等,当用户试图访问某个后端服务时,不会直接访问该服务的 svc,而是先到 ingress,而 pod 与 pod 之间是在同一个网段的,这样就可以让 ingress 直接与后端 pod 通信并完成反代,而 ingress 需要接入外部流量则需要 svc,NodePort 的 svc。为了让 svc 拥有负载功能,即外部访问任意一个 Node 都能访问到这个 svc,则又需要在 node 之上再增加一个 LoadBalancer,这样架构会导致 4 次反代性能会大打折扣
-
hostnetwork:
于是新的解决方案是让 ingress 共享节点的网络名称空间,相当于监听了宿主机的地址,所以边界流量直接经由 loadbalancer 或负载均衡器被打到了 ingress,并有它继续反代给真正的 pod,其中 loadbalancer 做四层代理给 ingress,ingress 做七层卸载给对应的 pod,但这样就会失去 ingress 的 svc,这样则只能在一个节点运行 ingress 也就造成了单点故障,所以这个 ingress 需要 DaemonSet 来控制 ingress,这样就恢复了高可用和负载能力,而大规模部署 k8s 集群时,我们会按比例挑出部分 node,并给 node 增加污点,让其他 pod 不可以运行在这些 node 上,但让 ingress 容忍这些污点加上 DaemonSet 来管理并让前端的 loadbalancer 调度
Ingress Controller
它与控制器不同,控制器作为 controllermanager 的子组件存在,而 Ingress 则单独特指一组 pod,而 ingress 的实现方式通常有三种
- Haproxy:并不被推荐
- nginx:主流
- Envoy:服务网格中多用此类服务
- Traefik:为微服务而生,与 nginx 竞争
Ingress 资源
我们知道 ingress 本身就是一个 web 服务了,但比如当我们使用 url 映射功能,让一个 url 通过 upstream server 配置映射到后端服务,在传统架构中非常容易实现,但容器内 pod 是有生命周期的,为了解决这个问题则需要引入 svc,通过这个 svc 关联至后端的 pod,但这个 svc 仅仅帮忙分类,不做转发节点使用,这个 svc 关联了多少 pod 就会写入 upstream 配置(此时写入配置的 ip 是 podip),所以这个 svc 可以是 headless 类型,这个 svc 是通过 ingress 资源写入 upstream 的,ingress 资源可以通过边界注入到 ingress controller 中并保存配置文件还可以通过 headless svc 动态的发现 pod 改变并写入配置文件和重载 nginx,此时就凸显出 nginx 作为传统建构中 web 服务的不足之处,Envoy 和 Traefik 都可以发现配置文件写入并自动重载自身服务实现动态机制,更加配合 ingress controller 的这种机制
部署 Ingress nginx
-
拖拽 github 仓库上的代码,并构建 ingress-nginx Controller
[root@master-0 ~]# yum install git [root@master-0 ~]# git clone https://github.com/kubernetes/ingress-nginx.git [root@master-0 ~]# cd /root/ingress-nginx/deploy/static/provider/cloud [root@master-0 cloud]# kubectl apply -f deploy.yaml
-
构建后端 pod 与 service
[root@master-0 ingress]# cat deploy-demo.yaml apiVersion: v1 kind: Service metadata: name: myapp namespace: default spec: selector: app: myapp release: canary type: ClusterIP clusterIP: 10.208.208.208 ports: - name: http targetPort: 80 port: 80 --- apiVersion: apps/v1 kind: Deployment metadata: name: myapp-deploy namespace: default spec: replicas: 3 selector: matchLabels: app: myapp release: canary template: metadata: labels: app: myapp release: canary spec: containers: - name: myapp image: nginx:1.7 ports: - name: http containerPort: 80 [root@master-0 ingress]# kubectl apply -f deploy-demo.yaml service/myapp created deployment.apps/myapp-deploy unchanged
-
此时,为了让 ingress controller 接入集群外部流量,我们可以修改 with-rbac.yaml 文件来实现共享 node 的网络名称空间,当然还可以给 ingress controller 增加一个 nodeport 的 service 的方式来实现,这里使用第二种方法
[root@master-0 ingress]# cat service-nodeport.yaml apiVersion: v1 kind: Service metadata: name: ingress-nginx namespace: ingress-nginx spec: type: NodePort ports: - name: http port: 80 targetPort: 80 protocol: TCP nodePort: 30080 - name: https port: 443 targetPort: 443 protocol: TCP nodePort: 30443 selector: app: ingress-nginx [root@master-0 ingress]# kubectl apply -f . service/myapp unchanged deployment.apps/myapp-deploy unchanged service/ingress-nginx created [root@master-0 ingress]# kubectl get svc -n ingress-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ingress-nginx NodePort 10.220.176.76 <none> 80:30080/TCP,443:30443/TCP 31s ... ...
-
使用 ingress 资源增加 nginx 规则
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-myapp namespace: default # 与发布的后端 pod 处在同一个名称空间 annotations: kubernetes.io/ingress.class: "nginx" # 标识使用 nginx spec: rules: - host: myapp.magedu.com # 虚拟机主机型,这个域名必须能被公网访问 http: paths: # 请求路径以及映射到后端的集合,可以有多个 - path: # 空即根值 backend: serviceName: myapp # 后端 pod 的信息 servicePort: 80
HTTPS 的证书处理
-
生成证书
[root@master-0 ingress]# openssl genrsa -out tls.key 2048 [root@master-0 ingress]# openssl req -new -x509 -key tls.key -out tls.crt -subj /C=CN/ST=Beijing/L=Beijing/O=DevOps/CN=magedu.com [root@master-0 ingress]# ls deploy-demo.yaml ingress-myapp.yaml service-nodeport.yaml tls.crt tls.key
-
将证书创建为 secret 资源
[root@master-0 ingress]# kubectl create secret tls ingress-secret --cert=tls.crt --key=tls.key secret/ingress-secret created [root@master-0 ingress]# kubectl describe secrets ingress-secret #base64编码 Name: ingress-secret Namespace: default Labels: <none> Annotations: <none> Type: kubernetes.io/tls Data ==== tls.key: 1675 bytes tls.crt: 1277 bytes
-
创建 https 的 yaml 文件
apiVersion: extensions/v1beta1 kind: Ingress metadata: name: ingress-myapp-tls namespace: default annotations: kubernetes.io/ingress.class: "nginx" spec: tls: #证书配置集合 - hosts: - myapp.magedu.com #列表形式 secretName: ingress-secret rules: - host: myapp.magedu.com http: paths: - path: backend: serviceName: myapp servicePort: 80