源码地址:https://github.com/polarismesh/polaris-sidecar
polaris-sidecar 作为 polaris 的本地边车代理,提供两个可选功能模式:
type NamingResolver interface {
// Name will return the name to resolver
Name() string
// Initialize will init the resolver on startup
Initialize(c *ConfigEntry) error
// Start the plugin runnable
Start(context.Context)
// Destroy will destroy the resolver on shutdown
Destroy()
// ServeDNS is like dns.Handler except ServeDNS may return an response or nil
ServeDNS(context.Context, dns.Question) *dns.Msg
}
dns和mesh两种模式都分别实现了这几个接口
func newAgent(configFile string, bootConfig *BootConfig) (*Agent, error) {
var err error
polarisAgent := &Agent{}
polarisAgent.config, err = parseYamlConfig(configFile, bootConfig)
if nil != err {
log.Errorf("[agent] fail to parse sidecar config, err: %v", err)
return nil, err
}
nameservers, searchNames := parseResolvConf(polarisAgent.config.bindLocalhost())
log.Infof("[agent] finished to parse /etc/resolv.conf, nameservers %s, search %s", nameservers, searchNames)
if len(polarisAgent.config.Recurse.NameServers) == 0 {
polarisAgent.config.Recurse.NameServers = nameservers
}
log.Infof("[agent] finished to parse sidecar config, current active config is %s", *polarisAgent.config)
// 初始化日志打印
err = log.Configure(polarisAgent.config.Logger)
log.Infof("[agent] success to init log config")
if err != nil {
return nil, err
}
for _, resolverCfg := range polarisAgent.config.Resolvers {
if !resolverCfg.Enable {
log.Infof("[agent] resolver %s is not enabled", resolverCfg.Name)
continue
}
name := resolverCfg.Name
handler := resolver.NameResolver(name)
if nil == handler {
log.Errorf("[agent] resolver %s is not found", resolverCfg.Name)
return nil, fmt.Errorf("fail to lookup resolver %s, consider it's not registered", name)
}
err = handler.Initialize(resolverCfg)
if nil != err {
for _, initHandler := range polarisAgent.resolvers {
initHandler.Destroy()
}
log.Errorf("[agent] fail to init resolver %s, err: %v", resolverCfg.Name, err)
return nil, err
}
log.Infof("[agent] finished to init resolver %s", resolverCfg.Name)
polarisAgent.resolvers = append(polarisAgent.resolvers, handler)
}
recurseAddresses := make([]string, 0, len(polarisAgent.config.Recurse.NameServers))
for _, nameserver := range polarisAgent.config.Recurse.NameServers {
recurseAddresses = append(recurseAddresses, fmt.Sprintf("%s:53", nameserver))
}
polarisAgent.udpServer = &dns.Server{
Addr: polarisAgent.config.Bind + ":" + strconv.Itoa(polarisAgent.config.Port), Net: "udp"}
polarisAgent.udpServer.Handler = &dnsHandler{
protocol: "udp",
resolvers: polarisAgent.resolvers,
searchNames: searchNames,
recursorTimeout: time.Duration(polarisAgent.config.Recurse.TimeoutSec) * time.Second,
recursors: recurseAddresses,
recurseEnable: polarisAgent.config.Recurse.Enable,
}
polarisAgent.tcpServer = &dns.Server{
Addr: polarisAgent.config.Bind + ":" + strconv.Itoa(polarisAgent.config.Port), Net: "tcp"}
polarisAgent.tcpServer.Handler = &dnsHandler{
protocol: "tcp",
resolvers: polarisAgent.resolvers,
searchNames: searchNames,
recursorTimeout: time.Duration(polarisAgent.config.Recurse.TimeoutSec) * time.Second,
recursors: recurseAddresses,
recurseEnable: polarisAgent.config.Recurse.Enable,
}
return polarisAgent, nil
}
上面代码主要逻辑如下:
func (p *Agent) Start(ctx context.Context) error {
for _, handler := range p.resolvers {
handler.Start(ctx)
log.Infof("[agent] success to start resolver %s", handler.Name())
}
errChan := make(chan error)
go func() {
errChan <- p.tcpServer.ListenAndServe()
}()
go func() {
errChan <- p.udpServer.ListenAndServe()
}()
var recvErrCounts int
defer func() {
for _, handler := range p.resolvers {
handler.Destroy()
}
}()
for {
select {
case err := <-errChan:
if nil != err {
return err
}
recvErrCounts++
if recvErrCounts == 2 {
return nil
}
case <-ctx.Done():
return nil
}
}
}
主要逻辑如下:
略
func (r *resolverMesh) Start(ctx context.Context) {
interval := time.Duration(r.config.ReloadIntervalSec) * time.Second
go func() {
ticker := time.NewTicker(interval)
defer ticker.Stop()
var currentServices map[string]struct{}
for {
select {
case <-ticker.C:
services, err := r.registry.GetCurrentNsService()
if err != nil {
log.Errorf("[mesh] error to get services, err: %v", err)
continue
}
if ifServiceListChanged(currentServices, services) {
log.Infof("[Mesh] services lookup are %v", services)
r.localDNSServer.UpdateLookupTable(services, r.config.DNSAnswerIp)
currentServices = services
}
case <-ctx.Done():
return
}
}
}()
}
主要流程如下: