第七篇:k8s loadbalancer与ingress实践

k8s可以通过三种方式将集群内服务暴露到外网,分别是NodePort、LoadBalancer、Ingress,其中NodePort作为基础通信形式我们在《k8s网络模型与集群通信》中进行了介绍,这里我们主要关注LoadBalancer和Ingress

LoadBalancer

loadbalancer是服务暴露到因特网的标准形式,和nodeport一样我们只需在创建service是指定type为loadbalancer即可,接着Service 的通过status.loadBalancer字段将需要创建的负载均衡器信息发布供负载均衡服务创建。不过loadbalancer是云服务商"专属",像腾讯云CLB、阿里云SLB,这样在创建service时会自动帮我们创建一个负载均衡器。

大多数云上负载均衡也是基于nodeport,他们的结构如下:

如果要在本地创建一个负载均衡器如何实现呢?

MetalLB[1],一个CNCF沙箱项目,使用标准路由协议(ARP/BGP),实现裸机K8s集群的负载均衡器。

安装方式可参考官方文档:installation[2]

L2(子网)模式的结构,图源[3]

安装后我们获得如下两个组件:

metallb-system/controller deployment。用于处理IP分配的控制器。•metallb-system/speakerdaemonset。集群中每个节点启动一个协议服务守护进程。

接着添加一个configmap配置metallb IP池。

复制代码
apiVersion: v1
kind: ConfigMap
metadata:
  namespace: metallb-system
  name: config
data:
  config: |
    address-pools:
    - name: default
      protocol: layer2
      addresses:
      - 192.168.1.240-192.168.1.250

这样当我们创建一个loadbalancer类型的service时,EXTERNAL-IP将会从地址池中获取一个用于外部访问的IP 192.168.1.243 当外部流量进入时,ARP将我们的请求地址广播获取所属的service,接着k8s内部 通过iptables 规则和 kube-proxy,将流量从服务端点引导到后端。

复制代码
#nginx_deployment_service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
  namespace: metallb-system
spec:
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        ports:
        - name: http
          containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  namespace: metallb-system
  name: nginx
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  type: LoadBalancer

查看service kubectl get svc

复制代码
NAME     TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
nginx    LoadBalancer   10.96.243.159   192.168.1.243   80:31052/TCP   40h

测试访问:curl 192.168.1.243

复制代码
# curl 192.168.1.243
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>

负载均衡可以建立在 OSI 网络模型的不同级别上,主要是在 L4(传输层,例如 TCP/UDP)和 L7(应用层,例如 HTTP)上。在 Kubernetes 中,Services是 L4 的抽象,LoadBalancer类型负载均衡依然有局限性,同时我们看到每创建一个service对应的负载均衡器都会消耗一个静态IP,这并不合理。当然k8s中的另一种资源对象ingress可工作在 L7 层实现应用程序协议(HTTP/HTTPS)的负载均衡。

Ingress

Ingress[4] 公开了从集群外部到集群内服务[5]的 HTTP 和 HTTPS 路由。流量路由由 Ingress 资源上定义的规则控制。我们可以将 Ingress 配置为服务提供外部可访问的 URL、负载均衡流量、终止 SSL/TLS,以及提供基于名称的虚拟主机等能力。

我们所说的Ingress包含两个部分:

•ingress k8s资源对象:流量路由规则的控制•ingress-controller控制器:控制器的实现有非常多,可参考官方文档中列表Ingress 控制器[6],这里我们使用k8s官方维护的控制器NGINX Ingress Controller[7]

外部流量进入集群时先经过ingress-controller,然后根据ingress配置的路由规则将请求转发到后端service。

ingress-controller

ingress-controller其实就是守护进程加一个反向代理的应用,守护进程不断监听集群中资源的变化,将ingress中的配置信息生成反向代理配置。在nginx-ingress controller中即生成nginx.conf的配置文件。

在本文中因为我们上面已经配置好了loadbalancer的服务,这样我们创建一个type为LoadBalancer的service关联这组pod,再把域名解析指向该地址,就实现了集群服务的对外暴露。当然你也可以使用NodePortHostnetwork的方式,感兴趣的小伙伴可以进行测试。

