Kubernetes Ingress Controller的使用介绍及高可用落地

栏目: 编程工具 · 发布时间: 5年前

内容简介:本文转载自从之前对ingress controller到现在了解架构和一些经验总结下,顺带给人科普少走弯路 需要看懂本文要具备一下知识点:

本文转载自 zhangguanzhang的博客

从之前对ingress controller到现在了解架构和一些经验总结下,顺带给人科普少走弯路 需要看懂本文要具备一下知识点:

  • Service实现原理和会应用
  • 知道反向代理原理,了解nginx和apache的vhost概念
  • 了解service的几种类型(Nodeport、clusterip、LB)
  • 四层和七层区别(不明白就这样去理解,七层最常见就是应用层的http,也就是url,四层是传输层,为tcp/udp端口)
  • 域名解析,/etc/hosts等基础知识

Ingress Controller介绍

Ingress Controller 是一个统称,并不是只有一个,有如下这些:

  • Ingress NGINX : Kubernetes 官方维护的方案,也是本次安装使用的 Controller。
  • F5 BIG-IP Controller : F5 所开发的 Controller,它能够让管理员通过 CLI 或 API 让 Kubernetes 与 OpenShift 管理 F5 BIG-IP 设备。
  • Ingress Kong : 著名的开源 API Gateway 方案所维护的 Kubernetes Ingress Controller。
  • Traefik : 是一套开源的 HTTP 反向代理与负载均衡器,而它也支援了 Ingress。
  • Voyager : 一套以 HAProxy 为底的 Ingress Controller。

Ingress Controller 的实现不只上面这些方案,还有很多可以在网络上找到这里不一一列出来了。

我们部署在集群里的服务的svc想暴露出来的时候,从长久眼光看和易于管理维护都是用的 Ingress Controller 来处理,clusterip非集群主机无法访问,Nodeport不方便长久管理和效率,LB服务多了不方便因为需要花费额外的钱,externalIPS不好用(后面有空写文章会说它)。

我们跑的大多服务都是应用层http(s),Ingress Controller使用service或者pod的网络将它暴露在集群外,然后它反向代理集群内的七层服务,通过vhost子域名那样路由到后端的服务, Ingress Controller 工作架构如下,借用traefik官方的图。

Kubernetes Ingress Controller的使用介绍及高可用落地

你可以将 api.domain.com 进来的流量路由到集群里api的pod,你可以将 backoffice.domain.com 流量路由到backoffice的一组pod上,虽说我们可以自己搭建一个nginx来代替掉 Ingress Controller ,但是要增加代理的service长期来看维护很不方便,在使用上 Ingress Controller 后可以用一种抽象的对象告诉controller添加对应的代理,也就是 kind: Ingress 。它里面描述了从Ingress Controller访问进来的ServerName和web的url要代理到集群里哪个service(以及service的port)等等具体信息。

