第一章
1.1 前世今生
DOCKER?
阿米巴
nginx
- MESOS
docker Swarm
轻量级的, 企业级需要k8s
Google Borg 管理系统?
Borg --Go--》Kubernetes
kubernetes
- 轻量级 Go 再语言级别支持进程管理,对资源占用比较小
- 开源
- 弹性伸缩
负载均衡: IPVS (章文嵩博士)
-1.2 知识图谱
!资源,资源清单语法,编写pod, 掌握pod的生命周期
···掌握各种控制器的
存储
- config map
- secret
- volume
- pv
服务分类:
有状态服务:DBMS
无状态服务:WEB LVS APACHE
- 调度器
- 集群安全
- HELM
HELM 原理
- 运维
1.5 组件说明
前身是borg 系统, 才用go语言的重构系统
!
ETCD
WAL: write ahead log
高可用集群副本数目最好>=3的奇数
组件
- APIServer:所有访问的入口
- Controller Manager: 维持副本的期望数目
- Scheduler:负责接收任务,选择合适的节点进行分配任务
- ETCD:键值对数据库,存储k8s集群所有重要信息
- Kubelet: 直接跟容器引擎交互实现容器的生命周期管理
- Kube-proxy:负责写入规则之IPtables, IPVs
- COREDNS:可以为集群中的svc创建一个域名IP的对应关系解析
- DASHBOARD:给K8s集群提供一个b/s结构访问体系
- Ingress Controller: 官方只能实现四层代理,Ingress可以实现七层代理
- Federation 提供一个可以跨集群中心多K8s统一管理功能
- Prometheus:提供一个k8s集群的监控能力
- ELK:提供K8s的集群日志同意分析接入平台
第二章 基础概念
2.1 POD 概念
- 自主式pod
- 控制器管理的pod
!虚拟化
pause是pod的根容器,pod中所有的container共享pause的网络栈和挂载卷
ReplicaSet
ReplicationController 用来确保容器应用的副本数始终保持在用户定义的副本数,即如果有容器异常退出,会自动创建新的Pod来替代,如果异常多出来的容器也会自动回收。
再新版本的kubernetes中建议使用ReplicaSet来取代ReplicationController
ReplicaSet和ReplicationController没有本质的不同,只是名字不一样,并且ReplicaSet支持集合式的selector
虽然ReplicaSet可以独立使用,但一般还是建议使用deployment来自动管理,这样就无需担心跟其他机制不兼容问题。
HPA用于 水平扩展
StatefulSet
是为了解决有状态服务的问题(Deployments和replicaSet 是为无状态服务而设计的)
- 稳定的持久化寸尺,即pod重新调度吼还是能访问到相同的持久化数据,基于PVC实现
- 稳定的网络标志,及Pod重新调度后其podname和hosname不变,基于headless service来实现
- 有序部署,有序扩展,即pod是有顺序的,再部署或者扩展的时候要依据定义的顺序一次进行,基于init container来实现的
- 有序收缩,有序删除
DaemonSet
DaemonSet确保全部Node上运行一个pod副本,当有Node加入集群时,也会为他们新增一个pod,当有Node从集群移除时,这些pod也会被回收。删除DaemonSet将会删除它创建的所有pod
一些DaemonSet的一些典型用法
- 在每个node上运行日志收集daemon 例如fluentd、logstash
- 再每个Node上运行监控daemon,例如prometheus Node Exporter
Job、 CronJob
Job负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个pod成功结束
Cron Job 管理基于时间的job即
- 再给定时间点只运行一次
- 周期性的再给定时间运行
服务发现
kubernetes 网络模型
Kubernetes德网络模型假定了所有Pod都在一个可以直接联通德扁平德网络空间
这在GCE(google compute engine)里面是现成的网络模型,Kubernetes假定这个网络已经存在
而在私有云里搭建Kubernetes集群,就不能假定这个网络已经存在,我们需要自己实现这个网络假设,将不同节点上的Docker容器之间的互相访问先打通,然后运行Kubernetes
- 同一个Pod内多个容器之间- localhost
- 各个pod之间的通讯 Overlay network
- Pod和service之间:各节点的IPtables
Flannel事CoreOs镇墩Kubernetes设计的一个网络规划服务,简单来说它的功能事让集群中的不同节点主机创建的Docker容器都具有全集群唯一的虚拟IP地址,而且它还能再这些IP地址之间建立一个覆盖网络(Overlay Network),通过这个覆盖网络,将数据包原封不动地传递到目
3 集群安装
4 资源清单
K8s中所有的得容都抽象为资源,资源实例化之后叫做对象
1 集群资源分类
- 名称空间级别
- 集群级别
- 元数据型
名称空间级别: kubeadm、 k8s、 kube-system
- 工作负载型资源(workload):Pod, ReplicaSet, Deployment, StatefulSet, DaemonSet, Job, Cron Job
- 服务发现及负载均衡型资源(Service Discovery Load Balance): Service, Ingress...
- 配置雨存储型资源: Volume(存储卷), CSI(容器存储接口,可以扩展各种各样的第三方存储卷)
- 特殊类型的存储卷:ConfigMap, Secret, DownwardAPI(把外部环境中的信息输出给容器)
集群级别: role
Namespace、Node、Role、ClusterRole、RoleBinding、ClusterRoleBinding
元数据型: HPA
PODTemplate、LimitRange
2 资源清单YAML格式
k8s中一般使用yaml格式的文件来创建符合我们预期期望的pod,这样的yaml文件一本成为资源清单
yaml语法
- 不允许使用Tab键, 只允许使用空格
- 缩进一致
标识注释,从这个字符一直到行尾,都会被解释器忽略
yaml 支持的数据结构
- 对象:键值对的集合,又称为映射、哈希、字典
- 数组: 一组按次序排列的值,又称为序列、列表
- 纯量(scalars) 单个的,不可再分的值
对象类型:对象的一组键值对,使用冒号结构标识
name: Steve
age: 18
hash: {name:Steve, age:19}
数组类型:一组连词线开头的行,构成一个数组
anmial:
- Cat
- Dog
复合类型:
对象和数组可以结合使用
langeages:
- Ruby
- Perl
- Python
websites:
YAML: yaml.org
Ruby:ruby.org
yaml允许使用两个感叹号,强制转换数据类型
~ 标识 null
字符串
单引号如果还含有但因哈,必须连续使用两个单引号转义
字符串可以写成多行,从第二行开始,必须有一个单空格缩进,换行符会被转为空格
多行字符串可以使用|保留换行符,也可以使用>折叠换行
+ 标识保留文字块末尾换行
- 标识删除字符串末尾换行符
2.3 常用字段的解释
- 必须存在的属性
- 额外参数
Pod 生命周期
InitC
Pod能够具有多个容器, 应用运行在容器里面,但是它也有一个或多个先于容器启动的Init容器
Init容器与普通的容器非常像,除了如下两点:
- Init容器总是运行到成功完成位置
- 每个Init容器都必须在下一个Init容器启动前成功完成
如果Pod的Init容器失败,Kubernetes会不断地重启改Pod,知道Init容器成功为止,然而如果Pod对应的restartPolicy为Never, 它不会重新启动。
Init容器的作用
因为Init容器具有与应用程序容器分离的单独镜像,所以它们启动相关代码具有如下优势
- 它们可以包含并运行实用工具,但是出于安全考虑,事不建议在应用程序容器镜像中包含这些实用工具。
- 他们可以包含实用工具和定制化代码来安装,但是不能出现在应用程序镜像中。例如,创建镜像没必要FROM另一个镜像,只需要在安装过程中使用类似sed、awk、python或dig这样的工具
- 应用程序镜像可以分理处创建和部署的角色,而没有必联合他们构建一个单独的镜像
- Init容器使用LinuxNamespace,所以相对应用程序容器来说,具有不同的文件系统视图。因此,它们能够具有访问Secret的权限,而应用程序容器则不能。
- 她们必须在应用程序容器启动之前完成,二应用程序容器时并行运行的,所以Init容器能够提供一种简单的阻塞或延迟应用容器的启动的方法,直到满足了一组先决条件
Init C的特殊说明
- 在Pod启动过程中,Init容器会顺序在网络和数据卷初始化之后启动,每个容器必须在下一个容器启动之前成功退出
- 如果由于运行时或失败退出,将导致容器启动失败,它会根据Pod的restartPolicy指定的策略进行重试,然而,如果Pod的restartPlolicy设置为Always。Init容器失败时会使用RestartPolicy
- 在所有的Init容器没有成功之前,Pod将不会变成Ready状态,Init容器的端口将不会在Service中进行聚集,正在初始化中的Pod处于Pending状态,但应该会将Initializing状态设置为True
- 如果Pod重启,所有Init容器必须重新执行
- #对Init容器spec的修改被限制在容器image字段,修改其他字段都不会生效,更改Init容器的Image字段,等价于重启该pod
- Init容器具有应用容器的所有字段,除了readinessProbe,因为Init容器无法定义不同于完成(completion)的就绪(readiness)之外的其他状态,这会在验证过程中强制执行
- 在Pod中的每个app和Init容器的名称必须唯一。与任何其他容器共享同一个名称,会在验证时抛出错误。
探针
探针是由kubelet对容器执行的定期诊断。要执行诊断,kubelet调用由容器实现的Handler,有三种类型的处理程序
- ExecAction: 在容器内执行指定命令,如果命令推出时返回码为0, 则诊断为成功
- TCPSocketAction:对指定端口上的容器的IP地址进行TCP检查。 如果端口打开,则诊断为是成功。
- HTTPGetAction: 对指定的端口和路径上的容器的IP地址执行HTTP Get请求。 如果响应的状态码大于等于200且小于400,则诊断为成功
每次探测都将获得一下三种结果
- 成功:容器通过了诊断
- 失败:
- 未知:诊断失败,因此不会采取任何行动。
探测方式
- livenessProbe:指示容器是否正在运行,如果存活探测失败,则kubelet会杀死容器,并且容器将受到起重启策略的影响。如果容器不提供存货探针,则默认状态为Success
- readinessProbe:指示容器是否准备好服务请求。 如果就绪探测失败,端点控制器将从与Pod匹配的所有Service的断电中删除该Pod的IP地址。初始延迟之前的就绪状态默认为Failure。如果容器不提供就绪探针,则默认状态为Success
资源清单 start 、 stop 、 相位(pod phase)
- 挂起(Pending):Pod已经被Kubernetes 系统接收,但有一个或者多个容器镜像尚未创建。等待时间包括调度Pod的时间和通过网络下载镜像的时间,这可能需要花点时间。
- 运行中(Running):该Pod已经绑定到一个节点上,Pod中所有的容器都已经被创建,至少有一个容器正在运行,或者正处于启动活重启状态。
- 成功(Succeeded)Pod中所有的容器都被成功种植且不会再重启。
- 失败(Failed)Pod中所有的容器都已中止了,并且至少有一个容器是因为失败种植。也就是说,容器以非0状态退出,或者被系统终止
- 未知(Unknown):因为某些原因无法取得Pod的状态,通常是因为与Pod所在的主机通信十八。
资源控制器
控制器说明
Pod的分类:
- 自主式Pod
- 控制器管理的Pod
- 什么是控制器?
Kubernetes中内建了很多controller,这些相当于一个状态机,用来控制Pod的具体状态和行为 控制器类型:
- ReplicationController 和 ReplicaSet
- Deployment
- DaemonSet
- StateFulSet
- Job/CronJob
- Horizontal Pod Autoscaling
RC和RS
RC用来确保容器应用的副本数始终报纸再用户定义的副本数,即如果有容器异常退出,会自动创建新的Pod来替代,而如果异常多出来的容器也会自动回收
再新版本的Kubernetes中建议使用RS来取代ReplicationController, RS跟RC没有本质的不容,指示名字不一样,并且ReplicaSet支持集合式的selector
Deployment
Deployment 为Pod 和ReplicaSet提供了一个声明式(declarative)方法,用来代替以前的RC方便管理。
- 定义Deployment来创建Pod和ReplicaSet
- 滚动升级和回滚应用
- 扩容和缩容
- 暂停和继续Deployment
命令式编程:侧重于如何实现程序
声明式编程: 侧重于想要什么,然后告诉计算机、引擎,让他帮你实现。
Deployment 通过 定义rs 来管理pod
DaemonSet
DaemonSet确保全部(或者一些)Node上运行一个Pod的副本,当有Node加入集群时,也会为她们新增一个Pod,当有Node从集群中移除时,这些Pod也会被回收。删除DaemonSet将会删除它创建的所有Pod
使用DaemonSet的一些典型用法:
- 运行集群存储Daemon,例如再每一个Node上运行glusterd,ceph
- 在每个Node上运行日志收集Daemon,例如fluentd,logstash
- 再每个Node上余小宁监控daemon,例如Prometheus Node Exporter,collectd,Datadog代理、New Relic 代理,活Ganglia
Job
Job'负责批处理任务,即仅执行一次的任务,它保证批处理任务的一个或多个Pod成功结束
CronJob
Cron Job 管理基于时间的Job 即
- 再给定时间点只运行一次
- 周期性的再给定时间点运行
Horizonal Autoscaling
RS RC 与 Deployment关联
RS 相比RC对打不同是RS支持集合式的selector
Kubertenes 所谓的副本监控是以label为基础的。
Deployment
Deployment为Pod喝ReplicaSet提供了一个声明式定义(declarative),用来替代以前的ReplicationController来方便的管理应用。典型的应用场景包括:
- 定义Deployment来创建Pod喝ReplicaSet
- 滚动升级喝回滚应用
- 扩容和缩容
- 暂停和继续Deployment
Deployment 更新策略
Deployment可以保证再升级时只有一定数量的Pod时down的,默认的,它会确保至少有比期望的Pod数量少一个是up状态(最多一个不可用)
Deployment同时也可以确保值创建出超过期望数量的一定的Pod,默认的,它会确保最多比期望的Pod数量做一个的Pod是up的(最多一个是surge)
未来的Kubernetes版本中,将从1-1 变成25%-25%
kubectl describe deployments
Rollover (多个rollout并行)
加入你创建了一个有5个 nginx:1.7.9 replica的deployument,但是当还只有3个nginx:1.7.9的replica创建出来的时候,你就开始更新含有5个nginx:1.9.1replica的deployment,在这种情况下,Deployment会立即杀掉一创建的3个nginx:1.7.9的pod,并开始创建nginx:1.9.1的pod。它不会等到所有的5个nginx:1.7.9的Pod都创建完成后才开始改变航道。
回退 Deployment
只要一个Deployment的rollout被触发,就会创建revision。也就是说当且仅当Deployment的Pod template(如'.spec.template')被更改,例如更新template中的label和容器镜像时,就会创建出一个新的revision。其他的更新,比如扩容Deployment不会创建revision——因此我们可以很方便的手动或者自动扩容。这意味着当您回退到历史revision时,只有Deployment中的Pod template部分才会回退
可以通过kubectl rollout status
命令查看Deployment是否完成,如果rollout成功完成,kubectl rollout status
将返回一个0值的ExitCode
清理Policy
可以通过设置.spec.revisionHistoryLimit
项来指定deoloyment最多保留多少revision历史记录。默认的会保留所有的revision;如果该项设置为0,Deployment就不允许回退了。
什么是DaemonSet
DaemonSet确保全部(或者部分)Node上余小宁一个Pod的副本。当有Node加入集群时,也会为他们新增一个Pod。当有Node从集群中移除时,这些Pod也会被回收。删除DaemonSet将会删除它创建的所有Pod。
使用Daemon的一些典型用法:
- 运行集群存储daemon,例如在每个Node上运行gluster,ceph
- 在每个Node上运行日志收集的Daemon
- 在每个Node上运行监控daemon
Job
Cronjob
CronJob 管理基于事件的Job
- 在给定时间点只运行一次
- 周期性的在改定时间点运行
使用条件:当前使用的Kubernetes集群,版本》=1.8
典型的用法:
- 在给定时间点调度Job运行
- 创建周期性运行的Job,例如,数据库备份,发送邮件
Cronjob Spec
- .spec.schedule 调度,必须字段, 指定任务运行周期,格式同Cron
- .spec.jobTemplate job 模板, 必须字段,指定需要运行的任务,格式同Job
- .spec.startingDeadlineSeconds 启动Job的期限,该字段是可选的。如果因为任何原因二错过了被调度的时间,那么错过执行时间的Job将被认为是失败的,如果没有指定,则没有期限。
.spec.concurrencyPolicy 并发策略,可选,制定了如何触雷被Cronjob 创建的Job的并发执行,只允许指定下面策略中的一种:
- Allow 允许并发执行
- Forbid 禁止并发运行,如果当前还有一个没完成的任务,就则直接跳过下一个。
- Replace 取消当前正在运行的Job,用一个新的来替换
- 注意,当前策略只能应用于同一个Cron Job创建的Job。如果存在多个Cron Job,她们创建的Job之间总是允许并发运行
- .spec.suspend 挂起,该字段也是可选的。如果设置为true,后续所有执行都会被挂起。它对已经开始执行的Job不起作用。默认值为false
- .spec.successfulJobHistoryLimit和 .spec.failedJobHistoryLimit 历史限制,是可选字段。她们制定了可以保留多少完成和失败的Job,默认情况下,她们分别设置为3和1,设置显示的值为0,相关类型的Job完成后将不被保留。
Cron Job 的一些限制
- 创建操作应该是幂等的
6 Service定义
SVC
负责去检测它所监控的pod的信息
Kubernetes service 定义里这样一种抽象:一个Pod的逻辑分组,一种可以访它们的策略,通常称为微服务,这一组pod能够被Service 访问到,通常是通过Label selector
Round Robin 仅有的一个算法
Service 能够提供负载均衡的能力,但是在使用上有一下限制:
- 只提供4层负载均衡能力,而没有7层功能。但是有时候可能需要更多的匹配规则来转发请求,在这点上4层负载均衡是不支持的。
4层负载均衡和4层负载均衡?
Service的类型
- ClusterIp
只能被集群内部的节点访问
默认类型,自动分配一个仅Cluster内部可以访问的虚拟IP - NodePort:在ClusterIp基础上为Service在每台机器上绑定一个端口,这样就可以通过
<NodeIp>:NodePort
来访问服务 - Loadbalancer: 在NodePort的基础上,接触Cloud Provider创建一个外部负载均衡器,将请求转发到
<NodeIp>:NodePort
- ExternalName
把集群外部的服务引入到集群内部来,在集群内布直接使用。没有任何类型代理被创建,这只有kubernetes1.7或更高版本的kube-dns才支持
VIP和Service代理
在Kubernetes集群中,每个Node运行一个kube-proxy进程, Kube-proxy负责为Service实现了一种VIP(虚拟Ip)的形式,而不是ExternalName的形式。在KubernetesV1.0版本,代理完全在userspace,在Kubernetes v1.1版本,新增么iptables带俩,但是并不似默认的运行模式。从Kubernetes v1.2起,默认是iptables代理。在Kubernetes v1.8.0中添加了ipvs代理
在Kubernetes 1.14版本开始默认使用ipvs代理
在Kubernetes v1.0版本,Service是4层(TCP/IP over IP)概念,在Kubernetes V1.1版本新增了Ingress API 用来标识7层服务
为什么不适用round-robin DNS?
最有意义的一点, DNS会在很多客户端进行缓存。
代理模式的分类
- userspace代理模式
- Iptable代理模式
- IPVS
-这种模式, kube-proxy会监视Kubernetes service对象和Endpoints, 调用netlink接口以响应的创建ipvs规则并定期与kubernetes service对象和Endpoints对象同步ipvs规则,以确保ipvs状态与期望一致。访问服务时,流量将被重定向到其中一个后端Pod。
与iptables类似,ipvs与netfilter的hook功能,但使用hash表作为底层数据结构,并在内核空间中工作。这意味着,ipvs可以更快的重定向流量,并且在同步代理规则时具有更好的性能。此外,IPVS为负载均衡算法提供了更多选项
rr:轮询
lc:最小连接数
dh:目标哈希
sh:源哈希
sed:最短期望延迟
nq:不排队调度
CLuster Ip
ClusterIp主要在每个node节点使用iptables,将发向ClusterIp对应对口的数据,抓发到kube-proxy中,然后kube-proxyu自己内部实现有负载均衡的方法,并可以查询到这个service下对应pod的地址和端口,进而把数据转发给对应的pod的地址和端口。
为了实现图上功能,需要以下几个组件协同工作:
- apiserver用户通过kubectl命令向apiserver发送创建service的命令,apiserver接收到请求后将数据存储到etcd中
- kube-proxy kubernetes的每个节点中都有一个叫做kube-proxy的进程,这个进程负责感知service,pod的变化,并将变化的信息写入本地的iptables规则中
- iptables使用NAT等技术将virtualIP的流量专注endpoint中
ClusterIp时集群内布虚拟的地址,NodePort是宿主机真实的物理网卡上面的ip地址的端口
Headless Service
有时不需要或者不想要负载均衡,以及单独的Service IP。遇到这种情况,可以通过指定Cluster Ip(spec.clusterIp)的值为None,来创建Headless service。这类service并不会分配ClusterIp, kube-proxy不会处理它们,而且平台也不会为他们进行负载均衡和路由。
Node Port
原理在于在node上开了一个端口,将向该端口的流量导入到kube-proxy,然后又kube-proxy进一步给到对应的pod
Load Balancer
load balancer和nodePort其实是同一种方式,区别在于loadBalancer比nodeport多了一步,就是可以调用cloud provider去创建 load balancer 向节点倒流
External Name
这种类型Service通过返回CNAME和它的值,可以将夫区映射到externalName字段的内容(例如,hub.atguihu.com) ExternalName service是service的特例,它没有selector,也没有定义任何的端口和Endpoint。相反的,对于运行在集群外部的服务,它通过返回该外部服务的别名来提供这种服务。
当查询主机my-service.default.sve.cluster.local(SVC_NAME.NAMESPACE.svc.cluster.local)时,集群的DNS服务将返回一个值,my.database.example.com的CNAME记录。访问这个服务的工作方式和其他的相同,唯一不同的是重定向发生在DNS层,而且不会进行代理或转发。
Service Ingress
Ingress HTTPs代理
7 存储
- configMap
- Secret
- Volume
- PC
ConfigMap
- 使用ConfigMap替代环境变量
secret
解决了 密码、token、密钥等敏感数据的配置问题。而不需要把这些数据暴露到镜像或者Pod Spec中,Secret 可以以Volume或者环境变量的方式使用
Secret有三种类型
- Service Account , 用来访问Kubernetes Api,由Kubernetes自动创建,并且会自动挂载到Pod的/run/secrets/kubernetes.io/serviceaccount目录中
- Opaque: base64编码格式的Secret,用来存储密码、密钥等
- Kubernetes.io/dockerconfigjson:用来存储私有docker registry的认证信息
Service Account
使用方式
- 将secret挂在到Volume中
- 将secret导出到环境变量中
Volume
容器磁盘上的文件的生命周期是短暂的,这就使得再容器钟运行重要应用时会出现一些问题。首先当容器崩溃时,kubelet会重启,但是容器中的文件将丢失——容器以干净的状态重新启动。其次,再Pod中同时运行多个容器,这些容器之间通常需要共享文件,Kubernetes中的Volume抽象就很好解决了这些问题
背景
Kubernetes中的卷有明确的寿命——与封装它的Pod相同。所以,卷的声明比Pod中所有容器都长,当着哥容器重启时数据仍然得以保存。当然,当Pod不再存在时,卷也不复存在。也许更重要的是,Kubernetes支持多种类型的卷,Pod可以同时使用任意数量的卷。
卷的类型
Kubernetes 支持一下类型的卷
Empty dir
当Pod被分配给节点时,首先创建emptyDir卷,并且只要该Pod再该节点上运行,该卷就会存在。正如卷的名字所述,它最初时空的。Pod中的容器可以读取和写入emptyDir卷重的相同文件,尽管该卷可以挂载到每个容器中的相同或不同路径上。当处于任何原因,节点中删除Pod时,emptyDir中的数据将被永久删除。
容器的崩溃不会从节点移除pod,因此,emptyDir卷中的数据再容器崩溃时是安全的
emptyDir的用法有:
- 暂存空间,例如用于基于磁盘的合并排序
- 用作长时间计算崩溃回复时的检查点
- Web服务器容器提供数据时,保存内容管理器容器提取的文件
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。