k8s_day02_01

apiserver 是整个k8s 系统的总线 ,是整个集群中唯一一个能存集群状态数据的位置。 但是apiserver 本身并不存,而是交给etcd 存储了。 所以etcd 在生产环境要做分布式冗余高可用,etcd 是基于go 语言、raft 协议研发的 强一致性分布式 的轻量级kv 存储系统

分布式、强一致的系统在协同时可能会发生脑裂,因此为了避免脑裂,集群的节点一般是奇数个,所以etcd 最少3个节点。因为apiserver 与etcd 是通过https 协议通信的 ,相当于apiserver 是无状态的,apiserver 做冗余就不必要和ectd 节点数量保持一致取奇数个,一般2个就够了,当然这也取决于我们的业务系统。apiserver 本质是https 服务, 监听在6443 端口,当api有多个时 , 客户端选择任意一个都行,所以可以把api 防止负载均衡器上,但是负载均衡器也可能单点失败,所以可以再配keepalived。nginx 用4层负载就行


kubespray 部署高可用k8s集群 k8s高可用集群的apiserver_php

而对于后端的server ,发生故障时,只要nginx 能探测到自己健康状态,并且摘除即可。

关于状态健康性检测,有2种,主动(AH)和被动(PH)检查

对于PH,通常叫做故障探测 或者叫异常值探测。nginx 做的探测 多数都是主动的,nginx 向后端发送请求,如果得到正常响应,就算健康。而被动检查 主要是观测 流量是否正常进行,如根据正常流量的响应码,是200还是502 判断。 还有就是根据相应时长,时间过长 大于正常平均时间就算有问题

controller manager 是控制器管理器,实现的作用是真正意义上是让k8s 所有功能得以实现的控制中心,k8s 有一个特点就是把运维日常工作代码化 ,代码化的集成位置就在controller 中。controller manager 中包含多个controller程序,把他们单个的controller 打包在一起成为一个组件,我们把它称为manager。

每个controller内部都有一个叫controller loop 的控制循环,这个死循环 会一直监视着 k8s 上所管理的那个对象的数据,比如pod数量,一旦不满足就会增减。

Scheduler 没有太大作用,除了调度,主要是调度Pod[现在IT架构,都讲究以应用为中心] ,k8s 的核心作用就算运行应用。Scheduler 会时刻关注每个节点上的资源可用量, 以及能为了更好运行这个应用所需要的运行环境,让二者做最佳匹配。当然如果最佳匹配的节点不止一个,如何选择呢? 至上而下随便选一个就行。当然也可以选择一个合适的节点调度存储卷


node 的主要作用就是为了运行Pod, node 的三个组件 :

kubelet ,是 整个apiserver 或者控制节点的 运行在每一个工作节点的agent,控制节点的大多数任务都是kebelet 执行的。所以可以认为控制平面派出到每一个节点上的 去执行控制平面所需要执行的任务,尤其像是创建删除pod 都是kebelet 完成的。也就意味着调度器调度完了, kubelet 就会知道这是调度到自己机器上的,它负责把创建容器的配置拿过来,在本机上调用container engine,如dockers ,

kube-proxy :

service 就是由 kube-proxy在每个主机上生成的iptables 或者ipvs 规则。为什么service 能调度后端的pod呢, 创建的每一个service 都存到api server 上了 ,只要是创建或删除service 的操作, kube-proxy 就会在对应的节点上生成一些iptables规则,以便本地的pod能被负责均衡的规则所调度。service 内部用的是一种叫random 的算法,把请求随机分配到pod上。当然也可以用ipvs, ipvs支持更多的算法,sh 、dh、rr、wrr、wlc 等等。虽然说k8s 未必对ipvs中的每种算法都支持,但是好在多余iptables 的只有一个random 算法。二 、如果k8s 中跑了太多的service ,iptables 规则将会巨多,上万条,性能就会大受影响,但ipvs 就不会。

kube-proxy 就是一个确保 分散运行在各个节点的pod能够被正常调度一个daemon 守护进程

docker

运维工程师的三大核心职能:故障管理、资源管理、变更管理 k8s 对这些都有涉及:

  • 故障管理: k8s 要部署日志分析展示系统用于容器排障
  • 资源管理: 需要部署基础设施服务 kube-dns ,kubeadm启动时 会自动帮你运行一个附件 coredns

k8s 依赖的重要附件