而官方的 Ingress Nginx 可以视为一个魔改的nginx,拥有集群赋予的RBAC权限后,能够有监听集群Ingress相关的变化能力,用户创建了 kind: Ingress , 例如上面trafik图里的Ingress大致就是下面这样。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress
spec:
  rules:
  - host: api.mydomain.com
    http:
      paths:
      - backend:
          serviceName: api
          servicePort: 80
  - host: domain.com
    http:
      paths:
      - path: /web/*
        backend:
          serviceName: web
          servicePort: 8080
  - host: backoffice.domain.com
    http:
      paths:
      - backend:
          serviceName: backoffice
          servicePort: 8080

只要创建了上面的Ingress后,ingress controller里会监听到从而生成对应的配置段后动态reload配置文件。

Ingress Controller部署

部署非常简单,一条命令创建即可,yml来源于 https://github.com/kubernetes/ingress-nginx/tree/master/deploy

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/mandatory.yaml

该yaml缺少向群外暴露的方式,我们先使用externalIPs方式创建svc来让它能从集群外面访问(此处先学工作原理,后面再讲高可用)。

$INGRESS_VIP 选取一个和宿主机同一个段没使用过的IP即可(实际上Ingress Nginx bind的端口不止80和443,这里不讨论,有兴趣的同学可以看容器里的默认配置文件)。

apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
  labels:
    app: ingress-nginx
spec:
  type: LoadBalancer
  externalIPs:
  - $INGRESS_VIP
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: ingress-nginx

上面的yaml里后面详细解释我们需要关注的配置项,先来创建ingress对象试试。

测试http 7层负载

部署了官方的ingress nginx后,我部署了一个nginx的pod,为它创建了一个名为nginx的service。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: nginx
spec:
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx
        name: nginx
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    app: nginx
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80

然后创建对应的一个ingress对象来暴露集群里这个nginx的http服务。

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: nginx-ingress
spec:
  rules:
  - host: nginx.testdomain.com
    http:
      paths:
      - backend:
          serviceName: nginx
          servicePort: 80

找到ingress nginx的pod名字后通过命令查看里面nginx配置文件能找到有对应的配置段生成。

$ kubectl -n ingress-nginx exec nginx-ingress-controller-6cdcfd8ff9-t5sxl -- cat /etc/nginx/nginx.conf
...
	## start server nginx.testdomain.com
	server {
		server_name nginx.testdomain.com ;
		
		listen 80;
		
		set $proxy_upstream_name "-";
		
		location / {
			
			set $namespace      "default";
			set $ingress_name   "nginx-ingress";
			set $service_name   "nginx";
			set $service_port   "80";
			set $location_path  "/";
            ........
	## end server nginx.testdomain.com      
...

找一台非集群的Windows机器(也可以mac,主要是有图形界面且非集群内机器),设置hosts文件把域名 nginx.testdomain.com 设置到对service的那个externalIPs的ip上,打开浏览器访问 nginx.testdomain.com 即可发现集群内的nginx已经暴露在集群外

注意:Ingress Controller虽然调用的是service,看起来按照nginx来理解转发是client–nginx–svc–pod; 实际上转发是client–nginx–pod,因为已经魔改了不能按照nginx的来理解,是直接负载到svc的endpoint上面的

另外低版本的ingress nginx的args参数 --default-backend-service=$(POD_NAMESPACE)/default-http-backend ,该参数指定ingress nginx的同namespace下名为 default-http-backend 的service作为默认访问的时候页面,通常那个时候是创建一个404页面的的pod和对应service,如果ingress nginx启动的时候没找到这个service会无法启动,新版本不是必须了,好像也自带404页面了。

另外ingress也能多路径,如下。

spec:
  rules:
  - host: xxxx.xxxx.xxx
    http:
      paths:
      - backend:
          serviceName: service-index
          servicePort: 80
        path: /
      - backend:
          serviceName: service-test-api
          servicePort: 80
        path: /api/

如何来4层负载

我们可以看到ingress nginx的args里有这两行。

- --tcp-services-configmap=$(POD_NAMESPACE)/tcp-services
- --udp-services-configmap=$(POD_NAMESPACE)/udp-services

从选项和值可以猜测出,要想代理四层(tcp/udp),得写同namespace里一个名为 tcp-serviceudp-service 的两个configmap的数据 四层的话这边我们创建一个 mysql 的pod,来代理3306端口到集群外面,则需要写tcp-services这个configmap。

kind: ConfigMap
apiVersion: v1
metadata:
  name: tcp-services
  namespace: ingress-nginx
data:
  3306: "default/mysql:3306"

四层写这两个ConfigMap的data即可,按照这样去写即可 out_port: namespaces/svc_name:port ,要给每个ingress加一些nginx里的配置可以查看官方的annotation字段以及值(traefik同理)。

Ingress Controller高可用

这里来讨论下 Ingress Controller 的高可用。

Ingress Controller到集群内的路径这部分都有负载均衡了,我们比较关注部署了Ingress Controller后,外部到它这段路怎么高可用?

上面的例子里service我使用的externalIPs,但是代理四层的时候会新加端口,需要每次人为去介入增加暴露端口?

流量从入口到 Ingress Controller 的pod有下面几种方式:

  • type为 LoadBalancer 的时候手写 externalIPs 很鸡肋,后面会再写文章去讲它
  • type为 LoadBalancer 的时候只有云厂商支持分配公网ip来负载均衡,LoadBalancer 公开的每项服务都将获得自己的 IP 地址,但是需要收费,且自己建立集群无法使用
  • 不创建service,pod直接用hostport,效率等同于 hostnetwork ,如果不代理四层端口还好,代理了需要修改pod的template来滚动更新来让nginx bind的四层端口能映射到宿主机上
  • Nodeport ,端口不是web端口(但是可以修改Nodeport的范围改成web端口),如果进来流量负载到Nodeport上可能某个流量路线到某个node上的时候因为 Ingress Controller 的pod不在这个node上,会走这个node的kube-proxy转发到Ingress Controller的pod上,多走一趟路
  • 不创建service,效率最高,也能四层负载的时候不修改pod的template,唯一要注意的是hostnetwork下pod会继承宿主机的网络协议,也就是使用了主机的dns,会导致svc的请求直接走宿主机的上到公网的dns服务器而非集群里的dns server,需要设置pod的 dnsPolicy: ClusterFirstWithHostNet 即可解决

写在最后

部署方式没多大区别开心就好。

  • DaemonSet + nodeSeletor
  • deploy设置replicas数量 + nodeSeletor + pod互斥
  • 所以可以一个vip飘在拥有存活的controller的宿主机上,云上的话就用slb来负载代替vip
  • 最后说说域名请求指向它,如果部署在内网或者办公室啥的,内网有dns server的话把ing的域名全部解析到ingress controller的宿主机ip上,否则要有人访问每个人设置/etc/hosts才能把域名解析来贼麻烦,如果没有dns server可以跑一个external-dns,它的上游dns是公网的dns服务器,办公网内机器的dns server指向它即可,云上的话把域名请求解析到对应ip即可
  • traefik和ingress nginx类似,不过它用 go 实现的

以上所述就是小编给大家介绍的《Kubernetes Ingress Controller的使用介绍及高可用落地》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Essential C++中文版

Essential C++中文版

李普曼 (Stanley B.Lippman) / 侯捷 / 电子工业出版社 / 2013-8-1 / CNY 65.00

本书以四个面向来表现C++的本质:procedural(面向过程的)、generic(泛型的)、object-based(基于对象的)、objectoriented(面向对象的)。全书围绕一系列逐渐繁复的程序问题,以及用以解决这些问题的语言特性来组织。循此方式,你将不只学到C++的功能和结构,也可学到它们的设计目的和基本原理。 本书适合那些已经开始从事软件设计,又抽不出太多时间学习新技术的程......一起来看看 《Essential C++中文版》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具