k8s学习笔记
k8s 学习笔记
K8s API设计原则
- 声明式
- API对象高内聚低耦合
- 高层API以操作意图为基础设计
- 底层API根据高层API的控制需要设计
- 避免简单封装,不要有外部API无法显示知道的内部隐藏机制
- API操作复杂度不要超过O(N)
- API对象状态不依赖网络连接状态
- 避免依赖全局状态
控制机制设计原则
- 控制逻辑应该只依赖当前的状态
- 容错处理
- 避免复杂状态机,不依赖无法监控的内部状态
- 保证模块出错时的自愈功能
- 必要时可以优雅的降级服务
K8s开放接口
CRI (Container Runtime Interface)
容器运行时接口,提供计算资源。 接口定义: api.proto
- RuntimeService: 容器的远程管理API
- ImageService: 镜像管理API
CNI (Container Network Interface)
容器网络接口,提供网络资源 接口定义: api.go
CSI (COntainer Storage Interface)
容器存储接口,提供存储资源 规范文档
K8s 网络插件
功能:
- 保证每个Pod拥有一个集群内唯一的IP地址
- 保证不同节点的IP地址划分不会重复
- 保证跨节点的Pod可以互相通信
- 保证不同节点的Pod可以与跨节点的主机互相通信
常见插件:
- Calico
- Canal
- Cilium
- Flannel
- Kube-router
- WeaveNet
K8s对象
k8s对象是持久化的条目,k8s使用这些条目去表示集群的状态,对象在k8s里描述如下信息:
- 什么容器化应用在运行(以及在哪个 Node 上)
- 可以被应用使用的资源
- 关于应用如何表现的策略,比如重启策略、升级策略,以及容错策略
k8s的工作就是保持这些对象存在。
对象与Spec状态
每个k8s对象都要包含两个嵌套的对象字段:
- spec 对象的期望状态
- status 对象的实际状态
例子:
# k8s API version
apiVersion: apps/v1beta1
# object type
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
每种对像的spec
不同,详情参见:https://kubernetes.io/docs/concepts/overview/kubernetes-api
Pod
- pod是k8s调度的基本单位,包含一个或者多个容器。在同一个pod内的容器会自动分配到同一个node上。
- pod会被分配一个唯一的ip地址,pod中所有的容器共享网络空间,可以通过localhost相互通讯。
- pod中的容器共享pod被分配的volume
- Pod由Controller管理和创建,Controller根据Pod模板(例如Replication Contoller, Jobs和DaemonSets)来创建实际的Pod
- Pod是非持久的,由controller提供扩展,自愈很升级等功能
init容器
Pod支持在应用容器启动前启动一个或者多个init容器。init容器遵循一下连个原则:
- Init 容器总是运行到成功完成为止。
- 每个 Init 容器都必须在下一个 Init 容器启动之前成功完成。
通过在PodSpec中添加initContainers
字段来添加init容器
注意initContainers
不支持readiness probe(存货探针)
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;']
Pause(Infra)容器
- 在pod中担任Linux命名空间共享的基础;
- 启用pid命名空间,开启init进程。
Pod中的容器通过Pause容器来共享网络/存储资源 原理: https://o-my-chenjian.com/2017/10/17/The-Pause-Container-Of-Kubernetes/
Pod生命周期
pod的可能状态如下:
- Pending
- Running
- Succeeded Pod 中的所有容器都被成功终止,并且不会再重启。 (Job型)
- Failed Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。
- Unknown
容器探针
探针是由 kubelet 对容器执行的定期诊断。k8s有三种方式来进行诊断:
- ExecAction 在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
- TCPSocketAction 对指定端口上的容器的 IP 地址进行 TCP 检查。如果端口打开,则诊断被认为是成功的。
- HTTPGetAction 对指定的端口和路径上的容器的 IP 地址执行 HTTP Get 请求。如果响应的状态码大于等于200 且小于 400,则诊断被认为是成功的。
每次探测的结果如下:
- 成功:容器通过了诊断。
- 失败:容器未通过诊断。
- 未知:诊断失败,因此不会采取任何行动。
探针类型
livenessProbe
指示容器是否正在运行。如果存活探测失败,则 kubelet 会杀死容器,并且容器将受到其 重启策略 的影响。如果容器不提供存活探针,则默认状态为 Success。readinessProbe
指示容器是否准备好服务请求。如果就绪探测失败,端点控制器将从与 Pod 匹配的所有 Service 的端点中删除该 Pod 的 IP 地址。初始延迟之前的就绪状态默认为 Failure。如果容器不提供就绪探针,则默认状态为 Success。
例子:
apiVersion: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- args:
- /server
image: k8s.gcr.io/liveness
livenessProbe:
httpGet:
# when "host" is not defined, "PodIP" will be used
# host: my-host
# when "scheme" is not defined, "HTTP" scheme will be used. Only "HTTP" and "HTTPS" are allowed
# scheme: HTTPS
path: /healthz
port: 8080
httpHeaders:
- name: X-Custom-Header
value: Awesome
initialDelaySeconds: 15
timeoutSeconds: 1
name: liveness
重启策略
- PodSpec中的restartPolicy字段
- 可能的值为:
- Always default
- OnFailure
- Never
Pod Hook
Pod hook(钩子)是由Kubernetes管理的kubelet发起的,当容器中的进程启动前或者容器中的进程终止之前运行,这是包含在容器的生命周期之中。可以同时为Pod中的所有容器都配置hook。hook有一下两种类型:
- exec: 执行一段命令
- HTTP: 发送HTTP请求 例子:
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: nginx
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
preStop:
exec:
command: ["/usr/sbin/nginx","-s","quit"]
在postStart操作执行完成之前,kubelet会锁住容器,不让应用程序的进程启动,也就是说也可以通过postStart操作也可以实现等待别的service启动完成
PDB(pod中断预算)
Pod中断分为自愿中断和非资源中断。非资源的中断为硬件/软件错误导致的Pod退出,自愿中断为人为发起操作导致的Pod退出。
用户可以通过为应用程序创建一个PodDisruptionBudget
, 这个PDB的作用是限制在同一时间自愿中断的复制应用程序中宕机的 Pod 的数量。如果应用的Pod数不足,
管理员在执行kubectl drain
等操作的时候会被阻塞,直到其它节点上的相应Pod启动,到达足够的pod数量。