简介:KubeStack is an OpenStack network provider for kubernetes.KubeStack is devided into two functions:

  • kubestack running on the same host with kube-controller-manager, which provides network management for openstack
  • kubestack running on each minion host, which setups container's network interfaces

kubestack.conf的默认配置文件如下所示:

[Global]
auth-url = http://${IF_IP}:5000/v2.0
username = admin
password = admin
tenant-name = admin
region = RegionOne
ext-net-id = ${EXT_NET_ID} [LoadBalancer]
create-monitor = yes
monitor-delay = 1m
monitor-timeout = 30s
monitor-max-retries = 3 [Plugin]
plugin-name = ovs

  

// kubestack.go

1、func main()

1、调用config, err := os.Open(configFile)打开配置文件,configFile默认为/etc/kubestack.conf

2、调用openstack, err := common.NewOpenStack(config)

3、调用server := kubestack.NewKubeHandler(openstack)

4、最后,调用server.Serve(port)进行监听,端口号默认为4237

OpenStack数据结构如下所示:

// OpenStack is an implementation of network provider Interface for OpenStack

type OpenStack struct {

  network    *gophercloud.ServiceClient
  identity   *gophercloud.ServiceClient
  provider   *gophercloud.ProviderClient
  region    string
  lbOpts    LoadBalancerOpts
  pluginOpts  PluginOpts   ExtNetID   string   Plugin    plugins.PluginInterface 
}

// pkg/common/openstack.go

2、func NewOpenStack(config io.Reader) (*OpenStack, error)

  • 调用err := gcfg.ReadInto(&cfg, config)读取配置信息
  • 调用provider, err := openstack.AuthenticatedClient(cfg.toAuthOptions()) 用于auth openstack
  • 调用identity, err := openstack.NewIdentityV2(provider, gophercloud.EndpointOpts{Availability: gophercloud.AvailabilityAdmin})用于find identity endpoint
  • 调用network, err := openstack.NewNetworkV2(provider, gophercloud.EndpointOpts{Region: cfg.Global.Region})
  • 创建 os := OpenStack{

    identity:    identity,

    network:    network,

    provider:    provider,

    region:     cfg.Global.Region,

    lbOpts:     cfg.LoadBalancer,

    pluginOpts:   cfg.Plugin,

    ExtNetID:    cfg.Global.ExtNetID,

  }

  • 当cfg.Plugin.PluginName 不为nil时:

    • integrationBriage := "br-int",若cfg.Plugin.IntegrationBridge不为"",则设置integrationBriage = cfg.Plugin.IntegrationBridge
    • 调用plugin, _ := plugins.GetNetworkPlugin(cfg.Plugin.PluginName)
    • 若plugin不为nil,则调用plugin.Init(integrationBriage),并且os.Plugin = plugin
  • 最后,返回return &os, nil

// pkg/plugins/plugins.go

// GetNetworkPlugin creates an instance of the named network plugin, or nil if

// the name is unkown. The error return is only used if the named plugin

// was known but failed to initialize

3、func GetNetworkPlugin(name string) (PluginInterface, error)

该函数仅仅调用f, found := plugins[name]获取plugin的Factory函数f(),调用该f()函数生成相应的PluginInterface

(如果相应的Plugin被支持,则相应的包在初始化的时候就已经在init()函数中进行了注册,因此一定能在此时找到)

PluginInterface数据结构如下所示:

type PluginInterface interface {

  SetupInterface(podName, podInfraContainerID string, port *ports.Port, ipcidr, gateway string, dnsServers []string, containerRuntime string) error

  DestroyInterface(podName, podInfraContainerID string, port *ports.Port, containerRuntime string) error

  Init(integrationBridge string) error

}

  

// pkg/kubestack/kubestack.go

4、func NewKubeHandler(driver *common.OpenStack) *kubeHandler

该函数仅仅只是初始化并注册grpc server,生成h := &KubeHandler{driver: driver, server: grpc.NewServer()}

kubeHandler的结构如下所示:

// KubeHandler forwards requests and responses between
// the docker daemon and the plugin.
type KubeHandler struct {
  driver  *common.OpenStack
  server  *grpc.Server
}

  

-------------到此为止,kubestack 初始化完成,接下来为网络的创建过程-------------

// pkg/kubestack/kubestack.go

1、func (h *KubeHandler) CreateNetwork(c context.Context, req *provider.CreateNetworkRequest) (*provider.CommonResponse, error)

1、首先调用req.Network.TenantID = h.driver.ToTenantID(req.Network.TenantID),将tenantName转换为tenantID

2、再调用err := h.driver.CreateNetwork(req.Network)创建网络

Network数据结构如下所示:

type Network struct {
  Name     string
  Uid      string
  TenantID   string
  SegmentID  int32
  Subnets   []*Subnet
  // Status of network
  // Valid value: Initializing, Active, Pending, Failed, Terminating
  Status    string
}

  

Subnet数据结构如下所示:

