1、基本概念
1.1、k8s
-
k8s是一个容器编排工具。它是集群架构,有master和node节点组成。master有api server,controller manager,scheduler调度器。node作为工作节点有kubelet,kube proxy和容器引擎如docker。
# api server 提供了资源操作的唯一入口,并提供认证、授权、访问控制、API注册和发现等机制; # controller manager 负责维护集群的状态,比如故障检测、自动扩展、滚动更新等; 各个不同的controller管理不同的资源,如replication controller管理deployment、statefulSet,daemonSet的生命周期;namespace controller管理namespace资源。 # scheduler 调度器,负责资源的调度,按照预定的调度策略将Pod调度到相应的机器上;亲和性、污点容忍、指定。 # etcd 分布式的键值对数据库,存储数据,可以持久化。 # kubelet 直接跟容器引擎(docker)交互(CRI容器运行接口)实现pod里面容器的生命周期管理 # kube proxy 负责为Service提供cluster内部的服务发现和负载均衡;写入规则至iptables或者ipvs。 # Container runtime 负责镜像管理以及Pod和容器的真正运行(CRI);docker或者rkt容器引擎等 --- # kube-dns 负责为整个集群提供DNS服务 # dashboard B/S访问体系 # ingress controller 官方四层代理,它可以实现7层代理,可以根据主机名,域名进行代理 # federation 集群联邦,跨集群中心多k8s统一管理功能 # prometheus 提供k8s集群的监控能力
更多细节可以参考Kubernetes中文手册。
-
流程
客户的启动容器等请求会先发给master节点,master节点有个scheduler调度器会分析node节点资源(cpu、内存)的可用状态,找到最佳适配的node来启动用户请求的容器。可见,Master节点主要还是负责管理和控制,Node节点是工作负载节点。 -
优点
滚动更新;弹性伸缩;负载均衡;适合微服务;轻量级;开源;
1.2、概念
-
Pod
Pod是Kubernetes中最基本的调度单元,一般说来,一个pod里只放一个容器,可以包含多个容器。
Pod逻辑上表示某种应用的一个实例,也就是容器的更上面的一层载体。它主要是无需关注容器引擎的具体实现是什么。docker或者其他如LXC 容器,rkt。k8s只管pod就行。一组相同功能的pod组成一个service对外提供访问。 pause容器: pod总会有一个“根容器”pause容器,它的存在可以使pod里面的容器之间可以进行共享,一是共享网络栈(localhost访问即可),二是共享存储卷。
-
Replication Controller,RC
Replication Controller,RC定义了副本数和创建容器的模板, 可以对pod以及里面的容器进行扩容,回滚,更新。保证按照预期的情况运行。
-
Replica Set,RS
Replica Set和Deployment,跟rc没有身本质区别, 唯一区别就是支持集合式的selector,对label支持集合的选取。 rc只支持等式的选取
-
Deployment
Deployment为Pod和Replica Set(下一代Replication Controller)提供声明式更新。 Deployment本身并不负责pod创建。它建立rs,由rs来创建。但是Deployments支持滚动更新。 虽然ReplicaSets可以独立使用,但是今天它主要被 Deployments 作为协调pod创建,删除和更新的机制。rc不支持rolling-update滚动更新。 即rs比rc多一个支持集合式的selector功能。label可以使用in,不仅仅是= deployment比又rs多支持rolling-update滚动更新的功能(创建多个rs),还支持版本记录、回滚、暂停升级等高级特性。
滚动更新:Deployment会创建多个rs,并且保存最近的历史几个rs。见下图。
-
HPA
Kubernetes有一个HPA(Horizontal Pod Autoscaler)的资源,可以实现基于CPU使用率的Pod自动伸缩的功能
-
StatefulSet
StatefulSet:用于有状态服务,它管理所有有状态的服务,比如MySQL、MongoDB集群等。而RC、Deployment、DaemonSet都是面向无状态的服务,它们所管理的Pod的IP、名字,启停顺序等都是随机的。
StatefulSet特点:
稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现。 稳定的网络标识符,即Pod重新调度后其PodName和HostName不变。 有序部署,有序扩展,基于init containers来实现。
重点
StatefulSet本质上是Deployment的一种变体,它为了解决有状态服务的问题。 它所管理的Pod拥有固定的Pod名称,启停顺序。 在StatefulSet中,Pod名字称为网络标识(hostname),还必须要用到共享存储。 在Deployment中,与之对应的服务是service, 而在StatefulSet中与之对应的headless service,headless service,即无头服务, headless service与service的区别就是它没有Cluster IP,解析它的名称时将返回该Headless Service对应的全部Pod的Endpoint列表。
-
DaemonSet
确保全部或者某些node(服务器)上运行一个pod的副本。跟屁虫的角色,比如日志收集,运行监控Prometheus。
-
Job
job,执行一次的pod。一些脚本的程序,比如备份脚本。cron job,定时执行。
-
Service
对外提供服务的角色。k8s的核心。 服务发现根据selector下选择服务条件的lable来进行联系。Service有ip:port。均衡负载(RR,轮询)内部已经实现好分配到某个pod执行。
2、网络通信
-
k8s认为所有的pod都在一个直接连通的扁平化的网络空间之中,每一个pod都有唯一ip地址。因此k8s的网络模型的名字叫做IP-perPod模型。
-
网络通信方式
同一个pod里面的多个容器:lo本地回环接口 各个pod之间: 在同一个node,则直接使用docker0或者cni0网桥进行转发。 不在同一个node节点,则使用覆盖网络overlay network或者underlay pod和service:各个节点的iptables规则/lvs 外网访问pod:通过service的nodeport或者云服务的负载均衡、或者更上一层的ingress、与主机同局域网的一个地址hostNetwork,利用宿主机的端口hostPort 等共5种方法 pod访问外网,SNAT转发
-
flannel
这个方案是flannel这个网络规划服务。让不同node为docker容器创建一个全集群唯一的虚拟ip地址。然后建立一个覆盖网络overlay network,通过这个覆盖网络将内容和虚拟ip信息包装起来,发送到另外一个node上。
3、资源清单
3.1、资源
k8s中所有的内容都抽象为资源,资源实例化之后,叫做对象。
一般k8s资源可以分为3类:一是,命名空间级别;二是,集群级别;三是,元数据型。
命名空间级别:
工作负载型资源对象(workload):pod,rc,ReplicaSet,Deployment,StatefulSet,DaemonSet,Job,Cronjob ...
服务发现及均衡资源对象:Service,Ingress ...
配置与存储资源对象:Volume(存储卷),CSI(容器存储接口,可以扩展各种各样的第三方存储卷),ConfigMap(当做配置中心来使用资源类型),Secret(保存敏感数据),DownwardAPI(把外部环境的信息输出给容器)
集群级资源:
Namespace,Node,Role,ClusterRole,RoleBinding,ClusterRoleBinding
元数据型资源:
HPA,PodTemplate(pod模板),LimitRange(资源限制)
3.2、资源清单
在k8s中,一般使用yaml格式的文件来创建符合我们预期期望的pod,这样的yaml文件我们一般称为资源清单。这些资源清单类型可以为Namespace、Pod、Service、Deployment等。
apiVersion: v1 #API版本
kind: Pod #资源类型必须大写
metadata: #元数据对象
name: pod-demo #如Pod名称
namespace: default #命名空间默认default
labels: #标签
app: myapp
spec: #详细对象
containers: #容器列表
- name: test1 #容器名称
image: qsm:latest #镜像
3.3、 Pod的声明周期
探测:在Pod的声明周期中保证里面的容器能够正常的提供服务。有些情况下:pod里面的容器存在,但是程序进程已经死亡了。常见就是Jenkins成功,但是服务因为某些原因没起来。
puas、init C、start、readiness、liveness、stop
1、首先是pod里面会创建puase根容器,共享网络栈和存储卷
2、然后执行初始化容器(init Containter),可有可无,主要初始化一些mainC所需要的东西,比如提前获取加密文件;或者检测其他服务是否正常启动等。
特点:一是总是运行到成功完成为止,失败会遵循MainC的重启策略。二是先来后到原则,前一个initC完全成功之后才会启动下一个initC。
3、接下来主容器(main Containter)运行,运行过程有4个点,
一个是start,刚开始运行容器的时候执行的命令。
一个是stop,容器结束的时候执行的命令。
中间有就绪检测readiness(检测成功完成之后,才能提供对外服务。不成功,即使pod的状态为running,但是ready显示0/1。)
中间有生存检测liveness(过程中,容器不能正常运行,会执行重启或者删除等操作)。
apiVersion: v1
kind: Pod
metadata:
name: qsm-pod
labels:
app: myapp
spec:
containers:
- name: qsm-container
image: busybox
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox
command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
- name: init-mydb
image: busybox
command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
上面的2个初始化容器是说检测到myservice和mydb才会成功
kind: Service
apiVersion: v1
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
---
kind: Service
apiVersion: v1
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
运行成功之后,Pod(qsm-pod)才会成功。原因是myservice和mydb对应的ip会写入coredns里面。
探针的三种类型
1、命令:指定在容器内执行的命令,返回0,则认为诊断成功
2、tcp:对ip+port进行检测,端口打开就任务诊断成功
3、http:执行一个http的get请求,返回码大于等于200,小于400认为诊断成功。
探测的2种方案(方式)
在Kubernetes上下文中就绪探针和存活探针被称作健康检查
1、就绪探针:经过短暂的延时,进行探测,检测成功完成之后,才能提供对外服务。不成功,即使pod的状态为running,但是ready显示0/1。svc也不会让其提供服务。
2、生存探针:经过短暂的延时,定时的进行检测程序是否还活着;若容器不能正常运行,会执行重启或者删除等操作,主要是看重启策略如何设置的。
注意:存活探针探测失败会导致pod重新启动,所以配置初始探测延迟initialDelaySeconds十分重要,要确保在应用准备之后探针才启动。否则,应用将无限重启!
举例
apiVersion: v1
kind: Pod
metadata:
name: readiness-httpget-pod
namespace: default
spec:
containers:
- name: readiness-httpget-container
image: busybox
imagePullPolicy: IfNotPresent
readinessProbe:
httpGet:
port: 8080
path: /health
initialDelaySeconds: 10 #探测延时时长,第一次探测前等待10秒,默认为0
periodSeconds: 3 #每3秒执行一次liveness探测,默认值10秒,最小1秒
livenessProbe:
exec:
command: ["test",