ingress-controller不是k8s内部组件,可以通过helm或资源清单方式安装,可查看ingress-nginx deploy[8]

复制代码
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-
nginx/controller-v1.1.0/deploy/static/provider/cloud/deploy.yaml

然后我们编辑service

复制代码
kubectl edit service/ingress-nginx-controller -n ingress-nginx

修改spec.type为LoadBalancer即可。

这样我们创建好了nginx-ingress controller,下一步就要配置ingress路由规则。

ingress规则

host:k8s.com

基于url的路由:

•/api/v1•/api/v2

这两个url分别路由到不同的service中

复制代码
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: test
  namespace: training
  annotations:
    ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
  - host: k8s.com
    http:
      paths:
      - path: /api/v1
        backend:
          serviceName: service-apiv1
          servicePort: 80
      - path: /api/v2
        backend:
          serviceName: service-apiv2
          servicePort: 80

ingress.kubernetes.io/rewrite-target是nginx-ingress controller的一个注解,当后端服务中暴露的 URL 与 Ingress 规则中指定的路径不同时可以通过此重定向。

查看svc可以看到此时控制器已经获得了一个EXTERNAL-IP

复制代码
#kubectl get svc -n ingress-nginx
NAME                                 TYPE           CLUSTER-IP     EXTERNAL-IP     PORT(S)                      AGE
ingress-nginx-controller             LoadBalancer   10.96.87.23    192.168.1.245   80:32603/TCP,443:31906/TCP   621d
ingress-nginx-controller-admission   ClusterIP      10.96.109.70   <none>          443/TCP                      621d

现在nginx-ingress controller和ingress路由规则都有了。

我们可以进入到nginx-ingress controller pod中查看nginx.conf可以看到此时我们的ingress配置已经被生成为路由规则。

接下来就是指定我们的backend,即上面的server-apiv1/2

我们添加两个用于暴露的service和deployment,和loadbalancer中测试清单一样,我们稍稍修改一下名称即可。

复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-apiv1
  namespace: training
spec:
  selector:
    matchLabels:
      app: nginx-apiv1
  template:
    metadata:
      labels:
        app: nginx-apiv1
    spec:
      containers:
      - name: nginx-apiv1
        image: nginx:latest
        ports:
        - name: http
          containerPort: 80

---
apiVersion: v1
kind: Service
metadata:
  namespace: training
  name: service-apiv1
spec:
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx-apiv1
  type: NodePort

将nginx-apiv1换成nginx-apiv2创建出另一个service和deployment。

最后修改hosts解析k8s.com

复制代码
192.168.1.245 k8s.com

使用curl命令测试url路由(记得在pod中添加测试文件,否则虽然url进行了路由但会出现404)。

复制代码
# curl k8s.com/api/v1/index.html
api v1
# curl k8s.com/api/v2/index.html
api v2

这样我们对ingress有了初步了解,ingress的路由规则可自定项较多也比较繁杂,可通过官方文档进一步学习。

相关推荐
小马爱打代码1 小时前
zookeeper:一致性原理和算法
分布式·zookeeper·云原生
1024find4 小时前
Spark on k8s部署
大数据·运维·容器·spark·kubernetes
kura_tsuki5 小时前
[Docker集群] Docker 容器入门
运维·docker·容器
能不能别报错17 小时前
K8s学习笔记(十六) 探针(Probe)
笔记·学习·kubernetes
能不能别报错18 小时前
K8s学习笔记(十四) DaemonSet
笔记·学习·kubernetes
火星MARK20 小时前
k8s面试题
容器·面试·kubernetes
Serverless社区21 小时前
阿里云函数计算 AgentRun 全新发布,构筑智能体时代的基础设施
阿里云·云原生·serverless·函数计算
赵渝强老师21 小时前
【赵渝强老师】Docker容器的资源管理机制
linux·docker·容器·kubernetes
能不能别报错1 天前
K8s学习笔记(十五) pause容器与init容器
笔记·学习·kubernetes
稚辉君.MCA_P8_Java1 天前
kafka解决了什么问题?mmap 和sendfile
java·spring boot·分布式·kafka·kubernetes