k8s ingress详解(2)

这一篇看一下ingress controller的实现

ingress controller是一个守护进程,部署为一个Kubernetes Pod

ingress controller通过watch ingresses接口,动态更新ingress的资源

官方的ingress controller实现内容:
1.从APIserver拉去配置信息
2.基于golang text/template 模块书写Nginx配置模板
3.重新加载nginx

官方Nginx ingress controller 定义
const (
    nginxConf = `
		events {
		  worker_connections 1024;
		}
		http {
			{{range $ing := .Items}}
				{{range $rule := $ing.Spec.Rules}}
				  server {
				    listen 80;
				    server_name {{$rule.Host}};
					{{ range $path := $rule.HTTP.Paths }}
					    location {{$path.Path}} {
					      proxy_set_header Host $host;
					      proxy_pass http://{{$path.Backend.ServiceName}}.{{$ing.Namespace}}.svc.cluster.local:{{$path.Backend.ServicePort}};
					    }
					{{end}}
				  }
				{{end}}
			{{end}}
		}`
)
这里通过定义nginxConf常量,实际内容为Nginx的配置模板

#配置加载
func (ngx *Manager) CheckAndReload(cfg config.Configuration, ingressCfg ingress.Configuration) error {
	ngx.reloadRateLimiter.Accept()
	ngx.reloadLock.Lock()
	defer ngx.reloadLock.Unlock()
	newCfg, err := ngx.template.Write(cfg, ingressCfg, ngx.testTemplate)
	if err != nil {
		return fmt.Errorf("failed to write new nginx configuration. Avoiding reload: %v", err)
	}
	changed, err := ngx.needsReload(newCfg)
	if err != nil {
		return err
	}
	if changed {
		if err := ngx.shellOut("nginx -s reload"); err != nil {
			return fmt.Errorf("error reloading nginx: %v", err)
		}
		glog.Info("change in configuration detected. Reloading...")
	}
	return nil
}

CheckAndReload的第一个参数的Nginx的全局配置参数,对于一个ingress controller启动后一般这些参数是不变的,我们关注的ingress的变化
ngx.template.Write(cfg, ingressCfg, ngx.testTemplate)实现了将ingress渲染到Nginx配置文件的过程
ngx.testTemplate用于测试配置文件是否正确,实际就是Nginx -t
ngx.template.Write就是调用的k8s.io\contrib\ingress\controllers\nginx\nginx\template\template.go Template.Write(cfg  config.Configuration,ingressCfg ingress.Configuration,isValidTemplate func([]byte) error) 函数

最终的配置conf 类型为 make(map[string]interface{}),一般的nginx用到的结构有:
type Configuration struct {
	Upstreams>     []*Upstream
	Servers      []*Server
	TCPUpstreams []*Location
	UDPUpstreams []*Location
}
type Upstream struct {
	Name     string
	Backends []UpstreamServer
	Secure   bool
}
type UpstreamServer struct {
	Address     string
	Port        string
	MaxFails    int
	FailTimeout int
}
type Server struct {
	Name              string
	Locations         []*Location
	SSL               bool
	SSLCertificate    string
	SSLCertificateKey string
	SSLPemChecksum    string
}
type Location struct {
	Path            string
	IsDefBackend    bool
	Upstream        Upstream
	Auth            auth.Nginx
	RateLimit       ratelimit.RateLimit
	Redirect        rewrite.Redirect
	SecureUpstream  bool
	Whitelist       ipwhitelist.SourceRange
	EnableCORS      bool
	ExternalAuthURL authreq.Auth
}

那么ingress.Configuration是怎么产生的呢
func (lbc *loadBalancerController) sync(key string) error {
	if !lbc.controllersInSync() {
		time.Sleep(podStoreSyncedPollPeriod)
		return fmt.Errorf("deferring sync till endpoints controller has synced")
	}

	// by default no custom configuration configmap
	cfg := &api.ConfigMap{}

	if lbc.nxgConfigMap != "" {
		// Search for custom configmap (defined in main args)
		var err error
		ns, name, _ := parseNsName(lbc.nxgConfigMap)
		cfg, err = lbc.getConfigMap(ns, name)
		if err != nil {
			return fmt.Errorf("unexpected error searching configmap %v: %v", lbc.nxgConfigMap, err)
		}
	}

	ngxConfig := lbc.nginx.ReadConfig(cfg)
	ngxConfig.HealthzURL = lbc.defHealthzURL

	ings := lbc.ingLister.Store.List()
	upstreams, servers := lbc.getUpstreamServers(ngxConfig, ings)

	return lbc.nginx.CheckAndReload(ngxConfig, ingress.Configuration{
		Upstreams:    upstreams,
		Servers:      servers,
		TCPUpstreams: lbc.getTCPServices(),
		UDPUpstreams: lbc.getUDPServices(),
	})
}

lbc.ingLister.Store.List()获取到了最新ingress配置

那这个函数又是怎么被调用到的
lbc.ingLister.Store, lbc.ingController = framework.NewInformer(
	&cache.ListWatch{
		ListFunc:  ingressListFunc(lbc.client, namespace),
		WatchFunc: ingressWatchFunc(lbc.client, namespace),
	},
	&extensions.Ingress{}, resyncPeriod, ingEventHandler)
通过listwatch机制检测ingress资源
当有增删改等动作时都会调用lbc.syncQueue.enqueue(obj)

lbc.syncQueue实际上是通过NewTaskQueue 函数转变loadBalancerController.sync而来,每次lbc.syncQueue被调用时loadBalancerController.sync都会被调用


func (lbc *loadBalancerController) Run() {
	glog.Infof("starting NGINX loadbalancer controller")
	go lbc.nginx.Start()

	go lbc.ingController.Run(lbc.stopCh)
	go lbc.endpController.Run(lbc.stopCh)
	go lbc.svcController.Run(lbc.stopCh)
	go lbc.secrController.Run(lbc.stopCh)
	go lbc.mapController.Run(lbc.stopCh)

	go lbc.syncQueue.run(time.Second, lbc.stopCh)
	go lbc.ingQueue.run(time.Second, lbc.stopCh)

	<-lbc.stopCh
}

go lbc.syncQueue.run(time.Second, lbc.stopCh)实际运行函数为worker,调用了sync
func (t *taskQueue) worker() {
	for {
		key, quit := t.queue.Get()
		if quit {
			close(t.workerDone)
			return
		}
		glog.V(3).Infof("syncing %v", key)
		if err := t.sync(key.(string)); err != nil {
			glog.Warningf("requeuing %v, err %v", key, err)
			t.requeue(key.(string))
		} else {
			t.queue.Forget(key)
		}

		t.queue.Done(key)
	}
}

其他关于secret,configmap,service,endpoint的controller不再赘述

按照官方的nginx ingress controller实现我们可以发现,实际上就是通过api与apiserver与api进行交互,监控configmap secret service endpoint等信息的变化进行加载然后reload的过程。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值