Add-ons

  • kubedns: coredns k8s内部使用的域名解析系统可以统称为 kubedns
  • dashboard, web ui: 可以通过网页创建pod service,但是这个ui 目前不是特别好用而且我们特别依赖它😂
  • 监控系统:Prometheus cncf 毕业的第二个项目 本身也是用go 写的
  • 集群日志系统:
    ElastichSearch ,ElastichSearch 本身并不收集日志,而是借助客户端收集工具 Filebeat/Fluented/fluent-bit等等, 其实日志收集器做起来是很简单的,大公司为了装逼都自己开发 ,日志展示系统 叫kibana ,这套完整的系统就叫EFK

k8s 为什么不用logstah ,是因为,logstash用的是一种叫 JRuby的语言开发【ruby是一种很小众的开发语言,类似csharp。python 的编译器是用C 开发的,所以python 可以叫做‘cpythjon’ 所以Jruby 是基于java 开发的,filebeat 收集日志只要占用大概2M内存,而logstash 需要占用2G,logstah 太吃资源显得太重量级,不适合在容器中收集日志】

  • 除了EFK外,第二种解决方案就是LOKI 。洛基, 是仿照普罗米修斯构建的一套日志收集系统,轻量级,是云原生应用。虽然功能没有EFK 多。它的日志展示系统就是Granfana
  • Ingress Controller:
    ingress 表示入站的意思。 k8s 内部可以愉快的交流,但是当我们想接入外部的流量时,可以使用node port 类型的service 。每一个nodeport 类型的service 就是相当于在集群的边界上挖了一个洞,作为集群管理者,很难知道哪里挖了洞,除非把所有的nodeport 类型的service 找出来。现在大多应用层都是走的https/hhtp 协议,为了方便统一管理,可以nginx 或者envoy 之类的应用做反向代理 来进行这些‘缺口/洞’。 Ingress Controller 就起着类似的功能 ,叫做 入站流量管理器,所有入站流量,都必须经过ingress 进行分派到后面需要与外部通讯的service
  • 除了上面之外的附件还有千千万,那就按需部署了 ,如Jenkins

==iaas : 按需创建主机 ==

paas: 按需开发并且部署程序 ,所以为了运行业务应用,可能还需要部署其他的插件

kubespray 部署高可用k8s集群 k8s高可用集群的apiserver_nginx_02

控制平面组件 和 kubelet 是 k8s 的 非常重要组件,如果被入侵或者流量劫持了,会带来灾难性后果,所以组件间的安全通信非常重要,所以k8s 的组件都是基于https 协议进行的,ks 的一套系统中需要3个ca

  • 第一套 etcdca ,etcd 本身既支持http 又支持https, 为了避免被破环, 做了peer的通信认证,点对点的认证,所以用https
  • apiserver 肯定也需要一套ca 叫错kubernates ca, 用于给apiserver 的客户端和服务端各发证书
    【scheduler 、controller、proxy、kubectl 、kubelet】 都需要客户端证书, apiserver 要服务端证书
    它们彼此之间是双向认证的,kubelet连接到apiserver后 , 要验证它的域名和证书保持一致,反之apisever也要验证kubelet的身份信息 简称 mtls 【mute TLS 】

如果手动部署k8s ,需要自己去建立这些证书密钥之类的,超麻烦。现在用的是kubeadm 部署的, kubeadm 已经GA ,可以在生产、和测试环境中使用。GA 叫做 genera availability 公共可用 。早2年,kubeadm 没有GA 是不敢在生产环境中部署的 ,用部署工具叫做github 上kubeeaz 的ansibe工具部署的,虽然部署效果一样。但是这个工具是k8s生态之外的一个工具,无法参与到k8s内生身的很多重要环节之中,而kubeadm 是ks SIG 【special instresting Groups 特殊兴趣小组】 提供的

  • front-proxy-ca 聚合器 和扩展 apiserver时用到的
  • 其实还有一个SA ,它不是证书,而是一个公钥私钥对

k8s 集群部署 和运行模型:3种

  • 二进制程序: 各个组件以二进制程序或rpm包手动管理
  • pod:
  • static pod 静态pod
  • pod : 常规pod 、控制器管理下的pod

kubespray 部署高可用k8s集群 k8s高可用集群的apiserver_运维_03

如图所示: 3种方式的附件都是 以pod 方式运行

第一种: master 、node 的所有组件 都可以以二进制程序部署的(左下第一个长方形图,cni flannel 除外),所有组件依靠init script 或者systenmd 管理

第二种: master 和node 的组件中,kubelet 和docker 仍然以二进制方式靠 init script 或者systenmd 管理(中间的正方形图),其他组件仍然以Pod方式运行 ,但是 master中的这些pod 是不受控制器管理的,而是受kubelet 直接借助一个叫配置清单的文件(manifest)管理 , kubelet 会监视某个目录是否有某个应用的清单,如果有就创建起来,而且只要发现那个pod 不在会自动创建起来,这叫静态pod。 以kubeadm 为代表

