所有文章

DOCKER源码-创建网络

Daemon结构体

daemon/daemon.go

type Daemon struct {
    // ... 省略多行 ...
    EventsService     *events.Events
    netController     libnetwork.NetworkController
    volumes           *volumesservice.VolumesService
    discoveryWatcher  discovery.Reloader
    // ... 省略多行 ...
}

Daemon中的netController字段负责网络相关操作,它是一个接口,其接口的定义和实现都在vendor/github.com/docker/libnetwork/controller.go文件中。

controller结构体

controller结构体实现了libnetwork.NetworkController接口,Daemon对象的对网络设备的增删改查都是调用controller对象的相关函数,其中创建网络的关键函数如下:
vendor/github.com/docker/libnetwork/controller.go

func (c *controller) NewNetwork(networkType, name string, id string, options ...NetworkOption) (Network, error) {
    // ... 省略多行 ...
    network := &network{
        name:             name,
        networkType:      networkType,
        generic:          map[string]interface{}{netlabel.GenericData: make(map[string]string)},
        ipamType:         defaultIpam,
        id:               id,
        created:          time.Now(),
        ctrlr:            c,
        persist:          true,
        drvOnce:          &sync.Once{},
        loadBalancerMode: loadBalancerModeDefault,
    }
    // ... 省略多行 ...
    err = c.addNetwork(network)
    // ... 省略多行 ...
    return network, nil
}

根据驱动创建网络

addNetwork()函数中先根据network对象的网络类型获取相应的驱动,然后调用该驱动对象的d.CreateNetwork()函数:
vendor/github.com/docker/libnetwork/controller.go

func (c *controller) addNetwork(n *network) error {
    d, err := n.driver(true)
    if err != nil {
        return err
    }
    // Create the network
    if err := d.CreateNetwork(n.id, n.generic, n, n.getIPData(4), n.getIPData(6)); err != nil {
        return err
    }
    n.startResolver()
    return nil
}

关键函数

以bridge网络驱动为例,展开其CreateNetwork()函数,它主要对一些关键的配置信息做检查,比如验证IPv4和IPv6的地址是否有误:
vendor/github.com/docker/libnetwork/drivers/bridge/bridge.go

func (d *driver) CreateNetwork(id string, option map[string]interface{}, nInfo driverapi.NetworkInfo, ipV4Data, ipV6Data []driverapi.IPAMData) error {
    // ... 省略多行 ...
    if err = d.createNetwork(config); err != nil {
        return err
    }
    return d.storeUpdate(config)
}

分步骤创建网络设备

vendor/github.com/docker/libnetwork/drivers/bridge/bridge.go

func (d *driver) createNetwork(config *networkConfiguration) (err error) {
    // ... 省略多行 ...
    for _, step := range []struct {
        Condition bool
        Fn        setupStep
    }{
        // 如果需要,在桥上启用IPv6。我们甚至对以前存在的桥这样做,
        // 因为它可能是在这里从以前的安装IPv6还不受支持,需要分配一个IPv6链接本地地址。
        {config.EnableIPv6, setupBridgeIPv6},
        // 我们确保在现有设备的情况下,网桥具有预期的dipv4和IPv6地址。
        {bridgeAlreadyExists && !config.InhibitIPv4, setupVerifyAndReconcile},
        // 启用IPv6转发
        {enableIPv6Forwarding, setupIPv6Forwarding},
        // 设置环回地址路由
        {!d.config.EnableUserlandProxy, setupLoopbackAddressesRouting},
        // 设置 IPTables.
        {d.config.EnableIPTables, network.setupIPTables},
        // 我们希望跟踪firewalld配置,以便在启动/重新加载时能够正确应用规则
        {d.config.EnableIPTables, network.setupFirewalld},
        // 设置IPv4的默认网关
        {config.DefaultGatewayIPv4 != nil, setupGatewayIPv4},
        // 设置IPv6的默认网关
        {config.DefaultGatewayIPv6 != nil, setupGatewayIPv6},
        // 添加网络间通信规则
        {d.config.EnableIPTables, setupNetworkIsolationRules},
        // 如果ICC关闭且启用了IPTables,则配置桥接网络过滤
        {!config.EnableICC && d.config.EnableIPTables, setupBridgeNetFiltering},
    } {
        if step.Condition {
            bridgeSetup.queueStep(step.Fn)
        }
    }
    return bridgeSetup.apply()
}

上面for循环中定义了10个函数,每个函数负责一项配置,我为每一步加上了中文注释,这些步骤被放在bridgeSetup对象中,最后调用bridgeSetup.apply()执行里面的每一个函数。


编写日期:2020-03-13