『K8S 入门』三:资源调度
一、Label 和 Selector
- 可以通过 Selector 基于 Label 匹配需要的资源
Label 标签
- 配置文件中(
metadata.labels
)配置
metadata: # Pod相关的元数据,用于描述Pod的数据
name: nginx-demo #Pod的名称
labels: # 定义Pod的标签,这个标签可以自己任意指定,是无所谓的
type: app # 自定义label标签,名字为type,值为app
version: 1.0.0 # 自定义label标签,描述版本号
namespace: 'default' # 命名空间的配置
- 查看 Labels
# 查看 Labels
kubectl get po --show-labels
# 通过命名空间查看
kubectl get po --show-labels -n kube-system
3. 临时创建 Labels
- 这些临时的 Labels 会丢失
# 添加 Labels
kubectl label po nginx-demo author=xz
# 复写 Labels
kubectl label po nginx-demo author=xzz --overwrite
- 如果要永久修改只能修改配置文件,或者使用下面方式修改
kubectl edit po nginx-demo
Selector 选择器
- 配置值
# 匹配某个 label
kubectl get po -l type=app
# 展示所有信息
kubectl get po -A -l type=app
# 顺便查询 labels
kubectl get po -A -l type=app --show-labels
# 刻画描述
kubectl get po -A -l 'version in (1.0.0, 1.1.0, 1.2.0)'
kubectl get po -A -l 'version in (1.0.0, 1.1.0, 1.2.0),type=app'
二、Deployment
- 创建
- 创建一个 deployment
kubectl create deploy nginx-deploy --image=nginx:1.7.9
# 查看资源
kubectl get deployments
kubectl get deploy
- depoy、replicaset、po 层级关系
- 可以看到名字是有层级规范的
kubectl get deploy
kubectl get replicaset
kubectl get po
- 获取 deployments 的配置文件
- 不要 status 部分,就可以获取这些配置值
# 把 deployments 的配置按照 yaml 形式输出
kubectl get deploy nginx-deploy -o yaml
# === 配置值描述 ===
# 注释的都是会默认生成的
apiVersion: apps/v1 # deployment api 版本
kind: Deployment # 资源类型为 deployment
metadata: # 元信息
#annotations:
# deployment.kubernetes.io/revision: "1"
#creationTimestamp: "2023-12-15T19:54:44Z"
#generation: 1
labels: # 标签
app: nginx-deploy # 具体的 key: value 配置形式
name: nginx-deploy # deployment 的名字
namespace: default # 所在的命名空间
#resourceVersion: "73676"
#uid: 79be9a06-7f20-42ac-a427-1e9cd5b089de
spec:
#progressDeadlineSeconds: 600
replicas: 1 # 期望副本数
revisionHistoryLimit: 10 # 进行滚动更新后,保留的历史版本数
selector: # 选择器,用于找到匹配的 RS
matchLabels: # 按照标签匹配
app: nginx-deploy # 匹配的标签 key/value
strategy: # 更新策略
rollingUpdate: # 滚动更新配置
maxSurge: 25% # 进行滚动更新时,更新的个数最多可以超过期望副本数的个数/比例
maxUnavailable: 25% # 进行滚动更新时,最大不可用比例更新比例,表示在所有副本数中,最多可以有多少个不更新成功
type: RollingUpdate # 更新类型,采用滚动更新
template: # pod 模板
metadata: # pod 的元信息
#creationTimestamp: null
labels: # pod 的标签
app: nginx-deploy
spec: # pod 期望信息
containers: # pod 的容器
- image: nginx:1.7.9 # 镜像
imagePullPolicy: IfNotPresent # 拉取策略
name: nginx # 容器名称
#resources: {}
#terminationMessagePath: /dev/termination-log
#terminationMessagePolicy: File
#dnsPolicy: ClusterFirst
restartPolicy: Always # 重启策略
#schedulerName: default-scheduler
#securityContext: {}
terminationGracePeriodSeconds: 30 # 删除操作最多宽限多长时间
- 滚动更新
- 滚动更新时,修改本地文件是无效果的
- 如果不更新 template 的配置,是不会触发自动更新
- 例如,先查看 deploy 中的标签
kubectl get deploy --show-labels
- 然后修改标签值,但是这时候并不会重发自动更新
kubectl edit deploy nginx-deploy
# ===== 更新 =====
...
labels:
app: nginx-deploy
test: "123" # 添加这个
...
# 通过这个命令可以看到 events 事件没有什么变化
kubectl describe deploy nginx-deploy
- 先做一个事情,增加一下副本数,这时候 po 变成 3 个,rs、deploy 还是 1 个
# ===== 更新 =====
...
spec:
progressDeadlineSeconds: 600
replicas: 3 # 更新这个
...
- (重点)尝试去修改镜像版本
# ===== 更新 =====
...
template:
metadata:
creationTimestamp: null
labels:
app: nginx-deploy
spec:
containers:
- image: nginx:1.9.1 # 更新这个
...
# 通过这个命令就可以看到 deploy 在更新
kubectl rollout status deploy nginx-deploy
# 或者用这个
kubectl get deploy --show-labels
# 或者看 events
kubectl describe deploy nginx-deploy
- 从这也可以看到这个更新过程(describe)
- 先创建两个 rs,先把其中 1 个 rs 的 pod 移到另外 1 个 rs,最后再清理旧的 rs
- 如果在更新过程中,快速地再次修改,k8s 会把上次的 rs 直接停止,再重新进行一次流程
- 从这也可以看出来旧的 rs 已经被替代
- 回滚
- 首先先对版本更新一个有问题的版本,查看更新过程,发现版本已经卡死
kubectl set image deployment/nginx-deploy nginx=nginx:1.91
- 因为相应的镜像死活拉不下来,其中一个 pod 拉取镜像失败,也可以通过下面命令查看一下情况
kubectl describe po nginx-deploy-f7f5656c7-z2bw7
- 先查看历史版本(因为没使用, record,所以才 none),可以看到有 3 个历史版本
kubectl rollout history deployment/nginx-deploy
# 只有这样 change-cause 才不会显示 none
kubectl set image deployment/nginx-deploy nginx=nginx:1.91 --record ***
- 查看 2 号版本的信息
kubectl rollout history deployment/nginx-deploy --revision=2
- (重点)回滚上一个版本
kubectl rollout undo deployment/nginx-deploy --to-revision=2
# 通过这个命令看到已经回退到 1.9.1 版本
kubectl edit deploy nginx-deploy
- 查看 rs 也可以看到也就只有第一个 rs 有数量了
- (注意)可以通过设置
.spec.revisonHistoryLimit
来指定 deployment 保留多少 revison,如果设置为 0,则不允许 deployment 回退了
- 扩容缩容
- 扩容:执行下面命令进行扩缩容,这时候并不会变更 rs
kubectl scale --replicas=6 deploy nginx-deploy
- 缩容:其实一样的,只是设置数字少点
kubectl scale --replicas=3 deploy nginx-deploy
- 暂停与恢复
- 由于每次对 pod template 中的信息发生修改后,都会触发更新 deployment 操作,那么此时如果频繁修改信息,就会产生多次更新,而实际上只需要执行最后一次更新即可,当出现此类情况时我们就可以暂停 deployment 的 rollout
- 首先先暂停配置
kubectl rollout pause deploy nginx-deploy
- 然后往模板中添加下面配置,会发现 rs 并没有新增加
kubectl edit deploy nginx-deploy
# ===== 更新 =====
...
spec: # pod 期望信息
containers: # pod 的容器
....
resources: # 下面这部分都是更新
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
...
# 可以通过这个命令看到最新版本的 change 没改变
kubectl rollout history deploy nginx-deploy --revision=4
- 恢复之后,通过 rs 或者 deploy 查看,已经有新增
kubectl rollout resume deploy nginx-deploy
三、StatefulSet
- 创建
- 首先创建目录,并且把 web.yml 放到里面
mkdir statefulset
cd statefulset
touch web.yml
- 其中 web.yml 内容如下
--- # 嵌套另外一个 yaml 的内容,暂时先不用管这个
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: nginx
---
apiVersion: apps/v1
kind: StatefulSet # StatefulSet 类型的资源
metadata:
name: web # StatefulSet 对象的名字
spec:
selector:
matchLabels:
app: nginx # 使用哪个 service 来管理 dns,就是和上面的 metadata.name 的 “nginx” 匹配
serviceName: "nginx"
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: nginx:1.7.9
ports: # 容器内部要暴露的端口
- containerPort: 80 # 具体暴露的端口号
name: web # 该端口配置的名字
- 执行 web.yml
kubectl create -f web.yml
# 如果出错可以执行下面的命令删除创建
kubectl delete sts web
kubectl delete svc nginx
- 通过下面命令会看到 pod 的创建
kubectl get po
- 下面尝试是否可以 ping 通。使用万能工具包
- (注意)容器主机内,用宿主机无法 ping 通
kubectl run -it --image busybox:1.28.4 dns-test --restart=Never --rm /bin/sh
# 测试下面命令
ping web-0.nginx # DNS 命名格式为:statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local 一般只要 statefulSetName-{0..N-1}.serviceName 就可
ping web-1.nginx
nslookup web-0.nginx
2. 扩容缩容
- 首先看到现在的容器也只有 3 个
- 这时扩容到 5 个
kubectl scale sts web --replicas=5
# 查看扩容过程
kubectl describe sts web
- 缩容也是用同样的命令,他是按数字从大到小进行缩容
- 镜像更新
- 目前还不支持直接更新 image,需要
patch
来间接实现,通过补丁,可以发现版本已经更新到 1.9.1
kubectl patch sts web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"nginx:1.9.1"}]'
# 查看版本更新版本
kubectl rollout history sts web
# 查看第 2 个版本的变化历史
kubectl rollout history sts web --revision=2
# 查看更新的动作
kubectl rollout status sts web
- 因为我们在配置中配置的实现是
RollingUpdate
更新策略,在 StatefulSet 中更新时是基于 pod 的顺序倒序更新的。利用滚动更新中的partition
属性,可以实现简易的灰度发布的效果
kubectl edit sts web
4. 灰度发布
- 首先把服务扩容到 5 台
- 修改滚动策略的
partition
为 3
# 修改
kubectl edit sts web
- 其中修改配置如下
...
spec:
containers:
- image: nginx:1.7.9
...
updateStrategy:
rollingUpdate:
partition: 3
type: RollingUpdate
...
- 然后分别查看一下每个 web-* 的 pod,会发现 3,4 已经更新版本到 1.7.9
kubectl describe po web-2
- 直接把
partition
改为 0,直接全量发布
- onDelete 策略
- 只有在 pod 被删除时会进行更新操作
- 先修改更新策略
kubectl edit sts web
- 修改的配置如下
...
updateStrategy:
type: OnDelete
...
- 然后再次修改 nginx 版本配置为 1.9.1,你会发现每个 web-* 的 pod 都根本不会变化,除非执行下面命令。你就可以每个 pod 操作一次之后,才会更新版本
kubectl describe pod web-4
- 级联删除
- 级联删除:删除 StatefulSet 时会同时删除 pod
kubectl delete statefulset web
- 非级联删除:删除 StatefulSet 时不会删除 pod,删除 sts 后,pod 就没人管了,此时再删除 pod 不会重建的
# 先重新创建
kubectl delete service nginx # 这个也要执行一下,好像 service 没删除
kubectl create -f web.yml
# 非级联删除
kubectl delete sts web --cascade=false
- StatefulSet 删除后 PVC 还会保留着,数据不再使用的话也需要删除
kubectl delete pvc ***
四、DaemonSet
- 解释
- 它是可以专门筛选节点,来帮助自动在节点层面创建 pod,例如那种专门采集日志数据的进程就有必要
- 不指定 Node 节点
- 不指定 Node 创建文件
# fluentd-ds.yml
apiVersion: apps/v1
kind: DaemonSet # 创建 DaemonSet 资源
metadata:
name: fluentd # 名字
spec:
selector: # 一定要写的
matchLabels:
app: logging # 匹配标签的值,和下面的 labels.app 对应
template: # 模板配置
metadata:
labels:
app: logging
id: fluentd
name: fluentd # 容器名
spec:
containers:
- name: fluentd-es
image: agilestacks/fluentd-elasticsearch:v1.3.0
env: # 环境变量
- name: FLUENTD_ARGS
value: -qq
volumeMounts: # 加载数据卷
- name: containers # 把下面命名为 containers 的容器卷加载到下面路径去
mountPath: /var/lib/docker/containers
- name: varlog
mountPath: /varlog
volumes: # 定义数据卷,主机路径模式,与 node 共享目录
- hostPath:
path: /var/lib/docker/containers # node 中的共享目录
name: containers
- hostPath:
path: /var/log
name: varlog
- 执行创建,默认会在我们的 2 个节点中创建
kubectl create -f fluentd-ds.yml
kubecttl get daemonset
kubectl get po -o wide
- 通过查看 Node 的时候,其实这时候并没有相应的 label,让我们 ds 选择部署到哪个节点去,所以默认就会往
非 master 节点
去部署
kubectl get nodes --show-labels
- 指定 Node 节点,使用节点选择器
- 首先标签一下其中一个 node
kubectl label no k8s-node1 type=microservices
- 编辑一下 ds
kubectl edit ds fluentd
- 其中增加配置如下,保存后查看 ds,发现就剩下 1 个了
...
template:
spec:
nodeSelector:
type: microservices
...
- 当给 node2 也加一个同样标签,相应的 fluentd 就会多创建 1 个
kubectl label no k8s-node2 type=microservices
4. 滚动更新
- 不建议使用
RollingUpdate
,建议使用OnDelete
模式,这样避免频繁更新 ds
五、HPA 自动扩缩容
- 概述
- 通过观察 pod 的 cpu、内存使用率或自定义 metrics 指标进行自动的扩容或缩容 pod 的数量
- 通常用于 Deployment,不适用于无法扩/缩容的对象,如 DaemonSet
- 开启指标服务
- 首先先重新执行 nginx-deploy.yaml 创建 Deployment,这时候副本是 1 就够了
- 对 nginx-deploy.yaml 先增加资源限制
...
spec:
template: # pod 模板
spec: # pod 期望信息
containers: # pod 的容器
- image: nginx:1.7.9 # 镜像
imagePullPolicy: IfNotPresent # 拉取策略
name: nginx # 容器名称
resources: # 增加资源限制
requests:
cpu: 10m # 等会拿来测试
memory: 128Mi
limits:
cpu: 200m
memory: 128Mi
...
- 替换一下配置文件
kubectl replace -f nginx-deploy.yaml
- 创建 HPA 自动扩缩容
kubectl autoscale deploy nginx-deploy --cpu-percent=20 --min=2 --max=5
# 会发现已经创建了 2 个 pod
kubectl get deploy
- 按照监测指标工具,否则没办法使用 top
# 下载 metrics-server 组件配置文件
wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml -O metrics-server-components.yaml
# 修改镜像地址为国内的地址
sed -i 's/registry.k8s.io\/metrics-server/registry.cn-hangzhou.aliyuncs.com\/google_containers/g' metrics-server-components.yaml
# 修改容器的 tls 配置,不验证 tls,在 containers 的 args 参数中增加这个参数
...
spec:
containers:
- args:
....
- --metric-resolution=15s
- --kubelet-insecure-tls # 加这个
...
# 安装组件
kubectl apply -f metrics-server-components.yaml
# 查看 pod 状态
kubectl get pods --all-namespaces | grep metrics
- 下面就可以执行 top,查看 pod 使用资源情况
kubectl top pods
- 为了能够把两个 pod 合到一起去,需要配置一下 service,首先先查看这 2 个 pod 有的标签,取
app=nginx
来进行匹配
kubectl get pod --show-labels
- 创建 nginx-svc.yml,并执行
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
selector:
app: nginx-deploy
ports:
- port: 80
targetPort: 80
name: web
- 执行下面命令,查看 svc 端口,其中 CLUSTER-IP 代表的是容器 ip,而 port 是容器内端口,执行 curl 命令就可以查看到内容
kubectl get svc
- 在另外一个 shell 里面,对 service 执行一个死循环,就会看到容器自动扩容了
while true; do wget -q -O- http://10.100.99.222 > /dev/null ; done
# 看到容器自动扩容
kubectl get pod
# cpu 飙升
kubectl get hpa
# 查看每个 pod 具体 cpu 使用率
kubectl top po
- 当停止掉死循环之后,就会发现容器自动缩容了
# 查看缩容细节
kubectl describe hpa nginx-deploy
# 已经缩容
kubectl get hpa