① k8s五分钟快速入门
k8s是谷歌开源的容器集群管理系统,是谷歌多年大规模容器管理技术Borg的开源版本,主要功能包括:
从功能上讲Kubernetes是一种综合的基于容器构建分布式系统的基础架构环境,它不仅能够实现基本的拉取用户镜像、运行容器,还可以提供路由网关、水平扩展、监控、备份、灾难恢复等一系列运维能力,而更重要的是Kubernetes可以按照用户的意愿和整个系统的规则,高度自动化的处理好容器之间的各种关系实现“编排”能力。
简单概括,提供创建应用>应用部署>提供服务>动态伸缩>应用更新一系列服务。
k8s主要由以下几个核心组件:
一个kubernetes集群由分布式存储etcd、控制节点controller以及服务节点Node组成。
如上图所示,Kubernetes在架构上主要由Master和Node两种类型的节点组成,这两种节点分别对应着控制节点和计算节点。其中Master即控制节点,是整个Kubernetes集群的大脑,负责整个集群的管理,比如容器的调度、维护资源的状态、自动扩展以及滚动更新等,并能根据集群系统资源的整体使用情况将作业任务自动分发到可用Node计算节点。
看Master节点主要由三个紧密协作的独立组件组合而成。
需要说明的是,上述组件在工作状态下还会产生许多需要进行持久化的数据,这些数据会通过kube-apiserver处理后统一保存到Etcd存储服务中。 所以从这个角度看kube-apiserver不仅是外部访问Kubernetes集群的入口,也是维护整个Kubernetes集群状态的信息中枢。
而在Kubernetes计算节点中,除了上述3个系统组件外,其他基本与Master节点相同,而其中最核心的部分就是kubelet组件。它的核心功能具如下:
在Kubernetes中kubelet会通过CRI接口同容器运行时进行交互,而容器运行时则通过叫做OCI容器运行时规范与底层Linux操作系统进行交互(涉及对Namespace、Cgroups等资源的操作,具体可以了解下Docker的技术原理)。需要强调的是,这里所说的容器运行时并不仅仅指Docker,而是所有实现了CRI接口规范的容器项目都可以作为Kubernetes的容器运行时存在。这是因为Kubernetes从设计之初就没有把Docker作为整个架构的核心,而只是将其作为最底层的一个容器运行时来实现。
况且从Kubernetes架构设计上看,Kubernetes并没有打算重复造轮子而对已有的容器技术进行替代,它更关注的是对运行在大规模集群中的各种任务根据其关系进行作业编排及管理,所以任何实现了CRI、CNI、CSI等协议标准的容器技术都可以无缝地与Kubernetes集成。从这个角度看,Docker与Kubernetes的关系并不是替代的关系,而是平台与组件的关系,Kubernetes可以利用现有的Docker容器运行时技术,但却并不完全依赖Docker。而这也正是Kubernetes为什么被称作容器编排技术而不仅仅只是容器技术的原因。
[1] Kubernetes和Docker的关系是什么?
[2] 《k8s入门指南》这是一个博主写的书
② 简述Kubernetes外部如何访问集群内的服务
对于Kubernetes,集群外的客户端默认情况,无法通过Pod的IP地址或者Service的虚拟IP地址:虚拟端口号进行访问。通常可以通过以下方式进行访问Kubernetes集群内的服务:
映射Pod到物理机:将Pod端口号映射到宿主机,即在Pod中采用hostPort方式,以使客户端应用能够通过物理机访问容器应用。
映射Service到物理机:将Service端口号映射到宿主机,即在Service中采用nodePort方式,以使客户端应用能够通过物理机访问容器应用。
映射Sercie到LoadBalancer:通过设置LoadBalancer映射到云服务商提供的LoadBalancer地址。这种用法仅用于在公有云服务提供商的云平台上设置Service的场景。我推荐你去看看时速云,他们是一家全栈云原生技术服务提供商,提供云原生应用及数据平台产品,其中涵盖容器云PaaS、DevOps、微服务治理、服务网格、API网关等。大家可以去体验一下。 如果我的回答能够对您有帮助的话,求给大大的赞。
③ k8s 基本使用(上)
本文将介绍 k8s 中的一些最基本的命令,并辅以解释一些基本概念来方便理解,也就是说,本文是一篇偏向实用性而非学术性的文章,如果你想提前了解一下 k8s 相关的知识的话,可以通过以下链接进行学习:
k8s 是经典的一对多模型,有一个主要的管理节点 master 和许多的工作节点 slaver 。当然,k8s 也可以配置多个管理节点,拥有两个以上的管理节点被称为 高可用 。k8s 包括了许多的组件,每个组件都是单运行在一个 docker 容器中,然后通过自己规划的虚拟网络相互访问。你可以通过 kubectl get pod -n kube-system 查看所有节点上的组件容器。
在管理节点中会比工作节点运行更多的 k8s 组件,我们就是靠着这些多出来的组件来对工作节点发号施令。他们都叫什么这里就不详细提了。反正对于”基本使用“来说,这些名字并不重要。
要想理解一个东西就要先明白它的内在理念。通俗点就是,k8s 做了什么?为了提供更加可靠的服务,就要增加服务器的数量,减少每个服务器的体量来平摊负载,而越来越多的虚拟机就会带来越来越高的运维成本。如何让少量的运维人员就可以管理数量众多的服务器及其上的服务呢?这就是 k8s 做的工作。
k8s 把数量众多的服务器重新抽象为一个统一的资源池 ,对于运维人员来说,他们面前没有服务器1、服务器2的概念,而是一个统一的资源池,增加新的服务器对运维人员来说,只是增加自资源池的可用量。不仅如此,k8s 把所有能用的东西都抽象成了资源的概念,从而提供了一套更统一,更简洁的管理方式。
接下来,我会把每个基本命令当做一节来进行介绍,并辅以介绍一些基本概念。本文介绍的命令涵盖了增删改查四方面,可参加下面表格,因为篇幅较长,我们将 create 及之后的不那么常用的命令放在下一篇文章 k8s 基本使用(下) 里讲:
接下来进入正题,首先来了解一下 k8s 中最最最常用的命令 kubectl get ,要记住,k8s 把所有的东西都抽象成了资源,而 kubectl get 就是用来查看这些资源的。最常见的资源就是 pod 。
不仅我们自己的服务是要包装成 pod 的,就连 k8s 自己也是运行在一堆 pod 上。接下来就让我们查看一下 k8s 的 pod :
-n 参数指定了要查看哪个命名空间下的 pod 。 k8s 所有的 pod 都被放置在 kube-system 命名空间下。
执行了 kubectl get pod -n kube-system 命令后,你就可以看到如下内容:
其中每一行就是一个资源,这里我们看到的资源是 pod 。你看到的 pod 数量可能和我的不一致,因为这个列表里包含了 k8s 在所有节点上运行的 pod ,你加入的节点越多,那么显示的 pod 也就越多。我们来一列一列的看:
kubectl get 可以列出 k8s 中所有资源
这里只介绍了如何用 kubectl 获取 pod 的列表。但是不要把 get 和 pod 绑定在一起,pod 只是 k8s 中的一种服务,你不仅可以 get pod ,还可以 get svc ( 查看服务 )、 get rs ( 查看副本控制器 )、 get deploy ( 查看部署 )等等等等,虽然说 kubectl get pod 是最常用的一个,但是如果想查看某个资源而又不知道命令是什么, kbuectl get <资源名> 就对了。
如果你想看更多的信息,就可以指定 -o wide 参数,如下:
加上这个参数之后就可以看到资源的所在 ip 和所在节点 node 了。
记得加上 -n
-n 可以说是 kubectl get 命令使用最频繁的参数了,在正式使用中,我们永远不会把资源发布在默认命名空间。所以,永远不要忘记在 get 命令后面加上 -n 。
kubectl get 命令可以列出 k8s 中的资源,而 kubectl get pod 是非常常用的查看 pod 的命令。而 -n 参数则可以指定 pod 所在的命名空间。
kubectl describe 命令可以用来查看某一资源的具体信息,他同样可以查看所有资源的详情, 不过最常用的还是查看 pod 的详情 。他也同样可以使用 -n 参数指定资源所在的命名空间。
举个例子,我们可以用下面命令来查看刚才 pod 列表中的某个 pod,注意不要忘记把 pod 名称修改成自己的:
然后你就可以看到很多的信息,咱们分开说,首先是基本属性,你可以在详细信息的开头找到它:
基本属性
其中几个比较常用的,例如 Node 、 labels 和 Controlled By 。通过 Node 你可以快速定位到 pod 所处的机器,从而检查该机器是否出现问题或宕机等。通过 labels 你可以检索到该 pod 的大致用途及定位。而通过 Controlled By ,你可以知道该 pod 是由那种 k8s 资源创建的,然后就可以使用 kubectl get <资源名> 来继续查找问题。例如上文 DaemonSet/kube-flannel-ds-amd64 ,就可以通过 kubectl get DaemonSet -n kube-system 来获取上一节资源的信息。
内部镜像信息
在中间部分你可以找到像下面一样的 Containers 段落。该段落详细的描述了 pod 中每个 docker 容器的信息,常用的比如 Image 字段,当 pod 出现 ImagePullBackOff 错误的时候就可以查看该字段确认拉取的什么镜像。其他的字段名都很通俗,直接翻译即可。
事件
在 describe 查看详情的时候,最常用的信息获取处就是这个 Event 段落了,你可以在介绍内容的末尾找到它,如下:
是的,如果你看到上面这样,没有任何 Events 的话,就说明该 pod 一切正常。当 pod 的状态不是 Running 时,这里一定会有或多或少的问题,长得像下面一样,然后你就可以通过其中的信息分析 pod 出现问题的详细原因了:
kubectl describe <资源名> <实例名> 可以查看一个资源的详细信息,最常用的还是比如 kubectl describe pod <pod名> -n <命名空间> 来获取一个 pod 的基本信息。如果出现问题的话,可以在获取到的信息的末尾看到 Event 段落,其中记录着导致 pod 故障的原因。
如果你想查看一个 pod 的具体日志,就可以通过 kubectl logs <pod名> 来查看。注意,这个只能查看 pod 的日志。通过添加 -f 参数可以持续查看日志。例如,查看 kube-system 命名空间中某个 flannel pod 的日志,注意修改 pod 名称:
然后就可以看到如下输出:
如果你发现某个 pod 的服务有问题,但是状态还是显示 Running ,就可以使用 kubectl logs 来查看其详细日志。
在本篇文章里,我们了解了 k8s 的宗旨和一些基本概念,并知道了最为常用的 get 、 descibe 及 logs 命令,知道了这三条命令之后就几乎可以从 k8s 中获取所有常用信息了。接下来的 k8s 基本使用(下) 里,我们会更深一步,来了解 k8s 中如何创建、修改及删除资源。
④ k8s 之 service ip
本文通过下面的例子,分析访问service ip的流程及iptables规则如何生效。
通过此yaml文件创建三个pod,一个client,两个nginx(监听在80端口),和一个service(将9999映射到nginx的80端口),实现到nginx后端的负载均衡。
查看创建的三个pod,两个nginx pod部署在worker1上,client部署在worker2上。
查看创建的service,可看到对应的两个endpoint。
service创建成功后,会在每个worker node上添加如下iptable规则
有如下三种访问service ip的场景,下面分别验证并分析iptables规则
a. 在client pod内部访问
b. 在worker node上访问
c. 在监听80端口的nginx pod中访问
a. 在client pod内部访问
然后进入nat表的处理,在PREROUTING 链上依次查找如下的规则
虽然POSTROUTING链上也有规则,但是都不匹配。
所以查找nat表的结果就是做了dnat。
b. 在worker node上访问
然后进入nat表的处理,依次查找如下的规则
在OUTPUT链上,匹配到dnat规则,将数据包的目的ip/port换成了10.1.139.84:80或者10.1.139.93:80,并且给数据包做了标记0x4000/0x4000。
根据MASQUERADE做snat时,源地址选择可以通过下面命令获取,在此例中,源ip为10.1.236.128
c. 在nginx pod访问
这里还要再分两种场景,负载均衡后的ip是发起访问的pod和不是发起访问的pod。比如 在nginx1 pod内部访问nginx的service服务,负载均衡后的ip为nginx1 pod的ip,或者为nginx2 pod的ip。
不同pod
在nginx1 pod内部访问nginx的service服务,负载均衡后的ip为nginx2 pod的ip。
将目的ip修改为10.1.139.93后,查找路由表时,发现只需要发给本worker上的calic6244c9748e即可。
此场景下的链接跟踪表项
同一个pod
在nginx1 pod内部访问nginx的service服务,负载均衡后的ip为nginx1 pod的ip。和上面的场景的区别是,不只做dnat,还要做snat。
将目的ip修改为10.1.139.84后,查找路由表时,发现只需要发给本worker上的calic6244c9748e。
但是在POSTROUTING处,还需要执行如下两条规则,因为数据包已经被打上标记0x4000/0x4000,所以在这里还要执行MASQUERADE,即snat
snat后的源ip可以通过如下命令获取
最后数据包经过dnat和snat后发给给本worker node上的calif67c1668c34。
此场景下的链接跟踪表项
⑤ k8s网络原理-ipvs
一、背景知识
本文主要介绍k8s网络中service 的两种模式(clusterIp、nodeport),数据是如何通过ipvs&iptables流转的。在学习上述知识的同时,还需要了解一下ipset、conntrack的相关知识。 往期回顾文章
1.1、ipset
ipset是什么?ipset其实是iptables的扩展,可以定义一些列地址的集合。拿黑名单来举例,我想让黑名单里面的ip拒绝访问网站(黑名单有很多个),按照传统iptables做法,需要在filter表添加很多规则匹配时一条一条匹配效率很低(严重影响性能),而有了ipset,则只用添加一条规则即可,使用hash结构效率很高。
而使用ipset命令如下
当然,ipset还支持 hash:ip,hash:ip,port,ip等多种hash key的组成,具体可以通过 ipset -h 查看。接下来说明一下 -m set 后面 src 和 dst 两个的含义。src 指来源,dst 指目标,此规则的意思是来自192.178.113.100 ip 访问本机8410端口的流量给DROP掉。
ipset使用hash结构,比iptables的链表遍历效率要高很多。ipset还有很多更加高级的玩法,本文就不在阐述了。
1.2、ipvs
lvs是什么?全称是Linux Virtual Server,是由章文嵩博士主导的开源负载均衡项目,目前已经集成到linux内核中。lvs提供了丰富的负载均衡能力,接收到用户请求后根据具体的负载均衡算法在内核态把请求转发到后端的某个server上,也就是说lvs不需要监听具体的端口。接下来我们看一下lvs的一些基本概念。
ipvs的原理如下。ipvs工作在iptables 的 input链上,VIP一般定义在DS节点上的一个虚拟ip,拿nat模式举例如下。
① : 当请求数据包到DS上最先经过iptables 的PREROUTING链,判断目标ip (VIP) 是本机的ip,于是把请求转发到INPUT链上。
② : 因为lvs工作在INPUT链上,数据到达INPUT链上后lvs会将用户请求和定义的后端服务做对比,如果是请求的后端服务,则使用某种负载均衡算法找到一个后端RIP,修改数据包的目的ip和端口为某个RIP的(DNAT转换)。
③ : 此时数据到达POSTROUTING链(不会做SNAT),数据包的源ip 为CIP,目的ip为RIP,数据包发往RIP上。
lvs提供了三种包转发模式,如下所示
由于k8s使用的是NAT模式,接下来看下 NAT模式下的数据包流向 。如下图所示
①:请求数据包到达DS,数据包经过PREROUTING链,此时ip 包 src ip为CIP,dst ip 为VIP
②:由于请求的VIP是DS上的虚拟ip,数据包发往INPUT链。
③:数据包到INPUT链上后,ipvs发现数据包请求是定义的集群服务,于是使用定义好的负载均衡算法找到一个具体的RS节点,做DNAT,修改数据包dst ip为RIP,数据包到达POSTROUTING链,发送给RS。
④:RS收到数据包后对比dst ip 发现是自己,接收数据包做处理,处理完成后ip 数据包 src ip 为RIP,dst ip 为CIP,把数据包发给DS。
⑤:DS 接收到RS的响应包,修改src ip 为自身的VIP,dst ip 为CIP,把数据包发送给client端。
三种模式对比&优缺点
接下来在简单聊一下ipvs的负载均衡策略,简单介绍下面四种。
上面介绍完了ipvs内核态的基本原理,接下来介绍一下如何使用 ipvsadm 用户态命令来操作ipvs。说明:此次试验是在四个虚拟机上,ipvs的模式使用的nat模式,RS的网关没有指向DS的ip(没办法做到)在DS节点上手动创建SNAT命令,下文有详细介绍。创建一个vip,在ip为192.168.113.101上
为vip添加RS
添加完成RS后,查看ipvs规则,如下图所示
client端的ip地址为192.168.113.102,client端要想直接访问vip的话,需要在client端添加静态路由,添加命令如下
添加完命令后,在client端curl 10.10.0.1:8410 发现不通,此时去某个RS上抓包如下
上图抓包显示,client 直接访问的vip,而数据包的目的ip 变为了rs的ip,因此可以看出ipvs做了DNAT转换。因为做了DNAT,RS发送响应数据直接发给client,client收到RS的数据包。client给vip发的包却收到了RS的响应包(client 想我从来没有给RS发过数据),因此client端会把此数据包丢弃。
因为ipvs没有做SNAT,接下来在DS上添加iptables规则自己实现SNAT的功能,添加完SNAT后, RS就看不到真实的CIP了 。
此时还是不通,查找资料后发现ipvs 的 conntrack 没有开,手动打开,后续文章介绍conntrack是什么,设置完成后可以愉快的访问了。
总结:通过ipvs提供的DNAT功能和负载均衡功能,很容易实现外部用户访问内网的需求。但是还要考虑高可用层面,比如主DS宕机VIP要漂移到备DS上,后端RS重启或宕机,ipvs负载均衡列表中要及时把有问题的RS剔除,这样才能真正的实现高可用。
1.3、conntrack
大家在家上网时用到的都是192.168.x.x的ip地址,这是私网ip地址。那么大家是如何能够成功的访问外网的呢?答案是路由器帮我们做了SNAT的功能,使我们发出的数据包的src ip变为路由器的公网ip,这样数据包就能在互联网上愉快的转发了。从而实现了对内网的保护。
那么问题来了,既然做了SNAT转换,那响应数据包回来以后路由器怎么知道转到哪台PC上呢?路由器可能链接了很多PC,不可能都给每一个PC转发吧。。。答案就是conntrack实现的。
接下来我拿上面ipvs的例子举例,我们手动实现了在DS上SNAT转换,在client上curl vip:8410,这时候查看DS上和client上的conntrack表如下
先从client上的连接跟踪分析起:主要看 src、dst、sport、dport这几个字段。
client发送数据包
client端发出数据包的src ip 为192.168.113.102,dst ip 为10.10.0.1 (VIP), sport 为35562这个端口,dport为8410(VIP 定义端口)。
client端接收响应数据包
期望src ip 为vip(10.10.0.1),dst ip 为CIP(192.168.113.102),sport为8410,dport为35562
DS接收数据包
DS接收到src ip 为CIP(192.168.113.102),dst ip 为vip(10.10.0.1),sport为35562,dport为8410的数据包
DS接收响应数据包
由于在DS侧做了DNAT转换,根据负载均衡策略找到了一个RS(RIP 192.168.113.99),同时也做了SNAT转换(判断是否是VIP和端口),转换为DS的DIP。所以当DS收到src ip 为192.168.113.99(RIP),dst ip 为192.168.113.101(DIP),sport为8080,dport为35562,会根据连接跟踪表找到这个包是192.168.113.102这个client发过来的,因此把数据包在转发给192.168.113.102:35562 上。
conntrack各个字段的含义
总结:
本文只是简单的说明了一下conntrack,并没有具体说明数据流经netfilter时何时创建记录,数据存储的数据结构啥样,底层比较复杂,感兴趣的大佬可以自行研究~
二、k8s网络通信
介绍完了ipset、ipvs、conntrack,接下来进入正题,看一下ipvs模式下k8s的网络通信。kube-proxy 的主要作用是watch apiserver,当监听到pod 或service变化时,修改本地的iptables规则或ipvs规则。
2.1、clusterIp模式
clusterIp模式为一个集群内部可访问的ip,集群外部没办法访问这个ip,试验环境如下:
创建完deployment和service后,查看一下service的ip如下。
接下来看下宿主机网卡、ipvs规则、ipset规则有什么变化
查看iptables 的nat表和filter表,看一下k8s创建了哪些规则以及经过哪些链
接下来分析一下curl 10.108.113.237 数据是如何走的,只讨论在nat表和filter表的流向,因为在mangle和raw都没有规则。
1、nat表PREROUTING链
①:数据首先进入PREROUTING链,所有请求都会进入KUBE-SERVICES链。
②:进入KUBE-SERVICES后,查看对应在此链上的规则,发现请求的目的ip和port在KUBE-CLUSTER-IP 对应的ipset里面(上面已有展示),匹配上了则跳往KUBE-MARK-MASQ链。
③:数据流向KUBE-MARK-MASQ链,主要做了mark 打标记的功能,iptables命令如下
④:之后走向KUBE-NODE-PORT链,因为没有定义nodepode 类型的service,此处先略过。 2、filter表的INPUT链
⑤:首先进入INPUT链,所有数据转向KUBE-FIREWALL链。
⑥:进入KUBE-FIREWALL链,如果发现数据包打了0x8000/0x8000,DROP掉。因为ipvs工作在INPUT链上,做完DNAT之后直接转发到POSTROUTING链上。
3、nat表POSTROUTING链
⑦:进入POSTROUTING链,所有数据转向KUBE-POSTROUTING链
⑧:进入KUBE-POSTROUTING链,对有0x4000/0x4000标记的数据包做SNAT转换,因为ipvs只有DNAT功能。
4、数据转发给flannel网卡,进行转发
⑨:flannel 根据具体的backend模式,对数据做封包等操作,然后发出去。flannel的网络模式比较复杂,之后会专门文章进行说明。
2.2、nodeport模式
要想把集群内部的服务可以让集群外部访问,可以使用nodeport模式在物理机上开一个端口,这样外部就能访问集群内部的服务了。说明:还是使用上面创建的deployment。
查看创建service的信息,发现也创建了集群内部的一个ip。
iptables规则如下
接下来看下ipset规则有什么变化,发现KUBE-NODE-PORT-TCP下的一个成员是刚才我们指定的那个nodePort的值。
接下来看一下iptables规则,nat表和filter表
1、nat表PREROUTING链
①:数据首先进入PREROUTING链,所有请求都会进入KUBE-SERVICES链。
②:ip和port匹配不上KUBE-CLUSTER-IP 的ipset,判断是访问的本地地址,进入KUBE-NODE-PORT链。
③:进入KUBE-NODE-PORT链后,判断访问端口在 KUBE-NODE-PORT-TCP ipset规则中,因此进入KUBE-MARK-MASQ链。
④:进入KUBE-MARK-MASQ链,对数据做mark标记
后续流程跟clusterIp一样,此处就不在阐述。
2.3、dns相关
k8s中的dns默认使用的是coredns,通过以下命令查看。k8s中定义的service是有域名的,访问域名要通过dns解析,此时coredns就发挥它的作用了。
上面的试验时我们创建了一个my-service 的nodePort的service,此时查看一下此域名对应的ip,如下图所示,域名解析出来的ip与service对应的ip相同,大功告成。
参考:
以上相关内容介绍了k8s service ipvs的相关实现,如有错误欢迎指出~
⑥ 什么是K8S
k8s全称kubernetes,这个名字大家应该都不陌生,k8s是为容器服务而生的一个可移植容器的编排管理工具,越来越多的公司正在拥抱k8s,并且当前k8s已经主导了云业务流程,推动了微服务架构等热门技术的普及和落地,正在如火如荼的发展。想要了解更多,我推荐你去看看时速云,他们是一家全栈云原生技术服务提供商,提供云原生应用及数据平台产品,其中涵盖容器云PaaS、DevOps、微服务治理、服务网格、API网关等。大家可以去体验一下。
希望能给您提供帮助,可以给个大大的赞不。
⑦ 09-kubernetes中的域名解析流程
从Kubernetes 1.11版本开始,Kubernetes集群的DNS服务由CoreDNS提供。CoreDNS是CNCF基金会的一个项目,是用Go语言实现的高性能、插件式、易扩展的DNS服务端。CoreDNS解决了KubeDNS的一些问题,例如dnsmasq的安全漏洞、externalName不能使用stubDomains设置,等等。
CoreDNS支持自定义DNS记录及配置upstream DNS Server,可以统一管理Kubernetes基于服务的内部DNS和数据中心的物理DNS。
CoreDNS没有使用多个容器的架构,只用一个容器便实现了KubeDNS内3个容器的全部功能。
从kubernetes官方提供的 coredns.yml 文件中,不难看出coredns服务配置至少需要一个ConfigMap、一个Deployment和一个Service共3个资源对象。ConfigMap coredns 主要配置文件Corefile的内容:
其中主要有二个地方来解析配置
1、这段配置的意思是cluster.local后缀的域名都是kubernetes内部域名,coredns会监控service的变化来修改域名的记录
2、如果coredns没有找到dns记录,则去找 /etc/resolv.conf 中的 nameserver 解析
接下来使用一个带有nslookup工具的Pod来验证DNS服务能否正常工作:
通过nslookup进行测试。
查找defaul命名空间存在的ng-deploy-80服务
如果某个Service属于不同的命名空间,那么在进行Service查找时,需要补充Namespace的名称,组合成完整的域名。下面以查找kubernetes-dashboard服务为例,
众所周知, DNS 服务器用于将域名转换为 IP (具体为啥要转换建议复习下 7 层网络模型). Linux 服务器中 DNS 解析配置位于 /etc/resolv.conf , 在 Pod 中也不例外,
DNS 策略可以逐个 Pod 来设定。当前kubernetes支持这4中DNS 策略
如果我们不填dnsPolicy, 默认策略就是 ClusterFirst 。
kubelet 在起 pause 容器的时候,会将其 DNS 解析配置初始化成集群内的配置。配置: 它的 nameserver 就是指向 coredns 的
k8s里面有4种DNS策略, 而coredns使用的DNS策略就是Default, 这个策略的意思就是继承宿主机上的/etc/resolve.conf, 所以coredns Pod 里面的/etc/resolve.conf 的内容就是宿主机上的内容。
在集群中 pod 之间互相用 svc name 访问的时候,会根据 resolv.conf 文件的 DNS 配置来解析域名,下面来分析具体的过程。
pod 的 resolv.conf 文件主要有三个部分,分别为 nameserver、search 和 option。而这三个部分可以由 K8s 指定,也可以通过 pod.spec.dnsConfig 字段自定义。
nameserver
resolv.conf 文件的第一行 nameserver 指定的是 DNS 服务的 IP,这里就是 coreDNS 的
clusterIP:
也就是说所有域名的解析,都要经过coreDNS的虚拟IP 10.100.0.2 进行解析, 不论是内部域还是外部域名。
search 域
resolv.conf 文件的第二行指定的是 DNS search 域。解析域名的时候,将要访问的域名依次带入 search 域,进行 DNS 查询。
比如我要在刚才那个 pod 中访问一个域名为 ng-deploy-80的服务,其进行的 DNS 域名查询的顺序是:
options
resolv.conf 文件的第三行指定的是其他项,最常见的是 dnots。dnots 指的是如果查询的域名包含的点 “.” 小于 5,则先走 search 域,再用绝对域名;如果查询的域名包含点数大于或等于 5,则先用绝对域名,再走 search 域。K8s 中默认的配置是 5。
也就是说,如果我访问的是 a.b.c.e.f.g ,那么域名查找的顺序如下:
通过 svc 访问
在 K8s 中,Pod 之间通过 svc 访问的时候,会经过 DNS 域名解析,再拿到 ip 通信。而 K8s 的域名全称为 "<service-name>.<namespace>.svc.cluster.local",而我们通常只需将 svc name 当成域名就能访问到 pod,这一点通过上面的域名解析过程并不难理解。
参考
(1)K8S落地实践 之 服务发现(CoreDNS)
https://blog.51cto.com/u_12965094/2641238
(2)自定义 DNS 服务
https://kubernetes.io/zh/docs/tasks/administer-cluster/dns-custom-nameservers/
(3)Kubernetes 服务发现之 coreDNS
https://juejin.cn/post/6844903965520297991
(4)Kubernetes 集群 DNS 服务发现原理
https://developer.aliyun.com/article/779121
(5)Kubernetes之服务发现和域名解析过程分析
https://www.jianshu.com/p/80ad7ff37744
⑧ 如何访问k8s集群内部署的mysql服务
虽然 kubernetes 社区一直在努力使得有状态应用成为一等公民,也推出了 statefulset 控制器支持 pod 的顺序部署,稳定的域名访问和存储访问。但鉴于 MySQL 部署运维的多样性和复杂性,在 kubernetes 上部署 MySQL 仍然要面临众多挑战。
1、业务流量入口的配置方式
传统虚拟机环境下,我们通过虚IP的方式,让业务应用都配置事先定义的一个虚IP为链接数据库的地址,然后由高可用服务保证虚IP始终能被路由到master数据库。在kubernetes中,出现了一层网络插件屏蔽了底层网络拓扑,高可用服务管理虚IP的方式需要随之适应调整,比如通过service结合标签完成虚IP的漂移,但service本身是kubernetes提供的一项功能,其可靠性和性能都取决于kubernetes服务的稳定。以性能来说,service是kubeproxy组件通过配置iptables实现的,当iptables规则较多时不可避免的会产生时延,需要我们针对性的解决。
2、容器隔离带来的监控视野问题
在 kubernetes 中,如果将 MySQL 制作为 container 运行在一个 pod 中,container 会将 MySQL 进程和运行环境隔离在一个单独的 namespace 中。监控组件在获取 MySQL 的一些 metirc 时,可能不得不进入与 MySQL 同一个 namespace 中,在部署和设计监控组件时需要考虑到这些限制。
3、存储在 kubernetes 中,支持配置各种不同的存储。
如果使用本地存储 local persistent volume,则需要绑定 MySQL 在一个固定的节点,这就完全浪费了 kubernetes 灵活调度的天然优势;而如果使用远程共享存储,确实是将 MySQL 进程与其存储完全解耦,使得 MySQL 进程可以在任意节点调度,然而考虑到高 I/O 吞吐量的情况,就不是那么美好了。设计时需要考量远程存储是否能够满足 MySQL 的带宽要求。
4、高可用/备份恢复
kubernetes 提供的 statefulset 控制器只能提供最基本的部署,删除功能,无法实现完善的 MySQL 集群高可用/备份恢复操作。对于有状态应用的部署,仍需要定制开发,所以多数公司提供了定制的 operator 来完成应用容器的管理。比如 etcd operator,MySQL operator,后文将为大家详述我测试使用 MySQL operator 的一些记录。
⑨ K8s中pod的数据通讯
k8s的网络通讯方式
k8s的网络模型假定是所有Pod都在一个可以直接联通的扁平的网路空间,我们需要自己实现这个网络假设,将不同节点上的Docker容器之间的互相访问先打通,然后运行K8s。
同一个Pod内的多个容器: 同一个pod共享一个网络命名空间,共享同一个linux协议栈
同一个节点各pod之间的通讯: 通过docker0网桥直接发送数据,不通过flannel
pod与service之间的通讯: 各节点的iptables规则。
pod到外网: pod向外网发送请求,查找路由表转发数据包到宿主机的网卡,宿主机网卡完成路由选择后,iptables执行Masquerade,把源IP更改为着网卡的IP,然后向外网发送请求。
flannel的功能是让集群中的不同节点主机创建的Docker容器具有集群唯一的虚拟IP地址,能够在这些Ip地址之间建立
一个覆盖网络(OverlayNetwork),通过这个覆盖网络,将数据包原封不动传递到目标容器内部。
不同节点的pod之间的访问:
首先,在node服务器上会安装flanneld的守护进程,这个进程会监听一个端口,这个端口是用于接收和转发数据包的端口,flanneld进程启动以后,会开启一个网桥叫flannel0,flannel0会抓取docker0转发的数据包,docker0会分配自己的IP到对应的pod上,如果是同一台主机中的不同pod的话,他们之间的通讯走的是docker0网桥。如果是不同节点之间的pod进行通讯,数据包源地址写自己的ip,目标地址写目标地址的ip,然后将数据发送到docker0网桥也就是网关,此时flannel0有自己钩子函数,将数据从docker0抓取,flannel0是flanneld开启端口,数据到了flanneld之后会将数据报文进行一个封装,然后将数据转发到目标节点,然后到了目标节点之后会将数据进行一次解封,到达目标节点的flanneld,然后数据会进行二次解封,flanneld会通过自己的端口将数据发送到docker0网桥,然后在对数据进行转发,从而发送到相应的目标pod。
这里的etcd与flannel的关系:
存储管理flannel可分配的IP地址段资源
监控etcd中每个pod的实际地址,并在内存中建立维护pod节点路由表。
flannel启动以后会向etcd中插入需要分配的网段以及这些网段分别分配在哪个节点上。