1.基于velero及minio实现etcd数据备份与恢复
1.1 Velero简介:
Velero 是vmware开源的一个云原生的灾难恢复和迁移工具,它本身也是开源的,采用Go语言编写,可以安全的备份、恢复和迁移Kubernetes集群资源数据,https://velero.io/。
Velero 是西班牙语意思是帆船,非常符合Kubernetes社区的命名风格,Velero的开发公司Heptio,已被VMware收购。
Velero 支持标准的K8S集群,既可以是私有云平台也可以是公有云,除了灾备之外它还能做资源移转,支持把容器应用从一个集群迁移到另一个集群。
Velero 的工作方式就是把kubernetes中的数据备份到对象存储以实现高可用和持久化,默认的备份保存时间为720小时,并在需要的时候进行下载和恢复。
Velero与etcd快照备份的区别:
etcd 快照是全局完成备份(类似于MySQL全部备份),即使需要恢复一个资源对象(类似于只恢复MySQL的一个库),但是也需要做全局恢复到备份的状态(类似于MySQL的全库恢复),即会影响其它namespace中pod运行服务(类似于会影响MySQL其它数据库的数据)。
Velero可以有针对性的备份,比如按照namespace单独备份、只备份单独的资源对象等,在恢复的时候可以根据备份只恢复单独的namespace或资源对象,而不影响其它namespace中pod运行服务。
velero支持ceph、oss等对象存储,etcd快照是一个为本地文件。
velero支持任务计划实现周期备份,但etcd快照也可以基于cronjob实现。
velero支持对AWS EBS创建快照及还原
https://www.qloudx.com/velero-for-kubernetes-backup-restore-stateful-workloads-with-aws-ebs-snapshots/
https://github.com/vmware-tanzu/velero-plugin-for-aws #Elastic Block Store
velero整体架构

1.2 备份流程
~# velero backup create myserver-ns-backup-${DATE} --include-namespaces myserver --kubeconfig=./skyliu.kubeconfig --
namespace velero-system
Velero 客户端调用Kubernetes API Server创建Backup任务。
Backup 控制器基于watch 机制通过API Server获取到备份任务。
Backup 控制器开始执行备份动作,其会通过请求API Server获取需要备份的数据。
Backup 控制器将获取到的数据备份到指定的对象存储server端

1.3 部署minio
root@k8s-master2:/usr/local/src# nerdctl pull minio/minio:RELEASE.2022-04-12T06-55-35Z
root@k8s-master2:/usr/local/src# mkdir -p /data/minio
#创建minio容器,如果不指定,则默认用户名与密码为 minioadmin/minioadmin,可以通过环境变量自定义,如下:
root@k8s-master2:/usr/local/src# nerdctl run --name minio \
-p 9000:9000 \
-p 9999:9999 \
--restart=always \
-e "MINIO_ROOT_USER=admin" \
-e "MINIO_ROOT_PASSWORD=12345678" \
-v /data/minio/data:/data \
-d minio/minio:RELEASE.2022-04-12T06-55-35Z server /data \
--console-address '0.0.0.0:9999'
minio web登录界面

bucket名称:velerodata,后期会使用

minio验证bucket

1.4 部署veleno
在master节点部署velero:
https://github.com/vmware-tanzu/velero #版本兼容性
部署velero:
root@k8s-master2:/usr/local/src# wget https://github.com/vmware-tanzu/velero/releases/download/v1.11.0/velero-v1.11.0-linux-amd64.tar.gz
root@k8s-master2:/usr/local/src# tar xvf velero-v1.11.0-linux-amd64.tar.gz
root@k8s-master2:/usr/local/src# cp velero-v1.11.0-linux-amd64/velero /usr/local/bin/
root@k8s-master2:/usr/local/src# velero --help
配置velero认证环境:
#工作目录:
root@k8s-master2:~# mkdir /data/velero -p
root@k8s-master2:~# cd /data/velero
root@k8s-master2:/data/velero#
#访问minio的认证文件:
root@k8s-master2:/data/velero# vim velero-auth.txt
[default]
aws_access_key_id = admin
aws_secret_access_key = 12345678
#准备user-csr文件:
root@k8s-master2:/data/velero# vim skyliu-csr.json
{
"CN": "awsuser",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
#准备证书签发环境:
root@k8s-master2:/data/velero# apt install golang-cfssl
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssl_1.6.1_linux_amd64
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssljson_1.6.1_linux_amd64
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssl-certinfo_1.6.1_linux_amd64
root@k8s-master2:/data/velero# mv cfssl-certinfo_1.6.1_linux_amd64 cfssl-certinfo
root@k8s-master2:/data/velero# mv cfssl_1.6.1_linux_amd64 cfssl
root@k8s-master2:/data/velero# mv cfssljson_1.6.1_linux_amd64 cfssljson
root@k8s-master2:/data/velero# cp cfssl-certinfo cfssl cfssljson /usr/local/bin/
root@k8s-master2:/data/velero# chmod a+x /usr/local/bin/cfssl*
#执行证书签:
>= 1.24.x:
root@k8s-deploy:~# scp /etc/kubeasz/clusters/k8s-cluster1/ssl/ca-config.json 192.168.121.111:/data/velero
root@k8s-master2:/data/velero# /usr/local/bin/cfssl gencert -ca=/etc/kubernetes/ssl/ca.pem -ca-key=/etc/kubernetes/ssl/ca-key.pem -config=./ca-config.json -profile=kubernetes ./skyliu-csr.json | cfssljson -bare skyliu
1.23 <=
root@k8s-master2:/data/velero# /usr/local/bin/cfssl gencert -ca=/etc/kubernetes/ssl/ca.pem -ca-key=/etc/kubernetes/ssl/ca-key.pem -config=/etc/kubeasz/clusters/k8s-cluster1/ssl/ca-config.json -profile=kubernetes ./skyliu-csr.json | cfssljson -bare skyliu
#验证证书:
root@k8s-master2:/data/velero# ll skyliu*
-rw-r--r-- 1 root root 997 May 22 08:44 skyliu.csr
-rw-r--r-- 1 root root 219 May 22 08:43 skyliu-csr.json
-rw------- 1 root root 1675 May 22 08:44 skyliu-key.pem
-rw-r--r-- 1 root root 1387 May 22 08:44 skyliu.pem
#分发证书到api-server证书路径:
root@k8s-master2:/data/velero# cp skyliu-key.pem /etc/kubernetes/ssl/
root@k8s-master2:/data/velero# cp skyliu.pem /etc/kubernetes/ssl/
#生成集群认证config文件:
# export KUBE_APISERVER="https://192.168.121.110:6443"
# kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/ssl/ca.pem \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=./skyliu.kubeconfig
#设置客户端证书认证:
# kubectl config set-credentials skyliu \
--client-certificate=/etc/kubernetes/ssl/skyliu.pem \
--client-key=/etc/kubernetes/ssl/skyliu-key.pem \
--embed-certs=true \
--kubeconfig=./skyliu.kubeconfig
#设置上下文参数:
# kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=skyliu \
--namespace=velero-system \
--kubeconfig=./skyliu.kubeconfig
#设置默认上下文:
# kubectl config use-context kubernetes --kubeconfig=skyliu.kubeconfig
#k8s集群中创建awsuser账户:
# kubectl create clusterrolebinding skyliu --clusterrole=cluster-admin --user=skyliu
#创建namespace:
# kubectl create ns velero-system
# 执行安装:
velero --kubeconfig ./skyliu.kubeconfig \
install \
--provider aws \
--plugins velero/velero-plugin-for-aws:v1.5.5 \
--bucket velerodata \
--secret-file ./velero-auth.txt \
--use-volume-snapshots=false \
--namespace velero-system \
--backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://192.168.121.111:9000
#验证安装:
root@k8s-master2:/data/velero# kubectl get pod -n velero-system
root@k8s-master2:/data/velero# kubectl get pod -n velero-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
velero-98bc8c975-pvbc6 0/1 PodInitializing 0 2m51s 10.200.107.241 192.168.121.115 <none> <none>
root@k8s-node2:~# nerdctl pull velero/velero-plugin-for-aws:v1.5.5
root@k8s-node2:~# nerdctl pull velero/velero:v1.11.0
root@k8s-master2:/data/velero# kubectl get pod -n velero-system
NAME READY STATUS RESTARTS AGE
velero-98bc8c975-q6c5d 1/1 Running 0 2m36s
1.5 对default ns进行备份
root@k8s-master2:/data/velero# DATE=`date +%Y%m%d%H%M%S`
root@k8s-master2:/data/velero# velero backup create default-backup-${DATE} \
--include-cluster-resources=true \
--include-namespaces default \
--kubeconfig=./skyliu.kubeconfig \
--namespace velero-system
#验证备份:
velero backup describe default-backup-20230523094751 -n velero-system
Name: default-backup-20230523094751
Namespace: velero-system
Labels: velero.io/storage-location=default
Annotations: velero.io/source-cluster-k8s-gitversion=v1.26.4
velero.io/source-cluster-k8s-major-version=1
velero.io/source-cluster-k8s-minor-version=26
Phase: Completed
Namespaces:
Included: default
Excluded: <none>
Resources:
Included: *
Excluded: <none>
Cluster-scoped: included
Label selector: <none>
Storage Location: default
Velero-Native Snapshot PVs: auto
TTL: 720h0m0s
CSISnapshotTimeout: 10m0s
ItemOperationTimeout: 1h0m0s
Hooks: <none>
Backup Format Version: 1.1.0
Started: 2023-05-23 09:48:06 +0000 UTC
Completed: 2023-05-23 09:48:09 +0000 UTC
Expiration: 2023-06-22 09:48:06 +0000 UTC
Velero-Native Snapshots: <none included>
验证

1.6 删除pod并验证数据恢复
#查看pod
root@k8s-master2:/data/velero# kubectl get pod
NAME READY STATUS RESTARTS AGE
net-test1 1/1 Running 1 (17m ago) 3h28m
删除pod
root@k8s-master2:/data/velero# kubectl delete pod net-test1
pod "net-test1" deleted
验证
root@k8s-master2:/data/velero# kubectl get pod
No resources found in default namespace.
恢复pod
velero restore create --from-backup default-backup-20230523094751 --wait --kubeconfig=./skyliu.kubeconfig --namespace velero-system
验证pod
root@k8s-master2:/data/velero# kubectl get pod
NAME READY STATUS RESTARTS AGE
net-test1 1/1 Running 0 41s

1.7 备份指定资源对象
root@k8s-master2:/data/velero# kubectl run net-test2 --image=alpine sleep 10000000000 -n myserver
pod/net-test2 created
root@k8s-master2:/data/velero# kubectl get pod -n myserver
NAME READY STATUS RESTARTS AGE
net-test2 1/1 Running 0 2m19s
root@k8s-master1:~/20230507/k8s-Resource-N76/case3-controller# kubectl get deploy -n myserver
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 2/2 2 2 64s
备份
root@k8s-master2:/data/velero# DATE=`date +%Y%m%d%H%M%S`
root@k8s-master2:/data/velero# velero backup create pod-backup-$DATE --include-cluster-resources=true --ordered-resources 'pods=myserver/net-test1' --namespace velero-system --include-namespaces=myserver
Backup request "pod-backup-20230523142250" submitted successfully.
Run `velero backup describe pod-backup-20230523142250` or `velero backup logs pod-backup-20230523142250` for more details.
删除deployment控制器
root@k8s-master1:~/20230507/k8s-Resource-N76/case3-controller# kubectl delete -f 3-deployment.yml
deployment.apps "nginx-deployment" deleted
root@k8s-master1:~/20230507/k8s-Resource-N76/case3-controller# kubectl get deploy -n myserver
No resources found in myserver namespace.
root@k8s-master2:/data/velero# velero restore create --from-backup pod-backup-20230523142250 --wait --kubeconfig=./skyliu.kubeconfig --namespace velero-system
Restore request "pod-backup-20230523142250-20230523143401" submitted successfully.
Waiting for restore to complete. You may safely press ctrl-c to stop waiting - your restore will continue in the background.
..................
Restore completed with status: Completed. You may check for more information using the commands `velero restore describe pod-backup-20230523142250-20230523143401` and `velero restore logs pod-backup-20230523142250-20230523143401`.
验证恢复
root@k8s-master2:/data/velero# kubectl get deploy -n myserver
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 2/2 2 2 3m23s

1.8 批量备份所有namespace
root@k8s-master2:~# cat /data/velero/ns-back.sh
#!/bin/bash
NS_NAME=`kubectl get ns | awk '{if (NR>2){print}}' | awk '{print $1}'`
DATE=`date +%Y%m%d%H%M%S`
cd /data/velero/
for i in $NS_NAME;do
velero backup create ${i}-ns-backup-${DATE} \
--include-cluster-resources=true \
--include-namespaces ${i} \
--kubeconfig=/root/.kube/config \
--namespace velero-system
done
root@k8s-master2:~# bash /data/velero/ns-back.sh

minio验证备份:

2.基于RBAC实现多账户授权
2.1 Kubernetes API 鉴权流程:

鉴权类型:https://kubernetes.io/zh/docs/reference/access-authn-authz/authorization
Node(节点鉴权):针对kubelet发出的API请求进行鉴权。
授予node节点的kubelet读取services、endpoints、secrets、configmaps等事件状态,并向API server更新pod与node状态。
Webhook: 是一个HTTP回调,发生某些事情时调用的HTTP调用。
# Kubernetes API 版本
apiVersion: v1
# API 对象种类
kind: Config
# clusters 代表远程服务。
clusters: - name: name-of-remote-authz-service
cluster:
# 对远程服务进行身份认证的 CA。
certificate-authority: /path/to/ca.pem
# 远程服务的查询 URL。必须使用 'https'。
server: https://authz.example.com/authorize
ABAC(Attribute-based access control ):基于属性的访问控制,1.6之前使用,将属性与账户直接绑定。
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1",
"kind": "Policy",
"spec":
{"user": "user1",
"namespace": "*",
"resource": "*",
"apiGroup": "*"}} #用户user1对所有namespace所有API版本的所有资源拥有所有权限((没有设置"readonly": true)。
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1",
"kind": "Policy",
"spec":
{"user": "user2",
"namespace": "myserver",
"resource": "pods",
"readonly": true}} #用户user2对namespace myserver的pod有只读权限。
--authorization-mode=...,RBAC,ABAC --authorization-policy-file=mypolicy.json #开启ABAC参数
RBAC(Role-Based Access Control):基于角色的访问控制,将权限与角色(role)先进行关联,然后将角色与用户进行绑定(Binding)从而继承角色中的权限
role