第三种: 相对于第二种来说 ,区别就是 , master上控制平面组件pod 是受控于自己专门的控制器管理,而不是kubelet. 应用场景就是共有云的kaas 服务 (阿里云亚马逊) ,只要你提供 master 和node 的数量,就能拉起一个集群,因为把拉起的过程全部代码化了,缺点就是贵,以动态pod的方式来运行这些控制组件pod


kubespray 部署高可用k8s集群 k8s高可用集群的apiserver_nginx_04

如果用kubeadm 来管理k8s ,它做不到以下事:它不会帮你创建主机,不会帮你管理主机,所以对于Laye1 基础设施层它管理不到 ,无法通过api 创建主机

kubeadm 主要在第二层实现了2个功能 bootstrapping(拉起引导)一个集群 ,并且提供一个基本的功能api

kubeadm 除了提供了coredns ,在第三层,并没有提供其他的附件

下图蓝色的部分是kubeadm 可以完成的任务,运行蓝色组件。(通常不认为kube-proxy是附件,但是有些机构认为)


kubespray 部署高可用k8s集群 k8s高可用集群的apiserver_php_05

k8s 没有实现网络插件,太复杂了,而是交给专业的网络公司。只留了一个容器网络接口

CNI:

Container Network Interface。 目前CNI 的解决方案 海了去,有几十种之多,但目前最流行的只有两个

  • flannel
    coreos 这家组织研发的,只实现了网络,而没有实现网络策略 , 简单易学 , 叠加和承载模型都支持, 性能也不差 hostgw 的机制 ,支持directRouting Vxlan 三种
  • Project Calico
    既实现了网络,又实现了网络策略 , 生产环境使用居多,而且支持BGP协议的underlay network 性能更强大
  • Cannel:
    网络功能用flannel 实现 , 策略用Calico 实现 , 现在已经废弃不再更新(因为作者后发现 相当于又实现了一遍Calico)

CNI通常要求组件有2个功能:第一网络解决方案,underlay 和overlay 都行. 第二, 网络策略:控制通信的 ,两个pod之间能不能通信 k8s并没有做任何限制,只要能部署就能通信.但是 如果是一个多租户环境 ,如公司里有多个团队,每个团队要独立隔离, 可认为每个团队就是一个租户,租户与租户之间要隔离, 但是就算是用名称空间隔离 起来, A租户去访问 B租户是没有任何问题的,

CRI : R untime 容器运行时

CSI: Storage 存储

flannel 是如何工作的?


kubespray 部署高可用k8s集群 k8s高可用集群的apiserver_客户端_06

节点网络: 各个物理节点 的网卡接口 真正通信的地方(无论是叠加还是承载网络模型 都必须有). 可以认为是是虚拟机Ip 所组成的, 172.29…0.0/16 自己规划

Pod 网络: flannel 用的是10.244.0.0/16 网段 , 会给每个物理节点分配一个子网 如10.244.1.0/24 .这个可以自己设置划分,若想运行最大数量pod,可以网段设置为8位,如10.0.0.0/8…通常一个节点主机 运行256 容器撑死 , 所以每个主机可以分配到一个C类子网(24 位掩码,1个255). 这样就可以支持256*256 台主机 可以自己选择,适配网络插件默认设定 会减少很多麻烦, 除非我们有特殊需要

service 网络: 默认flannel 用的是 10.96.0.0/12 地址 . 所以service 可用的地址为 10.96.0.1 ~10.111.255.255

[root@master01 ~]# kubectl  get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
demoapp      ClusterIP   10.107.176.51   <none>        80/TCP    2d7h
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP   2d9h
[root@master01 ~]#

service 是一个虚假网络 , service 地址不会设置在任何网卡或网络接口上,只是会出现在service相关的iptables或者ipvs 规则中做为服务访问入口或者端点 , 也会出现在dns解析记录中把service对应名称解析为对应ip service 网络 是由kube-proxy 管理 , 在哪里指定的呢,用 kubeadm 部署时, service-cidr参数 指定

–service-cidr string Use alternative range of IP address for service VIPs. (default “10.96.0.0/12”)

kubeadm 拉起一个集群的流程


kubespray 部署高可用k8s集群 k8s高可用集群的apiserver_运维_07

kubecofig 介绍

[root@master01 ~]# cd /etc/kubernetes/
[root@master01 kubernetes]# ls
admin.conf  controller-manager.conf  kubelet.conf  manifests  pki  scheduler.conf
[root@master01 kubernetes]#

