K8S架构图
通过架构图可以看到K8S的几个关键组件之间的工作方式
- APIS 是接受 scheduler ,controller manager, kubectl , etcd 等组件的调用
- 左边的是master节点,master节点里面的apis收到请求之后,就把请求发往对应的node节点里面的 kubelet中
k8s 组件
- APIS: 所有服务访问统一入口
- controller manager: 维护副本的期望数目
- scheduler: 负责接受任务,选择合适的节点分配任务
- etcd: 键值对数据库, 存储K8S所有信息
- kubelet: 直接跟容器引擎交互,实现容器的生命周期管理
- kube-proxy:负责写入规则至 IPTABLES,IPVS 实现服务映射访问
插件
- COREDNS: 可以为集群中的SVC创建一个域名IP的对应关系解析
- DASHBOARD:给K8S集群提供一个B/S结构访问体系
- INGRESS CONTROLLER: 实现7层代理
- FEDERATION:提供一个跨集群中心多K8S统一管理功能
- PROMETHEUS: 提供K8S集群的监控能力
概念
POD 概念
pod被控制器管理,不同类型的控制器管理的pod状态不同,控制器分为几种
ReplicationController & ReplicaSet & Deployment
replicationController 确保容器应用副本数始终保持在用户定义的副本数,如果有容器异常退出,会自动创建新的pod来替代。
replicaSet 跟 replicationController没有本质不同,官方建议使用replicaSet
建议使用Deployment来管理ReplicaSet
statefulSet
statefulSet 是为了解决 有状态服务的问题,其场景包括:
稳定的持久化存储,pod重新调度后还能访问到相同的持久化数据,基于PVC实现
稳定的网络标志,pod重新调度后其podname和hostname不变,基于headless service实现
有序部署,有序扩展,有序收缩,有序删除
DaemonSet
DaemonSet 确保全部nde上运行一个pod的副本,当有node加入集群时,会为他们新增一个pod。
典型用法:
在每个node上运行日志收集 daemon,例如 fluentd,logstash。
每个node上运行监控daemon,例如 prometheus
Job , Cronjob
job负责批处理任务,仅执行一次的任务,它保证批处理任务的一个或多个pod成功结束
Conjob管理基于时间的job,
给定时间点只运行一次
周期性的在给定时间点运行
网络通讯方式
同一个Pod内多个容器之间:lo
各pod之间通讯:overlay network
pod与service之间的通讯:各节点的iptables规则
flannel 网络解决方案
ETCD 给 flannel提供的数据:
存储管理flannel可分配id地址,监控ETCD中每个pod的实际地址,并在内存建立pod节点路由表
K8S中的资源
资源类型
- 名称空间级别: 不同名称空间之间相互资源是看不到的
工作负载型资源: pod,replicaSet,Deployment,statefulSet,DaemonSet,Job,ConJob
服务发现及负载均衡资源: service, ingress
配置与存储资源: volume,CSI
特殊类型 ConfigMap当配置中心使用,Secret保存敏感数据,DownwardAPI外部环境输出给容器 - 集群级别: role, 定义了之后,全部集群都可见
- 元数据型: HPA, 通过指标操作
资源清单
k8s中,使用yaml格式的文件来创建符合预期的pod,这样的 yaml文件成为资源清单
必须存在的属性
参数名 | 字段类型 | 说明 |
---|---|---|
version | string | k8s API 的版本,基本上是V1 |
kind | string | yaml文件定义的资源类型和角色,比如pod |
metadata | object | 元数据对象,固定就写metadata |
metadata.name | string | 元数据对象的名字,这里由我们编写,比如命名Pod的名字 |
metadata.namespace | string | 元数据对象的命名空间,由我们自身定义 |
spec | object | 详细定义对象,固定值就写spec |
spec.containers[] | list | spec对象的容器列表定义,是一个列表 |
spec.containers[].name | string | 这里定义容器的名字 |
spec.containers[].image | string | 这里定义要用的镜像名称 |
spec.containers[].imagePullPolicy | string | 定义镜像拉取策略,有Always,Never,IfNotPersent,默认Always |
spec.containers[].command[] | list | 指定容器启动命令,因为是数组可以指定多个,不指定则使用镜像打包时使用的启动命令 |
spec.containers[].args[] | list | 指定容器启动命令参数,可以指定多个 |
spec.containers[].workingDir | string | 指定容器工作目录 |
spec.containers[].volumeMounts[] | list | 指定容器内部的存储卷配置 |
spec.containers[].volumeMounts[].name | string | 指定可以被容器挂载的存储卷的名称 |
spec.containers[].volumeMounts[].mountPath | string | 指定可以被容器挂载的存储卷路径 |
spec.containers[].volumeMounts[].readOnly | string | 设置存储卷路径的读写模式,默认为读写模式 |
spec.containers[].ports[] | list | 指定容器需要用到的端口列表 |
spec.containers[].ports[].name | string | 指定端口名称 |
spec.containers[].ports[].containerPort | string | 指定容器需要监听的端口号 |
spec.containers[].ports[].hostPort | string | 指定容器所在主机需要监听的端口号,设置了hostport不能在同一台启动两个副本 |
spec.containers[].ports[].protocol | string | 指定端口协议,默认为tcp |
spec.containers[].env[] | list | 指定容器运行前需要设置的环境变量列表 |
spec.containers[].env[].name | string | 指定环境变量名称 |
spec.containers[].env[].value | string | 环境变量的值 |
spec.containers[].resources | object | 指定资源限制和资源请求的值 |
spec.containers[].resources.limits | object | 指定容器运行时资源的上限 |
spec.containers[].resources.limits.cpu | string | 指定cpu的限制 |
spec.containers[].resources.limits.memory | string | 内存的限制 |
spec.containers[].resources.requests | object | 指定容器启动和调度时限制设置 |
spec.containers[].resources.requests.cpu | string | cpu请求 |
spec.containers[].resources.requests.memory | string | 内存请求 |
spec.restartolicy | string | 定义pod重启策略,Always,OnFailure,Never |
spec.nodeSelector | object | 定义node的label过滤标签,kv格式指定 |
spec.imagePullSecrets | object | 定义pull镜像时使用secret名称,kv格式 |
spec.hostNetwork | boolean | 定义是否使用主机网络,默认false |
容器生命周期
- init容器
pod能够具有多个容器,应用运行在容器里面,但是它也可能有一个或多个先于应用容器启动的 init容器
init容器总是运行到成功完成为止
每个init容器必须在下一个init容器启动之前成功完成
如果pod的init容器启动失败K8S会不断重启pod直到成功,如果 pod 的 restartPolicy为Never就不会重启 - init 模板
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-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;']
这个模板创建了一个容器叫 myapp-container 然后两个init容器 init-myservice,init-mydb, init容器监听 myservice 和mydb
启动后发现init容器过不去,因为缺少了 myservice和mydb
创建一个myservice
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
当创建了一个myservice之后,init-service的容器就找到了myservice于是就是结束
再创建一个mydb
apiVersion: v1
kind: Service
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
- initC特殊说明
在pod启动过程中,init容器混顺序在 网络和数据卷初始化之后启动,每个容器必须在下一个容器启动之前成功退出。网络和数据卷的初始化是在 pause中完成的
探针
探针是由 kubelet 对容器执行的定期诊断,要执行诊断, kubelet 调用由容器实现的handler,有三种类型的处理程序
- execAction: 在容器内执行指定命令,如果命令退出时返回码为0则诊断成功
- TCPSocketAction 对指定端口的容器ip地址进行tcp检查,如果端口打开,则诊断被认为是成功的
- HTTPGetAction 对指定端口路径的容器进行get请求,如果状态码大于200小于400则认为是成功的
探测方式
- livenessProbe: 在整个生命周期中一直存在,不断探测容器是否存活,如果不存活了,kubelet就会杀死容器
- readinessProbe: 指示容器是否准备好请求,如果没准备好,容器状态就不是就绪状态
探针检测-
apiVersion: v1
kind: Service
metadata:
name: mydb
spec:
containers:
- name: test
image: .....
# 一直检测
livenessProbe:
httpGet:
path: /health
port: 8080
scheme: HTTP
# 程序开始的时候检测,如果不通过状态就不会就绪
readinessProbe:
httpGet:
path: /health
port: 8080
scheme: HTTP
start stop
apiVersion: v1
kind: Service
metadata:
name: mydb
spec:
containers:
- name : test
image: .....
lifecycle:
# 开始之前执行的东西
postStart:
exec:
command: ["bin/sh","-c","echo hello message > /usr/local/message"]
# 结束的之前执行的东西
preStop:
exec:
command: ["/usr/bin/nginx","-s","quit"]
容器的状态
- Pending : pod 已经被k8s系统接受,但有一个或多个镜像尚未被创建,需要等待
- Running : 正在运行中
- Succeeded : pod中所有容器被成功终止
- Failed : 所有容器终止,但是至少有一个是异常退出
- Unknow: pod与主机通信失败
k8s 排查错误
- 如果一个容器出现报错的时候, 调用 kubectl get pod查看
- 调用kubectl describe pod pod名称 ,查看pod信息
- 已经确定是test的容器出错,就查看test容器的日志信息, kubectl logs pod名称 -c 容器名称