大纲:nginx
• Kubernetes中如何发现服务git
• 如何发现Pod提供的服务github
• 如何使用Service发现服务服务器
• 如何使用kube-dns发现服务负载均衡
• kube-dns原理框架
• 组成dom
• 域名格式curl
• 配置分布式
注:本次分享内容基于Kubernetes 1.2版本!ide
下面从一个简单的例子开始讲解。
◆ 发现Pod提供的服务
首先使用nginx-deployment.yaml文件建立一个Nginx Deployment,文件内容如图所示:
首先建立两个运行Nginx服务的Pod:
使用kubectl create -f nginx-deployment.yaml指令建立,这样即可以获得两个运行nginx服务的Pod。待Pod运行以后查看一下它们的IP,并在k8s集群内经过podIP和containerPort来访问Nginx服务:
获取Pod IP:
在集群内访问Nginx服务:
看到这里相信不少人会有如下疑问:
1. 每次收到获取podIP太扯了,总不能每次都要手动改程序或者配置才能访问服务吧,要怎么提早知道podIP呢?
2. Pod在运行中可能会重建,IP变了怎么解?
3. 如何在多个Pod中实现负载均衡嘞?
这些问题使用k8s Service就能够解决。
◆ 使用Service发现服务
下面为两个Nginx Pod建立一个Service。使用nginx-service.yaml文件进行建立,文件内容以下:
建立以后,仍须要获取Service的Cluster-IP,再结合Port访问Nginx服务。
Service能够将pod IP封装起来,即便Pod发生重建,依然能够经过Service来访问Pod提供的服务。此外,Service还解决了负载均衡的问题,你们能够多访问几回Service,而后经过kubectl logs <Pod Name>来查看两个Nginx Pod的访问日志来确认。
获取IP:
在集群内访问Service:
虽然Service解决了Pod的服务发现和负载均衡问题,但存在着相似的问题:不提早知道Service的IP,仍是须要改程序或配置啊。看到这里有没有感受身体被掏空?
接下来聊聊kube-dns是如何解决上面这个问题的。
◆ 使用kube-dns发现服务
kube-dns能够解决Service的发现问题,k8s将Service的名称当作域名注册到kube-dns中,经过Service的名称就能够访问其提供的服务。
可能有人会问若是集群中没有部署kube-dns怎么办?不要紧,实际上kube-dns插件只是运行在kube-system命名空间下的Pod,彻底能够手动建立它。能够在k8s源码(v1.2)的cluster/addons/dns目录下找到两个模板(skydns-rc.yaml.in和skydns-svc.yaml.in)来建立,为你们准备的完整示例文件会在分享结束后提供获取方式,PPT中只截取了部份内容。
经过skydns-rc.yaml文件建立kube-dns Pod,其中包含了四个containers,这里开始简单过一下文件的主要部分,稍后作详细介绍。
第一部分能够看到kube-dns使用了RC来管理Pod,能够提供最基本的故障重启功能。
建立kube-dns Pod,其中包含了4个containers
接下来是第一个容器 etcd ,它的用途是保存DNS规则。
第二个容器 kube2sky ,做用是写入DNS规则。
第三个容器是 skydns ,提供DNS解析服务。
最后一个容器是 healthz ,提供健康检查功能。
有了Pod以后,还须要建立一个Service以便集群中的其余Pod访问DNS查询服务。经过skydns-svc.yaml建立Service,内容以下:
建立完kube-dns Pod和Service,而且Pod运行后,即可以访问kube-dns服务。
下面建立一个Pod,并在该Pod中访问Nginx服务:
建立以后等待kube-dns处于运行状态
再新建一个Pod,经过其访问Nginx服务
在curl-util Pod中经过Service名称访问my-nginx Service:
只要知道须要的服务名称就能够访问,使用kube-dns发现服务就是那么简单。
虽然领略了使用kube-dns发现服务的便利性,但相信有不少人也是一头雾水:kube-dns到底怎么工做的?在集群中启用了kube-dns插件,怎么就能经过名称访问Service了呢?
◆ Kube-dns组成
以前已经了解到kube-dns是由四个容器组成的,它们扮演的角色能够经过下面这张图来理解。
其中:
● SkyDNS是用于服务发现的开源框架,构建于etcd之上。做用是为k8s集群中的Pod提供DNS查询接口。项目托管于https://github.com/skynetservices/skydns
● etcd是一种开源的分布式key-value存储,其功能与ZooKeeper相似。在kube-dns中的做用为存储SkyDNS须要的各类数据,写入方为kube2sky,读取方为SkyDNS。项目托管于https://github.com/coreos/etcd。
● kube2sky是k8s实现的一个适配程序,它经过名为kubernetes的Service(经过kubectl get svc能够查看到该Service,由集群自动建立)调用k8s的list和watch API来监听k8s Service资源的变动,从而修改etcd中的SkyDNS记录。代码能够在k8s源码(v1.2)的cluster/addons/dns/kube2sky/目录中找到。
● exec-healthz是k8s提供的一种辅助容器,多用于side car模式中。它的原理是按期执行指定的Linux指令,从而判断当前Pod中关键容器的健康状态。在kube-dns中的做用就是经过nslookup指令检查DNS查询服务的健康状态,k8s livenessProbe经过访问exec-healthz提供的Http API了解健康状态,并在出现故障时重启容器。其源码位于https://github.com/kubernetes/contrib/tree/master/exec-healthz。
● 从图中能够发现,Pod查询DNS是经过ServiceName.Namespace子域名来查询的,但在以前的示例中只用了Service名称,什么原理呢?其实当咱们只使用Service名称时会默认Namespace为default,而上面示例中的my-nginx Service就是在default Namespace中,所以是能够正常运行的。关于这一点,后续再深刻介绍。
● skydns-rc.yaml中能够发现livenessProbe是设置在kube2sky容器中的,其意图应该是但愿经过重启kube2sky来从新写入DNS规则。
◆ 域名格式
接下来了解一下kube-dns支持的域名格式,具体为:<service_name>.<namespace>.svc.<cluster_domain>。
其中cluster_domain可使用kubelet的--cluster-domain=SomeDomain参数进行设置,同时也要保证kube2sky容器的启动参数中--domain参数设置了相同的值。一般设置为cluster.local。那么以前示例中的my-nginx Service对应的完整域名就是my-nginx.default.svc.cluster.local。看到这里,相信不少人会有疑问,既然完整域名是这样的,那为何在Pod中只经过Service名称和Namespace就能访问Service呢?下面来解释其中缘由。
◆ 域名解析配置
为了在Pod中调用其余Service,kubelet会自动在容器中建立域名解析配置(/etc/resolv.conf),内容为:
感兴趣的能够在网上查找一些resolv.conf的资料来了解具体的含义。之因此可以经过Service名称和Namespace就能访问Service,就是由于search配置的规则。在解析域名时会自动拼接成完整域名去查询DNS。
刚才提到的kubelet --cluster-domain参数与search的具体配置是相对应的。而kube2sky容器的--domain参数影响的是写入到etcd中的域名,kube2sky会获取Service的名称和Namespace,并使用--domain参数拼接完整域名。这也就是让两个参数保持一致的缘由。
◆ NS相关配置
kube-dns可让Pod发现其余Service,那Pod又是如何自动发现kube-dns的呢?在上一节中的/etc/resolv.conf中能够看到nameserver,这个配置就会告诉Pod去哪访问域名解析服务器。
相应的,能够在以前提到的skydns-svc.yaml中看到spec.clusterIP配置了相同的值。一般来讲建立一个Service并不须要指定clusterIP,k8s会自动为其分配,但kube-dns比较特殊,须要指定clusterIP使其与/etc/resolv.conf中的nameserver保持一致。
修改nameserver配置一样须要修改两个地方,一个是kubelet的--cluster-dns参数,另外一个就是kube-dns Service的clusterIP。
接下来从新梳理一下本文的主要内容:
● 在k8s集群中,服务是运行在Pod中的,Pod的发现和副本间负载均衡是咱们面临的问题。
● 经过Service能够解决这两个问题,但访问Service也须要对应的IP,所以又引入了Service发现的问题。
● 得益于kube-dns插件,咱们能够经过域名来访问集群内的Service,解决了Service发现的问题。
● 为了让Pod中的容器可使用kube-dns来解析域名,k8s会修改容器的/etc/resolv.conf配置。
有了以上机制的保证,就能够在Pod中经过Service名称和namespace很是方便地访问对应的服务了。
1. 问: 请问若是公司已有的应用接入的话,那么现有的没有接入的应用就没法访问了,由于这个服务发现是k8s集群内部的,外部没法访问。主要是k8s集群内的服务和集群外的己有的生产的域名访问如何实现,能在kube-dns整合吗?
答:两个问题能够抽象为k8s集群内与集群外服务连通性问题,咱们从两个方面讲:
1、集群内访问集群外
这个问题比较简单,集群内的Pod会继承Node上的DNS解析规则。所以只要Node能够访问的服务,Pod中也能够访问到。
另外,在1.4版本中,k8s支持了一种ExternalName类型的Service,能够与一个公网域名绑定,经过该Service能够访问对应公网服务。
2、集群外访问集群内
1. 能够将Service设置为NodePort类型,这样经过任意Node的IP和Service Port即可以访问Service。适合对外的Service比较少的场景。
2. 经过kube-proxy能够对外暴露集群内的服务。
3. 根据实际状况在集群内自定义实现反向代理。
2. 问:我想问下etcd这个容器能够省掉吗?k8s集群有etcd不能够共用吗?
答:理论上能够共用etcd。从隔离性的角度考虑来讲仍是分开好,这样kube-dns服务不会对整个k8s集群的稳定性产生影响。另外若是把kube-dns看作一个微服务的话,那么应该保证内部组件不依赖外部,能够独立运行。