type Subnet struct {

  Name      string
  Uid       string
  Cidr      string
  Gateway    string
  Tenantid    string
  Dnsservers   []string
  Routes     []*Route
}

  

// pkg/common/openstack.go

2、func (os *OpenStack) CreateNetwork(network *provider.Network) error

1、首先创建opts := networks.CreateOpts{

  Name:      network.Name,

  AdminStateUp:  &adminStateUp,

  TenantID:     network.TenantID,

}

再调用osNet, err := networks.Create(os.network, opts).Extract()创建网络

2、同样调用routerOpts := routers.CreateOpts{

  Name:      network.Name,

  TenantID:     network.TenantID,

  GatewayInfo:   &routers.GatewayInfo{NetworkID: os.ExtNetID},

}

再调用osRouter, err := routers.Create(os.network, routerOpts).Extract()创建router

3、最后,遍历network.Subnets创建子网

  1. 首先创建 subnetOpts := subnets.CreateOpts{

    NetworkID:      networkID,   //其实就是osNet.ID

    CIDR:         sub.Cidr,

    Name:         sub.Name,

    IPVersion:       gophercloud.IPv4,

    TenantID:       network.TenantID,

    GatewaryIP:      &sub.Gateway,

    DNSNameserver:    sub.Dnsservers,

  }

  再调用s, err := subnets.Create(os.network, subnetOpts).Extract()创建子网

  // 将子网加入router中

  2. 创建opts := routers.AddInterfaceOpts{SubnetID: s.ID},

    再调用routers.AddInterface(os.network, osRouter.ID, opts).Extract()

---------------------------------------创建pod-----------------------------------------

// pkg/kubestack/kubestack.go

1、func (h *KubeHandler) SetupPod(c context.Context, req *provider.SetupPodRequest) (*provider.CommonResponse, error)

该函数仅仅是调用h.driver.SetupPod(req.PodName, req.Namespace, req.PodInfraContainerID, req.Network, req.ContainerRuntime)

SetupPodRequest数据结构如下所示:

type SetupPodRequest struct {
  PodName      string
  Namespace     string
  ContainerRuntime  string
  PodInfraContainerID string
  Network       *Network
}

// pkg/common/openstack.go

2、func (os *OpenStack) SetupPod(podName, namespace, podInfraContainerID string, network *provider.Network, containerRuntime string)

1、调用portName := os.BuildPortName(podName, namespace, network.Uid),该函数的作用仅仅是将podNamePrefix和上述三个参数连成一个字符串而已

2、获取dns server的ip,调用networkPorts, err := os.ListPorts(network.Uid, "network:dhcp"),再遍历networkPorts,调用dnsServers = append(dnsServers, p.FixedIPs[0].IPAddress)

3、调用port, err := os.GetPort(portName),从openstack中获取port,如果port不存在,则调用portWithBinding, err := os.CreatePort(network.Uid, network.TenantID, portName, podHostname)创建一个

4、如果port.DeviceOwner和实际的deviceOwner不符,则更新hostname

5、调用subnet, err := os.getProviderSubnet(port.FixedIPs[0].SubnetID)获取子网和网关

6、最后,调用os.Plugin.SetupInterface(podName+"_"+namespace, podInfraContainerID, port, fmt.Sprintf("%s/%d", port.FixedIPs[0].IPAddress, prefixSize), subnet.Gateway, dnsServers, containerRuntime)为pod设置网卡

-----------------------------------OVS plugin实现---------------------------------------

OVSPlugin的数据结构很简单,如下所示:

type OVSPlugin struct {

  IntegrationBridage string

}

  

// pkg/plugins/openvswitch/openvswitch.go

1、func (p *OVSPlugin) Init(integrationBridge string) error

该函数仅仅将p.IntegrationBridage赋值为integrationBridge

// pkg/plugins/openvswitch/openvswitch.go

2、func (p *OVSPlugin) SetupInterface(podName, podInfraContainerID string, port *ports.Port, ipcidr, gatewary string, dnsServers []string, containerRuntime string) error

1、先调用err := p.SetupOVSInterface(podName, podInfraContainerID, port, ipcidr, gatewary, containerRuntime)创建OVS interface

2、再根据containerRuntime的不同,分别调用p.SetupDockerInterface(podName, podInfraContainerID, port, ipcidr, gateway)或者p.SetupHyperInterface(podName, podInfraContainerID, port, ipcidr, gateway, dnsServers)

// pkg/plugins/openvswitch/openvswitch.go

3、func (p *OVSPlugin)  SetupOVSInterface(podName, podInfraContainerID string, port *ports.Port, ipcidr, gateway string, containerRuntime string)

1、该函数调用exec.RunCommand函数创建一个veth pair以及一个bridge,并将其中一个veth加入bridge中

2、调用ovs-vsctl,对另一个veth进行操作

// pkg/plugins/openvswitch/openvswitch.go

4、func (p *OVSPlugin) SetupDockerInterface(podName, podInfraContainerID string, port *ports.Port, ipcidr, gateway string) error