rolebinding

2.2 简介
RBAC API声明了四种Kubernetes对象:Role、ClusterRole、RoleBinding和ClusterRoleBinding。
Role: 定义一组规则,用于访问命名空间中的 Kubernetes 资源。
RoleBinding: 定义用户和角色(Role)的绑定关系。
ClusterRole: 定义了一组访问集群中 Kubernetes 资源(包括所有命名空间)的规则。
ClusterRoleBinding: 定义了用户和集群角色(ClusterRole)的绑定关系。

https://kubernetes.io/zh/docs/reference/access-authn-authz/rbac/ #使用RBAC鉴权,RBAC是基于角色的访问控制(Role-Based Access Control)
https://kubernetes.io/zh/docs/reference/access-authn-authz/authorization/ #鉴权概述
配置role
2.2.1:在指定namespace创建账户:
root@k8s-master2:/data/velero# kubectl create sa sky -n sky
serviceaccount/sky created
2.2.2:创建role规则:
root@k8s-master2:/data/sky# cat sky-role.yaml
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: sky
name: sky-role
rules:
- apiGroups: ["*"]
resources: ["pods"]
#verbs: ["*"]
##RO-Role
verbs: ["get", "watch", "list"]
- apiGroups: ["*"]
resources: ["pods/exec"]
#verbs: ["*"]
##RO-Role
verbs: ["get", "watch", "list","put","create"]
- apiGroups: ["extensions", "apps/v1"]
resources: ["deployments"]
#verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
##RO-Role
verbs: ["get", "watch", "list"]
- apiGroups: ["*"]
resources: ["*"]
#verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
##RO-Role
verbs: ["get", "watch", "list"]
root@k8s-master2:/data/sky# kubectl apply -f sky-role.yaml
role.rbac.authorization.k8s.io/sky-role created
2.2.3:将规则与账户进行绑定:
root@k8s-master2:/data/sky# cat sky-role-bind.yaml
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: role-bind-sky
namespace: sky
subjects:
- kind: ServiceAccount
name: sky
namespace: sky
roleRef:
kind: Role
name: sky-role
apiGroup: rbac.authorization.k8s.io
root@k8s-master2:/data/sky# kubectl apply -f sky-role-bind.yaml
rolebinding.rbac.authorization.k8s.io/role-bind-sky created
2.2.4 创建token
root@k8s-master2:/data/sky# cat sky-token.yaml
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
name: sky-user-token
namespace: sky
annotations:
kubernetes.io/service-account.name: "sky"
root@k8s-master2:/data/sky# kubectl apply -f sky-token.yaml
secret/sky-user-token created
2.2.5:获取token名称:
root@k8s-master1:/usr/local/src# kubectl get secrets -A
NAMESPACE NAME TYPE DATA AGE
kube-system calico-etcd-secrets Opaque 3 33d
kubernetes-dashboard dashboard-admin-user kubernetes.io/service-account-token 3 5m21s
kubernetes-dashboard kubernetes-dashboard-certs Opaque 0 17m
kubernetes-dashboard kubernetes-dashboard-csrf Opaque 1 17m
kubernetes-dashboard kubernetes-dashboard-key-holder Opaque 2 17m
sky sky-user-token kubernetes.io/service-account-token 3 24h
velero-system cloud-credentials Opaque 1 30h
velero-system velero-repo-credentials Opaque 1 30h
2.2.6 获取token值
root@k8s-master1:/usr/local/src# kubectl describe secrets -n sky sky-user-token
Name: sky-user-token
Namespace: sky
Labels: <none>
Annotations: kubernetes.io/service-account.name: sky
kubernetes.io/service-account.uid: 19df0a38-8a4e-4148-a482-8a0afe405a41
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1310 bytes
namespace: 3 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IkVxTXUxaGxkeEk3SU1yZlJnNFViVzhBVnFNc3hRbnZFa1VMdDZaNkd3QlEifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJza3kiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlY3JldC5uYW1lIjoic2t5LXVzZXItdG9rZW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoic2t5Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiMTlkZjBhMzgtOGE0ZS00MTQ4LWE0ODItOGEwYWZlNDA1YTQxIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OnNreTpza3kifQ.aXC3o6ERVq8-Fd4KiI_EKY4Km8_ChbfEpKfiPecCK3TtvQaPmXEd-KOjWRoHv6ajaEM5tseIYa2vbE8vE7KUDedPYR0lf9jN-OBFO-Oa96J5Hsg8_BSvkB3D7DYafzU6g_jAfhi5yVzBGHvreoIksjLoGeRIUs5gh53hdY2Sh3nHykPfQpVPRqsxZMiX4wYzyKOPENs6zq34i8bhCi8LMGB-lyoq1wx694ajDjH7UalJpIGFAlVqd7WO2oF01_JAnSM5VWeNAU8YpL6NqdW2St1zIOdsdb3A_8e1eOtHhgb_T6oMVsuFzp5IL1VX_SoPaObh2QUVIyY1R2_P4iObtA
1.7:登录dashboard测试:

验证是否操作删除

配置clusterrole
root@k8s-master2:/data/sky# kubectl create sa sky510 -n sky
root@k8s-master2:/data/sky# cat sky-clusterrole.yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: CR
rules:
# Allow Metrics Scraper to get metrics from the Metrics server
- apiGroups: [""]
resources: ["pods", "nodes"]
verbs: ["get", "list", "watch"]
root@k8s-master2:/data/sky# cat sky-clusterrole-bind.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: CR-bind
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: CR
subjects:
- kind: ServiceAccount
name: sky510
namespace: sky
root@k8s-master2:/data/sky# cat sky510-token.yaml
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
name: sky510-user-token
namespace: sky
annotations:
kubernetes.io/service-account.name: "sky510"
root@k8s-master2:/data/sky# kubectl get secrets -n sky
NAME TYPE DATA AGE
sky-user-token kubernetes.io/service-account-token 3 24h
sky510-user-token kubernetes.io/service-account-token 3 11m
root@k8s-master2:/data/sky# kubectl describe secrets -n sky sky510-user-token
Name: sky510-user-token
Namespace: sky
Labels: <none>
Annotations: kubernetes.io/service-account.name: sky510
kubernetes.io/service-account.uid: 171a2619-286e-4db8-b831-3d12b9a596c8
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1310 bytes
namespace: 3 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IkVxTXUxaGxkeEk3SU1yZlJnNFViVzhBVnFNc3hRbnZFa1VMdDZaNkd3QlEifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJza3kiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlY3JldC5uYW1lIjoic2t5NTEwLXVzZXItdG9rZW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoic2t5NTEwIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiMTcxYTI2MTktMjg2ZS00ZGI4LWI4MzEtM2QxMmI5YTU5NmM4Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OnNreTpza3k1MTAifQ.Ptqaz4N8qUz_b3CIkFT150SIaUIABJPwsRdos2fIHdbBqQmY65YVPOU3b0i9oPpljpfrApNeQ7mrb9jch5ZRcARx12ysbn3yDIOis_o-3DH0MvV5mjCvVfd8ZQT4FKqj1pxPwRwQoqshiny34izW3PcmbKvn1Ah5-rgts0WmUJyB-kgFGLSG_EOX9bgXk0HkrrLY0FfccRNqHqohIDFcVZ3xdTazuYnFs3rZfY2coGWNG-tQLH4M6ku27iRGieqfUlmNvULJbQ7j1EWzYtGps1oWaj094PFwMT3_ws0XLhgELUOOIVkglS-Sjb-GCn9MvlJj8jNXwLcUQeYmDs3kGw
验证


