最全的Linux教程,Linux从入门到精通

======================

  1. linux从入门到精通(第2版)

  2. Linux系统移植

  3. Linux驱动开发入门与实战

  4. LINUX 系统移植 第2版

  5. Linux开源网络全栈详解 从DPDK到OpenFlow

华为18级工程师呕心沥血撰写3000页Linux学习笔记教程

第一份《Linux从入门到精通》466页

====================

内容简介

====

本书是获得了很多读者好评的Linux经典畅销书**《Linux从入门到精通》的第2版**。本书第1版出版后曾经多次印刷,并被51CTO读书频道评为“最受读者喜爱的原创IT技术图书奖”。本书第﹖版以最新的Ubuntu 12.04为版本,循序渐进地向读者介绍了Linux 的基础应用、系统管理、网络应用、娱乐和办公、程序开发、服务器配置、系统安全等。本书附带1张光盘,内容为本书配套多媒体教学视频。另外,本书还为读者提供了大量的Linux学习资料和Ubuntu安装镜像文件,供读者免费下载。

华为18级工程师呕心沥血撰写3000页Linux学习笔记教程

本书适合广大Linux初中级用户、开源软件爱好者和大专院校的学生阅读,同时也非常适合准备从事Linux平台开发的各类人员。

需要《Linux入门到精通》、《linux系统移植》、《Linux驱动开发入门实战》、《Linux开源网络全栈》电子书籍及教程的工程师朋友们劳烦您转发+评论

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以点击这里获取!

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

	},
	UpdateFunc: func(old, cur interface{}) {
		...
		updateCh.In() <- Event{
			Type: UpdateEvent,
			Obj:  cur,
		}
	},
}
...
store.informers.Ingress.AddEventHandler(ingEventHandler)
...

}


        可以看出,Ingress 协程定义了监听 ingress 信息的 informer 对象,并注册了相关事件的回调方法,在回调方法内向之前提到的 updateCh 写入了事件,进而也就达到了当资源变化时通知 Controller 主程向同步队列写入task的目的。


        反过头来,看一下 syncQueue ,首先找到其定义,跟踪到 internal/ingress/controller/nginx.go#NewNGINXController()



// NewNGINXController creates a new NGINX Ingress controller.
func NewNGINXController(config *Configuration, mc metric.Collector, fs file.Filesystem) *NGINXController {

n.syncQueue = task.NewTaskQueue(n.syncIngress)

}


       不难发现,队列的创建是通过 task.NewTaskQueue() 完成的,而且传入了关键的处理函数 n.syncIngress


       继续跟踪到 internal/task/queue.go#NewTaskQueue()



// NewTaskQueue creates a new task queue with the given sync function.
// The sync function is called for every element inserted into the queue.
func NewTaskQueue(syncFn func(interface{}) error) *Queue {
return NewCustomTaskQueue(syncFn, nil)
}

// NewCustomTaskQueue …
func NewCustomTaskQueue(syncFn func(interface{}) error, fn func(interface{}) (interface{}, error)) *Queue {
q := &Queue{
queue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()),
sync: syncFn,
workerDone: make(chan bool),
fn: fn,
}

return q
}


       可以看出,传入的处理函数 n.syncIngress 被赋值给 Queue 的 sync 属性了。实际上,syncQueue 的执行就是在反复执行该方法以消费队列里的元素。Queue 的 Run 定义可以在本文件中找到:



// Run starts processing elements in the queue
func (t *Queue) Run(period time.Duration, stopCh <-chan struct{}) {
wait.Until(t.worker, period, stopCh)
}

// worker processes work in the queue through sync.
func (t *Queue) worker() {
for {
key, quit := t.queue.Get()

if err := t.sync(key); err != nil {
t.queue.AddRateLimited(Element{
Key: item.Key,
Timestamp: time.Now().UnixNano(),
})
} else {
t.queue.Forget(key)
t.lastSync = ts
}

	t.queue.Done(key)
}

}


        同步队列协程的主要工作就是定期取出队列里的元素,并利用传入的 n.syncIngress (即 t.sync(key))方法处理队列里的元素。


        n.syncIngress 方法的定义在 internal/ingress/controller/controller.go#syncIngress()



