kubernetes源码分析 -- kube-proxy
Kube-proxy需要在每一个minion结点上运行。他的作用是service的代理,负责将业务连接到service后面具体执行结点(endpoints)。
我们列一下体现kube-proxy主要设计的代码部分。
总的来说kubernetes的代码可以从cmd看进去,看每个组件的启动过程,以及提供的业务。Cmd部分组织启动进程的过程以及代码调用,具体的代码实现在pkg里面。
Kube-proxy的重点代码是pkg中的serviceConfig、endpointsConfig(在pkg/proxy/config中),每个config中的mux,以及注册到config的处理函数proxier和endpointsHandler(这两个在pkg/proxy/userspace中),还有监听服务信息的API(代码也在pkg/proxy/config中)。
在执行kube-proxy命令的时候,NewProxyServerDefault函数依次创建serviceConfig,注册proxier;创建endpointConfig,注册endpointsHandler; 创建NewSourceAPI,在这里面会启动两个channel监听service和endpoint的变化,具体代码见下段:
|
serviceConfig := proxyconfig.NewServiceConfig() serviceConfig.RegisterHandler(proxier) endpointsConfig := proxyconfig.NewEndpointsConfig() endpointsConfig.RegisterHandler(endpointsHandler) proxyconfig.NewSourceAPI( client, config.ConfigSyncPeriod, serviceConfig.Channel("api"), endpointsConfig.Channel("api"), ) |
下面是代码调用依赖。我的画图工具太差,有点难看~~
在
proxyconfig.NewSourceAPI(
client,
config.ConfigSyncPeriod,
serviceConfig.Channel("api"),
endpointsConfig.Channel("api"),
这段代码中,serviceConfig和endpointsConfig会分别创建一个channel,并监听这个channel的消息收到后推送到config内的mux。
serviceConfig的创建在
func NewServiceConfig() *ServiceConfig {
updates := make(chan struct{})
store := &serviceStore{updates: updates, services: make(map[string]map[types.NamespacedName]api.Service)}
mux := config.NewMux(store)
bcaster := config.NewBroadcaster()
go watchForUpdates(bcaster, store, updates)
return &ServiceConfig{mux, bcaster, store}
}
他创建了mux,注入进mux的serviceStore会提供Merge方法:
func (s *serviceStore) Merge(source string, change interface{}) error {
这个方法加工组织收到的数据,并通知proxier,调用他的OnServiceUpdate方法。具体是怎么触发到的呢?Merge方法在加工好数据后,构造一个空的数据{}推给叫updates的 channel,他触发了前面注册进去的proxier。 代码是serviceConfig.RegisterHandler(proxier)。
这样,当service有变化就会触发到OnServiceUpdate。
以新增一个service为例,前端api将消息发过来最后触发OnServiceUpdate后,这个方法会启动一个随机端口并监听他;再通过修改iptables的方式,将发给service的portal(集群内虚地址)的报文全部截收,发给自己刚才监听的那个随机端口。随机端口收到消息后,会选择这个service的一个endpoint,并建立到这个endpoint的链接,同时转发client和endpoints直接的报文。
这里可以看到,kubernetes这种解决服务发现的方法,多转发了一次报文。
OnServiceUpdate调用了两个很重要的函数addServiceOnPort和openPortal,通过他们完成了上述工作。
func (proxier *Proxier) addServiceOnPort(service proxy.ServicePortName, protocol api.Protocol, proxyPort int, timeout time.Duration) (*serviceInfo, error) {
sock, err := newProxySocket(protocol, proxier.listenIP, proxyPort)
if err != nil {
return nil, err
}
_, portStr, err := net.SplitHostPort(sock.Addr().String())
if err != nil {
sock.Close()
return nil, err
}
portNum, err := strconv.Atoi(portStr)
if err != nil {
sock.Close()
return nil, err
}
si := &serviceInfo{
isAliveAtomic: 1,
proxyPort: portNum,
protocol: protocol,
socket: sock,
timeout: timeout,
activeClients: newClientCache(),
sessionAffinityType: api.ServiceAffinityNone, // default
stickyMaxAgeMinutes: 180, // TODO: parameterize this in the API.
}
proxier.setServiceInfo(service, si)
glog.V(2).Infof("Proxying for service %q on %s port %d", service, protocol, portNum)
go func(service proxy.ServicePortName, proxier *Proxier) {
defer util.HandleCrash()
atomic.AddInt32(&proxier.numProxyLoops, 1)
sock.ProxyLoop(service, si, proxier)
atomic.AddInt32(&proxier.numProxyLoops, -1)
}(service, proxier)
return si, nil
}
func (proxier *Proxier) openPortal(service proxy.ServicePortName, info *serviceInfo) error {
err := proxier.openOnePortal(info.portal, info.protocol, proxier.listenIP, info.proxyPort, service)
if err != nil {
return err
}
for _, publicIP := range info.externalIPs {
err = proxier.openOnePortal(portal{net.ParseIP(publicIP), info.portal.port, true}, info.protocol, proxier.listenIP, info.proxyPort, service)
if err != nil {
return err
}
}
for _, ingress := range info.loadBalancerStatus.Ingress {
if ingress.IP != "" {
err = proxier.openOnePortal(portal{net.ParseIP(ingress.IP), info.portal.port, false}, info.protocol, proxier.listenIP, info.proxyPort, service)
if err != nil {
return err
}
}
}
if info.nodePort != 0 {
err = proxier.openNodePort(info.nodePort, info.protocol, proxier.listenIP, info.proxyPort, service)
if err != nil {
return err
}
}
return nil
}
在addServiceOnPort中调用的重要函数是
func (udp *udpProxySocket) getBackendConn(activeClients *clientCache, cliAddr net.Addr, proxier *Proxier, service proxy.ServicePortName, timeout time.Duration) (net.Conn, error) {
activeClients.mu.Lock()
defer activeClients.mu.Unlock()
svrConn, found := activeClients.clients[cliAddr.String()]
if !found {
// TODO: This could spin up a new goroutine to make the outbound connection,
// and keep accepting inbound traffic.
glog.V(3).Infof("New UDP connection from %s", cliAddr)
var err error
svrConn, err = tryConnect(service, cliAddr, "udp", proxier)
if err != nil {
return nil, err
}
if err = svrConn.SetDeadline(time.Now().Add(timeout)); err != nil {
glog.Errorf("SetDeadline failed: %v", err)
return nil, err
}
activeClients.clients[cliAddr.String()] = svrConn
go func(cliAddr net.Addr, svrConn net.Conn, activeClients *clientCache, timeout time.Duration) {
defer util.HandleCrash()
udp.proxyClient(cliAddr, svrConn, activeClients, timeout)
}(cliAddr, svrConn, activeClients, timeout)
}
return svrConn, nil
}
他选择service的一个endpoint,并建立clientSock和endpointSock之间的连接
http://blog.csdn.net/zhaoguoguang/article/details/51225426
kubernetes源码分析 -- kube-proxy的更多相关文章
- Magnum Kubernetes源码分析(二)
Kubernetes Master Stack kubernetes master的stack的resources主要分为三个部分. master wait handle wait handle主要用 ...
- Magnum Kubernetes源码分析(一)
Magnum版本说明 本文以magnum的mitaka版本代码为基础进行分析. Magnum Kubernetes Magnum主要支持的概念有bay,baymodel,node,pod,rc,ser ...
- client-go客户端自定义开发Kubernetes及源码分析
介绍 client-go 是一种能够与 Kubernetes 集群通信的客户端,通过它可以对 Kubernetes 集群中各资源类型进行 CRUD 操作,它有三大 client 类,分别为:Clien ...
- ABP源码分析三十七:ABP.Web.Api Script Proxy API
ABP提供Script Proxy WebApi为所有的Dynamic WebApi生成访问这些WebApi的JQuery代理,AngularJs代理以及TypeScriptor代理.这些个代理就是j ...
- JAVA设计模式-动态代理(Proxy)源码分析
在文章:JAVA设计模式-动态代理(Proxy)示例及说明中,为动态代理设计模式举了一个小小的例子,那么这篇文章就来分析一下源码的实现. 一,Proxy.newProxyInstance方法 @Cal ...
- kubernetes垃圾回收器GarbageCollector Controller源码分析(二)
kubernetes版本:1.13.2 接上一节:kubernetes垃圾回收器GarbageCollector Controller源码分析(一) 主要步骤 GarbageCollector Con ...
- Kubernetes client-go Indexer / ThreadSafeStore 源码分析
Kubernetes client-go Indexer / ThreadSafeStore 源码分析 请阅读原文:原文地址 Contents 概述 Indexer 接口 ThreadSafe ...
- Kubernetes client-go 源码分析 - Reflector
概述入口 - Reflector.Run()核心 - Reflector.ListAndWatch()Reflector.watchHandler()NewReflector()小结 概述 源码版本: ...
- Kubernetes Deployment 源码分析(一)
概述Deployment 基础创建 DeploymentReplicaSet滚动更新失败回滚历史版本回滚其他特性小结 概述 Deployment 是最常用的 Kubernetes 原生 Workloa ...
随机推荐
- DRF频率、分页、解析器、渲染器
DRF的频率 频率限制是做什么的 开放平台的API接口调用需要限制其频率,以节约服务器资源和避免恶意的频繁调用. 频率组件原理 DRF中的频率控制基本原理是基于访问次数和时间的,当然我们可以通过自己定 ...
- Codeforces441B_Valera and Fruits(暴力)
Valera and Fruits time limit per test 1 second memory limit per test 256 megabytes input standard in ...
- pytorch调参经验(一)
个人博客:https://yifdu.github.io/2018/11/18/pytorch%E8%B0%83%E5%8F%82%E7%BB%8F%E9%AA%8C%EF%BC%88%E4%B8%8 ...
- MyBatis3用户指南
1. 范围和生命周期 SqlSessionFactoryBuilder -->SqlSessionFactory-->SqlSession-->Mapper 实例 SqlSe ...
- SQL Server 2008 sa用户可以登录,Windows身份验证无法登录
安装SQL Server 2008时一切正常,但是在启动时出现了问题.若使用SQL Server 身份验证,选择sa用户可以登录到系统,并正常使用.但是,若使用Windows身份验证,提示用户名或密码 ...
- 配置支持Basler的API函数的开发环境
第一步:文件说明 使用默认路径安装Basler pylon x86 4.2.1.4845.exe 以后生产的文件如下: 文件说明: apps为用于配置ip和调试相机的软件 bin为驱动程序 CLPro ...
- ORM到底是用还是不用?(复制)
ORM即Object/Relation Mapping的简写,一般称作“对象关系映射”,在Web开发中最常出没于和关系型数据库交互的地方.接口.中间件.库.包,你都可以这么称呼它.ORM我们可以结合P ...
- scp无密码访问scp -i
网上搜索,可以发现大概有以下情况 1.使用expect交互 2.sshpass 但因为他们都需要安装第三方的软件,不适合我们这样的场景,我们很多时间是绝不允许安装其他软件在客户机上的. 我的场景是在本 ...
- android线程学习心得
有一篇关于android线程讲的非常好,大家可以参考下,其中有一句话讲的非常好,就拿来做开篇之句: 当一个程序第一次启动时,Android会同时启动一个对应的主线程(Main Thread),主线程主 ...
- Java:出现错误提示(java.sql.SQLException:Value '0000-00-00' can not be represented as java.sql.Date)
Java:出现错误提示(java.sql.SQLException:Value '0000-00-00' can not be represented as java.sql.Date) 原因分析: ...