k8s学习笔记¶
概念¶
概念¶
什么是k8s¶
概念¶
Kubernetes这个名字源于希腊语,意思是舵手或 飞行员,是州长和 控制论的根源。 K8s 是将8个字母“ubernete”替换为“8”而得到的缩写。
优点¶
敏捷应用程序创建和部署:与VM映像使用相比,增加了容器映像创建的简便性和效率。
持续开发,集成和部署:通过快速简便的回滚(由于映像不变性)提供可靠且频繁的容器映像构建和部署。
Dev和Ops关注点分离:在构建/发布时而不是部署时创建应用程序容器映像,从而将应用程序与基础架构分离。
可观察性 不仅可以显示操作系统级别的信息和指标,还可以显示应用程序运行状况和其他信号。
开发,测试和生产的环境一致性:在笔记本电脑上运行与在云中运行相同。
云和OS分发可移植性:在Ubuntu,RHEL,CoreOS,本地,Google Kubernetes引擎以及其他任何地方运行。
以应用程序为中心的管理:提高在虚拟硬件上运行OS的抽象级别,以及使用逻辑资源在OS上运行应用程序。
松散耦合,分布式,弹性,解放的微服务:应用程序被分解为更小,独立的部分,可以动态部署和管理 - 而不是在一台大型单一用途机器上运行的胖整体堆栈。
资源隔离:可预测的应用程序性能。
资源利用:高效率和高密度。
k8s能做什么¶
服务发现和负载均衡
存储编排
自动部署和回滚
自动完成资源限制
自我修复
秘钥和配置管理
Kubernetes组件¶
主要组件¶
- kube-apiserver
提供集群管理的api入口
- etcd
一致且高度可用的kv存储,为k8s集群数据提供后端存储
- kube-scheduler
集群的调度管理
- kube-controller-manager
控制器管理器管理多个控制器, 每个控制器管理对应的资源
- cloud-controller-manager
云厂商提供的控制器管理器, 有多个控制器, 管理k8s和对应云资源的管理分配
节点组件¶
- kubelet
每个集群节点都要运行的服务,确保容器在pod中运行
- kube-proxy
维护主机网络规划和转发来实现服务的抽象,维护节点上的网络规则,运行从集群内部或者外部的网络会话 与pod进行网络通信。
- Container Runtime
负责容器运行的容器软件,如docker,rtk等实现了kubernetes cri运行时接口的。
插件¶
- DNS
集群dns服务
- Web UI
web管理的面板
- Container Resource Monitoring
容器资源的监控
- Cluster-level Logging
提供一个统一的方式查看和分析日志
Kubernetes API¶
API版本控制¶
为了更容易消除字段或重构资源表示,Kubernetes支持多个API版本,每个API版本位于不同的API路径,例如/api/v1或 /apis/extensions/v1beta1。
API扩展¶
目前提供2种方法进行扩展
自定义资源crd方式进行扩展
聚合层AA方式进行扩展
对象¶
理解对象¶
k8s中的对象是持久化的实体,ks8使用这些实体来表示整个集群的状态,对象是目标性记录,记录的期望状态。我们对对象实体的操作(kubectl dashboard sdk等方式)都是和api server进行操作的。
对象规约(Spec)与状态(Status)¶
几乎每个对象都有这2个字段spec和status的。spec这个字段配置的是对象的期望状态,status是描述的当前状态。在任何时刻k8s的控制平面都会积极维护对象的实际状态,使之与期望状态一致。
描述 Kubernetes 对象¶
创建k8s对象,必须提供一个对象的规约用来描述对象的期望状态,还需要一些基本信息,比如名称。使用kubectl创建对象的时候,我们一般使用yaml格式,在kubectl发送请求到api server的时候会将yaml格式转换为json的格式的。 下面是一个简单的deployment实例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
接下来就可以通过kubectl apply -f nginx-deployment.yaml 方式进行创建
关键字段说明¶
- apiVersion:
这个是描述对象使用的api 版本信息的,具体是apps/v1 还是哪个beta版本的
- kind:
对象类型,具体是pod类型,还是deployment类型
- metadata:
帮助唯一表示对象的一些数据,属于对象的元数据信息,一般要有一个name uid和可选择的namespace的。
对象管理¶
对象管理的方式比较多, 这里主要说下kubectl方式,有如下几种方式。
管理技术 |
作用与 |
建议环境 |
学习难度 |
---|---|---|---|
指令式命令 |
活跃对象 |
开发项目 |
最低 |
指令式对象配置 |
单个文件 |
生产项目 |
中等 |
声明式对象配置 |
文件目录 |
生产项目 |
最高 |
指令式¶
kubectl create deployment nginx --image nginx
- 优点:
简单
- 缺点:
没法审计跟踪
没法模板化
指令式对象配置¶
kubectl create -f nginx.yaml
kubectl delte -f nginx.yaml -f redis.yaml
kubectl replace -f nginx.yaml
- 优点:
配置文件可以存储到版本控制系统中
对象配置可以与流程集成
对象配置提供了创建新对象的模板
- 缺点:
对活动对象的更新必须反映在配置文件中,不然下次替换会丢失
声明式对象配置¶
kubectl diff -R-f configs/
kubectl apply -R -f configs/
- 优点:
对活动对象的更改及时未合并到配置文件中,也会被保留下来。
可以自动检测每个文件的操作类型(这个文件是更新的,另外一个是创建的)
- 缺点:
难调试
名称¶
k8s资源的具体名字 ,需要在metadata.name中指定。 名字来标识在同类资源中的唯一性
uid¶
系统生成的随机字符串,用于表示唯一的资源对象。 udi标识在整个集群的唯一性。
命名空间¶
命名空间用于划分资源的一个逻辑分组, 可以用户环境隔离(生产和开发环境隔离) 配合网络插件完成网络隔离。
命名空间提供一个范围,资源的名称需要在命名空间下是唯一的,命名空间不能相互嵌套,命名空间是并列的, 每个资源只能在一个命名空间下。 查看所有命名空间
kubectl get namespace
NAME STATUS AGE
default Active 18m
kube-node-lease Active 18m
kube-public Active 18m
kube-system Active 18m
这4个ns是默认就会创建的
default: 没有指定命名空间的对象使用这个命名空间
kube-system: 系统创建对象使用的命名空间
kube-public: 所有用户都可以读取
kube-node-lease: 这个名字空间用于与各个节点租期(lease)对象,这个对象的设计是的集群规模比较大的时候节点的心跳检查得到提升。
不是所有的资源都要归属一个命名空间, node,pv都是不属于任何一个命名空间的。 更详细的可以通过命令获取
kubectl api-resource --namespaced=false
kubectl api-resource --namespaced=true
标签¶
标签是一个对象, 包含多个kv对象。
常用标签
“release” : “stable”, “release” : “canary”
“environment” : “dev”, “environment” : “qa”, “environment” : “production”
“tier” : “frontend”, “tier” : “backend”, “tier” : “cache”
“partition” : “customerA”, “partition” : “customerB”
“track” : “daily”, “track” : “weekly”
标签选择器¶
用于根据标签选择特定k8s资源对象,有基于等值和集合的2中选择方式。 yaml资源定义清单文件中使用matchLabels或者matchExpressions2种方式来选择资源。
注解¶
注解和标签一样都是kv数据, 只是不能用于选择,可以指定下如下信息。 负责人信息,出处,git提交信息或者版本号。
字段选择器¶
用于筛选特定字段匹配特定值的资源
kubectl get statefulsets,services --field-selector metadata.namespace!=default
kubectl get pods -l 'environment in (production, qa)'
集合选择器¶
上面是通过kubectl方式具体怎么在yaml使用选择呢。 这个地方给个样例。
selector:
matchLabels:
component: redis
matchExpressions:
- {key: tier, operator: In, values: [cache]}
- {key: environment, operator: NotIn, values: [dev]}
推荐使用的标签¶
注解¶
注解也是描述元数据的一种方式,当时注解和标签不同的是,这个不能被选择和标识对象。 注解里面的数据可以是结构化的数据,也可以是非结构化的数据。
哪些信息建议使用注解呢¶
构建信息,发布时间,git分支,pr数量,仓库地址等。
日志记录,监控地址,审计地址等。
团队网址等
架构¶
节点¶
节点是Kubernetes中的工作机器。接受控制面的管理。 节点上面有kubelet 容器运行时(docker或者rtk)以及kube-proxy。
地址¶
Hostname: 主机名字
ExternalIP: 外部ip
InternalIP: 内部ip
状态¶
OutOfDisk
Ready 就绪
MemoryPressure 内存压力
PIDPressure 进程过多
DiskPressure 磁盘空闲不足
NetworkUnavailable 网络不可达
ConfigOK
节点控制器¶
节点控制器为节点分配cidr块
使节点控制器的内部节点列表与云提供商的可用计算机列表保持同步
监控节点的健康状况。节点控制器负责在节点变得无法访问时将NodeStatus的NodeReady条件更新为ConditionUnknown
负责驱逐在有污点的节点上运行的pod(1.6以后)
可以负责创建表示节点条件的污点(1.8以后)
kubelet 负责创建和更新 NodeStatus 和 Lease 对象。
kubelet默认美5分钟更新node status, 默认10s更新一次租期信息。如果失败的话会指数级回退。
节点管理¶
标记一个节点不可调度
kubectl cordon <nodename>
Note
DaemonSet 通常提供节点本地的服务,即使节点上的负载应用已经被腾空,这些服务也仍需 运行在节点之上。
一个监控节点的描述信息说明
节点的描述信息包含如下几个部分内容
名字、角色、标签、注解、污点、创建时间、是否可以调度、租期信息
地址信息
事件
先决条件
容量数据(cpu, memory,pod)
分配情况
系统信息
pod cidr
[root@zhaojiedi-elk-2 ~]# kubectl describe node zkdemo-1.epc.duxiaoman.com
# 基本信息展示, 名字,角色,标签和主机信息
Name: zkdemo-1.epc.duxiaoman.com
Roles: <none>
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=zkdemo-1.epc.duxiaoman.com
kubernetes.io/os=linux
Annotations: flannel.alpha.coreos.com/backend-data: {"VNI":1,"VtepMAC":"b6:5b:04:70:59:c0"}
flannel.alpha.coreos.com/backend-type: vxlan
flannel.alpha.coreos.com/kube-subnet-manager: true
flannel.alpha.coreos.com/public-ip: 10.157.31.40
kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock
node.alpha.kubernetes.io/ttl: 0
volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp: Fri, 24 Sep 2021 19:08:39 +0800
# 污点信息,是否不可调度,租期信息,身份信息
Taints: <none>
Unschedulable: false
Lease:
HolderIdentity: zkdemo-1.epc.duxiaoman.com
AcquireTime: <unset>
RenewTime: Fri, 24 Sep 2021 20:11:07 +0800
# 状况进展,开始是网络不可达的,然后作为几个探测后,就ready了。
Conditions:
Type Status LastHeartbeatTime LastTransitionTime Reason Message
---- ------ ----------------- ------------------ ------ -------
NetworkUnavailable False Fri, 24 Sep 2021 19:21:34 +0800 Fri, 24 Sep 2021 19:21:34 +0800 FlannelIsUp Flannel is running on this node
MemoryPressure False Fri, 24 Sep 2021 20:10:29 +0800 Fri, 24 Sep 2021 19:08:39 +0800 KubeletHasSufficientMemory kubelet has sufficient memory available
DiskPressure False Fri, 24 Sep 2021 20:10:29 +0800 Fri, 24 Sep 2021 19:08:39 +0800 KubeletHasNoDiskPressure kubelet has no disk pressure
PIDPressure False Fri, 24 Sep 2021 20:10:29 +0800 Fri, 24 Sep 2021 19:08:39 +0800 KubeletHasSufficientPID kubelet has sufficient PID available
Ready True Fri, 24 Sep 2021 20:10:29 +0800 Fri, 24 Sep 2021 19:19:52 +0800 KubeletReady kubelet is posting ready status
Addresses:
InternalIP: 10.157.31.40
Hostname: zkdemo-1.epc.duxiaoman.com
# 容量信息,表示机器有多少资源的
Capacity:
cpu: 2
ephemeral-storage: 20510288Ki
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 8173780Ki
pods: 110
# 分配的资源情况
Allocatable:
cpu: 2
ephemeral-storage: 18902281390
hugepages-1Gi: 0
hugepages-2Mi: 0
memory: 8071380Ki
pods: 110
# 系统信息,
System Info:
Machine ID: f58b2b87d0c14042984f07b3654572ca
System UUID: 30950B98-CED8-4BFB-B006-9A572CC41A86
Boot ID: 574a0c40-db74-4600-b676-9dfa50caf862
Kernel Version: 3.10.0-1160.42.2.el7.x86_64
OS Image: CentOS Linux 7 (Core)
Operating System: linux
Architecture: amd64
Container Runtime Version: docker://20.10.8
Kubelet Version: v1.22.2
Kube-Proxy Version: v1.22.2
PodCIDR: 10.244.2.0/24
PodCIDRs: 10.244.2.0/24
Non-terminated Pods: (2 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits Age
--------- ---- ------------ ---------- --------------- ------------- ---
kube-system kube-flannel-ds-v74v6 100m (5%) 100m (5%) 50Mi (0%) 50Mi (0%) 62m
kube-system kube-proxy-prl4c 0 (0%) 0 (0%) 0 (0%) 0 (0%) 62m
# 分配的资源情况
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
Resource Requests Limits
-------- -------- ------
cpu 100m (5%) 100m (5%)
memory 50Mi (0%) 50Mi (0%)
ephemeral-storage 0 (0%) 0 (0%)
hugepages-1Gi 0 (0%) 0 (0%)
hugepages-2Mi 0 (0%) 0 (0%)
# 事件信息
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Starting 62m kubelet Starting kubelet.
Normal NodeHasSufficientMemory 62m (x2 over 62m) kubelet Node zkdemo-1.epc.duxiaoman.com status is now: NodeHasSufficientMemory
Normal NodeHasNoDiskPressure 62m (x2 over 62m) kubelet Node zkdemo-1.epc.duxiaoman.com status is now: NodeHasNoDiskPressure
Normal NodeHasSufficientPID 62m (x2 over 62m) kubelet Node zkdemo-1.epc.duxiaoman.com status is now: NodeHasSufficientPID
Normal NodeAllocatableEnforced 62m kubelet Updated Node Allocatable limit across pods
Normal NodeReady 51m kubelet Node zkdemo-1.epc.duxiaoman.com status is now: NodeRead
节点可靠性¶
节点控制器把逐出速率限制在每秒 –node-eviction-rate 个(默认为 0.1)。 这表示它每 10 秒钟内至多从一个节点驱逐 Pod。 一个可用区的节点变为不健康时,节点的驱逐行为将发生改变,检查不健康的node百分比,若果超过–unhealthy-zone-threshold (默认为 0.55),驱逐的速率将会降低,降低为每秒 –secondary-node-eviction-rate 个(默认为 0.01)。 如果集群规模比较小,如果集群较小(意即小于等于 –large-cluster-size-threshold 个节点 - 默认为 50),驱逐操作会停止。
节点控制器还会驱逐哪些运行在noexecute污点节点上面的pod。
节点容量¶
node对象会跟踪节点的资源容量的,通过自注册方式生成注册期间的报告自身容量数据,默认k8s是使用机器全部的资源的, 可以设置一些预留资源给非k8s服务或者容器使用的。
k8s将资源分为几个部分
kube-reserved: 用来给kubelet 容器运行时 节点问题监控器等k8s系统守护进程资源预留的
system-reserved: 这个部分是系统预留,主要给类似sshd udev等系统守护进程预留的资源
eviction-hard: 节点的内存压力降导致系统内存不足,影响整个节点上面的pod服务Pod,将不能使用超过 capacity-eviction-hard 所 指定的资源量。因此,为驱逐而预留的资源对 Pod 是不可用的。
节点拓扑¶
待补充。
主节点通信¶
集群到master节点¶
所有组件都是需要和apiserver交互。
pod启动的时候, 会注入证书和服务账户令牌到pod中,
apiserver到kubelet¶
从apiserver到kubelet的连接用于:
获取pod的日志。
附加(通过kubectl)到运行的pod。
提供kubelet的端口转发功能。
apiserver到pod,service,node¶
从apiserver到节点,pod或服务的连接默认为纯HTTP连接,因此既未经过身份验证也未加密。它们可以通过前缀https:到 API URL中的节点。
控制器¶
控制器有个期望状态,当前状态,控制器控制当前状态到期望状态。
控制器模式¶
一个控制器至少追踪一种类型的k8s资源,这些对象都有一个spec字段标识对象的期望状态,改资源控制器负责其当前状态接近期望状态。
通过api服务器来控制¶
job控制器是一个k8s内置的控制器,通过和集群的api服务器交互来管理状态。 job控制器就是通知api服务器来创建和移除pod,控制面其他组件跟进新的消息作出梵音(调度并运行pod)并且完成工作。
直接控制¶
相比job控制器,有些控制器需要对集群外部的一些东西进行修改,比如如果你使用一个控制回路保证集群中有足够的节点,节点不够的时候自动调用云厂商创建新的节点。 对应的控制器需要从api服务器获取自身需要的状态信息,然后直接和外部系统进行通信,并使得当前状态接近期望状态。
控制器做出了一些变更以使得事物更接近你的期望状态, 之后将当前状态报告给集群的 API 服务器。 其他控制回路可以观测到所汇报的数据的这种变化并采取其各自的行动。
设计¶
k8s内部有很多控制器,针对资源类型设计多种控制器,deployment的控制器,管理deployment创建的pod。 job控制器管理job创建pod。
云控制器管理器¶
使用云基础设施技术,你可以在公有云、私有云或者混合云环境中运行 Kubernetes。 Kubernetes 的信条是基于自动化的、API 驱动的基础设施,同时避免组件间紧密耦合。
组件 cloud-controller-manager 是指云控制器管理器, 云控制器管理器是指嵌入特定云的控制逻辑的 控制平面组件。 云控制器管理器使得你可以将你的集群连接到云提供商的 API 之上, 并将与该云平台交互的组件同与你的集群交互的组件分离开来。
功能¶
节点控制器: 节点控制器负责在云基础设施中创建新的服务器,并创建节点对象,节点控制器从云提供商获取当前租户的主机信息。 路由控制器: 配置云平台的路由,方便及其不同节点上的容器之间是可以相互通信的。 服务控制器: 集成基础设施负载均衡设备
鉴权¶
垃圾回收¶
垃圾回收是k8s用于清理集群资源各种机制的统称。
哪些资源需要清理¶
失败的pod
运行完毕的job pod
没有引用的对象
未使用的景象和容器
存储类(根据回收策略进行清理)
过期的csr(证书前面请求)
节点租用信息
容器¶
镜像¶
容器镜像是风中了应用程序和运行环境,容器镜像是可执行的软件包,可以单独运行。
镜像需要通过镜像仓库管理,然后在pod里面进行引用这个镜像地址即可。
更新镜像¶
默认的镜像拉取策略为IfNotPresent,如果镜像存在,会跳过镜像的拉取, 如果需要强制拉取,可以采取下面几种方式。
修改imagePullPolicy: Always
修改image的tag为latest
省略imagePullPolicy和要使用的镜像标签
启用AlwaysPullImages准入控制器
Note
应该避免使用latest这种tag作为镜像的tag,应该使用具体的tag版本号。
使用私有仓库¶
使用google容器仓库
使用aws容器仓库
使用azure容器仓库
配置节点验证私有仓库(所有pod可以读取已配置的仓库)
预先拉取镜像
在pod上面指定imagePullSecrets
在pod上面设置serverAccountName,在具体的serverAccountName上面设置具体的secret信息。
具体的使用如下: todo
容器环境¶
容器环境内容¶
容器环境内容有如下几个部分
文件系统,一个镜像和多个卷
容器自身信息
集群其他对象信息
容器信息¶
容器信息,pod名称和命名空间可以通过下行api转换为环境变量 样例todo
集群信息¶
创建容器时正在运行的所有服务都可以作为该容器的环境变量,对于名为A的服务,当映射到名为B的容器时,
A_SERVICE_HOST=<the host the service is running on>
A_SERVICE_PORT=<the port the service is running on>
样例todo
容器运行时类¶
你可以在不同的 Pod 设置不同的 RuntimeClass,以提供性能与安全性之间的平衡。 例如,如果你的部分工作负载需要高级别的信息安全保证,你可以决定在调度这些 Pod 时尽量使它们在使用硬件虚拟化的容器运行时中运行。 这样,你将从这些不同运行时所提供的额外隔离中获益,代价是一些额外的开销。
设置方法¶
todo
生命周期回调¶
回调方式¶
回调的生命周期可以在PostStart和PreStop进行配置的。
PostStart: 在容器被创建之后立即被执行。
PreStop: 在容器因 API 请求或者管理事件(诸如存活态探针、启动探针失败、资源抢占、资源竞争等) 而被终止之前
具体处理程序实现¶
Exec: 执行一个脚本
HTTP: 发送一个http请求
回调处理程序的日志不会在 Pod 事件中公开。 如果处理程序由于某种原因失败,它将播放一个事件。
todo 具体实践
工作负载¶
pods¶
pod是可以在k8s创建和管理的、最小的可部署的计算单元。
pod是一组容器,这些容器共享存储、网络、以及怎么运行这些容器的声明。
什么是pod¶
pod的共享上下文包括一组linux命名空间、控制组和可能一些其他的隔离方面。
pod可以说是共享命名空间和文件卷的一组docker容器。
Pod 天生地为其成员容器提供了两种共享资源:网络和 存储。
静态pod¶
静态pod是由特定节点上的kubelet守护进程管理,不需要api服务器看到他们,大部分的pod都是通过控制面板来管理的,对于静态pod是通过kubelet直接监控每个pod,并在失效时候重启。
kubelet自动尝试为每个静态pod在api服务器上面创建一个镜像pod,这意味节点上运行的pod在api服务器上面是可见的,但不可以通过api 服务器进行控制。
pods生命周期¶
pod生命周期¶
pod的生命周期开始pending阶段,正常启动后进入Running状态,后续失败或者成功进入Succeeded或者Failed状态。
pod在其生命周期,指挥被调度一次,知道这个pod停止或者终止。
Pod 自身不具有自愈能力。如果 Pod 被调度到某节点 而该节点之后失效,Pod 会被删除;类似地,Pod 无法在因节点资源 耗尽或者节点维护而被驱逐期间继续存活。Kubernetes 使用一种高级抽象 来管理这些相对而言可随时丢弃的 Pod 实例,称作 控制器。
Pod 阶段¶
Pending: 已经被k8s接受,还没有创建或者运行。比如容器还在拉取镜像中就是pending中的。
Running: pod已经绑定到某个节点,pod里面的容器已经创建完毕,至少有一个容器在运行中。
Succeeded: 成功终止了,不在重启。
Failed: 所有的容器都已经终止了,至少有一个容器失败终止,非0状态终止或者系统终止。
Unknown: 因为某些原因无法取得pod的状态,这种情况通常因为pod所在主机通信失联了。
容器状态¶
一旦调度器将 Pod 分派给某个节点,kubelet 就通过 容器运行时 开始为 Pod 创建容器。 容器的状态有三种 - Waiting(等待) - Running(运行中) - Terminated(已终止)
容器重启策略¶
重启策略有如下几个
Always
OnFailure
Never
restartPolicy仅仅针对同一个节点上kubelet的容器重启动作
Pod 状况¶
pod的状态有如下几个。
PodScheduled: 表示pod已经被调度到某个节点。
ContainersReady: pod中所有的容器已经就绪。
Initialized: 所有的Init容器都成功启动。
Ready: 启动完毕,可以提供服务,应该诶添加对应服务的负载均衡上的。
容器探针¶
probe是kubelet对pod执行定期的诊断,kubelet调用容器实现的handler处理程序,有三类。
ExecAction: 在容器内执行指定命令。如果命令退出时返回码为 0 则认为诊断成功。
TCPSocketAction: 对容器的 IP 地址上的指定端口执行 TCP 检查。如果端口打开,则诊断被认为是成功的。
HTTPGetAction: 对容器的 IP 地址上指定端口和路径执行 HTTP Get 请求。如果响应的状态码大于等于 200 且小于 400,则诊断被认为是成功的。
执行结果如下
Success: 成功的
Failure: 失败的
Unknown: 未知的
三种探针
livenessProbe: 存活性探测,期望在特定状态或者不健康的时候重新启动。
readinessProbe: 是否就绪探测,需要确定合适才可以给这个pod接受流量需要这个。
startupProbe: 是否启动探测,容器需要启动很久的,
pod终止¶
pod的终止是优雅的, 容器运行时会发送一个TERM信号到每个容器的主进程,如果超过一个时间还没有关闭,就会发送KILl信号,之后pod就会从api服务器上面移除。
强制删除pod¶
默认清理是有30s的宽限期限的。快速立刻的办法是。 设置 –grace-period=0 的同时额外设置 –force 参数才能发起强制删除请求。
init容器¶
Init 容器是一种特殊容器,在 Pod 内的应用容器启动之前运行。Init 容器可以包括一些应用镜像中不存在的实用工具和安装脚本。
和普通容器区别¶
init容器支持应用容器的全部字段和特性,包括资源限制、数据卷和安全设置,
init不支持lifecycle livenessprobe,readinessprobe和startupProbe.
init的容器是顺序执行的,上一个成功了,当前这个才可以执行,所有的都运行完成了, pod才开始正常的pod工作。
init容器使用场景¶
使用一些工具生成一个新的镜像
镜像构建和部署镜像分离
权限分离, init容器可以读写,pod容器只能读取。
延迟启动,确保容器启动前置成功。
注意点¶
如果pod重启,所有init容器必须重新执行的,对init容器的image修改,会触发容器重启的, 请注意保持init容器代码幂等性。
pod拓扑分布约束¶
拓扑分布约束来控制pod在集群内故障域之间的分布。例如区域(region),可用区(zone)这样有利于实现高可用并提升资源使用率。
先决条件¶
可以给节点所在的区域进行拓扑标记。
# 给其中一个节点进行标记,标记为region区域, zone 可用区
kubectl label node zkdemo-1.epc.duxiaoman.com region=beijing zone=a
# 确认下
kubectl get node --show-labels=true
这里我没有那么多机器,应该根据实际部署的位置进行标记, 这里我们假定我有2个区域,每个区域都有2个可用区。 一共4个work节点。
拓扑标记建议使用如下标签名字: topology.kubernetes.io/region和 topology.kubernetes.io/zone. 这个如果有cloud-coller-manager的时候应该会自动设置的。
pod分布约束¶
1kind: Pod
2apiVersion: v1
3metadata:
4 name: mypod
5 labels:
6 foo: bar
7spec:
8 topologySpreadConstraints:
9 - maxSkew: 1
10 topologyKey: zone
11 whenUnsatisfiable: DoNotSchedule
12 labelSelector:
13 matchLabels:
14 foo: bar
15 containers:
16 - name: pause
17 image: k8s.gcr.io/pause:3.1
先说明下几个字段
topologySpreadConstraints: 指定拓扑约束的, 可以有多个约束规则的。
maxSkew: 描述分布不均匀程度,是2个拓扑域差值
topologyKey: 拓扑标签的key,这里我们使用了zone
whenUnsatisfiable: 如果pod不满足分布约束的时候如何处理, donotschedule是不要调度,scheduleanyway是继续调度,进行偏差最小化。
labelSelector: 用于查找匹配的po,根据这个来统计各个拓扑域的pod数量。
设置集群级别的默认约束¶
apiVersion: kubescheduler.config.k8s.io/v1beta1
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: PodTopologySpread
args:
defaultConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
defaultingType: List
干扰¶
临时容器¶
临时容器是一个特殊的容器,在现有pod中临时运行,方便完成用户发起的操作,比如故障排除。
临时容器和普通容器区别¶
临时容器和其他的容器不同之处在于对资源或者执行的保障,并且不会自动重启,好多字段也是不支持的。
没有端口配置,探活等字段也是不允许的。
资源分配不可变的。
用途¶
当由于容器崩溃或容器镜像不包含调试工具而导致 kubectl exec 无用时, 临时容器对于交互式故障排查很有用。
具体怎么创建
kubectl debug -it ephemeral-demo --image=busybox --target=ephemeral-demo
工作负载资源¶
deployments¶
创建depolyments¶
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4 name: nginx-deployment
5 labels:
6 app: nginx
7spec:
8 replicas: 3
9 selector:
10 matchLabels:
11 app: nginx
12 template:
13 metadata:
14 labels:
15 app: nginx
16 spec:
17 containers:
18 - name: nginx
19 image: nginx:1.14.2
20 ports:
21 - containerPort: 80
kubectl apply -f deploy-nginx.yml
kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-66b6c48dd5-bxwbl 1/1 Running 0 4m19s
nginx-deployment-66b6c48dd5-xppgn 1/1 Running 0 4m19s
nginx-deployment-66b6c48dd5-xv65j 1/1 Running 0 4m19s
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 7m2s
主要字段说明:
NAME: 列出名称
READY: 显示的是就绪个数/期望个数
UP-TO-DATE: 已经更新的副本数量
AVAILABLE: 当前可供应用使用的副本数量
AGE: 应用程序运行的时间
更新¶
修改文件的镜像版本,然后再次apply一次。
kubectl get deploy -w
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 1 3 18m
nginx-deployment 4/3 1 4 19m
nginx-deployment 3/3 1 3 19m
nginx-deployment 3/3 2 3 19m
nginx-deployment 4/3 2 4 20m
nginx-deployment 4/3 3 4 20m
nginx-deployment 3/3 3 3 20m
nginx-deployment 4/3 3 4 20m
nginx-deployment 3/3 3 3 20m
查看变更¶
kubectl rollout history deploy nginx-deployment 1 ↵ 2470 21:04:51
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1 <none>
2 <none>
3 <none>
获取上线进度¶
vim deploy_nginx.yml
kubectl apply -f deploy_nginx.yml
deployment.apps/nginx-deployment configured
kubectl rollout status deployment nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
deployment "nginx-deployment" successfully rolled out
升级失败的可能原因¶
镜像拉取问题
权限不足
配额不足
就绪探测错误
限制范围问题
运行时候配置错误
statefulset¶
statefulset是用来管理有状态应用的工作负载api对象 和deployment不同的是,这些pod都有每个独立的粘性id,永久不变的id.
使用场景¶
稳定的唯一标识的
稳定的、持久的存储
有序的,优雅的部署和缩放
有序的,自动的滚动更新。
创建statefulset¶
需要一个svc
1apiVersion: v1
2kind: Service
3metadata:
4 name: nginxsvc
5 labels:
6 app: nginx
7spec:
8 ports:
9 - name: web
10 port: 80
11 selector:
12 app: nginx
13 clusterIP: None
14
15
16
需要存储类
1apiVersion: storage.k8s.io/v1
2kind: StorageClass
3metadata:
4 name: low
5provisioner: kubernetes.io/glusterfs
6parameters:
7 resturl: "http://10.157.89.215:8077"
8 clusterid: "b8bc571569b52c572f56b19a5f6b6d9a"
9 restauthenabled: "true"
10 restuser: "admin"
11 restuserkey: "admin"
12 gidMin: "40000"
13 gidMax: "50000"
14 volumetype: "replicate:2"
创建sts
1apiVersion: apps/v1
2kind: StatefulSet
3metadata:
4 name: nginx
5 labels:
6 app: nginx
7spec:
8 replicas: 2
9 selector:
10 matchLabels:
11 app: nginx
12 serviceName: nginxsvc
13 template:
14 metadata:
15 name: nginx
16 labels:
17 app: nginx
18 spec:
19 containers:
20 - name: nginx
21 image: nginx
22 ports:
23 - name: web
24 containerPort: 80
25 volumeMounts:
26 - name: www
27 mountPath: /usr/share/nginx/html
28 volumeClaimTemplates:
29 - metadata:
30 name: www
31 spec:
32 storageClassName: low
33 accessModes:
34 - ReadWriteMany
35 resources:
36 requests:
37 storage: 10M
38
39
40
41
42
创建出来的pod名称是$(StatefulSet 名称)-$(序号),管理域的这个服务格式为: $(服务名称).$(命名空间).svc.cluster.local,其中 cluster.local 是集群域。
pod对应的dns域为$(pod 名称).$(所属服务的 DNS 域名)
部署和缩容保障¶
对于n个副本的sts,当部署pod的时候,依次创建的,顺序为0..N-1
删除pod的时候,它们是逆序终止的,顺序为 N-1..0。
在将缩放操作应用到 Pod 之前,它前面的所有 Pod 必须是 Running 和 Ready 状态。
主要属性说明¶
podManagementPolicy: OrderedReady 一个一个来,Parallel 并行的。
daemonset¶
daemonset是确保全部或者部分节点上运行一个pod的副本,当有节点接入的时候,能自动添加一个pod上去,移除的时候,pod也会被回收。
使用场景¶
每个节点运行集群的守护进程
日志收集守护进程
运行监控守护进程
创建daemonset¶
1apiVersion: apps/v1
2kind: DaemonSet
3metadata:
4 name: fluentd-elasticsearch
5 namespace: kube-system
6 labels:
7 k8s-app: fluentd-logging
8spec:
9 selector:
10 matchLabels:
11 name: fluentd-elasticsearch
12 template:
13 metadata:
14 labels:
15 name: fluentd-elasticsearch
16 spec:
17 tolerations:
18 # this toleration is to have the daemonset runnable on master nodes
19 # remove it if your masters can't run pods
20 - key: node-role.kubernetes.io/master
21 operator: Exists
22 effect: NoSchedule
23 containers:
24 - name: fluentd-elasticsearch
25 image: quay.io/fluentd_elasticsearch/fluentd:v2.5.2
26 resources:
27 limits:
28 memory: 200Mi
29 requests:
30 cpu: 100m
31 memory: 200Mi
32 volumeMounts:
33 - name: varlog
34 mountPath: /var/log
35 - name: varlibdockercontainers
36 mountPath: /var/lib/docker/containers
37 readOnly: true
38 terminationGracePeriodSeconds: 30
39 volumes:
40 - name: varlog
41 hostPath:
42 path: /var/log
43 - name: varlibdockercontainers
44 hostPath:
45 path: /var/lib/docker/containers
应用一下,通过如下命令查看
kubectl get pod -n kube-system |grep flu ✔ 2701 17:07:17
fluentd-elasticsearch-724f7 0/1 ContainerCreating 0 19s
fluentd-elasticsearch-r8jth 0/1 ContainerCreating 0 19s
发现,我们3个节点的, 一个master,2个node的, 可以看到这个没有调度到pod上面的。 问题出在哪里了。看下
master节点是有污点的,不可调度的,也就是,需要修改配置文件,添加我们的ds容忍这个污点即可。
具体添加片段如下:
spec:
tolerations:
# this toleration is to have the daemonset runnable on master nodes
# remove it if your masters can't run pods
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
通过describe可以看到
Tolerations:
node.kubernetes.io/disk-pressure:NoSchedule op=Exists
node.kubernetes.io/memory-pressure:NoSchedule op=Exists
node.kubernetes.io/not-ready:NoExecute op=Exists
node.kubernetes.io/pid-pressure:NoSchedule op=Exists
node.kubernetes.io/unreachable:NoExecute op=Exists
node.kubernetes.io/unschedulable:NoSchedule op=Exists
部分容忍我们都没有配置的,发现ds控制器自动帮忙给添加了。
daemon pod通信¶
推送,在ds pod里面直接把数据推送到一个数据库里面。
node ip port: pod可以使用host port 每个节点监听特定端口即可被访问。
dns: 创建一个无头服务,可以通过endpoint或者域名解析获取
service: 这个没办法获取所有节点的, 每次请求被调度到一个节点,不确定是哪个节点的。
jobs¶
jobs是创建一个或者多个pods的,当数量达到成功的个数阈值时候,任务就结束了, job是可以配置并行的。
job样例¶
1apiVersion: batch/v1
2kind: Job
3metadata:
4 name: pi
5spec:
6 ttlSecondsAfterFinished: 100
7 template:
8 spec:
9 containers:
10 - name: pi
11 image: perl
12 command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
13 restartPolicy: Never
14 backoffLimit: 4
15 parallelism: 2
应用一下,通过如下命令查看
kubectl get job
NAME COMPLETIONS DURATION AGE
pi 0/1 of 2 4s 4s
kubectl describe job pi
Name: pi
Namespace: default
Selector: controller-uid=d4d9a0cc-92c2-4d62-b632-9f209f765d16
Labels: controller-uid=d4d9a0cc-92c2-4d62-b632-9f209f765d16
job-name=pi
Annotations: <none>
Parallelism: 2
Completions: <unset>
Completion Mode: NonIndexed
Start Time: Wed, 06 Oct 2021 11:37:21 +0800
Completed At: Wed, 06 Oct 2021 11:37:45 +0800
Duration: 24s
Pods Statuses: 0 Running / 2 Succeeded / 0 Failed
Pod Template:
Labels: controller-uid=d4d9a0cc-92c2-4d62-b632-9f209f765d16
job-name=pi
Containers:
pi:
Image: perl
Port: <none>
Host Port: <none>
Command:
perl
-Mbignum=bpi
-wle
print bpi(2000)
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 51s job-controller Created pod: pi--1-rwc87
Normal SuccessfulCreate 51s job-controller Created pod: pi--1-9r6qf
Normal Completed 27s job-controller Job completed
job的并行执行¶
非并行: 通常启用一个pod,当pod终止后,视为pod完成状态。
具有确定完成计数的job: .spec.completions设为一个非0的,当成功的pod个数达到spec.completions后就认为pod完成。spec.completionmod=indexed时候,每个pod会有一个不同的索引。
带有工作队列冰箱的job: .spec.parallelism 多个pod协同,每个pod从队列取出来部分任务,每个pod都可以确定其他的pod是否完成,job任何pod成功终止,不在创建新的pod。
垃圾回收¶
k8s的垃圾回收的作用是删除某些曾经拥有属主但是 现在没有属主的对象。
属主和附属¶
某些 Kubernetes 对象是其它一些对象的属主。 例如,一个 ReplicaSet 是一组 Pod 的属主。 具有属主的对象被称为是属主的 附属 。 每个附属对象具有一个指向其所属对象的 metadata.ownerReferences 字段。
控制垃圾收集器删除附属¶
删除对象的时候可以级联删除的, 删除模式可以是后台模式和前台模式的。
如果删除对象,不删除他的附属对象,那么这些附属对象就是孤立对象。
前台级联删除¶
对象仍然可以通过rest api 可见
对象的deletionTimestamp字段被设置。
对象的metadata.finalizers字段包含foregroundDeletion。
后台级联删除¶
在 后台级联删除 模式下,Kubernetes 会立即删除属主对象,之后垃圾收集器 会在后台删除其附属对象。
删除样例¶
# 启动一个代理
kubectl proxy --port=8080
# 后台删除
curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/replicasets/my-repset \
-d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Background"}' \
-H "Content-Type: application/json"
# 前台删除
curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/replicasets/my-repset \
-d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \
-H "Content-Type: application/json"
# 让辅助成为孤立对象
curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/replicasets/my-repset \
-d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
-H "Content-Type: application/json"
# kubeclt方式
kubectl delete replicaset my-repset --cascade=orphan
ttl控制器¶
ttl控制器提供一种ttl机制来限制已完成执行的资源对象的生命周期,目前只处理job,以后可能支持其他类型资源。
TTL 控制器¶
TTL 控制器现在只支持 Job。集群操作员可以通过指定 Job 的 .spec.ttlSecondsAfterFinished 字段来自动清理已结束的作业(Complete 或 Failed)
使用ttl注意点¶
我们可以在资源创建后或者快ttl过期的时候修改ttl的, 但是一旦job过期,通过api修改ttl时间得到成功响应,系统不保证job被保留。
ttl控制器使用存储在k8s的时间戳来确定ttl是过去的, 对集群的时间偏差很敏感,可能导致ttl控制器在错误的时间清理掉资源对象。
crontab¶
cronjob可以完成周期调度,执行作业的。 区别了单独一次的job.
crontab简述¶
cronjobs对于创建周期性的,反复重复的任务很有用。
cronjob样例¶
1apiVersion: batch/v1
2kind: Job
3metadata:
4 name: pi
5spec:
6 ttlSecondsAfterFinished: 100
7 template:
8 spec:
9 containers:
10 - name: pi
11 image: perl
12 command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
13 restartPolicy: Never
14 backoffLimit: 4
15 parallelism: 2
具体crontab表达式可以参考下 crontab.guru
CronJob 限制¶
cronjob根据其计划编排,在每次执行任务的时候大约会创建一个job,之所以是大约,在某些情况下会创建2个job,或者无job。因此job应该是幂等的。
Warning
如果 startingDeadlineSeconds 的设置值低于 10 秒钟,CronJob 可能无法被调度。 这是因为 CronJob 控制器每 10 秒钟执行一次检查。
CronJob 仅负责创建与其调度时间相匹配的 Job,而 Job 又负责管理其代表的 Pod。
服务、负载均衡和联网¶
服务¶
将运行在一组 Pods 上的应用程序公开为网络服务的抽象方法。
k8s为pods提供自己的ip地址,并为一组pod提供相同的dns名字,可以通过他们完成负载均衡。
service资源¶
逻辑上的一组 Pod,一种可以访问它们的策略 —— 通常称为微服务。 Service 所针对的 Pods 集合通常是通过选择算符来确定的。
定义service¶
定义service或者一个负载均衡,主要是2个部分, 后端是那些节点,哪个端口还有协议等。 后端是那些节点是可以通过标签选择器来选择即可, 具体的端口需要通过spec.ports来指定的。
定义service样例¶
1apiVersion: v1
2kind: Service
3metadata:
4 name: my-service
5spec:
6 selector:
7 app: myapp
8 ports:
9 - port: 80
10 targetPort: 8080
# 查看创建的服务
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
glusterfs-dynamic-37d63494-2b84-4820-94c8-20cb328315f5 ClusterIP 10.101.172.236 <none> 1/TCP 8d
glusterfs-dynamic-d6cfa4b3-54d2-4174-b481-e5fb67eed218 ClusterIP 10.109.124.189 <none> 1/TCP 8d
glusterfs-dynamic-de235013-3d3a-42f0-8e39-b094a4761b5e ClusterIP 10.97.26.122 <none> 1/TCP 8d
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 13d
my-service ClusterIP 10.98.65.196 <none> 80/TCP 4s
nginxsvc ClusterIP None <none> 80/TCP 9d
# 查看创建的endpoint
kubectl get ep
NAME ENDPOINTS AGE
glusterfs-dynamic-37d63494-2b84-4820-94c8-20cb328315f5 10.157.89.216:1,10.157.31.40:1,10.157.89.215:1 8d
glusterfs-dynamic-d6cfa4b3-54d2-4174-b481-e5fb67eed218 <none> 8d
glusterfs-dynamic-de235013-3d3a-42f0-8e39-b094a4761b5e 10.157.89.216:1,10.157.31.40:1,10.157.89.215:1 8d
kubernetes 10.157.89.215:6443 13d
my-service <none> 9s
nginxsvc 10.244.1.10:80,10.244.2.9:80 9d
没有选择符的service¶
这种主要适用在如下几个场景中。
生产环境使用外部的数据库
服务在另外一个ns中,或者别的集群中。
服务迁移k8s中间阶段,部分服务还在非k8s中。
创建外部服务过程¶
1apiVersion: v1
2kind: Service
3metadata:
4 name: mydb
5spec:
6 ports:
7 - port: 3306
8 targetPort: 3306
1apiVersion: v1
2kind: Endpoints
3metadata:
4 name: mydb
5subsets:
6- addresses:
7 - ip : 192.168.0.5
8 ports:
9 - port: 3306
# 查看服务
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
glusterfs-dynamic-37d63494-2b84-4820-94c8-20cb328315f5 ClusterIP 10.101.172.236 <none> 1/TCP 8d
glusterfs-dynamic-d6cfa4b3-54d2-4174-b481-e5fb67eed218 ClusterIP 10.109.124.189 <none> 1/TCP 8d
glusterfs-dynamic-de235013-3d3a-42f0-8e39-b094a4761b5e ClusterIP 10.97.26.122 <none> 1/TCP 8d
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 13d
my-service ClusterIP 10.98.65.196 <none> 80/TCP 11m
mydb ClusterIP 10.98.213.29 <none> 3306/TCP 65s
nginxsvc ClusterIP None <none> 80/TCP 9d
# 查看endpoint
kubectl get ep
NAME ENDPOINTS AGE
glusterfs-dynamic-37d63494-2b84-4820-94c8-20cb328315f5 10.157.89.216:1,10.157.31.40:1,10.157.89.215:1 8d
glusterfs-dynamic-d6cfa4b3-54d2-4174-b481-e5fb67eed218 <none> 8d
glusterfs-dynamic-de235013-3d3a-42f0-8e39-b094a4761b5e 10.157.89.216:1,10.157.31.40:1,10.157.89.215:1 8d
kubernetes 10.157.89.215:6443 13d
my-service <none> 11m
mydb 192.168.0.5:3306 21s
nginxsvc 10.244.1.10:80,10.244.2.9:80 9d
超出容量的endpoint¶
如果某个ep资源超过1000的话,会被截断的, 另外添加一个注解。endpoints.kubernetes.io/over-capacity: truncated。
虚拟 IP 和 Service 代理¶
在k8s中,每个node是运行一个kube-proxy进程的,kube-proxy负责为service实现一种vip的形式。
为啥不使用dns轮训
不遵守记录ttl设置
无限期缓存
大量解析会是的dns高负载
userspace 代理模式
iptables 代理模式
IPVS 代理模式
在ipvs模式下,kube-proxy会监视k8s的服务和端点,调用netLink接口完成创建ipvs规则,并定期同步。访问服务的时候流量定向到具体后端pod之一。
ipvs大力模式类似于iptables模式的netfilter挂钩函数,但是使用哈希表作为基础数据结构。兵器在内核空间工作,延迟更短,支持更高的网络流量吞吐量。
支持多种流量调度算法
rr:轮替(Round-Robin)
lc:最少链接(Least Connection),即打开链接数量最少者优先
dh:目标地址哈希(Destination Hashing)
sh:源地址哈希(Source Hashing)
sed:最短预期延迟(Shortest Expected Delay)
nq:从不排队(Never Queue)
- 会话粘性
service.spec.sessionAffinity 设置为 “ClientIP” (默认值是 “None”),来基于客户端的 IP 地址选择会话关联。 service.spec.sessionAffinityConfig.clientIP.timeoutSeconds 来设置最大会话停留时间
多端口service¶
多端口server建议给server.ports[*].name进行指定,减少端口歧义。
服务发现¶
k8s支持2中基本的服务于发现模式,环境变量和dns。
环境变量¶
当 Pod 运行在 Node 上,kubelet 会为每个活跃的 Service 添加一组环境变量。 它同时支持 Docker links兼容 变量 (查看 makeLinkVariables)、 简单的 {SVCNAME}_SERVICE_HOST 和 {SVCNAME}_SERVICE_PORT 变量。 这里 Service 的名称需大写,横线被转换成下划线。
Warning
pod使用环境变量前,这个服务必须是有的,没有没法使用。
DNS¶
支持集群的 DNS 服务器(例如 CoreDNS)监视 Kubernetes API 中的新服务,并为每个服务创建一组 DNS 记录。 如果在整个集群中都启用了 DNS,则所有 Pod 都应该能够通过其 DNS 名称自动解析服务。
Kubernetes DNS 服务器是唯一的一种能够访问 ExternalName 类型的 Service 的方式。
无头服务¶
有时不需要或不想要负载均衡,以及单独的 Service IP。 遇到这种情况,可以通过指定 Cluster IP(spec.clusterIP)的值为 “None” 来创建 Headless Service。
带选择符的服务: ,Endpoint 控制器在 API 中创建了 Endpoints 记录, 并且修改 DNS 配置返回 A 记录
无选择符的服务: 不会创建endpoint记录,externalName会查询cname记录,其他的会查询同名endpoint。
发布服务(服务类型)¶
service的类型比较多的。 主要是如下几种。
ClusterIP:通过集群的内部 IP 暴露服务,选择该值时服务只能够在集群内部访问。 这也是默认的 ServiceType。
NodePort:通过每个节点上的 IP 和静态端口(NodePort)暴露服务。 NodePort 服务会路由到自动创建的 ClusterIP 服务。 通过请求 <节点 IP>:<节点端口>,你可以从集群的外部访问一个 NodePort 服务。
LoadBalancer:使用云提供商的负载均衡器向外部暴露服务。 外部负载均衡器可以将流量路由到自动创建的 NodePort 服务和 ClusterIP 服务上。
ExternalName:通过返回 CNAME 和对应值,可以将服务映射到 externalName 字段的内容(例如,foo.bar.example.com)。 无需创建任何类型代理。
支持的协议¶
tcp
udp
sctp
HTTP
Proxy
pod与service的dns¶
k8s为服务和pod创建dns记录, 可以使用dns名称而非地址访问服务。
Service 的名字空间¶
看一个service的配置文件 /etc/resolv.conf
# kubectl get svc |grep nginx
nginxsvc ClusterIP None <none> 80/TCP 9d
# kubectl exec svc/nginxsvc -- cat /etc/resolv.conf
nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local epc.duxiaoman.com
options ndots:5
DNS记录¶
哪些对象可以获得dns记录?
Services
Pods
服务A记录¶
普通服务(除了无头服务)回馈有一个dns记录,my-svc.my-namespace.svc.cluster-domain.example的这种形式的。
服务SRV记录¶
_my-port-name._my-port-protocol.my-svc.my-namespace.svc.cluster-domain.example 这种形式。
Pod A记录¶
pod-ip-address.my-namespace.pod.cluster-domain.example
Pod 的 DNS 策略¶
Default: pod从运行的节点集成名称解析配置
ClusterFirst: 与配置的集群与后缀不匹配的dns查询都转发到从节点集成的上游名称服务器
ClusterFirstWithHostNet: 对于以 hostNetwork 方式运行的 Pod,应显式设置其 DNS 策略
None: 设置忽略k8s环境变量的dns设置,pod会使用dnsconfig字段锁提供的dns设置。
Note
“Default” 不是默认的 DNS 策略。如果未明确指定 dnsPolicy,则使用 “ClusterFirst”。
Pod 的 DNS 配置¶
dnsConfig 字段是可选的,它可以与任何 dnsPolicy 设置一起使用。 但是,当 Pod 的 dnsPolicy 设置为 “None” 时,必须指定 dnsConfig 字段。
nameservers:将用作于 Pod 的 DNS 服务器的 IP 地址列表。 最多可以指定 3 个 IP 地址。当 Pod 的 dnsPolicy 设置为 “None” 时, 列表必须至少包含一个 IP 地址,否则此属性是可选的。 所列出的服务器将合并到从指定的 DNS 策略生成的基本名称服务器,并删除重复的地址。
searches:用于在 Pod 中查找主机名的 DNS 搜索域的列表。此属性是可选的。 指定此属性时,所提供的列表将合并到根据所选 DNS 策略生成的基本搜索域名中。 重复的域名将被删除。Kubernetes 最多允许 6 个搜索域。
options:可选的对象列表,其中每个对象可能具有 name 属性(必需)和 value 属性(可选)。 此属性中的内容将合并到从指定的 DNS 策略生成的选项。 重复的条目将被删除。
扩展 DNS 配置¶
对于 Pod DNS 配置,Kubernetes 默认允许最多 6 个 搜索域( Search Domain) 以及一个最多 256 个字符的搜索域列表。
如果启用 kube-apiserver 和 kubelet 的特性门控 ExpandedDNSConfig,Kubernetes 将可以有最多 32 个 搜索域以及一个最多 2048 个字符的搜索域列表。
使用 Service 连接到应用¶
访问 Service¶
k8s支持2中查找服务的模式, 环境变量和dns
保护 Service¶
我们只在集群内部访问了 Nginx 服务器。在将 Service 暴露到因特网之前,我们希望确保通信信道是安全的。 为实现这一目的,可能需要:
用于 HTTPS 的自签名证书(除非已经有了一个识别身份的证书)
使用证书配置的 Nginx 服务器
使证书可以访问 Pod 的 Secret
准备公钥和私钥
1KEY=nginx.key
2CERT=nginx.crt
3openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout $KEY -out $CERT -subj "/CN=nginxsvc/O=nginxsvc"
执行上面的脚本,生成证书,然后执行下面脚本完成secret的创建
# 直接跟进文件创建
kubectl create secret tls nginxsvc.tls --key=nginx.key --cert=nginx.crt
# 通过命令方式,进行归档成为文件
kubectl get secret nginxsvc.tls -o yaml >nginxsvc.tls
准备个nginx配置下
curl 'https://raw.githubusercontent.com/kubernetes/examples/master/staging/https-nginx/default.conf' >default.conf
kubectl get cm nginxconfigmap -o yaml >nginxconfigmap.yaml
准备nginx service和deployment
1apiVersion: v1
2kind: Service
3metadata:
4 name: my-nginx
5 labels:
6 run: my-nginx
7spec:
8 type: NodePort
9 ports:
10 - port: 8080
11 targetPort: 80
12 protocol: TCP
13 name: http
14 - port: 443
15 protocol: TCP
16 name: https
17 selector:
18 run: my-nginx
19---
20apiVersion: apps/v1
21kind: Deployment
22metadata:
23 name: my-nginx
24spec:
25 selector:
26 matchLabels:
27 run: my-nginx
28 replicas: 1
29 template:
30 metadata:
31 labels:
32 run: my-nginx
33 spec:
34 volumes:
35 - name: secret-volume
36 secret:
37 secretName: nginxsvc.tls
38 - name: configmap-volume
39 configMap:
40 name: nginxconfigmap
41 containers:
42 - name: nginxhttps
43 image: bprashanth/nginxhttps:1.0
44 ports:
45 - containerPort: 443
46 - containerPort: 80
47 volumeMounts:
48 - mountPath: /etc/nginx/ssl
49 name: secret-volume
50 - mountPath: /etc/nginx/conf.d
51 name: configmap-volume
访问测试
# 确认ip
kubectl get pod my-nginx-77fd8b978f-rcvh2 -o yaml |grep podip -i
podIP: 10.244.2.219
podIPs:
# 测试访问
$ curl -k https://10.244.2.219/ |grep Welcome
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 612 100 612 0 0 6274 0 --:--:-- --:--:-- --:--:-- 6309
<title>Welcome to nginx!</title>
<h1>Welcome to nginx!</h1>
ingress¶
ingress是对集群汇总服务的外部访问进行管理的api对象,典型的访问是http
ingress可以提供负载均衡、ssl终结和基于名称的虚拟托管。
ingress是什么¶
ingress是公开了从集群外部到集群内部服务的http和https路由。
先安装一个ingress控制器,这里我选择了trafik了。 安装方法参考: https://doc.traefik.io/traefik/getting-started/install-traefik/
kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
name: "foo"
namespace: production
spec:
rules:
- host: example.net
http:
paths:
- path: /bar
pathType: Exact
backend:
service:
name: service1
port:
number: 80
- path: /foo
pathType: Exact
backend:
service:
name: service1
port:
number: 80
defaultBackend¶
没有rules的ingress将所有流量发送到同一个默认后端,这个通常是ingress控制器的配置选项,而非在ingress的资源中指定。
路径类型¶
pathtype这个就是路径类型,目前支持三种。
ImplementationSpecific: 这种类型的具体使用看ingress class了。
Exact: 精确匹配URL路径,区分大小写。
Prefix: 基于/分割的url就路径前缀匹配,
多重匹配¶
在某些情况下,Ingress 中的多条路径会匹配同一个请求。 这种情况下最长的匹配路径优先。 如果仍然有两条同等的匹配路径,则精确路径类型优先于前缀路径类型。
主机名通配符¶
主机名可以是精确匹配(例如foo.bar.com)或者使用通配符来匹配 (例如*.foo.com)。 精确匹配要求 HTTP host 头部字段与 host 字段值完全匹配。 通配符匹配则要求 HTTP host 头部字段与通配符规则中的后缀部分相同。
默认 Ingress 类¶
将一个 IngressClass 资源的 ingressclass.kubernetes.io/is-default-class 注解设置为 true 将确保新的未指定 ingressClassName 字段的 Ingress 能够分配为这个默认的 IngressClass.
服务内部流量策略¶
服务内部流量策略开启了内部流量限制,只是路由内部流量都和发起方处于相同节点的服务端点,这种机制能节省开销,提升效率。
工作原理¶
kube-proxy 基于 spec.internalTrafficPolicy 的设置来过滤路由的目标服务端点。 当它的值设为 Local 时,只选择节点本地的服务端点。 当它的值设为 Cluster 或缺省时,则选择所有的服务端点。 启用特性门控 ServiceInternalTrafficPolicy 后, spec.internalTrafficPolicy 的值默认设为 Cluster。
端点切片¶
端点切片是用来缓解endpoints变化时需要处理大量的网络流量和处理的。
地址类型¶
endpointslice支持的三种地址类型
ipv4
ipv6
fqdn
网络策略¶
网络策略控制网络流量,出站入栈设置规则。
前提条件¶
网格策略需要通过网络插件来实现的,
样例¶
1apiVersion: networking.k8s.io/v1
2kind: NetworkPolicy
3metadata:
4 name: test-network-policy
5 namespace: default
6spec:
7 podSelector:
8 matchLabels:
9 role: db
10 policyTypes:
11 - Ingress
12 - Egress
13 ingress:
14 - from:
15 - ipBlock:
16 cidr: 172.17.0.0/16
17 except:
18 - 172.17.1.0/24
19 - namespaceSelector:
20 matchLabels:
21 project: myproject
22 - podSelector:
23 matchLabels:
24 role: frontend
25 ports:
26 - protocol: TCP
27 port: 6379
28 egress:
29 - to:
30 - ipBlock:
31 cidr: 10.0.0.0/24
32 ports:
33 - protocol: TCP
34 port: 5978
主要字段含义:
podSelect: 设置策略应用的pod是那些。 ingress: 入栈策略, 控制那些来源访问选定的pod egress: 出站策略,控制选定的pod可以访问外部的。
可以放行一段端口范围的。
存储¶
卷¶
容器都是临时的, 重启都会回到一个干净状态的,怎么保证数据的存储就是一个问题, 另外一个pod里面是包含多个容器的, 怎么在几个容器共享文件? 这就需要卷。
nfs¶
使用 subPath¶
有时,在单个 Pod 中共享卷以供多方使用是很有用的。 volumeMounts.subPath 属性可用于指定所引用的卷内的子路径,而不是其根路径。
d之一。
卷快照¶
卷快照能力为 Kubernetes 用户提供了一种标准的方式来在指定时间点 复制卷的内容,并且不需要创建全新的卷。例如, 这一功能使得数据库管理员 能够在执行编辑或删除之类的修改之前对数据库执行备份。
卷快照样例¶
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: new-snapshot-test
spec:
volumeSnapshotClassName: csi-hostpath-snapclass
source:
persistentVolumeClaimName: pvc-test
d之一。
持久卷¶
持久卷是集群中的一块存储,可以由管理员实现供应或者存储类动态供应。
持久卷申请¶
PV 卷的供应有两种方式:静态供应或动态供应。
静态供应¶
管理员需要提前创建一个pv。
动态供应¶
管理员提供存储类即可, 使用者pvc申请指定这个存储类,会自动创建pv的。
回收¶
回收策略
保留(Retain)
删除
回收
目前,仅 NFS 和 HostPath 支持回收(Recycle)。 AWS EBS、GCE PD、Azure Disk 和 Cinder 卷都支持删除(Delete)。
卷模式¶
volumeMode 属性设置为 Filesystem 的卷会被 Pod 挂载(Mount) 到某个目录。 如果卷的存储来自某块设备而该设备目前为空,Kuberneretes 会在第一次挂载卷之前 在设备上创建文件系统。
访问模式¶
ReadWriteOnce: 被一个节点读写挂载 RWO
ReadOnlyMany: 卷可以被多个节点只读挂载 ROX
ReadWriteMany: 卷可以被多个节点读写挂载 RWX
ReadWriteOncePod: 卷可以被单个pod读写方式挂载,RWOP
存储类¶
早前,Kubernetes 使用注解 volume.beta.kubernetes.io/storage-class 而不是 storageClassName 属性。 这一注解目前仍然起作用,不过在将来的 Kubernetes 发布版本中该注解会被彻底废弃。
卷的状态¶
Available(可用)– 卷是一个空闲资源,尚未绑定到任何申领;
Bound(已绑定)– 该卷已经绑定到某申领;
Released(已释放)– 所绑定的申领已被删除,但是资源尚未被集群回收;
Failed(失败)– 卷的自动回收操作失败。
基于卷快照恢复卷¶
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: restore-pvc
spec:
storageClassName: csi-hostpath-sc
dataSource:
name: new-snapshot-test
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
d之一。
卷快照类¶
就像 StorageClass 为管理员提供了一种在配置卷时描述存储“类”的方法, VolumeSnapshotClass 提供了一种在配置卷快照时描述存储“类”的方法。
VolumeSnapshotClass 资源¶
存储类¶
存储类是提供动态pv分配的。存储类一旦创建不能对其更新的。
存储类资源样例¶
1apiVersion: storage.k8s.io/v1
2kind: StorageClass
3metadata:
4 name: low
5provisioner: kubernetes.io/glusterfs
6parameters:
7 resturl: "http://10.157.89.215:8077"
8 clusterid: "b8bc571569b52c572f56b19a5f6b6d9a"
9 restauthenabled: "true"
10 restuser: "admin"
11 restuserkey: "admin"
12 gidMin: "40000"
13 gidMax: "50000"
14 volumetype: "replicate:2"
回收策略¶
如果存储类没有没有指定回收策略,默认是delete的。
允许卷扩展¶
当下层 StorageClass 的 allowVolumeExpansion 字段设置为 true 时。
挂载选项¶
挂载选项通过mountOption来指定的。 如果卷插件不支持挂载选项,却指定了挂载选项,则制备操作会失败。 挂载选项在 StorageClass 和 PV 上都不会做验证,如果其中一个挂载选项无效,那么这个 PV 挂载操作就会失败。
卷绑定模式¶
卷绑定模式控制卷绑定和动态制备的发生时候, 默认情况immediate是pvc有了就创建和完成绑定的。 这个时候pod还没有调度呢。
可以修改为WaitForFirstConsumer方式,但是不是每个存储类都支持的。
动态卷供应¶
可以提供多个存储类, 比如slow来表示分配低速的stat盘, fast来表示分配告诉的ssd盘。
临时卷¶
临时卷和pod生命周期一致的, pod结束后这个卷就没有了。
临时卷的类型¶
emptyDir: pod启动的时候,存储空间来自本地的kubelet或者内存。
configmap、downloadapi、secret: 将不同的类型资源注入到pod中。
通用临时卷: 尺寸永久卷的存储程序提供。
csi临时卷: 特定的csi驱动程序支持。
配置¶
configmap¶
configmap是一种api对象,用来将费机密性的数据保持到键值对中,
ConfigMap¶
使用configmap可以保障配置和应用程序代码的分离。
configmap创建样例¶
apiVersion: v1
kind: ConfigMap
metadata:
name: game-demo
data:
# 类属性键;每一个键都映射到一个简单的值
player_initial_lives: "3"
ui_properties_file_name: "user-interface.properties"
# 类文件键
game.properties: |
enemy.types=aliens,monsters
player.maximum-lives=5
user-interface.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
data部分是个kv数据, 如果多行数据的话, 可以使用|来使用。
如何使用configmap的数据¶
容器命令和参数内
容器的环境变量
只读卷添加一个文件,应用读取
编写代码在pod中运行,通过api方式读取configmap。
pod使用configmap样例¶
apiVersion: v1
kind: Pod
metadata:
name: configmap-demo-pod
spec:
containers:
- name: demo
image: alpine
command: ["sleep", "3600"]
env:
# 定义环境变量
- name: PLAYER_INITIAL_LIVES # 请注意这里和 ConfigMap 中的键名是不一样的
valueFrom:
configMapKeyRef:
name: game-demo # 这个值来自 ConfigMap
key: player_initial_lives # 需要取值的键
- name: UI_PROPERTIES_FILE_NAME
valueFrom:
configMapKeyRef:
name: game-demo
key: ui_properties_file_name
volumeMounts:
- name: config
mountPath: "/config"
readOnly: true
volumes:
# 你可以在 Pod 级别设置卷,然后将其挂载到 Pod 内的容器中
- name: config
configMap:
# 提供你想要挂载的 ConfigMap 的名字
name: game-demo
# 来自 ConfigMap 的一组键,将被创建为文件
items:
- key: "game.properties"
path: "game.properties"
- key: "user-interface.properties"
path: "user-interface.properties"
这个pod使用了2种, 第一种环境变量方式, 通过valuefrom方式,指定了环境变量的value从一个configmap的特定key获取。 第二种方式,通过读取一个configmap的特定key,弄成多个文件,然后这个卷包含多个文件的, 挂载到pod中,然后给pod使用。
几种方式的不同¶
通过环境变量的方式,不会自动更新的,通过文件方式,文件可以自动改变的。
不可变更的 ConfigMap¶
Kubernetes 特性 不可变更的 Secret 和 ConfigMap 提供了一种将各个 Secret 和 ConfigMap 设置为不可变更的选项。
一旦某 ConfigMap 被标记为不可变更,则 无法 逆转这一变化,,也无法更改 data 或 binaryData 字段的内容。 你只能删除并重建 ConfigMap。 因为现有的 Pod 会维护一个对已删除的 ConfigMap 的挂载点,建议重新创建 这些 Pods。
configmap¶
configmap是一种api对象,用来将费机密性的数据保持到键值对中,
ConfigMap¶
使用configmap可以保障配置和应用程序代码的分离。
configmap创建样例¶
apiVersion: v1
kind: ConfigMap
metadata:
name: game-demo
data:
# 类属性键;每一个键都映射到一个简单的值
player_initial_lives: "3"
ui_properties_file_name: "user-interface.properties"
# 类文件键
game.properties: |
enemy.types=aliens,monsters
player.maximum-lives=5
user-interface.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
data部分是个kv数据, 如果多行数据的话, 可以使用|来使用。
如何使用configmap的数据¶
容器命令和参数内
容器的环境变量
只读卷添加一个文件,应用读取
编写代码在pod中运行,通过api方式读取configmap。
pod使用configmap样例¶
apiVersion: v1
kind: Pod
metadata:
name: configmap-demo-pod
spec:
containers:
- name: demo
image: alpine
command: ["sleep", "3600"]
env:
# 定义环境变量
- name: PLAYER_INITIAL_LIVES # 请注意这里和 ConfigMap 中的键名是不一样的
valueFrom:
configMapKeyRef:
name: game-demo # 这个值来自 ConfigMap
key: player_initial_lives # 需要取值的键
- name: UI_PROPERTIES_FILE_NAME
valueFrom:
configMapKeyRef:
name: game-demo
key: ui_properties_file_name
volumeMounts:
- name: config
mountPath: "/config"
readOnly: true
volumes:
# 你可以在 Pod 级别设置卷,然后将其挂载到 Pod 内的容器中
- name: config
configMap:
# 提供你想要挂载的 ConfigMap 的名字
name: game-demo
# 来自 ConfigMap 的一组键,将被创建为文件
items:
- key: "game.properties"
path: "game.properties"
- key: "user-interface.properties"
path: "user-interface.properties"
这个pod使用了2种, 第一种环境变量方式, 通过valuefrom方式,指定了环境变量的value从一个configmap的特定key获取。 第二种方式,通过读取一个configmap的特定key,弄成多个文件,然后这个卷包含多个文件的, 挂载到pod中,然后给pod使用。
几种方式的不同¶
通过环境变量的方式,不会自动更新的,通过文件方式,文件可以自动改变的。
不可变更的 ConfigMap¶
Kubernetes 特性 不可变更的 Secret 和 ConfigMap 提供了一种将各个 Secret 和 ConfigMap 设置为不可变更的选项。
一旦某 ConfigMap 被标记为不可变更,则 无法 逆转这一变化,,也无法更改 data 或 binaryData 字段的内容。 你只能删除并重建 ConfigMap。 因为现有的 Pod 会维护一个对已删除的 ConfigMap 的挂载点,建议重新创建 这些 Pods。
secret¶
secret是包含少量敏感信息,对比confimap来说,这个就是机密信息。其他基本一致。
如何使用configmap的数据¶
作为挂载到一个或多个容器上的 卷 中的文件。
作为容器的环境变量
由 kubelet 在为 Pod 拉取镜像时使用
secret的类型¶
服务账号令牌 Secret¶
服务账号用于存储服务账号令牌信息的, 可以使用注解来使用kubernetes.io/service-account-name ,然后pod可以通过serviceAccountName指定。
Docker 配置 Secret¶
kubectl create secret docker-registry secret-tiger-docker \
--docker-username=tiger \
--docker-password=pass113 \
--docker-email=tiger@acme.com
基本身份认证 Secret¶
kubernetes.io/basic-auth 类型用来存放用于基本身份认证所需的凭据信息。 使用这种 Secret 类型时,Secret 的 data 字段必须包含以下两个键:
username: 用于身份认证的用户名;
password: 用于身份认证的密码或令牌。
SSH 身份认证 Secret¶
提供 SSH 身份认证类型的 Secret 仅仅是出于用户方便性考虑。
TLS Secret¶
字段必须包含 tls.key 和 tls.crt 主键,尽管 API 服务器 实际上并不会对每个键的取值作进一步的合法性检查。
策略¶
限制范围¶
默认情况下,k8s的容器使用的计算资源是没有限制的,一个LimitRange对象可以提供的限制能力如下:
在一个命名空间中实施对每个pod或者container的最小和最大的资源使用量的限制。
在一个命名空间中实施对每个pvc能申请最小和最大的存储大小的限制。
在一个命名空间中实施对一种资源的申请值和限制值比值的控制。
设置一个命名空间中对计算资源的默认申请和限制,并且自动注入到运行的多个容器中。
为命名空间配置默认的内存请求和限制¶
todo 样例
d之一。
资源配额¶
当多个用户或团队使用固定的节点数目的集群时候,担心有人超过自己使用的资源量。资源配额主要是帮忙管理员解决这个问题的。
可以通过这种方式工作:
不通团队在不通的命名空间工作。
集群管理员可以为每个命名空间创建一个或者多个resourceQuota对象。
如果创建pod的没有指资源信息,就会错误的, 如果超过总量,就是403了。
计算资源配额¶
limits.cpu 所有非终止状态的 Pod,其 CPU 限额总量不能超过该值。
limits.memory 所有非终止状态的 Pod,其内存限额总量不能超过该值。
requests.cpu 所有非终止状态的 Pod,其 CPU 需求总量不能超过该值。
requests.memory 所有非终止状态的 Pod,其内存需求总量不能超过该值。
hugepages-<size> 对于所有非终止状态的 Pod,针对指定尺寸的巨页请求总数不能超过此值。
cpu 与 requests.cpu 相同。
memory 与 requests.memory 相同。
存储资源配额¶
requests.storage 所有 PVC,存储资源的需求总量不能超过该值。
persistentvolumeclaims 在该命名空间中所允许的 PVC 总量。
<storage-class-name>.storageclass.storage.k8s.io/requests.storage 在所有与 <storage-class-name> 相关的持久卷申领中,存储请求的总和不能超过该值。
<storage-class-name>.storageclass.storage.k8s.io/persistentvolumeclaims 在与 storage-class-name 相关的所有持久卷申领中,命名空间中可以存在的持久卷申领总数。
对象数量配额¶
count/<resource>.<group>:用于非核心(core)组的资源
count/<resource>:用于核心组的资源
配额作用域¶
每个配额应该有一组相关的作用域, 配额支队作用域内的资源生效。
Terminating 匹配所有 spec.activeDeadlineSeconds 不小于 0 的 Pod。
NotTerminating 匹配所有 spec.activeDeadlineSeconds 是 nil 的 Pod。
BestEffort 匹配所有 Qos 是 BestEffort 的 Pod。
NotBestEffort 匹配所有 Qos 不是 BestEffort 的 Pod。
PriorityClass 匹配所有引用了所指定的优先级类的 Pods。
CrossNamespacePodAffinity 匹配那些设置了跨名字空间 (反)亲和性条件的 Pod。
scopeSelector:
matchExpressions:
- scopeName: PriorityClass
operator: In
values:
- middle
根据服务的优先级设置不同的配额样例¶
apiVersion: v1
kind: List
items:
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-high
spec:
hard:
cpu: "1000"
memory: 200Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["high"]
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-medium
spec:
hard:
cpu: "10"
memory: 20Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["medium"]
- apiVersion: v1
kind: ResourceQuota
metadata:
name: pods-low
spec:
hard:
cpu: "5"
memory: 10Gi
pods: "10"
scopeSelector:
matchExpressions:
- operator : In
scopeName: PriorityClass
values: ["low"]
d之一。
进程id约束与预留¶
k8s中允许你限制一个pod可以使用的进程pid数量,你也可以为每个节点预留一定数量的可分配的pid,提供给操作系统和守护进程使用。
节点级别 PID 限制¶
Kubernetes 允许你为系统预留一定量的进程 ID。为了配置预留数量,你可以使用 kubelet 的 –system-reserved 和 –kube-reserved 命令行选项中的参数 pid=<number>。 你所设置的参数值分别用来声明为整个系统和 Kubernetes 系统 守护进程所保留的进程 ID 数目。
Pod 级别 PID 限制¶
Kubernetes 允许你限制 Pod 中运行的进程个数。你可以在节点级别设置这一限制, 而不是为特定的 Pod 来将其设置为资源限制。 每个节点都可以有不同的 PID 限制设置。 要设置限制值,你可以设置 kubelet 的命令行参数 –pod-max-pids,或者 在 kubelet 的配置文件 中设置 PodPidsLimit。
d之一。
调度、抢占和驱逐¶
调度器¶
在k8s中,调度器是讲pod放置到合适的node上,然后对应kubelet才能运行这些pod。
概述¶
调度器会通过k8s的watch机制来发现集群中新创建且尚未被调度到node上的pod, 调度器会发现的每隔一个调度的pod调度到合适的node上面运行。
kube-scheduler¶
这个是k8s集群的默认调度器,并且是集群控制面板的一部分。调度器打分,得分最高的node来运行pod, 调度器将这个决定通知给api server 这个过程叫绑定。
调度流程¶
过滤
打分
过滤阶段会将所有满足pod调度需求的node选出来,打分阶段,调度器回味pod从列表中选择最合适的node。 最后调度器会将pod调度到得分最高的node上面,如果得分相同,随机选择一个。
d之一。
将pod分配给节点¶
nodeselector¶
nodeselector是节点选择约束最简单的方式,
可以给node打标签,然后通过pod如下配置即可。
nodeSelector:
disktype: ssd
亲和性和反亲和性¶
这个相对nodeselector更像是软限制,nodeselector像是强制限制。
主要是2个关键词
requiredDuringSchedulingIgnoredDuringExecution
preferredDuringSchedulingIgnoredDuringExecution
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/e2e-az-name
operator: In
values:
- e2e-az1
- e2e-az2
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: another-node-label-key
operator: In
values:
- another-node-label-value
containers:
- name: with-node-affinity
image: k8s.gcr.io/pause:2.0
反亲和性配置¶
podAntiAffinity
nodeName¶
nodeName 是节点选择约束的最简单方法,但是由于其自身限制,通常不使用它。
d之一。
pod开销¶
在节点上运行pod时,pod本身占用大量系统资源,这些资源运行pod内容器所需要的资源附加资源,pod开销是一个特性,用于计算pod基础设施在容器请求和限制只上消耗的资源。
定义开销¶
---
kind: RuntimeClass
apiVersion: node.k8s.io/v1
metadata:
name: kata-fc
handler: kata-fc
overhead:
podFixed:
memory: "120Mi"
cpu: "250m"
污点和容忍度¶
污点是节点用来排斥一些pod调度的。 容忍度是pod来说的, 污点和容忍度需要相互配合,用来避免pod被分配到不合适的节点上。
打污点¶
kubectl taint nodes node1 key1=value1:NoSchedule
移除污点¶
kubectl taint nodes node1 key1=value1:NoSchedule-
pod容忍¶
通过pod.spec.tolerations即可。
使用场景¶
专用节点
配置了特殊硬件的节点
基于污点的驱逐
优先级和抢占¶
pod可以有优先级,优先级表示已一个pod相对其他的pod的重要性,如果一个pod无法调度,调度程序会尝试抢占优先级毕竟低的pod。
Warning
可以通过创建resourcequota来限制用户创建高优先级的pod。 避免驱逐别的pod.
如何使用优先级¶
先创建一个优先级类
然后在使用pod的deployment或者其他类资源的template指定对应priorityClassName为新建的优先级类
k8s内置了2个优先级类,system-cluster-critical 和system-node-critical
PriorityClass¶
PriorityClass 还有两个可选字段:globalDefault 和 description。 globalDefault 字段表示这个 PriorityClass 的值应该用于没有 priorityClassName 的 Pod。 系统中只能存在一个 globalDefault 设置为 true 的
样例¶
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority
value: 1000000
globalDefault: false
description: "此优先级类应仅用于 XYZ 服务 Pod。"
抢占策略¶
PreemptionPolicy默认是PreeemptLowerPriority的, 可以抢占低优先级的pod的, 如果这个值为never那就不会抢占的。
Pod 优先级对调度顺序的影响¶
当启用 Pod 优先级时,调度程序会按优先级对悬决 Pod 进行排序, 并且每个悬决的 Pod 会被放置在调度队列中其他优先级较低的悬决 Pod 之前。 因此,如果满足调度要求,较高优先级的 Pod 可能会比具有较低优先级的 Pod 更早调度。 如果无法调度此类 Pod,调度程序将继续并尝试调度其他较低优先级的 Pod。
被提名节点¶
当 Pod P 抢占节点 N 上的一个或多个 Pod 时, Pod P 状态的 nominatedNodeName 字段被设置为节点 N 的名称。 该字段帮助调度程序跟踪为 Pod P 保留的资源,并为用户提供有关其集群中抢占的信息。 请注意,Pod P 不一定会调度到“被提名的节点(Nominated Node。
抢占的限制¶
被抢占的牺牲者体面终止, 如果想让低优先级快速终止,可以设置终止时间为很小的一个数值。
支持pdb pod disruptionbudget,但不保证。允许多副本应用程序的所有者限制因自愿性质的干扰而同时终止的 Pod 数量。
是仅针对同等或更高优先级的 Pod 设置 Pod 间亲和性。
节点压力驱逐¶
节点压力驱逐是kubelet主动终止pod以回收节点资源的过程。
kubelet 监控集群节点的 CPU、内存、磁盘空间和文件系统的 inode 等资源。 当这些资源中的一个或者多个达到特定的消耗水平, kubelet 可以主动地使节点上一个或者多个 Pod 失效,以回收资源防止饥饿。
在节点压力驱逐期间,kubelet 将所选 Pod 的 PodPhase 设置为 Failed。这将终止 Pod。
节点压力驱逐不同于 API 发起的驱逐。
kubelet 并不理会你配置的 PodDisruptionBudget 或者是 Pod 的 terminationGracePeriodSeconds。 如果你使用了软驱逐条件,kubelet 会考虑你所配置的 eviction-max-pod-grace-period。 如果你使用了硬驱逐条件,它使用 0s 宽限期来终止 Pod。
驱逐信号¶
驱逐信号是特定资源在特定时间点的当前状态。 kubelet 使用驱逐信号,通过将信号与驱逐条件进行比较来做出驱逐决定, 驱逐条件是节点上应该可用资源的最小量。
驱逐信号 描述
memory.available memory.available := node.status.capacity[memory] - node.stats.memory.workingSet
nodefs.available nodefs.available := node.stats.fs.available
nodefs.inodesFree nodefs.inodesFree := node.stats.fs.inodesFree
imagefs.available imagefs.available := node.stats.runtime.imagefs.available
imagefs.inodesFree imagefs.inodesFree := node.stats.runtime.imagefs.inodesFree
pid.available pid.available := node.stats.rlimit.maxpid - node.stats.rlimit.curproc
驱逐条件¶
驱逐条件的形式为 [eviction-signal][operator][quantity],样例: memory.available<10%
软驱逐条件
你可以既指定软驱逐条件宽限期,又指定 Pod 终止宽限期的上限,,给 kubelet 在驱逐期间使用。 如果你指定了宽限期的上限并且 Pod 满足软驱逐阈条件, 则 kubelet 将使用两个宽限期中的较小者。 如果你没有指定宽限期上限,kubelet 会立即杀死被驱逐的 Pod,不允许其体面终止。
硬驱逐条件
硬驱逐条件没有宽限期。当达到硬驱逐条件时, kubelet 会立即杀死 pod,而不会正常终止以回收紧缺的资源。
kubelet 具有以下默认硬驱逐条件:
memory.available<100Mi
nodefs.available<10%
imagefs.available<15%
nodefs.inodesFree<5%(Linux 节点)
节点条件¶
节点条件 驱逐信号 描述
MemoryPressure memory.available 节点上的可用内存已满足驱逐条件
DiskPressure nodefs.available、nodefs.inodesFree、imagefs.available 或 imagefs.inodesFree 节点的根文件系统或映像文件系统上的可用磁盘空间和 inode 已满足驱逐条件
PIDPressure pid.available (Linux) 节点上的可用进程标识符已低于驱逐条件
kubelet 驱逐时 Pod 的选择¶
首先考虑资源使用量超过其请求的 BestEffort 或 Burstable Pod。 这些 Pod 会根据它们的优先级以及它们的资源使用级别超过其请求的程度被逐出。 资源使用量少于请求量的 Guaranteed Pod 和 Burstable Pod 根据其优先级被最后驱逐。
最小驱逐回收¶
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
evictionHard:
memory.available: "500Mi"
nodefs.available: "1Gi"
imagefs.available: "100Gi"
evictionMinimumReclaim:
memory.available: "0Mi"
nodefs.available: "500Mi"
imagefs.available: "2Gi"
节点内存不足行为¶
kubelet 根据 Pod 的服务质量(QoS)为每个容器设置一个 oom_score_adj 值。
服务质量 oom_score_adj
Guaranteed -997
BestEffort 1000
Burstable min(max(2, 1000 - (1000 * memoryRequestBytes) / machineMemoryCapacityBytes), 999)
api发起的驱逐¶
api发起的住区是调用eviction api 创建驱逐对象,在体面的终止pid的过程。
可以通过kubectl drain 这样的命令发起驱逐。
API 发起的驱逐将遵从你的 PodDisruptionBudgets 和 terminationGracePeriodSeconds 配置。
扩展资源的资源装箱¶
可以给扩展资源配置分数,辅助调度系统为节点评分,提高打醒集群中稀缺资源的资源利用率
apiVersion: kubescheduler.config.k8s.io/v1beta1
kind: KubeSchedulerConfiguration
profiles:
# ...
pluginConfig:
- name: RequestedToCapacityRatio
args:
shape:
- utilization: 0
score: 10
- utilization: 100
score: 0
resources:
- name: intel.com/foo
weight: 3
- name: intel.com/bar
weight: 5
RequestedToCapacityRatioResourceAllocation 优先级函数如何对节点评分¶
请求的资源
intel.com/foo: 2
Memory: 256MB
CPU: 2
资源权重
intel.com/foo: 5
Memory: 1
CPU: 3
FunctionShapePoint {{0, 0}, {100, 10}}
节点 Node 1 配置
可用:
intel.com/foo : 4
Memory : 1 GB
CPU: 8
已用:
intel.com/foo: 1
Memory: 256MB
CPU: 1
节点得分:
intel.com/foo = resourceScoringFunction((2+1),4)
= (100 - ((4-3)*100/4)
= (100 - 25)
= 75
= rawScoringFunction(75)
= 7
Memory = resourceScoringFunction((256+256),1024)
= (100 -((1024-512)*100/1024))
= 50
= rawScoringFunction(50)
= 5
CPU = resourceScoringFunction((2+1),8)
= (100 -((8-3)*100/8))
= 37.5
= rawScoringFunction(37.5)
= 3
NodeScore = (7 * 5) + (5 * 1) + (3 * 3) / (5 + 1 + 3)
= 5
调度框架¶
框架工作流程¶
调度框架定义了一些扩展点,调度器插件注册后在一个或者多个扩展点调用,这些插件中的一些可以改变调度决策,而另一些用于提供信息。
每次调度一个pod的尝试都分为2个阶段,及调度周期和绑定周期。
调度周期和绑定周期¶
调度周期为pod选择一个节点,绑定周期将该决策应用于集群,调度周期和绑定周期一起被称为调度上下文。
调度周期是串行的,而绑定周期是可能同时运行的。 如果确定pod是不可调度或者存在内部错误,择可以终止调度周期或者绑定周期,pod将返回队列并充实。
扩展点¶

- 队列排序
队列排序插件用于对调度队列中的 Pod 进行排序。 队列排序插件本质上提供 less(Pod1, Pod2) 函数。 一次只能启动一个队列插件。
- 前置过滤
前置过滤插件用于预处理 Pod 的相关信息,或者检查集群或 Pod 必须满足的某些条件。 如果 PreFilter 插件返回错误,则调度周期将终止。
- 过滤
过滤插件用于过滤出不能运行该 Pod 的节点。对于每个节点, 调度器将按照其配置顺序调用这些过滤插件。如果任何过滤插件将节点标记为不可行, 则不会为该节点调用剩下的过滤插件。节点可以被同时进行评估。
- 后置过滤
这些插件在筛选阶段后调用,但仅在该 Pod 没有可行的节点时调用。 插件按其配置的顺序调用。如果任何后过滤器插件标记节点为可调度, 则其余的插件不会调用。典型的后筛选实现是抢占,试图通过抢占其他 Pod 的资源使该 Pod 可以调度。
- 前置评分
前置评分插件用于执行 “前置评分” 工作,即生成一个可共享状态供评分插件使用。 如果 PreScore 插件返回错误,则调度周期将终止。
- 评分
评分插件用于对通过过滤阶段的节点进行排名。调度器将为每个节点调用每个评分插件。 将有一个定义明确的整数范围,代表最小和最大分数。 在标准化评分阶段之后,调度器将根据配置的插件权重 合并所有插件的节点分数。
- 标准化评分
标准化评分插件用于在调度器计算节点的排名之前修改分数。 在此扩展点注册的插件将使用同一插件的评分 结果被调用。 每个插件在每个调度周期调用一次。
- Reserve
Reserve 是一个信息性的扩展点。 管理运行时状态的插件(也成为“有状态插件”)应该使用此扩展点,以便 调度器在节点给指定 Pod 预留了资源时能够通知该插件。 这是在调度器真正将 Pod 绑定到节点之前发生的,并且它存在是为了防止 在调度器等待绑定成功时发生竞争情况。
- Permit
Permit 插件在每个 Pod 调度周期的最后调用,用于防止或延迟 Pod 的绑定。批准,拒绝,等待。
- 预绑定
预绑定插件用于执行 Pod 绑定前所需的任何工作。 例如,一个预绑定插件可能需要提供网络卷并且在允许 Pod 运行在该节点之前 将其挂载到目标节点上。
- Bind
Bind 插件用于将 Pod 绑定到节点上。直到所有的 PreBind 插件都完成,Bind 插件才会被调用。 各绑定插件按照配置顺序被调用。绑定插件可以选择是否处理指定的 Pod。 如果绑定插件选择处理 Pod,剩余的绑定插件将被跳过。
- 绑定后
这是个信息性的扩展点。 绑定后插件在 Pod 成功绑定后被调用。这是绑定周期的结尾,可用于清理相关的资源。
- Unreserve
这是个信息性的扩展点。 如果 Pod 被保留,然后在后面的阶段中被拒绝,则 Unreserve 插件将被通知。 Unreserve 插件应该清楚保留 Pod 的相关状态。
调度器性能调优¶
在大规模及群众,需要平衡调度的延迟的精度问题
延迟问题: pod快速就位
精度问题: 调度器作出的放置不是糟糕的。
设置阈值¶
percentageOfNodesToScore 这个接受0-100的整数值,表示x%的机器来挑选。
节点打分阈值¶
要提升调度性能,kube-scheduler 可以在找到足够的可调度节点之后停止查找。 在大规模集群中,比起考虑每个节点的简单方法相比可以节省时间。 如果不指定的话, 100节点是50%,5000节点是10%,调度器至少对5%的节点打分,除非用户将该参数设置的低于5.
集群管理¶
证书¶
在使用客户端证书认证的场景下,你可以通过 easyrsa、openssl 或 cfssl 等工具以手工方式生成证书。
openssl¶
生成一个2048位的ca.key 文件
openssl genrsa -out ca.key 2048
在ca.key的基础上,生成证书文件
openssl req -x509 -new -nodes -key ca.key -subj "/CN=${MASTER_IP}" -days 10000 -out ca.crt
生成一个 2048 位的 server.key 文件:
openssl genrsa -out server.key 2048
创建一个用于生成证书签名请求(CSR)的配置文件。 保存文件(例如:csr.conf)前,记得用真实值替换掉尖括号中的值(例如:<MASTER_IP>)。
[ req ]
default_bits = 2048
prompt = no
default_md = sha256
req_extensions = req_ext
distinguished_name = dn
[ dn ]
C = <country>
ST = <state>
L = <city>
O = <organization>
OU = <organization unit>
CN = <MASTER_IP>
[ req_ext ]
subjectAltName = @alt_names
[ alt_names ]
DNS.1 = kubernetes
DNS.2 = kubernetes.default
DNS.3 = kubernetes.default.svc
DNS.4 = kubernetes.default.svc.cluster
DNS.5 = kubernetes.default.svc.cluster.local
IP.1 = <MASTER_IP>
IP.2 = <MASTER_CLUSTER_IP>
[ v3_ext ]
authorityKeyIdentifier=keyid,issuer:always
basicConstraints=CA:FALSE
keyUsage=keyEncipherment,dataEncipherment
extendedKeyUsage=serverAuth,clientAuth
subjectAltName=@alt_names
基于上面的配置文件生成证书签名请求:
openssl req -new -key server.key -out server.csr -config csr.conf
基于 ca.key、ca.key 和 server.csr 等三个文件生成服务端证书:
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
-CAcreateserial -out server.crt -days 10000 \
-extensions v3_ext -extfile csr.conf
查看证书签名请求
openssl req -noout -text -in ./server.csr
查看证书: .. code-block:: bash
openssl x509 -noout -text -in ./server.crt
管理资源¶
组织资源配置¶
许多应用需要创建多个配置资源, 比如deployment和service的, 可以通过将多个资源放置到一个文件中。 多个资源通过—进行分割即可。 资源将按照他们在文件中的顺序创建,
也是可以通过目录形式,通过读取目录即可。 会自动识别后缀为yml yaml json这些文件。
kubectl 中的批量操作¶
# 通过起初创建的文件进行删除
kubectl delete -f https://k8s.io/examples/application/nginx-app.yaml
# 命令式删除特定资源
kubectl delete deployments/my-nginx services/my-nginx-svc
# 资源删除指定标签删除,不建议
kubectl delete deployment,services -l app=nginx
金丝雀部署(Canary Deployments)¶
如何做个金丝雀发布。 对于一个服务来说, 有个service 有个deployment的, 我们通过service选择的时候既能选择到老的deployment也能选择个数为1个的新的deployment, 这样就接收了一些流量。 通过后续的调整实例数量, 逐步下掉老的deployment即可完成一个发布。
具体可以通过track标签来区别不同的版本。
线上稳定的deployment配置
name: frontend
replicas: 3
labels:
app: guestbook
tier: frontend
track: stable
image: gb-frontend:v3
金丝雀的版本
name: frontend-canary
replicas: 1
labels:
app: guestbook
tier: frontend
track: canary
image: gb-frontend:v4
- 服务选择
- selector:
app: guestbook tier: frontend
kubectl edit¶
不建议使用这种方式, 可以通过get到一个yaml文件,然后编辑文件后重新apply即可。
集群网络系统¶
集群网络系统是k8s的核心系统,网络系统的4个主要问题。
高度耦合的容器间通信,
pod间通信,
pod和服务间通信
外部和服务间通信
k8s网络模型¶
每个pod都有它自己的地址,在这个模型里,从端口分配、命名、服务发现、负载均衡、应用配置和迁移的角度来看,pod都可以视为虚拟机或者物理机器。
基本要求
节点上的pod可以不通过nat和其他的任何节点上的pod进行通信。
节点上的代理(kubelet)可以和节点上的所有pod进行通信。
Kubernetes 的 IP 地址存在于 Pod 范围内 - 容器共享它们的网络命名空间 - 包括它们的 IP 地址和 MAC 地址。 这就意味着 Pod 内的容器都可以通过 localhost 到达各个端口。 这也意味着 Pod 内的容器都需要相互协调端口的使用,但是这和虚拟机中的进程似乎没有什么不同, 这也被称为“一个 Pod 一个 IP”模型。
04-k8s系统组件指标¶
通过系统组件指标可以更好的了解系统内内部发横的情况,系统组件指标用于构建仪表盘和报警特别有用。
k8s中组件的指标¶
大多数情况下,可以通过http访问组件/metrics端点来海阔去组件的度量值。
主要组件包括如下。
kube-controller-manager
kube-proxy
kube-apiserver
kube-scheduler
kubelet