转载:
https://hansedong.github.io/2018/11/20/9/
https://hansedong.github.io/2018/11/22/10/
文章目录
kube-dns
作用:主要监听了两个资源
- Service资源
- Endpoints资源
为什么需要监控 Endpoints 资源?
// 开启一个 KubeDNS 处理实例
func NewKubeDNS(client clientset.Interface, clusterDomain string, timeout time.Duration, configSync config.Sync) *KubeDNS {
kd := &KubeDNS{
kubeClient: client,
domain: clusterDomain,
cache: treecache.NewTreeCache(),
cacheLock: sync.RWMutex{},
nodesStore: kcache.NewStore(kcache.MetaNamespaceKeyFunc),
reverseRecordMap: make(map[string]*skymsg.Service),
clusterIPServiceMap: make(map[string]*v1.Service),
domainPath: util.ReverseArray(strings.Split(strings.TrimRight(clusterDomain, "."), ".")),
initialSyncTimeout: timeout,
configLock: sync.RWMutex{},
configSync: configSync,
}
// 监听并处理 Endpoints 资源
kd.setEndpointsStore()
// 监听并处理 Services 资源
kd.setServicesStore()
return kd
}
// setServicesStore 负责处理 Service 资源
func (kd *KubeDNS) setServicesStore() {
// Returns a cache.ListWatch that gets all changes to services.
kd.servicesStore, kd.serviceController = kcache.NewInformer(
kcache.NewListWatchFromClient(
kd.kubeClient.Core().RESTClient(),
"services",
v1.NamespaceAll,
fields.Everything()),
&v1.Service{},
resyncPeriod,
// 这里也可以看出来,它其实主要针对 Service 的 增删改做 handle 处理
kcache.ResourceEventHandlerFuncs{
AddFunc: kd.newService,
DeleteFunc: kd.removeService,
UpdateFunc: kd.updateService,
},
)
}
// 同上
func (kd *KubeDNS) setEndpointsStore() {
// Returns a cache.ListWatch that gets all changes to endpoints.
kd.endpointsStore, kd.endpointsController = kcache.NewInformer(
kcache.NewListWatchFromClient(
kd.kubeClient.Core().RESTClient(),
"endpoints",
v1.NamespaceAll,
fields.Everything()),
&v1.Endpoints{},
resyncPeriod,
kcache.ResourceEventHandlerFuncs{
AddFunc: kd.handleEndpointAdd,
UpdateFunc: kd.handleEndpointUpdate,
// If Service is named headless need to remove the reverse dns entries.
DeleteFunc: kd.handleEndpointDelete,
},
)
}
我们看一下,如果 K8S 有 Service 资源创建出来,kube-dns 容器都做些什么
// 针对 K8S 中 Service 资源的创建,做处理
func (kd *KubeDNS) newService(obj interface{}) {
if service, ok := assertIsService(obj); ok {
glog.V(3).Infof("New service: %v", service.Name)
glog.V(4).Infof("Service details: %v", service)
// 1、如果 Service 是 ExternaName 类型,则创建 cname 记录
// 稍微提一下,K8S 中的 Service,有几种类型:ClusterIP、NodePort、LoadBalancer、ExternaName
// ExternalName services are a special kind that return CNAME records
if service.Spec.Type == v1.ServiceTypeExternalName {
kd.newExternalNameService(service)
return
}
// 2、如果是无头服务,则处理无头服务方式的DNS记录(A记录),无头服务的域名记录有些不同,所以这里是单独进行处理的
// 需要说明的是,我们刚刚提到的 Endpoints 资源,其实主要就是用在无头服务上的。
// if ClusterIP is not set, a DNS entry should not be created
if !v1.IsServiceIPSet(service) {
if err := kd.newHeadlessService(service); err != nil {
glog.Errorf("Could not create new headless service %v: %v", service.Name, err)
}
return
}
if len(service.Spec.Ports) == 0 {
glog.Warningf("Service with no ports, this should not have happened: %v",
service)
}
// 3、创建正常的 Service DNS 记录
kd.newPortalService(service)
}
}
上面提到,Service 的创建操作,会涉及到 newHeadlessService 无头服务域名记录的操作,具体如下:
// 创建无头服务Service的域名记录
// Generates skydns records for a headless service.
func (kd *KubeDNS) newHeadlessService(service *v1.Service) error {
// Create an A record for every pod in the service.
// This record must be periodically updated.
// Format is as follows:
// For a service x, with pods a and b create DNS records,
// a.x.ns.domain. and, b.x.ns.domain.
key, err := kcache.MetaNamespaceKeyFunc(service)
if err != nil {
return err
}
// 根据 Service 名称获取key,在根据 Key,获取这个 Service 下的 Endpoints,用来生成特殊的无头服务的域名记录
e, exists, err := kd.endpointsStore.GetByKey(key)
if err != nil {
return fmt.Errorf("failed to get endpoints object from endpoints store - %v", err)
}
// 如果这个 Service 下没有 Endpoints,将不生成域名记录,一旦有endpoints之后,就会生成。
if !exists {
glog.V(1).Infof("Could not find endpoints for service %q in namespace %q. DNS records will be created once endpoints show up.",
service.Name, service.Namespace)
return nil
}
if e, ok := e.(*v1.Endpoints); ok {
return kd.generateRecordsForHeadlessService(e, service)
}
return nil
}
如果 Service 下没有Endpoints,不处理,一旦有 Endpoints 产生,立即生成域名记录:
// 根据 Endpoints,创建无头服务记录
func (kd *KubeDNS) addDNSUsingEndpoints(e *v1.Endpoints) error {
// 先根据 Endpoints 超出其属于哪个 Service
svc, err := kd.getServiceFromEndpoints(e)
if err != nil {
return err
}
// 判断这个 Service 是不是无头服务的 Service,如果不是,直接返回
if svc == nil || v1.IsServiceIPSet(svc) || svc.Spec.Type == v1.ServiceTypeExternalName {
// No headless service found corresponding to endpoints object.
return nil
}
// 如果是无头服务的 Service,生成域名记录
return kd.generateRecordsForHeadlessService(e, svc)
}