// syncIngress collects all the pieces required to assemble the NGINX
// configuration file and passes the resulting data structures to the backend
// (OnUpdate) when a reload is deemed necessary.
func (n *NGINXController) syncIngress(interface{}) error {

// 获取最新配置信息
....
// 构造 nginx 配置
pcfg := &ingress.Configuration{
	Backends:              upstreams,
	Servers:               servers,
	PassthroughBackends:   passUpstreams,
	BackendConfigChecksum: n.store.GetBackendConfiguration().Checksum,
}
...
// 不能避免 reload,就执行 reload 更新配置
if !n.IsDynamicConfigurationEnough(pcfg) {
	...
	err := n.OnUpdate(*pcfg)
	...
}
...
// 动态更新配置
err := wait.ExponentialBackoff(retry, func() (bool, error) {
	err := configureDynamically(pcfg, n.cfg.ListenPorts.Status, n.cfg.DynamicCertificatesEnabled)
	...
})
...

}


       reload 配置的函数定义位于 internal/ingress/controller/nginx.go#OnUpdate(),具体就不解释了,读者可自行查阅。


       这里主要看下动态更新是怎么完成的,函数定义位于 internal/ingress/controller/nginx.go#configureDynamically()



// configureDynamically encodes new Backends in JSON format and POSTs the
// payload to an internal HTTP endpoint handled by Lua.
func configureDynamically(pcfg *ingress.Configuration, port int, isDynamicCertificatesEnabled bool) error {
backends := make([]*ingress.Backend, len(pcfg.Backends))

for i, backend := range pcfg.Backends {
	var service *apiv1.Service
	if backend.Service != nil {
		service = &apiv1.Service{Spec: backend.Service.Spec}
	}
	luaBackend := &ingress.Backend{
		Name:                 backend.Name,
		Port:                 backend.Port,
		SSLPassthrough:       backend.SSLPassthrough,
		SessionAffinity:      backend.SessionAffinity,
		UpstreamHashBy:       backend.UpstreamHashBy,
		LoadBalancing:        backend.LoadBalancing,
		Service:              service,
		NoServer:             backend.NoServer,
		TrafficShapingPolicy: backend.TrafficShapingPolicy,
		AlternativeBackends:  backend.AlternativeBackends,
	}

	var endpoints []ingress.Endpoint
	for _, endpoint := range backend.Endpoints {
		endpoints = append(endpoints, ingress.Endpoint{
			Address: endpoint.Address,
			Port:    endpoint.Port,
		})
	}

	luaBackend.Endpoints = endpoints
	backends[i] = luaBackend
}

url := fmt.Sprintf("http://localhost:%d/configuration/backends", port)
err := post(url, backends)
if err != nil {
	return err
}

if isDynamicCertificatesEnabled {
	err = configureCertificates(pcfg, port)
	if err != nil {
		return err
	}
}

return nil

}


      可以看出,确实是通过请求 Lua 后端来实现动态配置更新的,使用的是典型的 http post 方法。后续的动态更新动作转交给 Lua 模块负责。因为 Lua 以模块形式嵌入 Nginx 运行,因此其更新配置也就在一定程度上避免了 reload。


      目前来看,具体 Serive Pod 的变化不会导致 reload 的发生,因为服务内容器的负载均衡已经移交给 Lua 处理,而 Service 的增减变化仍通过配置文件形式更新,会导致 reload 发生。这可以从 nginx 的配置文件看出:



> 
> ...  
>  http {  
>      ...  
>      upstream **upstream\_balancer** {  
>          server 0.0.0.1; # placeholder  
>          balancer\_by\_lua\_block {  
>              **balancer.balance()**  
>          }  
>          keepalive 32;  
>      }  
>        
>      server {  
>          server\_name **wordpress.local** ;  
>          listen 80;  
>          listen [::]:80;  
>          set $proxy\_upstream\_name "-";  
>          location / {  
>              ...  
>              proxy\_pass **http://upstream\_balancer**;  
>              proxy\_redirect                          off;  
>          }  
>      }  
>  }
> 
> 
> 


       可以看到当添加了 wordpress 服务后,在 nginx 配置中确实添加了 一个 server 条目,但该条目中没有具体指出后端的容器地址,而是指向了一个叫 **upstream\_balancer** 的地址,这个 balancer 其实是由 Lua 动态提供路由的。既然没有实际的容器后端在配置文件中进行配置,自然地,服务中容器数量的增减变化也就不必修改 nginx 配置文件了,这就是免 reload 的关键!简单推测,Lua 模块所做的就是维持一个服务到容器的映射关系,动态地提供负载均衡路由。




**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