kubecofig 就是/etc/kubernetes/目录下的文件

[root@master01 kubernetes]# cat admin.conf 
apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM1ekNDQWMrZ0F3SUJBZ0lCQURBTkJna3Foa2lHOXcwQkFRc0ZyT3NqRERsYWtLQgpjcEJmbTZFbjRRSERPVE03aWxHdWZNck9OZ2MrbFpUZlgvY3B1elVvOUxwS0Z6eE5pT2RiNUFzeCtiTmk1bFg0CjQvQjNMbnBqN2tmZzF4bG1EY1Q1VVllMjhsNnRZQUxCQmszTAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
    server: https://kubeapi.magedu.com:6443
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: kubernetes-admin
  name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
  user:
    client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURFekNDQWZ1Z0F3SUJBZ0lJT0F5T2o1c2NRMk13RFFZSktvWklnQwpR2kzWEZ5d09ZZVBwYXdYMGZOdXlGNE5BdFpmWHYvS3JRY1hiY1pQazU0eWsKcjRjbXVmSXJGb1EwbWNSSkNyazFBWU1qMmVOQUJjcz0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
    client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBNlB3cnFoK0lLeFRnWkliczJEZndRT1bHVHVFdEYWh6WXR3MUdwL05EK0dNSE9yLwpHUFNjVDlEcjdoVWdza29BMWVTM2owbS9hRjlQQVpCK0NKOGR3amJKOXVlOGhyY3YrRU9LQjdzPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
[root@master01 kubernetes]#

主要就是集群的地址端口 , 集群的名称, 访问集群时用的用户名称以及相关证书,私钥信息.

为什么要写在配置文件中?https 是无状态协议, 每一次访问都要认证 ,不这样就要以命令行的方式指定认证信息. 特麻烦. admin.conf 是 kubectl 客户端以超级管理员(相当于root)的身份连接到apiserver 上时使用的

controller-manager.conf : 控制平面组件除了 apiserver 都是apiserver的客户端,都需要认证 , scheduler.conf也是同理

真正的证书都在/etc/kubernetes/pki/ 目录下

[root@master01 kubernetes]# ll /etc/kubernetes/pki/
total 56
-rw-r--r-- 1 root root 1298 Nov 25 00:26 apiserver.crt
-rw-r--r-- 1 root root 1135 Nov 25 00:26 apiserver-etcd-client.crt
-rw------- 1 root root 1675 Nov 25 00:26 apiserver-etcd-client.key
-rw------- 1 root root 1679 Nov 25 00:26 apiserver.key
-rw-r--r-- 1 root root 1143 Nov 25 00:26 apiserver-kubelet-client.crt
-rw------- 1 root root 1675 Nov 25 00:26 apiserver-kubelet-client.key
-rw-r--r-- 1 root root 1066 Nov 25 00:26 ca.crt
-rw------- 1 root root 1679 Nov 25 00:26 ca.key
drwxr-xr-x 2 root root  162 Nov 25 00:26 etcd
-rw-r--r-- 1 root root 1078 Nov 25 00:26 front-proxy-ca.crt
-rw------- 1 root root 1679 Nov 25 00:26 front-proxy-ca.key
-rw-r--r-- 1 root root 1103 Nov 25 00:26 front-proxy-client.crt
-rw------- 1 root root 1679 Nov 25 00:26 front-proxy-client.key
-rw------- 1 root root 1675 Nov 25 00:26 sa.key
-rw------- 1 root root  451 Nov 25 00:26 sa.pub
[root@master01 kubernetes]#

静态pod 清单文件

[root@master01 kubernetes]#  ll /etc/kubernetes/manifests/
total 16
-rw------- 1 root root 2118 Nov 25 00:26 etcd.yaml
-rw------- 1 root root 3176 Nov 25 00:26 kube-apiserver.yaml
-rw------- 1 root root 2858 Nov 25 00:26 kube-controller-manager.yaml
-rw------- 1 root root 1413 Nov 25 00:26 kube-scheduler.yaml
[root@master01 kubernetes]#

Taint and the label master : 给master 节点打污点,污点是高级调度策略的一种 ,pod 不会调度到有污点的机器上,所以新建的pod 不会在master 上

Bootstrap Token: 生成一个引导令牌 : 也就是生成一个随机字符串当密码. 这个令牌是会过期的,且符合CA的签名

kubeadm join kubeapi.magedu.com:6443 --token sjh4s0.lsj3y7swfjpf9d2g
–discovery-token-ca-cert-hash sha256:f65cce015ac254b3e7c3a0cac59ac031079d9c31ffac12f31940a57d15c30764