kubenetes源码分析之DNS(六)

上一篇介绍了kubends相关代码,但他并不是直接提供服务的,而是dnsmasq-nanny。nanny这个单词是保姆的意思,就是一个dns服务的保姆,挺形象的,那么我们看看这个保姆是如何服务的。
首先看服务启动:

func main() {
    parseFlags()
    glog.V(0).Infof("opts: %v", opts)

    sync := config.NewFileSync(opts.configDir, opts.syncInterval)

    dnsmasq.RunNanny(sync, opts.RunNannyOpts)
}

有两个点需要主要第一是dnsmasq启动参数:

    opts = struct {
        dnsmasq.RunNannyOpts
        configDir    string
        syncInterval time.Duration
    }{
        RunNannyOpts: dnsmasq.RunNannyOpts{
            DnsmasqExec:     "/usr/sbin/dnsmasq",
            RestartOnChange: false,
        },
        configDir:    "/etc/k8s/dns/dnsmasq-nanny",
        syncInterval: 10 * time.Second,
    }

制定启动路径和参数目录,当然这些参数也是可以通过外面传入进行修改。
第二个问题是sync文件监听器,当configdir下的配置文件修改后会自动重新加载服务。具体看下面实现:

func (syncSource *kubeFileSyncSource) Periodic() <-chan syncResult {
    // TODO: drive via inotify?
    go func() {
        ticker := syncSource.clock.Tick(syncSource.period)
        for {
            if result, err := syncSource.load(); err != nil {
                glog.Errorf("Error loading config from %s: %v", syncSource.dir, err)
            } else {
                syncSource.channel <- result
            }
            <-ticker
        }
    }()
    return syncSource.channel
}

将变化的结果(配置文件名和文件内容)放到syncSource.channel中。说清楚了这两个问题后,接着回到第一个函数启动服务,

func RunNanny(sync config.Sync, opts RunNannyOpts) {
    defer glog.Flush()

    currentConfig, err := sync.Once()
    if err != nil {
        glog.Errorf("Error getting initial config, using default: %v", err)
        currentConfig = config.NewDefaultConfig()
    }

    nanny := &Nanny{Exec: opts.DnsmasqExec}
    nanny.Configure(opts.DnsmasqArgs, currentConfig)
    if err := nanny.Start(); err != nil {
        glog.Fatalf("Could not start dnsmasq with initial configuration: %v", err)
    }

    configChan := sync.Periodic()

    for {
        select {
        case status := <-nanny.ExitChannel:
            glog.Flush()
            glog.Fatalf("dnsmasq exited: %v", status)
            break
        case currentConfig = <-configChan:
            if opts.RestartOnChange {
                glog.V(0).Infof("Restarting dnsmasq with new configuration")
                nanny.Kill()
                nanny = &Nanny{Exec: opts.DnsmasqExec}
                nanny.Configure(opts.DnsmasqArgs, currentConfig)
                nanny.Start()
            } else {
                glog.V(2).Infof("Not restarting dnsmasq (--restartDnsmasq=false)")
            }
            break
        }
    }
}

先通过nanny.Start()启动服务,下面是for的死循环中select,当配置变化后重启服务。
下面看看nanny.Start()怎么启动服务的

func (n *Nanny) Start() error {
    glog.V(0).Infof("Starting dnsmasq %v", n.args)

    n.cmd = exec.Command(n.Exec, n.args...)
    stderrReader, err := n.cmd.StderrPipe()
    if err != nil {
        return err
    }

    stdoutReader, err := n.cmd.StdoutPipe()
    if err != nil {
        return err
    }

    if err := n.cmd.Start(); err != nil {
        return err
    }

    logToGlog := func(stream string, reader io.Reader) {
        bufReader := bufio.NewReader(reader)
        for {
            bytes, err := bufReader.ReadBytes('\n')
            if len(bytes) > 0 {
                glog.V(1).Infof("%v", string(bytes))
            }
            if err == io.EOF {
                glog.V(1).Infof("%v", string(bytes))
                glog.Warningf("Got EOF from %v", stream)
                return
            } else if err != nil {
                glog.V(1).Infof("%v", string(bytes))
                glog.Errorf("Error reading from %v: %v", stream, err)
                return
            }
        }
    }

    go logToGlog("stderr", stderrReader)
    go logToGlog("stdout", stdoutReader)

    n.ExitChannel = make(chan error)
    go func() {
        n.ExitChannel <- n.cmd.Wait()
    }()

    return nil
}

就是通过exec.Command(n.Exec, n.args…)启动dnsmasq服务。停止服务就简单了Process.Kill()停止进程,并把cmd(/usr/sbin/dnsmasq)置空,和上面对应:

func (n *Nanny) Kill() error {
    glog.V(0).Infof("Killing dnsmasq")
    if n.cmd == nil {
        return fmt.Errorf("Process is not running")
    }

    if err := n.cmd.Process.Kill(); err != nil {
        glog.Errorf("Error killing dnsmasq: %v", err)
        return err
    }

    n.cmd = nil

    return nil
}

dnsmasq-nanny服务相对比较简单,主要还是依赖dnsmasq。还剩最后一个细节没有交代清楚就是kubedns和dnsmasq-nanny什么关系,看看dnsmasq-nanny的启动参数就明白了:

        - --server=/__PILLAR__DNS__DOMAIN__/127.0.0.1#10053
        - --server=/in-addr.arpa/127.0.0.1#10053
        - --server=/ip6.arpa/127.0.0.1#10053

其实kubedns是dnsmasq的upstream,是它的上游服务器,当然如果你的局域网内还有自己DNS域名服务器,也可以都加入进来。所以他是一个很好中继器。关于dnsmasq本身我还想讲解一下,它有两个重要的功能:dns服务和dncp服务。

关于dhcp服务

# dhcp动态分配的地址范围
dhcp-range=192.168.1.50,192.168.1.150,48h
# dhcp服务的静态绑定
dhcp-host=00:0C:29:5E:F2:6F,192.168.1.201,os02

关于dns服务

# 设置静态IP解析相当于hosts配置
address=/doubleclick.net/127.0.0.1

可以设置upstream

server=10.36.8.40

还可以设置某个域名的upstream

server=/cluster.local/172.30.0.1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柳清风09

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值