当前位置:网站首页>flannel 原理 之 子网划分
flannel 原理 之 子网划分
2022-04-23 14:11:00 【Mrpre】
flannel 原理 之 子网划分
Docker
通常情况下, 2台物理机上分别安装Docker,Docker分别在2台物理机上,docker0的网桥,其IP地址属于私网网段,例如物理机地址是10.x.x.x,docker0地址通常是192.x.x.x。 任何在物理机上启动的container,其分配的eth0地址都是 192.x.x.x。 但是2台独立的物理机上的container之间是无法通信的,因为物理网络里是没有192.x.x.x网段的信息,无法对其进行路由,更何况物理网络作为基础设施,也不可能动态的去添加容器网络相关的路由。
flannel 解决的问题,其实就是 部署在多台不同物理机(ECS)上的容器,如何进行网络通信。
flannel
子网划分
flannel无论哪种运行模式,都会对物理机的docker配置信息进行修改,例如 flannel启动之后会修改 /usr/lib/systemd/system/docker.service 注入 DOCKER_OPT_BIP="–bip=xx.xx.xx.xx/24" 使得当前机器上启动的的容器以此网段作为容器的地址。而具体网段信息是保存在etcd中的,每台node上面的flannel都监听了这个,flannel读取etcd解析,然后确定自己网段,修改docker配置。
ETCD中提前存储了flannel的网段,例如ETCDCTL_API=2 etcdctl mk /atomic.io/network/config '{ "Network": "182.48.0.0/16" }'
其中配置格式是json格式,需要和flannel解析格式匹配。该配置告诉所有flannel进程,flannel所在的node上申请的容器ip,必须在这个网段之内。
type Config struct {
Network ip.IP4Net
SubnetMin ip.IP4
SubnetMax ip.IP4
SubnetLen uint
BackendType string `json:"-"`
Backend json.RawMessage `json:",omitempty"`
}
flannel读取网段配置以及解析流程
// Fetch the network config (i.e. what backend to use etc..).
config, err := getConfig(ctx, sm)
if err == errCanceled {
wg.Wait()
os.Exit(0)
}
func getConfig(ctx context.Context, sm subnet.Manager) (*subnet.Config, error) {
// Retry every second until it succeeds
for {
config, err := sm.GetNetworkConfig(ctx)
if err != nil {
log.Errorf("Couldn't fetch network config: %s", err)
} else if config == nil {
log.Warningf("Couldn't find network config: %s", err)
} else {
log.Infof("Found network config - Backend type: %s", config.BackendType)
return config, nil
}
select {
case <-ctx.Done():
return nil, errCanceled
case <-time.After(1 * time.Second):
fmt.Println("timed out")
}
}
}
# subnet/etcdv2/local_manager.go 读取etcd中的网段信息
func (m *LocalManager) GetNetworkConfig(ctx context.Context) (*Config, error) {
cfg, err := m.registry.getNetworkConfig(ctx)
if err != nil {
return nil, err
}
//获取到 { "Network": "182.48.0.0/16" },然后解析,解析的例如,182.48.0.0/16这个网段,解析后 SubnetMin是182.48.1.0,SubnetMax是182.48.255.0
return ParseConfig(cfg)
}
# subnet/etcdv2/registry.go
func (esr *etcdSubnetRegistry) getNetworkConfig(ctx context.Context) (string, error) {
key := path.Join(esr.etcdCfg.Prefix, "config")
resp, err := esr.client().Get(ctx, key, &etcd.GetOptions{
Quorum: true})
if err != nil {
return "", err
}
//通过etcd获取到 { "Network": "182.48.0.0/16" }
return resp.Node.Value, nil
}
flannel读取到etcd数据后,由于有多台node的存在,每台node需要再次根据16位掩码,确定自己的子网掩码,这样,每台node上容器启动的ip都不会冲突,在ParseConfig中,已经有逻辑确定了16位掩码情况下子网网段为24掩码,其他情况下是 为 n+2。24位掩码的意思值,当前node生成容器的ip是 182.48.{y}.x,x为 0~254。那么就存在一个问题,就是每台node上面{y}肯定不能配置一样。
# main.go
bn, err := be.RegisterNetwork(ctx, &wg, config)
if err != nil {
log.Errorf("Error registering network: %s", err)
cancel()
wg.Wait()
os.Exit(1)
}
# 路径和架构有关
func (be *UdpBackend) RegisterNetwork(ctx context.Context, wg *sync.WaitGroup, config *subnet.Config) (backend.Network, error) {
l, err := be.sm.AcquireLease(ctx, &attrs)
switch err {
case nil:
......
}
}
func (m *LocalManager) AcquireLease(ctx context.Context, attrs *LeaseAttrs) (*Lease, error) {
config, err := m.GetNetworkConfig(ctx)
if err != nil {
return nil, err
}
for i := 0; i < raceRetries; i++ {
l, err := m.tryAcquireLease(ctx, config, attrs.PublicIP, attrs)
switch err {
case nil:
return l, nil
case errTryAgain:
continue
default:
return nil, err
}
}
return nil, errors.New("Max retries reached trying to acquire a subnet")
}
tryAcquireLease
函数中,先从etcd读取老的配置,查看是否当前node存在子网配置信息,通常如果只是flannel重启并且之前启动成功过,那么此时都会读到配置
flannel中,存入etcd的格式的路径是 $PREFIX/subnets/,key为网段,value为node的ip。
$ETCDCTL_API=2 etcdctl ls /coreos.com/network/subnets
/coreos.com/network/subnets/182.48.56.0-24
/coreos.com/network/subnets/182.48.17.0-24
$ETCDCTL_API=2 etcdctl get /coreos.com/network/subnets/182.48.56.0-24
{
"PublicIP":"11.238.116.75"}
func (m *LocalManager) tryAcquireLease(ctx context.Context, config *Config, extIaddr ip.IP4, attrs *LeaseAttrs) (*Lease, error) {
leases, _, err := m.registry.getSubnets(ctx)
if err != nil {
return nil, err
}
// Try to reuse a subnet if there's one that matches our IP
//遍历获取到的所有key,判断其value是否是自己node的ip,是表示已经有配置信息的,使用之即可
if l := findLeaseByIP(leases, extIaddr); l != nil {
// Make sure the existing subnet is still within the configured network
if isSubnetConfigCompat(config, l.Subnet) {
log.Infof("Found lease (%v) for current IP (%v), reusing", l.Subnet, extIaddr)
}
}
tryAcquireLease
函数中,如果没有当前node的配置,就创建一个配置。防止多个node的flannel并发创建相同的网段的手段也很简单,使用了参数prevExist=false防止同时写成功;失败后,外部循环再次进行创建子网的操作,直到成功。
if sn.Empty() {
// no existing match, grab a new one
sn, err = m.allocateSubnet(config, leases)
if err != nil {
return nil, err
}
}
exp, err := m.registry.createSubnet(ctx, sn, attrs, subnetTTL)
switch {
case err == nil:
log.Infof("Allocated lease (%v) to current node (%v) ", sn, extIaddr)
return &Lease{
Subnet: sn,
Attrs: *attrs,
Expiration: exp,
}, nil
case isErrEtcdNodeExist(err):
return nil, errTryAgain
default:
return nil, err
}
至此,多个物理机(Node)上的flannel进程,从182.48.0.0/16这个配置的网段中,生成了自己的子网,例如 182.48.1.0/24,182.48.2.0/24,并且将配置保存在etcd上面,以保证其他节点不占用。并且以此子网,修改了Docker启动参数,是的Docker启动的容器以子网为准。
版权声明
本文为[Mrpre]所创,转载请带上原文链接,感谢
https://wonderful.blog.csdn.net/article/details/115180077
边栏推荐
- Some experience of using dialogfragment and anti stepping pit experience (getactivity and getdialog are empty, cancelable is invalid, etc.)
- grep无法重定向到文件的问题
- Introduction to loan market quotation interest rate (LPR) and loan benchmark interest rate
- Preview CSV file
- Gartner预测云迁移规模大幅增长;云迁移的优势是什么?
- XX project structure notes
- 使用Executors类快速创建线程池
- openstack理论知识
- 金融行业云迁移实践 平安金融云整合HyperMotion云迁移解决方案,为金融行业客户提供迁移服务
- 线程组ThreadGroup使用介绍+自定义线程工厂类实现ThreadFactory接口
猜你喜欢
处理 mkdir:无法创建目录“aaa“:只读文件系统
容灾有疑问?点这里
常见存储类型和FTP主被动模式解析
Some good articles on pthread multithreading
统信UOS PHP7.2.3升级至PHP7.2.24
Notes on Visio drawing topology
Tongxin UOS uninstall php7 2.24, install php7 4.27 ; Uninstall and then install PHP 7.2.34
x509证书cer格式转pem格式
使用Executors类快速创建线程池
多云数据流转?云上容灾?年前最后的价值内容分享
随机推荐
sar命令详解
Web page, adaptive, proportional scaling
mysql 5.1升级到5.67
void*是怎样的存在?
获取线程返回值Future接口与FutureTask类使用介绍
MySQL数据库讲解(十)
Five ways of using synchronized to remove clouds and fog are introduced
KVM学习资源
Mysql的安装过程(已经安装成功的步骤说明)
Introduction to the use of semaphore for inter thread control
微信小程序客服接入,实现发送和接收消息
Use the executors class to quickly create a thread pool
Essential difference between restful WebService and gSOAP webservice
什么是云迁移?云迁移的四种模式分别是?
Operation instructions of star boundary automatic text translator (advanced version)
Logback logger and root
mysql 5.1升级到5.68
微信小程序将原生请求通过es6的promise来进行优化
gif转为静态图片处理
DP energy Necklace