K8s学习笔记 (2)
@ wgjak47 | 星期六,七月 20 日,2019 年 | 5 分钟阅读 | 更新于 星期六,七月 20 日,2019 年

k8s学习笔记

k8s 学习笔记

K8s API设计原则

  1. 声明式
  2. API对象高内聚低耦合
  3. 高层API以操作意图为基础设计
  4. 底层API根据高层API的控制需要设计
  5. 避免简单封装,不要有外部API无法显示知道的内部隐藏机制
  6. API操作复杂度不要超过O(N)
  7. API对象状态不依赖网络连接状态
  8. 避免依赖全局状态

控制机制设计原则

  1. 控制逻辑应该只依赖当前的状态
  2. 容错处理
  3. 避免复杂状态机,不依赖无法监控的内部状态
  4. 保证模块出错时的自愈功能
  5. 必要时可以优雅的降级服务

K8s开放接口

CRI (Container Runtime Interface)

容器运行时接口,提供计算资源。 接口定义: api.proto

  • RuntimeService: 容器的远程管理API
  • ImageService: 镜像管理API

CNI (Container Network Interface)

容器网络接口,提供网络资源 接口定义: api.go

CSI (COntainer Storage Interface)

容器存储接口,提供存储资源 规范文档

K8s 网络插件

功能:

  1. 保证每个Pod拥有一个集群内唯一的IP地址
  2. 保证不同节点的IP地址划分不会重复
  3. 保证跨节点的Pod可以互相通信
  4. 保证不同节点的Pod可以与跨节点的主机互相通信

常见插件:

  • Calico
  • Canal
  • Cilium
  • Flannel
  • Kube-router
  • WeaveNet

benchmark

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

  1. pod是k8s调度的基本单位,包含一个或者多个容器。在同一个pod内的容器会自动分配到同一个node上。
  2. pod会被分配一个唯一的ip地址,pod中所有的容器共享网络空间,可以通过localhost相互通讯。
  3. pod中的容器共享pod被分配的volume
  4. Pod由Controller管理和创建,Controller根据Pod模板(例如Replication Contoller, Jobs和DaemonSets)来创建实际的Pod
  5. Pod是非持久的,由controller提供扩展,自愈很升级等功能

init容器

Pod支持在应用容器启动前启动一个或者多个init容器。init容器遵循一下连个原则:

  1. Init 容器总是运行到成功完成为止。
  2. 每个 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)容器

  1. 在pod中担任Linux命名空间共享的基础;
  2. 启用pid命名空间,开启init进程。

Pod中的容器通过Pause容器来共享网络/存储资源 原理: https://o-my-chenjian.com/2017/10/17/The-Pause-Container-Of-Kubernetes/

Pod生命周期

pod的可能状态如下:  

  1. Pending
  2. Running
  3. Succeeded Pod 中的所有容器都被成功终止,并且不会再重启。 (Job型)
  4. Failed Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。
  5. Unknown

pod phase

容器探针

探针是由 kubelet 对容器执行的定期诊断。k8s有三种方式来进行诊断:

  1. ExecAction 在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
  2. TCPSocketAction 对指定端口上的容器的 IP 地址进行 TCP 检查。如果端口打开,则诊断被认为是成功的。
  3. HTTPGetAction 对指定的端口和路径上的容器的 IP 地址执行 HTTP Get 请求。如果响应的状态码大于等于200 且小于 400,则诊断被认为是成功的。

每次探测的结果如下:

  1. 成功:容器通过了诊断。
  2. 失败:容器未通过诊断。
  3. 未知:诊断失败,因此不会采取任何行动。

探针类型

  1. livenessProbe 指示容器是否正在运行。如果存活探测失败,则 kubelet 会杀死容器,并且容器将受到其 重启策略 的影响。如果容器不提供存活探针,则默认状态为 Success。
  2. 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

重启策略

  1. PodSpec中的restartPolicy字段
  2. 可能的值为:
  • Always default
  • OnFailure
  • Never

Pod Hook

Pod hook(钩子)是由Kubernetes管理的kubelet发起的,当容器中的进程启动前或者容器中的进程终止之前运行,这是包含在容器的生命周期之中。可以同时为Pod中的所有容器都配置hook。hook有一下两种类型:

  1. exec: 执行一段命令
  2. 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数量。