1、先创建一个veth对,tapName和vifName,并且将tapName加入之前创建的bridge中

2、将vifName的MAC地址设置为port.MACAddress

3、根据podInfraContainerID容器的pid找到对应的net ns,并把它软链接到/var/run/netns目录,从而能用ip命令对其直接进行操作。

4、将vifName加入net ns中,再删除其中的eth0网卡,再将vifName重命名为eth0

5、调用`ip addr add dev eth0 ipcidr`添加ip,以及`ip route add default via gateway`创建默认路由

// pkg/plugins/openvswitch/openvswitch.go

5、func (p *OVSPlugin) SetupHyperInterface(podName, podInfraContainerID string, port *ports.Port, ipcidr, gateway string, dnsServers []string)

1、首先获取bridge和tapName

2、创建interfaceSpec := map[string]string{

  "bridge":    bridge,

  "ifname":    tapName,

  "mac":     port.MACAddress,

  "ip":       ipcidr,

  "gateway":   gateway,

} 生成network interface的配置

3、调用podSpec, err := p.getHyperPodSpec(podName)获取原始的hyper配置,并解码至specData中

4、调用specData["interfaces"] = []map[string]string{interfaceSpec}将network interface的配置加入其中

5、在specData["dns"]的基础之上添加dnsServers

6、最后调用newPodSpec, err := json.Marshal(specData)和p.saveHyperPodSpec(string(newPodSpec), podName)将新的hyper配置写入文件中

注:Neutron Port代表的是一个逻辑交换机中的一个虚拟交换机端口。虚拟机实例将自己的网卡和这些端口相连,这些逻辑端口同时定义了接入到它们中的接口的MAC地址和IP地址。当一个IP地址和一个端口关联起来的时候,这意味着这个端口和一个子网相连,因为这个IP地址就是从一个特定子网的allocation pool中获取的。

kubestack 源码分析的更多相关文章

  1. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  2. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  3. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  4. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  5. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  6. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  7. java使用websocket,并且获取HttpSession,源码分析

    转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...

  8. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

  9. ABP源码分析三:ABP Module

    Abp是一种基于模块化设计的思想构建的.开发人员可以将自定义的功能以模块(module)的形式集成到ABP中.具体的功能都可以设计成一个单独的Module.Abp底层框架提供便捷的方法集成每个Modu ...

随机推荐

  1. 推荐一个不错的plist拆解工具,untp

    需要安装python以及pip 中文说明 A command line tool to split TexturePacker published files. install pip install ...

  2. TCP协议的三次握手和四次挥手过程

    TCP是一种面向连接(连接导向)的.可靠的基于字节流的传输层通信协议.TCP将用户数据打包成报文段,它发送后启动一个定时器,另一端收到的数据进行确认.对失序的数据重新排序.丢弃重复数据. 1.TCP/ ...

  3. 接口测试脚本之Jsoup解析HTML

    第一次接触jsoup还是在处理收货地址的时候,当时在写一个下单流程,需要省市区id以及详细门牌号等等,因此同事介绍了jsoup,闲来无事,在此闲扯一番! 1.我们来看下,什么是jsoup,先来看看官方 ...

  4. RIP协议两个版本对不连续子网的支持情况实验

    一.连续子网与不连续子网 我们经常见到说RIPv1不支持不连续子网,仅支持连续子网,那么什么是连续子网,什么是不连续子网呢? l  不连续子网:指在一个网络中,某几个连续由同一主网划分的子网在中间被多 ...

  5. iOS 给tableView设置contentInset不生效?

    给tableView设置contentInset的时候如果tableView中内容比较多,超过一个屏幕,设置的contentInset是生效的,但是呢,如果页面内容比较少,我们会发现设置content ...

  6. ECMall中Widgets模式的布局引擎

    自己做过框架的人,可能都会思考一个问题,模板引擎需要什么特性? Widgets模式,很多系统中都有出现,但对于纯开发人员,不管前端或后台人员来说,都觉得稍微麻烦了一点.因为他将界面硬生生的拆分出了很多 ...

  7. Ubuntu SVN服务器的搭建与配置(转)

    Ubuntu SVN服务器的搭建与配置 一.         安装 sudo apt-get install subversion sudo apt-get install libapache2-sv ...

  8. Squares - poj 2002(hash)

    枚举两个点作为一条边,求出正方形的另外两个点,利用hash查找另外两个点. #include<stdio.h> #include<string.h> #include<s ...

  9. yum 安装出错--"Couldn't resolve host 'mirrors.aliyun.com'"

    1.yum 安装出错 [root@iz25m0z7ik3z ~]#yum install mysql [root@iZ25m0z7ik3Z ~]#yum install mysql Loaded pl ...

  10. 如何给RecyclerView加上滚动条--现在就教你

    时隔许久,我又要更博了,含蓄的话不多说了,今天我们的主题是这个RecyclerView.至于为什么要加个scrollBar?因为我的业务需求是需要一个实现成这样的, 效果图:(可能看起来比较粗糙,但功 ...