二:基于kube-config文件登录:
2.1:创建csr文件:
root@k8s-master2:~/test# cat sky-csr.json
{
"CN": "China",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
2.2:签发证书:
root@k8s-master2:~/test# apt install golang-cfssl
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssl_1.6.1_linux_amd64
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssljson_1.6.1_linux_amd64
wget https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssl-certinfo_1.6.1_linux_amd64
root@k8s-master2:~/test# mv cfssl-certinfo_1.6.1_linux_amd64 cfssl-certinfo
root@k8s-master2:~/test# mv cfssl_1.6.1_linux_amd64 cfssl
root@k8s-master2:~/test# mv cfssljson_1.6.1_linux_amd64 cfssljson
root@k8s-master2:~/test# cp cfssl-certinfo cfssl cfssljson /usr/local/bin/
root@k8s-master2:~/test# chmod a+x /usr/local/bin/cfssl*
root@k8s-master2:~/test# cfssl gencert -ca=/etc/kubernetes/ssl/ca.pem -ca-key=/etc/kubernetes/ssl/ca-key.pem -config=/data/velero/ca-config.json -profile=kubernetes sky-csr.json | cfssljson -bare hui
root@k8s-master2:~/test# ls
hui.csr hui-key.pem hui.pem sky-csr.json
2.3:生成普通用户kubeconfig文件:
root@k8s-master2:~/test# kubectl config set-cluster hui --certificate-authority=/etc/kubernetes/ssl/ca.pem --embed-certs=true --server=https://192.168.121.188:6443 --kubeconfig=hui.kubeconfig #--embed-certs=true为嵌入证书信息
2.4:设置客户端认证参数:
# cp *.pem /etc/kubernetes/ssl/
# kubectl config set-credentials hui \
--client-certificate=/etc/kubernetes/ssl/hui.pem \
--client-key=/etc/kubernetes/ssl/hui-key.pem \
--embed-certs=true \
--kubeconfig=hui.kubeconfig
2.5:设置上下文参数(多集群使用上下文区分)
https://kubernetes.io/zh/docs/concepts/configuration/organize-cluster-access-kubeconfig/
# kubectl config set-context hui \
--cluster=hui \
--user=hui \
--namespace=sky \
--kubeconfig=hui.kubeconfig
2.5: 设置默认上下文
# kubectl config use-context hui --kubeconfig=hui.kubeconfig
2.6 创建用户
root@k8s-master2:~/test# kubectl create sa hui -n sky
serviceaccount/hui created
root@k8s-master2:~/test# kubectl get sa -n sky
NAME SECRETS AGE
default 0 47h
hui 0 17m
sky 0 47h
sky510 0 22h
#创建clusterrole
root@k8s-master2:~/test# cat hui-clusterrole.yaml
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: love
rules:
# Allow Metrics Scraper to get metrics from the Metrics server
- apiGroups: [""]
resources: ["pods", "nodes"]
verbs: ["get", "list", "watch"]
root@k8s-master2:~/test# kubectl apply -f hui-clusterrole.yaml
clusterrole.rbac.authorization.k8s.io/love created
root@k8s-master2:~/test# kubectl get clusterrole
NAME CREATED AT
love 2023-05-25T15:14:08Z
#创建clusterrolebinding
root@k8s-master2:~/test# cat hui-clusterrole-bind.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: love-bind
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: love
subjects:
- kind: ServiceAccount
name: hui
namespace: sky
root@k8s-master2:~/test# kubectl apply -f hui-clusterrole-bind.yaml
clusterrolebinding.rbac.authorization.k8s.io/love-bind created
root@k8s-master2:~/test# kubectl get clusterrolebinding
NAME ROLE AGE
love-bind ClusterRole/love 118s
#创建token
root@k8s-master2:~/test# cat hui-token.yaml
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
name: hui-user-token
namespace: sky
annotations:
kubernetes.io/service-account.name: "hui"
root@k8s-master2:~/test# kubectl apply -f hui-token.yaml
secret/hui-user-token created
root@k8s-master2:~/test# kubectl get secrets -n sky hui-user-token
NAME TYPE DATA AGE
hui-user-token kubernetes.io/service-account-token 3 51s
2.7:获取token:
root@k8s-master2:~/test# kubectl describe secrets -n sky hui-user-token
Name: hui-user-token
Namespace: sky
Labels: <none>
Annotations: kubernetes.io/service-account.name: hui
kubernetes.io/service-account.uid: ee40508e-b9c6-4771-8e1e-017f264a0fa5
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1310 bytes
namespace: 3 bytes
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IkVxTXUxaGxkeEk3SU1yZlJnNFViVzhBVnFNc3hRbnZFa1VMdDZaNkd3QlEifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJza3kiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlY3JldC5uYW1lIjoiaHVpLXVzZXItdG9rZW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiaHVpIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiZWU0MDUwOGUtYjljNi00NzcxLThlMWUtMDE3ZjI2NGEwZmE1Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OnNreTpodWkifQ.gRXgpn3wn3O5Bs6JMYW_TxRebLVwiNZFQZyj7NunHKIIR8__uQr1ISbaYNaIDSdwHVuKZ0ZUZNUGhJ5YHQX5JjIttl8WrOknWLLkCzLf2_uBcpOQo_5HsfpedfNFfmm9o1O1gLVu2uN9JQfbMALI6jwV0lAmnSc120G_xwpIY0f9oXNnVa59vzCpKGy5k5UKU3sTG7xrbJty0HiGZRrBRBSer1AMPe4TLG8OOg7sRd_AwRQ9WtnM16U5p7Q5A2MaVX8dhM6NbIPIurbkeynJsyn_bI-qOLixq2Kb8YABejqAuWXECfyMhSv3KfnYuzEdc-Yxx38V5KS-_ajquIP-bQ
2.8:将token写入用户kube-config文件:
root@k8s-master2:~/test# vim hui.kubeconfig
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURtakNDQW9LZ0F3SUJBZ0lVWmc5Si9YeFlndUFjSDh1dVdrcjVOQkpkZkxvd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1pERUxNQWtHQTFVRUJoTUNRMDR4RVRBUEJnTlZCQWdUQ0VoaGJtZGFhRzkxTVFzd0NRWURWUVFIRXdKWQpVekVNTUFvR0ExVUVDaE1EYXpoek1ROHdEUVlEVlFRTEV3WlRlWE4wWlcweEZqQVVCZ05WQkFNVERXdDFZbVZ5CmJtVjBaWE10WTJFd0lCY05Nak13TkRJd01USTFNREF3V2hnUE1qRXlNekF6TWpjeE1qVXdNREJhTUdReEN6QUoKQmdOVkJBWVRBa05PTVJFd0R3WURWUVFJRXdoSVlXNW5XbWh2ZFRFTE1Ba0dBMVVFQnhNQ1dGTXhEREFLQmdOVgpCQW9UQTJzNGN6RVBNQTBHQTFVRUN4TUdVM2x6ZEdWdE1SWXdGQVlEVlFRREV3MXJkV0psY201bGRHVnpMV05oCk1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBclVzakptRlQyK3NSL3BUVHEvRUEKdnh5Ly9QKzZkdWNGV1RtcG4xN1BBK1FKNVVvUHRwODVlekNYRitrSU5mOEFFYmp2RWxlZnEwK3pnOC9NbFpTMAo3dUlHSFBmUmxjTGdzdGdJNHBEODlKRW0zRkNxS3VIWE5pUURnZW1uc3VKeHRFWTNlclRpNUtNUWxXQkFyK2EvCjRUNk5xWmdwOVZEUjArWDVGSEo5Q2ZiaHdROFI3SUxDaFluaXltanlwR1Q5aEYyQjhoVUF2MHhLL1QrRk1ZN0YKTFEreHVaV1RYSS9mN0V0OTVBd3hOYnAyS1pvOTFUSTR4aXhRSGhsWEwyS0duaGE1YThvbVQrZjdhVWtWR2c1dQoydUVVelkxaGE5R2swVS92VjkzdXR2Z1R1cHJZWXlPaEsvcHY0MW4xYVRBMTN5Mmw0ZE1LV3RVQXdEM214WHd6CnJ3SURBUUFCbzBJd1FEQU9CZ05WSFE4QkFmOEVCQU1DQVFZd0R3WURWUjBUQVFIL0JBVXdBd0VCL3pBZEJnTlYKSFE0RUZnUVUxWVZBTkpnVWFnbk4xUHY1KyswWG5yQWh5T2N3RFFZSktvWklodmNOQVFFTEJRQURnZ0VCQUlkZQpNN2xvM0duaGI3REU0VjlKM3RuNGFUaS9lWVh4bENJcVVtR1RwMW9QRTJNc2dMcjZvcXFnd3dIcEJ3bnFrc3FMCmYvQ3FSazB1S1NTVXFzVzduK2lPMDZXMFZlUUhaNHdicm9LUXNNd1Z0d2tObDY0UGVheHp1K3NSd2FHVXVBZmoKaTJDSHJyRFFUVlgzTnpyZzQ5RE9obXJ4QTFORFRYeXB1NG55bkVFN1VjZDlaMzhLbjhnM1hCN1FzS1Q2QjVKLwpNNVF5SE9QcHBJbHFVeWhaTDdLTkE5QkF5bTRGeU4xUGt2bUxTeCthdkZhRnp6Qk1jQ1B6SWpPMHBwOTU0blZXClBQS24vQkhWUWhmbmNsN1FEQmRCN2ErYzAyUFJCbXN0VnJIN2lPVHB3V3A2Rjk3UmRjSnl1QkJoZWVaR1ZYQTcKUEE5ajRYV1JUOWhPdDlaNUxIST0KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
server: https://192.168.121.188:6443
name: hui
contexts:
- context:
cluster: hui
namespace: sky
user: hui
name: hui
current-context: hui
kind: Config
preferences: {}
users:
- name: hui
user:
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUQwekNDQXJ1Z0F3SUJBZ0lVQlo2VnNOaXZWWm16ZUhwSGhBQ3VwSlVkVXYwd0RRWUpLb1pJaHZjTkFRRUwKQlFBd1pERUxNQWtHQTFVRUJoTUNRMDR4RVRBUEJnTlZCQWdUQ0VoaGJtZGFhRzkxTVFzd0NRWURWUVFIRXdKWQpVekVNTUFvR0ExVUVDaE1EYXpoek1ROHdEUVlEVlFRTEV3WlRlWE4wWlcweEZqQVVCZ05WQkFNVERXdDFZbVZ5CmJtVjBaWE10WTJFd0lCY05Nak13TlRJMU1UUXpPREF3V2hnUE1qQTNNekExTVRJeE5ETTRNREJhTUdBeEN6QUoKQmdOVkJBWVRBa05PTVJBd0RnWURWUVFJRXdkQ1pXbEthVzVuTVJBd0RnWURWUVFIRXdkQ1pXbEthVzVuTVF3dwpDZ1lEVlFRS0V3TnJPSE14RHpBTkJnTlZCQXNUQmxONWMzUmxiVEVPTUF3R0ExVUVBeE1GUTJocGJtRXdnZ0VpCk1BMEdDU3FHU0liM0RRRUJBUVVBQTRJQkR3QXdnZ0VLQW9JQkFRRFBJbnRTZGZVeEdZZzBGQ2JCZU10VVVBdFAKWXRCQkQ1VFc0STQ4TDRWZUFmV0hyZFNzQ20wamg2OXVNTEZ6MUZCeFlCbmpmZGRWZEdFUVY2aGx3UW85TzExbgpHOUFCWTdVUnltdmxoSnJZWHVsZnY2UUFOSlZkVFFaZytkNTZ4bTFXMjVGUVl5NGFmT2d2blA3NWgyY2hZOVpVCkhlaytjcTh4ZHlEeUgyVHN1alhHb215bzBEL3lWblBpMG5tTjlLajNEOXQ3TFNJM0s2cmRrdEt1ckhXU1o1WHAKV0wxWWxpdDNxYzV5aDNpT0grSittMzZTdllkMUthMGphZ3hTdlFvMy9wN24rOUtMSXFvMFliajh4UldUbFp6VwpoMUt2RWtwVE1zK0FFK0Y0THFRZXZOVUlPanUvWWNDYTZmcWl2UXIwMHg4aExqZDNUcE9rYVV0RCt1dHRBZ01CCkFBR2pmekI5TUE0R0ExVWREd0VCL3dRRUF3SUZvREFkQmdOVkhTVUVGakFVQmdnckJnRUZCUWNEQVFZSUt3WUIKQlFVSEF3SXdEQVlEVlIwVEFRSC9CQUl3QURBZEJnTlZIUTRFRmdRVXNoQzl3T3lsVWw5MXl6cm8xMERmQUIwVgpTZEl3SHdZRFZSMGpCQmd3Rm9BVTFZVkFOSmdVYWduTjFQdjUrKzBYbnJBaHlPY3dEUVlKS29aSWh2Y05BUUVMCkJRQURnZ0VCQUgzQk5IYXVzajZlQUV5RWw5SWNVS0Q5MGdFZHJhTkZaQUpXdlVUcG10aFV5cG1QTkhsUk9pQloKcTZwM0tmU1kyVHVxdm1wNzJHTzNCcHFaZzNjamdkdHBEbjl4SjZKNjNjTjZXYmc1WmM4NTlMMk9ETWlyc3UxcwpHNXMxNXhobmphYW8vSHRzSkIvTVQ3VW1HVnFmbTVNdVVGd2Ztd1d2T3lpK0FZTmxFL1pOTjZWbVVnQTBCSUVtClhhOXpTdUN4VitmdHBvTWljNFJKQjE2emFrVGg4SVFyMU9YNlJMTVBpOTg5S1NoL01JVjNqTmNjK2NlZm02dVYKTFAwVitCdlUvZVZZZC94bW9veVM0Z1pIeWpiSEhYeHdjdGhYN0NzeEthOWphNGJnNk1WcGx0SHBadVE5VWFuSQpYRmpnVDBXbGF2bDlBMWdJSks2aTdiaERaT2xsY3VFPQotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFb3dJQkFBS0NBUUVBenlKN1VuWDFNUm1JTkJRbXdYakxWRkFMVDJMUVFRK1UxdUNPUEMrRlhnSDFoNjNVCnJBcHRJNGV2YmpDeGM5UlFjV0FaNDMzWFZYUmhFRmVvWmNFS1BUdGRaeHZRQVdPMUVjcHI1WVNhMkY3cFg3K2sKQURTVlhVMEdZUG5lZXNadFZ0dVJVR011R256b0w1eisrWWRuSVdQV1ZCM3BQbkt2TVhjZzhoOWs3TG8xeHFKcwpxTkEvOGxaejR0SjVqZlNvOXcvYmV5MGlOeXVxM1pMU3JxeDFrbWVWNlZpOVdKWXJkNm5PY29kNGpoL2lmcHQrCmtyMkhkU210STJvTVVyMEtOLzZlNS92U2l5S3FOR0c0L01VVms1V2Mxb2RTcnhKS1V6TFBnQlBoZUM2a0hyelYKQ0RvN3YySEFtdW42b3IwSzlOTWZJUzQzZDA2VHBHbExRL3JyYlFJREFRQUJBb0lCQVFDdS9EMWNrMlFaSDYydAorVndvVStqS0NIa1ZqcS9LVnVSeGh2RUNMVThvOU5TODA0QjMrckxxc2lUbEhPTzhxNTl0dURjR3RYZmxyRlNYCm5zWVhlRFl6Tm1TWXg2azRrMGdUaUlNUU9hOHFuVHZnZEtDU3Y5bHpJYkFDMnZRMW1rNGljNGxXZFFNc3cxclAKWm4wTXhuTzhoSUE3UGEyZTRQblordjd0TE5KeEhQVWdZUjJZNE92eUM2R3ZDaHJia2pxYlRvNy8vQm9zRGJHdApMd0xPazl6REJ5eHJQQmcrc0o2TnZOaVFqNmlyUjJBeVFEQWRNTElwcFM1SUlVYWFwaGNmUTJHZjhyZVM0dmdwCjNaRkduK1dNV3VKdW5ZTUVrNDBaZzY1WTdMUHk3aC94QW9UV1QvSCtRaEdoZXc2NnZsMCtHNHRJYUZsd0xYdFcKRFpIYVVUOUJBb0dCQU40c0NSanpyd0wxTWJYTGpnK05Lb1RZaXVqRVZEQ1FQVlBQbDZPQnNsSHRhYUFaV3FCWAprcDJnM2djQ0YxaW84YXpHV1pRLzJTT3V6QVdDRDNPeFB6UEo3UEo1dHUxelNyWFJQRnh0Um1oaldTd29EL0xYCjdGd1BDU3EzWEtkaDJqOGplNEFCVUhaNzJoS2pMZlBjam0yb1U2WjUxRUE4d1FYTVNlaDNUNHR4QW9HQkFPNnMKVDlPQzFEOUY3eTBuSkZXTzBORXU1WEpXNm01QUlSMnNUdWRuOGx3KzVKUG8yM3pVYjVXMUMydWp6SDFnU0FTZAp1Q2pjR01rak5odDJEdUNLbkFjaHBlNzYvWGFOWnhjeVM4MitFeVhaL0RocFZLTVRWL1FCRVIxZ1NrMmY3a2J3CmkxRzR3djVUYm1EWk15L2VDQkhzbS93ZW1ReTl1UlNxRFFlVytnbTlBb0dBYlhsYlhqMHRIcEw5Vkt3aHF3NFAKUm5pQk1pTVRyUDVXQ2NjLzNDU2JYbjFTejczT2h6Vy9uQVpaZ1RDSm1ubGM1SnEwSnpXeTVEOU1idVpnZ014MAo3U3J4bzZWUCt2OFZjRFBTdjJSbERpanVGckVDOHRGc3VRdjdvMTNJdlAyZGtnRUU2TlU4OWJVZmhwRjdvaThxCnkyUG5IQi9wODJFOFo0UDdZeDN2UnpFQ2dZQTc1M0hOczV1VUdmaHpDOHo1MEhPbTNTOW5xRnNFdXdIVTBjZW8KR3hYZ2cwU1p2eXMveEk0Uk5EU2VtcWtibXN2WXBNRnhOL1RjbndMWWw2UWFSWS90MWtzd2xUeUN3ZkRyQ0l1dwpJeEhwUVRJbDhvSDB3RWttREJLQW5nZG9Qa2p1OHpiMGx2d1NHMXlyNERnUnZwZWw4QTRpbElkemhEYnM4ZFY5Clh5NTR2UUtCZ0FWbktUajM2dTdib0o1Ui9hbTJ5UGpsOElRRmVqbGhSUUpXdlRDZERBWUVPRkQwbTZZUEwvR2oKc3ZCaGFmL2xwZy9tYk12U0lxYWppTlVpL2owNEFhTjF5SS9HV0J0N0xFMVRWTkdEVlprQkNKQVl3aE1oQjRDcAozWVhldkMvUEkrVlc5bkt0VFptMUxURkVMOGNaM1I4aUthTjhaNWtXM21OdjNwL3NpYzdmCi0tLS0tRU5EIFJTQSBQUklWQVRFIEtFWS0tLS0tCg==
token: eyJhbGciOiJSUzI1NiIsImtpZCI6IkVxTXUxaGxkeEk3SU1yZlJnNFViVzhBVnFNc3hRbnZFa1VMdDZaNkd3QlEifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJza3kiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlY3JldC5uYW1lIjoiaHVpLXVzZXItdG9rZW4iLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiaHVpIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiZWU0MDUwOGUtYjljNi00NzcxLThlMWUtMDE3ZjI2NGEwZmE1Iiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OnNreTpodWkifQ.gRXgpn3wn3O5Bs6JMYW_TxRebLVwiNZFQZyj7NunHKIIR8__uQr1ISbaYNaIDSdwHVuKZ0ZUZNUGhJ5YHQX5JjIttl8WrOknWLLkCzLf2_uBcpOQo_5HsfpedfNFfmm9o1O1gLVu2uN9JQfbMALI6jwV0lAmnSc120G_xwpIY0f9oXNnVa59vzCpKGy5k5UKU3sTG7xrbJty0HiGZRrBRBSer1AMPe4TLG8OOg7sRd_AwRQ9WtnM16U5p7Q5A2MaVX8dhM6NbIPIurbkeynJsyn_bI-qOLixq2Kb8YABejqAuWXECfyMhSv3KfnYuzEdc-Yxx38V5KS-_ajquIP-bQ
3.9:dashboard登录测试:

3.通过HPA控制器及metric-server根据pod CPU利用率实现pod副本的弹性伸缩
3.1 pod伸缩简介
根据当前pod的负载,动态调整 pod副本数量,业务高峰期自动扩容pod的副本数以尽快响应pod的请求。
在业务低峰期对pod进行缩容,实现降本增效的目的。
公有云支持node级别的弹性伸缩

3.2 手动调整pod副本数:
root@k8s-master1:~# kubectl get pod -n myserver #当前pod副本数
NAME READY STATUS RESTARTS AGE
myserver-myapp-deployment-name-fb44b4447-pwwxq 1/1 Running 1 (5h15m ago) 11d
myserver-myapp-frontend-deployment-855c89f977-th64z 1/1 Running 2 (5h15m ago) 11d
myserver-tomcat-app1-deployment-86bc8cbcb5-k9vc7 1/1 Running 7 (5h15m ago) 18d
root@k8s-master1:~# kubectl --help | grep scale #命令使用帮助
scale Set a new size for a deployment, replica set, or replication controller
autoscale Auto-scale a deployment, replica set, stateful set, or replication controller
root@k8s-master1:~# kubectl scale --help
root@k8s-master1:~# kubectl scale deployment myserver-tomcat-app1-deployment --replicas=2 -n myserver
deployment.apps/myserver-tomcat-app1-deployment scaled
验证pod副本数:
root@k8s-master1:~# **kubectl get pod -n myserver
NAME READY STATUS RESTARTS AGE
myserver-myapp-deployment-name-fb44b4447-pwwxq 1/1 Running 1 (5h53m ago) 11d
myserver-myapp-frontend-deployment-855c89f977-th64z 1/1 Running 2 (5h53m ago) 11d
myserver-tomcat-app1-deployment-86bc8cbcb5-gdczd 1/1 Running 0 42s
myserver-tomcat-app1-deployment-86bc8cbcb5-k9vc7 1/1 Running 7 (5h53m ago) 18d
3.3 动态伸缩控制器类型:
水平pod自动缩放器(HPA): 基于pod 资源利用率横向调整pod副本数量。
垂直pod自动缩放器(VPA): 基于pod资源利用率,调整对单个pod的最大资源限制,不能与HPA同时使用。
集群伸缩(Cluster Autoscaler,CA): 基于集群中node 资源使用情况,动态伸缩node节点,从而保证有CPU和内存资源用于创建pod

3.4 PA控制器简介:
Horizontal Pod Autoscaling (HPA)控制器,根据预定义好的阈值及pod当前的资源利用率,自动控制在k8s集群中运行的pod数量(自动弹性水平自动伸缩).
-horizontal-pod-autoscaler-sync-period #默认每隔15s(可以通过–horizontal-pod-autoscaler-sync-period修改)查询metrics的资源使用情况。
--horizontal-pod-autoscaler-downscale-stabilization #缩容间隔周期,默认5分钟。
--horizontal-pod-autoscaler-sync-period #HPA控制器同步pod副本数的间隔周期
--horizontal-pod-autoscaler-cpu-initialization-period #初始化延迟时间,在此时间内pod的CPU资源指标将不会生效,默认为5分钟。
--horizontal-pod-autoscaler-initial-readiness-delay #用于设置pod准备时间, 在此时间内的 pod 统统被认为未就绪及不采集数据,默认为30秒。
--horizontal-pod-autoscaler-tolerance #HPA控制器能容忍的数据差异(浮点数,默认为0.1),即新的指标要与当前的阈值差异在0.1或以上, 即要大于1+0.1=1.1,或小于1-0.1=0.9,比如阈值为CPU利用率50%,当前为80%,那么80/50=1.6 > 1.1则会触发扩容,分之会缩容。即触发条件:avg(CurrentPodsConsumption) / Target >1.1 或 <0.9=把N个pod的数据相加后根据pod的数量计算出平均数除以阈值,大于1.1就扩容,小于0.9就缩容。
计算公式:TargetNumOfPods = ceil(sum(CurrentPodsCPUUtilization) / Target) #ceil是一个向上取整的目的pod整数。
指标数据需要部署metrics-server,即HPA使用metrics-server作为数据源。
https://github.com/kubernetes-sigs/metrics-server
在k8s 1.1引入HPA控制器,早期使用Heapster组件采集pod指标数据,在k8s 1.11版本开始使用Metrices Server完成数据采集,然后将采集到的数据通过API(Aggregated API,汇总API),例如metrics.k8s.io、custom.metrics.k8s.io、external.metrics.k8s.io,然后再把数据提供给HPA控制器进行查询,以实现基于某个资源利用率对pod进行扩缩容的目的。
3.5 metrics-server 部署:
Metrics Server 是 Kubernetes 内置的容器资源指标来源。
Metrics Server 是通过node节点上的 Kubelet 收集资源指标,并通过Metrics API在 Kubernetes apiserver 中公开指标数据,以供Horizontal Pod Autoscaler和Vertical Pod Autoscaler使用,也可以通过访问kubectl top node/pod 查看指标数据。
下载地址:https://github.com/kubernetes-sigs/metrics-server/releases/tag/v0.6.3



#部署metrics-server
root@k8s-master2:~/test# cat metrics-server-v0.6.1.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
k8s-app: metrics-server
name: metrics-server
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
k8s-app: metrics-server
rbac.authorization.k8s.io/aggregate-to-admin: "true"
rbac.authorization.k8s.io/aggregate-to-edit: "true"
rbac.authorization.k8s.io/aggregate-to-view: "true"
name: system:aggregated-metrics-reader
rules:
- apiGroups:
- metrics.k8s.io
resources:
- pods
- nodes
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
labels:
k8s-app: metrics-server
name: system:metrics-server
rules:
- apiGroups:
- ""
resources:
- nodes/metrics
verbs:
- get
- apiGroups:
- ""
resources:
- pods
- nodes
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
labels:
k8s-app: metrics-server
name: metrics-server-auth-reader
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: extension-apiserver-authentication-reader
subjects:
- kind: ServiceAccount
name: metrics-server
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
k8s-app: metrics-server
name: metrics-server:system:auth-delegator
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:auth-delegator
subjects:
- kind: ServiceAccount
name: metrics-server
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
k8s-app: metrics-server
name: system:metrics-server
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:metrics-server
subjects:
- kind: ServiceAccount
name: metrics-server
namespace: kube-system
---
apiVersion: v1
kind: Service
metadata:
labels:
k8s-app: metrics-server
name: metrics-server
namespace: kube-system
spec:
ports:
- name: https
port: 443
protocol: TCP
targetPort: https
selector:
k8s-app: metrics-server
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
k8s-app: metrics-server
name: metrics-server
namespace: kube-system
spec:
selector:
matchLabels:
k8s-app: metrics-server
strategy:
rollingUpdate:
maxUnavailable: 0
template:
metadata:
labels:
k8s-app: metrics-server
spec:
containers:
- args:
- --cert-dir=/tmp
- --secure-port=4443
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --kubelet-use-node-status-port
- --metric-resolution=15s
image: bitnami/metrics-server:0.6.1 #修改镜像为国内镜像
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 3
httpGet:
path: /livez
port: https
scheme: HTTPS
periodSeconds: 10
name: metrics-server
ports:
- containerPort: 4443
name: https
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /readyz
port: https
scheme: HTTPS
initialDelaySeconds: 20
periodSeconds: 10
resources:
requests:
cpu: 100m
memory: 200Mi
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
runAsUser: 1000
volumeMounts:
- mountPath: /tmp
name: tmp-dir
nodeSelector:
kubernetes.io/os: linux
priorityClassName: system-cluster-critical
serviceAccountName: metrics-server
volumes:
- emptyDir: {}
name: tmp-dir
---
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
labels:
k8s-app: metrics-server
name: v1beta1.metrics.k8s.io
spec:
group: metrics.k8s.io
groupPriorityMinimum: 100
insecureSkipTLSVerify: true
service:
name: metrics-server
namespace: kube-system
version: v1beta1
versionPriority: 100
root@k8s-master2:~/test# kubectl apply -f metrics-server-v0.6.1.yaml
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created
#验证pod指标数据
root@k8s-master2:~/test# kubectl top pod
NAME CPU(cores) MEMORY(bytes)
net-test1 0m 0Mi
net-test2 0m 1Mi
net-test3 0m 2Mi
#验证node指标数据
root@k8s-master2:~/test# kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
192.168.121.111 221m 11% 1556Mi 58%
192.168.121.112 291m 7% 1724Mi 47%
192.168.121.113 347m 8% 1676Mi 46%
3.6 web服务与HPA控制器部署
手动创建HPA控制器-不推荐
root@k8s-master2:~/test# kubectl autoscale deployment/myserver-tomcat-deployment --min=2 --max=10 --cpu-percent=80 -n myserver
horizontalpodautoscaler.autoscaling/myserver-tomcat-deployment autoscaled
root@k8s-master2:~/test# cat tomcat-app1.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app1-deployment-label
name: magedu-tomcat-app1-deployment
namespace: magedu
spec:
replicas: 5
selector:
matchLabels:
app: magedu-tomcat-app1-selector
template:
metadata:
labels:
app: magedu-tomcat-app1-selector
spec:
containers:
- name: magedu-tomcat-app1-container
image: tomcat:7.0.93-alpine
#image: lorel/docker-stress-ng
#args: ["--vm", "2", "--vm-bytes", "256M"]
##command: ["/apps/tomcat/bin/run_tomcat.sh"]
imagePullPolicy: IfNotPresent
##imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
resources:
limits:
cpu: 1
memory: "512Mi"
requests:
cpu: 500m
memory: "512Mi"
---
kind: Service
apiVersion: v1
metadata:
labels:
app: magedu-tomcat-app1-service-label
name: magedu-tomcat-app1-service
namespace: magedu
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
#nodePort: 40003
selector:
app: magedu-tomcat-app1-selector
#部署web服务
root@k8s-master2:~/test# kubectl apply -f tomcat-app1.yaml
3.7 部署HPA
root@k8s-master2:~/test# cat hpa.yaml
apiVersion: autoscaling/v1 #定义API版本
kind: HorizontalPodAutoscaler #对象类型
metadata:
namespace: magedu
name: magedu-tomcat-app1-deployment
labels:
app: magedu-tomcat-app1
version: v2beta1
spec:
scaleTargetRef: #定义水平伸缩的目标对象,Deployment、ReplicationController/ReplicaSet
apiVersion: apps/v1
kind: Deployment
name: magedu-tomcat-app1-deployment
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 60
#metrics: #调用metrics数据定义
#- type: Resource
# resource:
# name: cpu
# targetAverageUtilization: 60
#- type: Resource
# resource:
# name: memory
#通过yaml文件部署HPA控制器
root@k8s-master2:~/test# kubectl apply -f hpa.yaml
root@k8s-master2:~/test# kubectl get hpa -n magedu
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
magedu-tomcat-app1-podautoscaler Deployment/magedu-tomcat-app1-deployment 0%/60% 3 20 3 26m
root@k8s-master2:~/test# kubectl describe hpa magedu-tomcat-app1-podautoscaler -n magedu


4.kubernetes中container、Pod、Namespace内存及CPU等资源限制
• 1.kubernetes中资源限制概括
• 2.kubernetes对单个容器的CPU及memory实现资源限制
• 3.kubernetes对单个pod的CPU及memory实现资源限制
• 4.kubernetes对整个namespace的CPU及memory实现资源限制
4.1 kubernetes中资源限制概括

1.如果运行的容器没有定义资源(memory、CPU)等限制,但是在namespace定义了LimitRange限制,那么该容器会继承LimitRange中的默认限制。
2.如果namespace没有定义LimitRange限制,那么该容器可以只要宿主机的最大可用资源,直到无资源可用而触发宿主机(OOM Killer)。
https://kubernetes.io/zh/docs/tasks/configure-pod-container/assign-cpu-resource/
CPU 以核心为单位进行限制,单位可以是整核、浮点核心数或毫核(m/milli):
2=2核心=200% 0.5=500m=50% 1.2=1200m=120%
https://kubernetes.io/zh/docs/tasks/configure-pod-container/assign-memory-resource/
memory 以字节为单位,单位可以是E、P、T、G、M、K、Ei、Pi、Ti、Gi、Mi、Ki
1536Mi=1.5Gi
requests(请求)为kubernetes scheduler执行pod调度时node节点至少需要拥有的资源。
limits(限制)为pod运行成功后最多可以使用的资源上限。

4.2 .kubernetes对单个容器的CPU及memory实现资源限制

root@k8s-master1:/apps/magedu# cat case2-pod-memory-and-cpu-limit.yml
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
kind: Deployment
metadata:
name: limit-test-deployment
namespace: magedu
spec:
replicas: 1
selector:
matchLabels: #rs or deployment
app: limit-test-pod
# matchExpressions:
# - {key: app, operator: In, values: [ng-deploy-80,ng-rs-81]}
template:
metadata:
labels:
app: limit-test-pod
spec:
containers:
- name: limit-test-container
image: lorel/docker-stress-ng
resources:
limits:
cpu: "1.2"
memory: "512Mi"
requests:
memory: "100Mi"
cpu: "500m"
#command: ["stress"]
args: ["--vm", "2", "--vm-bytes", "256M"]
#nodeSelector:
# env: group1
root@k8s-master1:/apps/magedu# kubectl apply -f case2-pod-memory-and-cpu-limit.yml

4.3.kubernetes对单个pod的CPU及memory实现资源限制
Limit Range是对具体某个Pod或容器的资源使用进行限制
https://kubernetes.io/zh/docs/concepts/policy/limit-range/
限制namespace中每个Pod或容器的最小与最大计算资源
限制namespace中每个Pod或容器计算资源request、limit之间的比例
限制namespace中每个存储卷声明(PersistentVolumeClaim)可使用的最小与最大存储空间
设置namespace中容器默认计算资源的request、limit,并在运行时自动注入到容器中
root@k8s-master1:/apps/magedu# cat case3-LimitRange.yaml
apiVersion: v1
kind: LimitRange
metadata:
name: limitrange-magedu
namespace: magedu
spec:
limits:
- type: Container #限制的资源类型
max:
cpu: "2" #限制单个容器的最大CPU
memory: "2Gi" #限制单个容器的最大内存
min:
cpu: "500m" #限制单个容器的最小CPU
memory: "512Mi" #限制单个容器的最小内存
default:
cpu: "500m" #默认单个容器的CPU限制
memory: "512Mi" #默认单个容器的内存限制
defaultRequest:
cpu: "500m" #默认单个容器的CPU创建请求
memory: "512Mi" #默认单个容器的内存创建请求
maxLimitRequestRatio:
cpu: 2 #限制CPU limit/request比值最大为2
memory: 2 #限制内存limit/request比值最大为1.5
- type: Pod
max:
cpu: "4" #限制单个Pod的最大CPU
memory: "4Gi" #限制单个Pod最大内存
- type: PersistentVolumeClaim
max:
storage: 50Gi #限制PVC最大的requests.storage
min:
storage: 30Gi #限制PVC最小的requests.storage
root@k8s-master1:/apps/magedu# kubectl apply -f case3-LimitRange.yaml
限制案例1:CPU与内存 RequestRatio比例限制
root@k8s-master1:/apps/magedu# cat case4-pod-RequestRatio-limit.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
labels:
app: magedu-wordpress-deployment-label
name: magedu-wordpress-deployment
namespace: magedu
spec:
replicas: 1
selector:
matchLabels:
app: magedu-wordpress-selector
template:
metadata:
labels:
app: magedu-wordpress-selector
spec:
containers:
- name: magedu-wordpress-nginx-container
image: nginx:1.16.1
imagePullPolicy: Always
ports:
- containerPort: 80
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
resources:
limits:
cpu: 0.5
memory: 0.5Gi
requests:
cpu: 0.5
memory: 0.5Gi
- name: magedu-wordpress-php-container
image: php:5.6-fpm-alpine
imagePullPolicy: Always
ports:
- containerPort: 80
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
resources:
limits:
cpu: 0.5
memory: 0.5Gi
requests:
cpu: 0.5
memory: 0.5Gi
- name: magedu-wordpress-redis-container
image: redis:4.0.14-alpine
imagePullPolicy: Always
ports:
- containerPort: 80
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
resources:
limits:
cpu: 1
memory: 1Gi
requests:
cpu: 1
memory: 1Gi
---
kind: Service
apiVersion: v1
metadata:
labels:
app: magedu-wordpress-service-label
name: magedu-wordpress-service
namespace: magedu
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
nodePort: 30033
selector:
app: magedu-wordpress-selector
root@k8s-master1:/apps/magedu# kubectl apply -f case4-pod-RequestRatio-limit.yaml
限制案例2:CPU与内存或超分限制:
root@k8s-master1:/apps/magedu# cat case5-pod-cpu-limit.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
labels:
app: magedu-wordpress-deployment-label
name: magedu-wordpress-deployment
namespace: magedu
spec:
replicas: 1
selector:
matchLabels:
app: magedu-wordpress-selector
template:
metadata:
labels:
app: magedu-wordpress-selector
spec:
containers:
- name: magedu-wordpress-nginx-container
image: nginx:1.16.1
imagePullPolicy: Always
ports:
- containerPort: 80
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
resources:
limits:
cpu: 1
memory: 1Gi
requests:
cpu: 500m
memory: 512Mi
- name: magedu-wordpress-php-container
image: php:5.6-fpm-alpine
imagePullPolicy: Always
ports:
- containerPort: 80
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
resources:
limits:
#cpu: 2.8
cpu: 2
memory: 1Gi
requests:
cpu: 1.5
memory: 512Mi
---
kind: Service
apiVersion: v1
metadata:
labels:
app: magedu-wordpress-service-label
name: magedu-wordpress-service
namespace: magedu
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
nodePort: 30033
selector:
app: magedu-wordpress-selector
root@k8s-master1:/apps/magedu# kubectl apply -f case5-pod-cpu-limit.yaml
4.4 kubernetes对整个namespace的CPU及memory实现资源限制
https://kubernetes.io/zh/docs/concepts/policy/resource-quotas/
限定某个对象类型(如Pod、service)可创建对象的总数;
限定某个对象类型可消耗的计算资源(CPU、内存)与存储资源(存储卷声明)总数
root@k8s-master1:/apps/magedu# cat case6-ResourceQuota-magedu.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: quota-magedu
namespace: magedu
spec:
hard:
requests.cpu: "8"
limits.cpu: "8"
requests.memory: 4Gi
limits.memory: 4Gi
requests.nvidia.com/gpu: 4
pods: "100"
services: "100"
root@k8s-master1:/apps/magedu# kubectl apply -f case6-ResourceQuota-magedu.yaml
限制案例1:验证namespace Pod副本数限制:
root@k8s-master1:/apps/magedu# cat case7-namespace-pod-limit-test.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
labels:
app: magedu-nginx-deployment-label
name: magedu-nginx-deployment
namespace: magedu
spec:
replicas: 5
selector:
matchLabels:
app: magedu-nginx-selector
template:
metadata:
labels:
app: magedu-nginx-selector
spec:
containers:
- name: magedu-nginx-container
image: nginx:1.16.1
imagePullPolicy: Always
ports:
- containerPort: 80
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
resources:
limits:
cpu: 1
memory: 1Gi
requests:
cpu: 1
memory: 1Gi
---
kind: Service
apiVersion: v1
metadata:
labels:
app: magedu-nginx-service-label
name: magedu-nginx-service
namespace: magedu
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
nodePort: 30033
selector:
app: magedu-nginx-selector
root@k8s-master1:/apps/magedu# kubectl apply -f case7-namespace-pod-limit-test.yaml
限制案例2:CPU总计核心数限制:
root@k8s-master1:/apps/magedu# cat case8-namespace-cpu-limit-test.yaml
kind: Deployment
apiVersion: apps/v1
metadata:
labels:
app: magedu-nginx-deployment-label
name: magedu-nginx-deployment
namespace: magedu
spec:
replicas: 6
selector:
matchLabels:
app: magedu-nginx-selector
template:
metadata:
labels:
app: magedu-nginx-selector
spec:
containers:
- name: magedu-nginx-container
image: nginx:1.16.1
imagePullPolicy: Always
ports:
- containerPort: 80
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
resources:
limits:
cpu: 2
memory: 100Mi
requests:
cpu: 2
memory: 100Mi
---
kind: Service
apiVersion: v1
metadata:
labels:
app: magedu-nginx-service-label
name: magedu-nginx-service
namespace: magedu
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
nodePort: 30033
selector:
app: magedu-nginx-selector
root@k8s-master1:/apps/magedu# kubectl apply -f case8-namespace-cpu-limit-test.yaml
5.node、pod的亲和与反亲和
pod调度流程


5.1 nodeSelector案例:
nodeSelector 基于node标签选择器,将pod调度的指定的目的节点上。
https://kubernetes.io/zh/docs/concepts/scheduling-eviction/assign-pod-node/
可用于基于服务类型干预Pod调度结果,如对磁盘I/O要求高的pod调度到SSD节点,对内存要求比较高的pod调度的内存较高的节点。也可以用于区分不同项目的pod,如将node添加不同项目的标签,然后区分调度。
root@k8s-node1:~# kubectl describe node 192.168.121.113 #默认标签
Name: 192.168.121.113
Roles: node
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=192.168.121.113
kubernetes.io/os=linux
kubernetes.io/role=node
为node节点打标签:
root@k8s-node1:~# kubectl label node 192.168.121.113 project="magedu"
root@k8s-node1:~# kubectl label node 192.168.121.113 disktype="ssd"
将pod调度到目的node,yaml文件中指定的key与value必须精确匹配:
root@k8s-master1:~# cat case1-nodeSelector.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app2-deployment-label
name: magedu-tomcat-app2-deployment
namespace: magedu
spec:
replicas: 4
selector:
matchLabels:
app: magedu-tomcat-app2-selector
template:
metadata:
labels:
app: magedu-tomcat-app2-selector
spec:
containers:
- name: magedu-tomcat-app2-container
image: tomcat:7.0.94-alpine
imagePullPolicy: IfNotPresent
#imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
resources:
limits:
cpu: 1
memory: "512Mi"
requests:
cpu: 500m
memory: "512Mi"
nodeSelector:
project: magedu
disktype: ssd
root@k8s-master1:~# kubectl apply -f case1-nodeSelector.yaml
deployment.apps/magedu-tomcat-app2-deployment created
5.2 nodeName案例:

为node节点打标签:
root@k8s-node1:~# kubectl label node 192.168.121.113 disktype=ssd
root@k8s-node2:~# kubectl label node 192.168.121.114 disktype=ssd
创建pod:
root@k8s-master1:~# cat case2-nodename.yml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app2-deployment-label
name: magedu-tomcat-app2-deployment
namespace: magedu
spec:
replicas: 1
selector:
matchLabels:
app: magedu-tomcat-app2-selector
template:
metadata:
labels:
app: magedu-tomcat-app2-selector
spec:
nodeName: 192.168.121.113
containers:
- name: magedu-tomcat-app2-container
image: tomcat:7.0.94-alpine
imagePullPolicy: IfNotPresent
#imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
resources:
limits:
cpu: 1
memory: "512Mi"
requests:
cpu: 500m
memory: "512Mi"
root@k8s-master1:~# kubectl apply -f case2-nodename.yaml
5.3 node affinity
affinity是Kubernetes 1.2版本后引入的新特性,类似于nodeSelector,允许使用者指定一些Pod在Node间调度的约束,目前支持两种形式
requiredDuringSchedulingIgnoredDuringExecution #必须满足pod调度匹配条件,如果不满足则不进行调度
preferredDuringSchedulingIgnoredDuringExecution #倾向满足pod调度匹配条件,不满足的情况下会调度的不符合条件的Node上
IgnoreDuringExecution表示如果在Pod运行期间Node的标签发生变化,导致亲和性策略不能满足,也会继续运行当前的Pod。
Affinity与anti-affinity的目的也是控制pod的调度结果,但是相对于nodeSelector,Affinity(亲和)与anti-affinity(反亲和)的功能更加强大:
affinity与nodeSelector对比:
1、亲和与反亲和对目的标签的选择匹配不仅仅支持and,还支持In、NotIn、Exists、DoesNotExist、Gt、Lt。
In:标签的值存在匹配列表中(匹配成功就调度到目的node,实现node亲和)
NotIn:标签的值不存在指定的匹配列表中(不会调度到目的node,实现反亲和)
Gt:标签的值大于某个值(字符串)
Lt:标签的值小于某个值(字符串)
Exists:指定的标签存在
2、可以设置软匹配和硬匹配,在软匹配下,如果调度器无法匹配节点,仍然将pod调度到其它不符合条件的节点。
3、还可以对pod定义亲和策略,比如允许哪些pod可以或者不可以被调度至同一台node。
注:
如果定义一个nodeSelectorTerms(条件)中通过一个matchExpressions基于列表指定了多个operator条件,则只要满足其中一个条件,就会被调度到相应的节点上,即or的关系,即如果nodeSelectorTerms下面有多个条件的话,只要满足任何一个条件就可以了,见 case 3.1.1。
如果定义一个nodeSelectorTerms中都通过一个matchExpressions(匹配表达式)指定key匹配多个条件,则所有的目的条件都必须满足才会调度到对应的节点,即and的关系,即果matchExpressions有多个选项的话,则必须同时满足所有这些条件才能正常调度,见case 3.1.2 。

5.3.1.1:硬亲和-nodeAffinity-requiredDuring-matchExpressions
多个matchExpressions条件,则只要满足其中一个条件,就会被调度到相应的节点上,即or的关系
为node节点打标签:
root@k8s-node1:~# kubectl label node 192.168.121.113 project="magedu"
root@k8s-node1:~# kubectl label node 192.168.121.113 disktype="ssd"
root@k8s-master1:~# cat case3-1.1-nodeAffinity-requiredDuring-matchExpressions.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app2-deployment-label
name: magedu-tomcat-app2-deployment
namespace: magedu
spec:
replicas: 1
selector:
matchLabels:
app: magedu-tomcat-app2-selector
template:
metadata:
labels:
app: magedu-tomcat-app2-selector
spec:
containers:
- name: magedu-tomcat-app2-container
image: tomcat:7.0.94-alpine
imagePullPolicy: IfNotPresent
#imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions: #2个matchExpressions
- key: disktype #匹配条件1,有一个key但是有多个values、则只要匹配成功一个value就可以调度
operator: In
values:
- ssd # 只有一个value是匹配成功也可以调度
- xxx
- matchExpressions:
- key: project #匹配条件1,有一个key但是有多个values、则只要匹配成功一个value就可以调度
operator: In
values:
- xxx #即使这俩条件都匹配不上也可以调度,即多个matchExpressions只要有任意一个能匹配任何一个value就可以调用。
- nnn
创建pod:
root@k8s-master1:~# kubectl apply -f case3-1.1-nodeAffinity-requiredDuring-matchExpressions.yaml
验证pod调度结果:
root@k8s-master1:~# kubectl get pod -n magedu -o wide
NAME READY STATUS RESTARTS AGE IP NODE
magedu-tomcat-app2-deployment-69886c7c85-2ttx7 1/1 Running 0 4s 10.200.218.30 192.168.121.113
一个matchExpressions匹配多个条件,则所有的目的条件都必须满足才会调度到对应的节点,即and的关系
为node节点打标签:
root@k8s-node1:~# kubectl label node 192.168.121.113 project="magedu"
root@k8s-node1:~# kubectl label node 192.168.121.113 disktype="ssd"
root@k8s-master1:~# cat case3-1.2-nodeAffinity-requiredDuring-matchExpressions.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app2-deployment-label
name: magedu-tomcat-app2-deployment
namespace: magedu
spec:
replicas: 1
selector:
matchLabels:
app: magedu-tomcat-app2-selector
template:
metadata:
labels:
app: magedu-tomcat-app2-selector
spec:
containers:
- name: magedu-tomcat-app2-container
image: tomcat:7.0.94-alpine
imagePullPolicy: IfNotPresent
#imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions: #只有一个matchExpressions
- key: disktype #匹配条件1,同一个key的多个value只有有一个匹配成功就认为当前key匹配成功
operator: In
values:
- ssd
- hdd
- key: project #匹配条件2,当前key也要匹配成功一个value,即条件1和条件2必须同时每个key匹配成功一个value,否则不调度
operator: In
values:
- magedu
root@k8s-master1:~# kubectl apply -f case3-1.2-nodeAffinity-requiredDuring-matchExpressions.yaml
deployment.apps/magedu-tomcat-app2-deployment created
验证pod调度结果:
root@k8s-master1:~# kubectl get pod -n magedu -o wide
NAME READY STATUS RESTARTS AGE IP NODE
magedu-tomcat-app2-deployment-7f4b7457db-rgljj 1/1 Running 0 3s 10.200.151.216 192.168.121.113
case5.3-2.1:软亲和-nodeAffinity-preferredDuring
root@k8s-master1:~# cat case3-2.1-nodeAffinity-preferredDuring.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app2-deployment-label
name: magedu-tomcat-app2-deployment
namespace: magedu
spec:
replicas: 1
selector:
matchLabels:
app: magedu-tomcat-app2-selector
template:
metadata:
labels:
app: magedu-tomcat-app2-selector
spec:
containers:
- name: magedu-tomcat-app2-container
image: tomcat:7.0.94-alpine
imagePullPolicy: IfNotPresent
#imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80 #软亲和条件1,weight值越大优先级越高,越优先匹配调度
preference:
matchExpressions:
- key: project
operator: In
values:
- magedu
- weight: 60 #软亲和条件2,在条件1不满足时匹配条件2
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
修改node label,测试pod能否调度软策略优先级较高的节点:
root@k8s-master1:~# kubectl label node 192.168.121.113 disktype=ssd && kubectl label node 192.168.121.114 project=magedu
root@k8s-master1:~# kubectl apply -f case3-2.1-nodeAffinity-preferredDuring.yaml
root@k8s-master1:~# kubectl get pod -n magedu -o wide
NAME READY STATUS RESTARTS AGE IP NODE
magedu-tomcat-app2-deployment-68b779c448-hk2w2 1/1 Running 0 11s 10.200.151.207 192.168.121.114
case5.3-2.2:硬亲和与软亲和结合使用-nodeAffinity-requiredDuring-preferredDuring
root@k8s-master1:~# cat case3-2.2-nodeAffinity-requiredDuring-preferredDuring.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app2-deployment-label
name: magedu-tomcat-app2-deployment
namespace: magedu
spec:
replicas: 1
selector:
matchLabels:
app: magedu-tomcat-app2-selector
template:
metadata:
labels:
app: magedu-tomcat-app2-selector
spec:
containers:
- name: magedu-tomcat-app2-container
image: tomcat:7.0.94-alpine
imagePullPolicy: IfNotPresent
#imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: #硬亲和
nodeSelectorTerms:
- matchExpressions: #硬匹配条件1
- key: "kubernetes.io/role"
operator: NotIn
values:
- "master" #硬性匹配key 的值kubernetes.io/role不包含master的节点,即绝对不会调度到master节点(node反亲和)
preferredDuringSchedulingIgnoredDuringExecution: #软亲和
- weight: 80
preference:
matchExpressions:
- key: project
operator: In
values:
- magedu
- weight: 60
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
root@k8s-master1:~# kubectl apply -f case3-2.2-nodeAffinity-requiredDuring-preferredDuring.yaml
创建pod并验证:
# kubectl apply -f case3-2.2-nodeAffinity-requiredDuring-preferredDuring.yaml
# kubectl get pod -n magedu
NAME READY STATUS RESTARTS AGE IP NODE
magedu-tomcat-app2-deployment-d4df9556b-s898k 1/1 Running 0 5s 10.200.151.221 192.168.121.114
5.3-3.1 node 反亲和-nodeantiaffinity
root@k8s-master1:~# cat case3-3.1-nodeantiaffinity.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app2-deployment-label
name: magedu-tomcat-app2-deployment
namespace: magedu
spec:
replicas: 1
selector:
matchLabels:
app: magedu-tomcat-app2-selector
template:
metadata:
labels:
app: magedu-tomcat-app2-selector
spec:
containers:
- name: magedu-tomcat-app2-container
image: tomcat:7.0.94-alpine
imagePullPolicy: IfNotPresent
#imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions: #匹配条件1
- key: disktype
operator: NotIn #调度的目的节点没有key为disktype且值为hdd的标签
values:
- hdd #绝对不会调度到含有label的key为disktype且值为hdd的节点,即会调度到没有key为disktype且值为hdd的hdd的节点
对node打上标签,测试是否不会调度到该节点:
root@k8s-master1:~# kubectl label node 192.168.121.115 disktype="hdd"
创建pod:
root@k8s-master1:~# kubectl apply -f case3-3.1-nodeantiaffinity.yaml deployment.apps/magedu-tomcat-app2-deployment created
验证pod调度结果:
root@k8s-master1:~# kubectl get pod -n magedu -o wide
NAME READY STATUS RESTARTS AGE IP NODE
magedu-tomcat-app2-deployment-6895d96bb-pwkbx 1/1 Running 0 2s 10.200.218.33 192.168.121.113
5.4 Pod Affinity与anti-affinity简介
Pod亲和性与反亲和性可以基于已经在node节点上运行的Pod的标签来约束新创建的Pod来调度到的目的节点,注意不是基于node上的标签,而是使用的已经运行在node上的pod标签匹配。
其规则的格式为如果 node节点 A已经运行了一个或多个满足调度新创建的Pod B的规则,那么新的Pod B在亲和的条件下会调度到A节点之上,而在反亲和性的情况下则不会调度到A节点至上。
其中规则表示一个具有可选的关联命名空间列表的LabelSelector,只所以Pod亲和与反亲和需可以通过LabelSelector选择namespace,是因为Pod是命名空间限定的而node不属于任何nemespace,所以node的亲和与反亲和不需要namespace,因此作用于Pod标签的标签选择算符必须指定选择算符应用在哪个命名空间。
从概念上讲,node节点是一个拓扑域(具有拓扑结构的区域、宕机的时候的故障域),比如k8s集群中的单台node节点、一个机架、云供应商可用区、云供应商地理区域等,可以使topologyKey来定义亲和或者反亲和的颗粒度是node级别还是可用区级别,以便kubernetes调度系统用来识别并选择正确的目的拓扑域
Pod 亲和性与反亲和性的合法操作符(operator)有 In、NotIn、Exists、DoesNotExist。
在Pod亲和性配置中,在requiredDuringSchedulingIgnoredDuringExecution和preferredDuringSchedulingIgnoredDuringExecution中,topologyKey不允许为空(Empty topologyKey is not allowed.).
在Pod反亲和性中配置中,requiredDuringSchedulingIgnoredDuringExecution和preferredDuringSchedulingIgnoredDuringExecution 中,topologyKey也不可以为空(Empty topologyKey is not allowed.)。
对于requiredDuringSchedulingIgnoredDuringExecution要求的Pod反亲和性,准入控制器LimitPodHardAntiAffinityTopology被引入以确保topologyKey只能是 kubernetes.io/hostname,如果希望 topologyKey 也可用于其他定制拓扑逻辑,可以更改准入控制器或者禁用。
除上述情况外,topologyKey 可以是任何合法的标签键
case5.4-4.1:部署web服务
编写yaml文件,在magedu anmespace部署一个nginx服务,nginx pod将用于后续的pod 亲和及反亲和测试,且pod的label如下:
app: python-nginx-selector
project: python
root@k8s-master1:~# cat case4-4.1-nginx.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: python-nginx-deployment-label
name: python-nginx-deployment
namespace: magedu
spec:
replicas: 1
selector:
matchLabels:
app: python-nginx-selector
template:
metadata:
labels:
app: python-nginx-selector
project: python
spec:
containers:
- name: python-nginx-container
image: nginx:1.20.2-alpine
#command: ["/apps/tomcat/bin/run_tomcat.sh"]
#imagePullPolicy: IfNotPresent
imagePullPolicy: Always
ports:
- containerPort: 80
protocol: TCP
name: http
- containerPort: 443
protocol: TCP
name: https
env:
- name: "password"
value: "123456"
- name: "age"
value: "18"
# resources:
# limits:
# cpu: 2
# memory: 2Gi
# requests:
# cpu: 500m
# memory: 1Gi
---
kind: Service
apiVersion: v1
metadata:
labels:
app: python-nginx-service-label
name: python-nginx-service
namespace: magedu
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
nodePort: 30014
- name: https
port: 443
protocol: TCP
targetPort: 443
nodePort: 30453
selector:
app: python-nginx-selector
project: python #一个或多个selector,至少能匹配目标pod的一个标签
root@k8s-master1:~# kubectl apply -f case4-4.1-nginx.yaml
deployment.apps/python-nginx-deployment created
service/python-nginx-service created
case5.4-4.2:Pod Affinity-软亲和
基于软亲和实现多pod在一个node:
先创建一个nginx服务,后续的服务和nginx运行在同一个node节点
root@k8s-master1:~# cat case4-4.2-podaffinity-preferredDuring.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app2-deployment-label
name: magedu-tomcat-app2-deployment
namespace: magedu
spec:
replicas: 1
selector:
matchLabels:
app: magedu-tomcat-app2-selector
template:
metadata:
labels:
app: magedu-tomcat-app2-selector
spec:
containers:
- name: magedu-tomcat-app2-container
image: tomcat:7.0.94-alpine
imagePullPolicy: IfNotPresent
#imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
affinity:
podAffinity: #Pod亲和
#requiredDuringSchedulingIgnoredDuringExecution: #硬亲和,必须匹配成功才调度,如果匹配失败则拒绝调度。
preferredDuringSchedulingIgnoredDuringExecution: #软亲和,能匹配成功就调度到一个topology,匹配不成功会由kubernetes自行调度。
- weight: 100
podAffinityTerm:
labelSelector: #标签选择
matchExpressions: #正则匹配
- key: project
operator: In
values:
- python
topologyKey: kubernetes.io/hostname
namespaces:
- magedu
root@k8s-master1:~# kubectl apply -f case4-4.2-podaffinity-preferredDuring.yaml
deployment.apps/magedu-tomcat-app2-deployment created
验证pod调度结果:
root@k8s-master1:~# kubectl get pod -n magedu -o wide
NAME READY STATUS RESTARTS AGE IP NODE
magedu-tomcat-app2-deployment-78b64f4b55-sqhxq 1/1 Running 0 3s 10.200.151.220 192.168.121.113
python-nginx-deployment-7bbc6bf578-sxrmm 1/1 Running 0 91s 10.200.151.217 192.168.121.113
case5.4-4.3:Pod Affinity-硬亲和:
基于硬亲和实现多个pod调度在一个node:
先创建一个nginx服务,后续的服务和nginx运行在同一个node节点
root@k8s-master1:~# cat case4-4.3-podaffinity-requiredDuring.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app2-deployment-label
name: magedu-tomcat-app2-deployment
namespace: magedu
spec:
replicas: 1
selector:
matchLabels:
app: magedu-tomcat-app2-selector
template:
metadata:
labels:
app: magedu-tomcat-app2-selector
spec:
containers:
- name: magedu-tomcat-app2-container
image: tomcat:7.0.94-alpine
imagePullPolicy: IfNotPresent
#imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution: #硬亲和
- labelSelector:
matchExpressions:
- key: project
operator: In
values:
- python
topologyKey: "kubernetes.io/hostname"
namespaces:
- magedu
实现硬亲和pod调度
root@k8s-master1:~# kubectl apply -f case4-4.3-podaffinity-requiredDuring.yaml
deployment.apps/magedu-tomcat-app2-deployment created
验证pod调度结果:
root@k8s-master1:~# kubectl get pod -n magedu -o wide
NAME READY STATUS RESTARTS AGE IP NODE
magedu-tomcat-app2-deployment-5b8cfcfc8c-2jxdc 1/1 Running 0 24s 10.200.218.26 192.168.121.113
python-nginx-deployment-7bbc6bf578-hpx99 1/1 Running 0 27s 10.200.218.31 192.168.121.113
case5.4-4.4:podAntiAffinity-硬反亲和
基于硬反亲和实现多个pod调度不在一个node:
先创建一个nginx服务,后续的服务和nginx运行在同一个node节点
root@k8s-master1:~# cat case4-4.4-podAntiAffinity-requiredDuring.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app2-deployment-label
name: magedu-tomcat-app2-deployment
namespace: magedu
spec:
replicas: 1
selector:
matchLabels:
app: magedu-tomcat-app2-selector
template:
metadata:
labels:
app: magedu-tomcat-app2-selector
spec:
containers:
- name: magedu-tomcat-app2-container
image: tomcat:7.0.94-alpine
imagePullPolicy: IfNotPresent
#imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: project
operator: In
values:
- python
topologyKey: "kubernetes.io/hostname"
namespaces:
- magedu
实现硬反亲和pod调度:
root@k8s-master1:~/case/case# kubectl apply -f case4-4.4-podAntiAffinity-requiredDuring.yaml
deployment.apps/magedu-tomcat-app2-deployment created
验证pod调度结果:
root@k8s-master1:~# kubectl get pod -n magedu -o wide
NAME READY STATUS RESTARTS AGE IP NODE
magedu-tomcat-app2-deployment-6d56968789-lk4zj 1/1 Running 0 9s 10.200.151.226 192.168.121.115
python-nginx-deployment-7bbc6bf578-hpx99 1/1 Running 0 10m 10.200.218.31 192.168.121.113
case5.4-4.5:podAntiAffinity-软反亲和
基于软亲和实现多个pod调度不在一个node:
root@k8s-master1:~# cat case4-4.5-podAntiAffinity-preferredDuring.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app2-deployment-label
name: magedu-tomcat-app2-deployment
namespace: magedu
spec:
replicas: 20
selector:
matchLabels:
app: magedu-tomcat-app2-selector
template:
metadata:
labels:
app: magedu-tomcat-app2-selector
spec:
containers:
- name: magedu-tomcat-app2-container
image: tomcat:7.0.94-alpine
imagePullPolicy: IfNotPresent
#imagePullPolicy: Always
ports:
- containerPort: 8080
protocol: TCP
name: http
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: project
operator: In
values:
- python
topologyKey: kubernetes.io/hostname
namespaces:
- magedu
实现软亲和pod调度
root@k8s-master1:~# kubectl apply -f case4-4.5-podAntiAffinity-preferredDuring.yaml
deployment.apps/magedu-tomcat-app2-deployment created
验证pod调度结果:
root@k8s-master1:~# kubectl get pod -n magedu -o wide
NAME READY STATUS RESTARTS AGE IP NODE
magedu-tomcat-app2-deployment-64dff7b7f7-5rzx4 1/1 Running 0 18s 10.200.218.35 192.168.121.115
python-nginx-deployment-7bbc6bf578-j4ctx 1/1 Running 0 24s 10.200.151.210 192.168.121.113
6 污点与容忍

6.1 污点简介
污点(taints),用于node节点排斥 Pod调度,与亲和的作用是完全相反的,即taint的node和pod是排斥调度关系。
容忍(toleration),用于Pod容忍node节点的污点信息,即node有污点信息也会将新的pod调度到node
https://kubernetes.io/zh/docs/concepts/scheduling-eviction/taint-and-toleration/
污点的三种类型:
NoSchedule: 表示k8s将不会将Pod调度到具有该污点的Node上
root@k8s-master1:~# kubectl taint nodes 192.168.121.113 key1=value1:NoSchedule #设置污点
node/192.168.121.113 tainted
root@k8s-master1:~# kubectl describe node 192.168.121.113 #查看污点
Taints: key1=value1:NoSchedule
root@k8s-master1:~# kubectl taint node 192.168.121.113 key1:NoSchedule- #取消污点
node/192.168.121.113 untainted
PreferNoSchedule: 表示k8s将尽量避免将Pod调度到具有该污点的Node上
NoExecute: 表示k8s将不会将Pod调度到具有该污点的Node上,同时会将Node上已经存在的Pod强制驱逐出去
root@k8s-master1:~# kubectl taint nodes 192.168.121.113 key1=value1:NoExecute
6.2容忍简介
tolerations容忍:定义 Pod 的容忍度(可以接受node的哪些污点),容忍后可以将Pod调度至含有该污点的node。
基于operator的污点匹配:
如果operator是Exists,则容忍度不需要value而是直接匹配污点类型。
如果operator是Equal,则需要指定value并且value的值需要等于tolerations的key
节点打上污点信息:
root@k8s-master1:~# kubectl taint nodes 192.168.121.113 key1=value1:NoSchedule
测试对污点容忍和不容忍分别能否调度:
root@k8s-master1:~# cat case5.1-taint-tolerations.yaml
kind: Deployment
#apiVersion: extensions/v1beta1
apiVersion: apps/v1
metadata:
labels:
app: magedu-tomcat-app1-deployment-label
name: magedu-tomcat-app1-deployment
namespace: magedu
spec:
replicas: 2
selector:
matchLabels:
app: magedu-tomcat-app1-selector
template:
metadata:
labels:
app: magedu-tomcat-app1-selector
spec:
containers:
- name: magedu-tomcat-app1-container
#image: harbor.magedu.net/magedu/tomcat-app1:v7
image: tomcat:7.0.93-alpine
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
protocol: TCP
name: http
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
---
kind: Service
apiVersion: v1
metadata:
labels:
app: magedu-tomcat-app1-service-label
name: magedu-tomcat-app1-service
namespace: magedu
spec:
type: NodePort
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
#nodePort: 40003
selector:
app: magedu-tomcat-app1-selector
root@k8s-master1:~# kubectl apply -f case5.1-taint-tolerations.yaml
root@k8s-master1:~# kubectl get pod -n magedu -o wide
NAME READY STATUS RESTARTS AGE IP NODE
magedu-tomcat-app1-container-64dff7b7f7-5rzx4 1/1 Running 0 18s 10.200.218.35 192.168.121.115
magedu-tomcat-app1-container-64dff7b7f7-4cde1 1/1 Running 0 24s 10.200.151.210 192.168.121.115
污点的删除:
root@k8s-master1:~# kubectl taint nodes 192.168.121.113 key1:NoSchedule-
7.pod驱逐
7.1 驱逐简介:
点压力驱逐是由各kubelet进程主动终止Pod,以回收节点上的内存、磁盘空间等资源的过程,kubelet监控当前node节点的CPU、内存、磁盘空间和文件系统的inode等资源,当这些资源中的一个或者多个达到特定的消耗水平,kubelet就会主动地将节点上一个或者多个Pod强制驱逐,以防止当前node节点资源无法正常分配而引发的OOM(OutOfMemory)。
https://kubernetes.io/zh/docs/concepts/scheduling-eviction/node-pressure-eviction/
宿主机内存:
memory.available #node节点可用内存,默认 <100Mi
nodefs是节点的主要文件系统,用于保存本地磁盘卷、emptyDir、日志存储等数据,默认是/var/lib/kubelet/,或者是通过kubelet通过
--root-dir所指定的磁盘挂载目录
nodefs.inodesFree #nodefs的可用inode,默认<5%
nodefs.available #nodefs的可用空间,默认<10%
imagefs是可选文件系统,用于给容器提供运行时存储容器镜像和容器可写层。
imagefs.inodesFree #imagefs的inode可用百分比
imagefs.available #imagefs的磁盘空间可用百分比,默认<15%
pid.available #可用pid百分比
示例:
evictionHard:
imagefs.inodesFree: 5%
imagefs.available: 15%
memory.available: 300Mi
nodefs.available: 10%
nodefs.inodesFree: 5%
pid.available: 5%
kube-controller-manager实现 eviction:
node宕机后的驱逐
kubelet实现的eviction:
基于node负载、资源利用率等进行pod驱逐
驱逐(eviction,节点驱逐),用于当node节点资源不足的时候自动将pod进行强制驱逐,以保证当前node节点的正常运行。
Kubernetes基于是QoS(服务质量等级)驱逐Pod , Qos等级包括目前包括以下三个:
Guaranteed: #limits和request的值相等,等级最高、最后被驱逐
resources:
limits:
cpu: 500m
memory: 256Mi
requests:
cpu: 500m
memory: 256Mi
Burstable: #limit和request不相等,等级折中、中间被驱逐
resources:
limits:
cpu: 500m
memory: 256Mi
requests:
cpu: 256m
memory: 128Mi
BestEffort: #没有限制,即resources为空,等级最低、最先被驱逐
eviction-signal:kubelet捕获node节点驱逐触发信号,进行判断是否驱逐,比如通过cgroupfs获取memory.available的值来进行下一步匹配。
operator:操作符,通过操作符对比条件是否匹配资源量是否触发驱逐。
quantity:使用量,即基于指定的资源使用值进行判断,如memory.available: 300Mi、nodefs.available: 10%等。
比如:nodefs.available<10%
以上公式为当node节点磁盘空间可用率低于10%就会触发驱逐信号
7.2 软驱逐:
软驱逐不会立即驱逐pod,可以自定义宽限期,在条件持续到宽限期还没有恢复,kubelet再强制杀死pod并触发驱逐:
软驱逐条件:
• eviction-soft: 软驱逐触发条件,比如memory.available < 1.5Gi,如果驱逐条件持续时长超过指定的宽限期,可以触发Pod驱逐。
• eviction-soft-grace-period:软驱逐宽限期, 如 memory.available=1m30s,定义软驱逐条件在触发Pod驱逐之前必须保持多长时间。
• eviction-max-pod-grace-period:终止pod的宽限期,即在满足软驱逐条件而终止Pod时使用的最大允许宽限期(以秒为单位)
7.3 硬驱逐:
硬驱逐条件没有宽限期,当达到硬驱逐条件时,kubelet 会强制立即杀死 pod并驱逐:
kubelet 具有以下默认硬驱逐条件(可以自行调整):
memory.available<100Mi
nodefs.available<10%
imagefs.available<15%
nodefs.inodesFree<5%(Linux 节点)
kubelet service文件:
# vim /etc/systemd/system/kubelet.service
kubelet配置文件:
# vim /var/lib/kubelet/config.yaml
evictionHard:
imagefs.available: 15%
memory.available: 300Mi
nodefs.available: 10%
nodefs.inodesFree: 5%
https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/reserve-compute-resources/
--kube-reserved #kube-reserved 定于给 kube 组件预留的CPU及memory等资源
--system-reserved #用于为sshd、udev 等系统守护进程定义预留资源,用于sshd、udev等进程使用
--eviction-hard #Pod硬驱逐资源阈值
浙公网安备 33010602011771号