k8s-运维

K8S运维

记录以下管理k8s集群会用到或者我觉得可能会用到的东西.

证书管理

CA: 根证书颁发机构

通过kubeadm管理,目录路径: /etc/kubernetes/pki

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
├── apiserver.crt
├── apiserver-etcd-client.crt
├── apiserver-etcd-client.key
├── apiserver.key
├── apiserver-kubelet-client.crt
├── apiserver-kubelet-client.key
├── ca.crt
├── ca.key
├── etcd
│ ├── ca.crt
│ ├── ca.key
│ ├── healthcheck-client.crt
│ ├── healthcheck-client.key
│ ├── peer.crt
│ ├── peer.key
│ ├── server.crt
│ └── server.key
├── front-proxy-ca.crt
├── front-proxy-ca.key
├── front-proxy-client.crt
├── front-proxy-client.key
├── sa.key
└── sa.pub
  • apiserver.crtapiserver.key: 这是 Kubernetes API 服务器的 TLS 证书和私钥。它们用于保护 API 服务器的通信。

  • apiserver-etcd-client.crtapiserver-etcd-client.key: 这些是 API 服务器用来安全连接到 etcd 集群的客户端证书和私钥。

  • apiserver-kubelet-client.crtapiserver-kubelet-client.key: 这些是 API 服务器用于与集群中每个 kubelet 安全通信的客户端证书和私钥。

  • ca.crtca.key: 这是您集群的根证书颁发机构 (CA) 的证书和私钥。几乎所有的组件证书都由这个 CA 签发。

  • etcd/ca.crtetcd/ca.key: 这是用于 etcd 集群的专用 CA 的证书和私钥。etcd 是 Kubernetes 数据的存储后端。

  • etcd/healthcheck-client.crtetcd/healthcheck-client.key: 在 etcd 集群中执行健康检查的客户端证书和私钥。

  • etcd/peer.crtetcd/peer.key: etcd 节点之间通信的对等证书和私钥。

  • etcd/server.crtetcd/server.key: etcd 服务器用于与其他组件(如 apiserver)通信的 TLS 证书和私钥。

  • front-proxy-ca.crtfront-proxy-ca.key: 是前端代理颁发机构的证书和私钥,用于代理客户端与 API 服务器之间的通信。

  • front-proxy-client.crtfront-proxy-client.key: 这是用于 Kubernetes API 服务器前端的代理客户端的证书和私钥。

  • sa.keysa.pub: 这些是用于签名和验证服务账户令牌的私钥和公钥

生成

1
2
# kubeadm 在初始化集群时会自动生成所需的所有证书。如果需要手动为新的服务或组件生成证书,可以使用
kubeadm init phase certs <cert-name>

查看过期时间

1
kubeadm certs check-expiration

更新

1
2
kubeadm certs renew <cert-name>
kubeadm certs renew all

证书更新后要重启对应组件才能生效,在生产环境中就涉及不停机更新,pod驱逐等操作,最好在测试环境演练好并做好备份再在生产环境操作.

删除/备份

操作/etc/kubernetes/pki目录

节点分配

  • 节点亲和性

    调度器(scheduler)上一个比较复杂,但更为强大的功能

    1. 必须规则(required)

      也称为硬性规则,规则必须被满足,pod才能被调度.定义字段:requiredDuringSchedulingIgnoredDuringExecution

    2. 首选规则(preferred)

      也称为软性规则,调度器会尽量满足这些规则.定义字段:preferredDuringSchedulingIgnoredDuringExecution

    3. 操作符

      • In/NotIn: 确保节点标签包含/不包含在给定的值的列表中
      • Exists/NotExists: 节点标签存在/不存在给定的key,不管value是什么
      • Gt/Lt: 用于基于数值的标签,保证节点标签拥有大于/小于特定数值的key
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    apiVersion: v1
    kind: Pod
    metadata:
    name: with-node-affinity
    spec:
    containers:
    - name: nginx-container
    image: nginx
    affinity:
    nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution: # 硬性
    nodeSelectorTerms:
    - matchExpressions:
    - key: disktype
    operator: In
    values:
    - ssd
    preferredDuringSchedulingIgnoredDuringExecution: # 软性
    - weight: 1 # 软性可以有多个规则,根据权重决定优先级
    preference:
    matchExpressions:
    - key: team
    operator: In
    values:
    - research
  • NodeSelector

    标签选择器,比较简单,就是通过标签,让pod运行在特定的节点上

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    apiVersion: v1
    kind: Pod
    metadata:
    name: simple-pod
    spec:
    containers:
    - name: simple-container
    image: nginx
    nodeSelector: # 通过标签选择节点
    disktype: ssd

探针

  • 启动(startup): 用于确定容器内的应用是否已经启动完整,直到启动探针检测成功,才会应用后两个探针.
  • 存活(liveness): 检查容器是否在运行,检测失败,kubelet就会杀死容器根据重启策略重新启动.
  • 就绪(readiness): 检测容器内应用是否已经准备好接受流量,如果检测失败,就会从它关联的所有service中除名.(不负载流量给它)

三种探针都有三种探测方式: http get / tcp socket / exec

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
apiVersion: v1
kind: Pod
metadata:
name: example-pod
spec:
containers:
- name: example-container
image: example-image
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15
timeoutSeconds: 1
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
timeoutSeconds: 1
periodSeconds: 10
failureThreshold: 3
startupProbe:
httpGet:
path: /start
port: 8080
initialDelaySeconds: 5
timeoutSeconds: 1
periodSeconds: 10
failureThreshold: 30

pod资源限制

主要通过limitsrequests来限制容器可以调用的资源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
apiVersion: v1
kind: Pod
metadata:
name: example-pod
spec:
containers:
- name: example-container
image: example-image
resources:
requests: # 容器启动所需的最小资源量
memory: "64Mi"
cpu: "250m"
limits: # 容器可以使用的最大资源量
memory: "128Mi"
cpu: "500m"

动态扩容

k8s的动态扩容有三种形式

  1. 水平扩容(HPA)

    依赖metrics-server收集的资源使用数据来决定是否和何时进行扩容.水平扩容主要是针对pod副本的数量进行扩容.比如cpu使用率超过80%,就加一个副本.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    apiVersion: autoscaling/v1
    kind: HorizontalPodAutoscaler
    metadata:
    name: example-hpa
    namespace: default
    spec:
    scaleTargetRef: # 监控的target
    apiVersion: apps/v1
    kind: Deployment
    name: example-deployment
    minReplicas: 1 # cpu利用率低于50%,则会减少pod数量,最少1个
    maxReplicas: 10 # 扩容最多10个
    targetCPUUtilizationPercentage: 50 # 如果cpu利用率超过50%则会扩容
  2. 垂直扩容(VPA)

    与HPA类似,也是依赖metrics-server,但是垂直扩容针对的是pod的使用资源扩容.比如cpu使用率超过80%,就给这个pod加更多的cpu资源.垂直扩容比较适合一些不方便直接加副本的应用,主要是一些有状态应用.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    apiVersion: autoscaling.k8s.io/v1
    kind: VerticalPodAutoscaler
    metadata:
    name: example-vpa
    namespace: default
    spec:
    targetRef: # 监控的target
    apiVersion: "apps/v1"
    kind: Deployment
    name: example-deployment
    updatePolicy:
    updateMode: "Auto"
    resourcePolicy:
    containerPolicies: # vpa的资源调整是在容器级别上操作的,但是vpa的操作和决策(启动,更新,重启,扩缩容等)都是pod级别上的
    - containerName: example-container
    minAllowed: # 限制容器可以使用资源的最少值
    cpu: 100m
    memory: 100Mi
    maxAllowed: # 限制容器可以使用资源的最大值
    cpu: 1
    memory: 1Gi
    controlledResources: ["cpu", "memory"]

    关于VPA的minAllowed/maxAllowed和pod定义的limits/requests:

    VPA不会更改limits,minAllowed/maxAllowed更多的是对VPA行为的指导,VPA会在minAllowed/maxAllowed的约束范围内给requests提出建议.如果VPA给出的requests低于pod定义的requests或高于limits,且VPA策略允许它这样做,那么VPA就会重启pod并应用它的建议.

  3. 集群扩容(Cluster AutoScaler)

    通过k8s.gcr.io/cluster-autoscaler:v1.20.0这个镜像,通过K8S-API获取所需的信息,例如当前集群的资源使用情况和pod的调度需求(特别是因为资源不足而处于pending状态的pod),然后调用对应公有云平台的API(AWS,GCP等)或私有环境(openstack,vmware vsphere等)的API,实现节点的自动扩缩容.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    apiVersion: apps/v1
    kind: Deployment
    metadata:
    name: cluster-autoscaler
    namespace: kube-system
    labels:
    app: cluster-autoscaler
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: cluster-autoscaler
    template:
    metadata:
    labels:
    app: cluster-autoscaler
    spec:
    containers:
    - image: k8s.gcr.io/cluster-autoscaler:v1.20.0
    name: cluster-autoscaler
    resources:
    limits:
    cpu: 100m
    memory: 300Mi
    requests:
    cpu: 100m
    memory: 300Mi
    command:
    - ./cluster-autoscaler
    - --v=4
    - --stderrthreshold=info
    - --cloud-provider=your-cloud-provider # aws/gcp/azure/external(自托管的集群)
    - --nodes=min:max:NodeGroup1 # 每个--nodes标志对应一个节点组(node group).节点组是相同类型和配置的节点的集合.每个节点组都有最少和最大节点数以及节点组名
    - --nodes=min:max:NodeGroup2 # 为了更好地控制和优化资源利用,可以针对不同的工作负载创建不同的节点组(比如一些资源占用较高的应用就分配到拥有大量cpu,内存资源的节点组种)
    # 节点组的定义根据不同的平台来,比如aws就是auto scaling group,gcp就是instance group
    - --namespace=kube-system
    env:
    - name: AWS_REGION
    value: your-region # 对于 AWS,你需要设置区域
    - name: ACCESS_KEY
    valueFrom:
    secretKeyRef:
    key: accessKey
    name: cloud-provider-credentials
    - name: SECRET_KEY
    valueFrom:
    secretKeyRef:
    key: secretKey
    name: cloud-provider-credentials
    volumeMounts:
    - name: ssl-certs
    mountPath: /etc/ssl/certs/ca-certificates.crt # 确保适应你的云提供商和操作系统
    readOnly: true
    volumes:
    - name: ssl-certs
    hostPath:
    path: /etc/ssl/certs/ca-certificates.crt # 确保适应你的云提供商和操作系统

NetworkPolicy

有状态白名单,没有放行的流量就是拒绝所有,ACK必考,面试也被问过,需要CNI支持,比如calico,至少要记住关键的flag.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default # 策略所在的名称空间,也是策略生效的名称空间
spec:
podSelector: # 策略应用的具体pod
matchLabels:
role: db
policyTypes: # 表示该策略是应用到哪个方向的流量
- Ingress
- Egress
ingress: # 入流量白名单
- from:
- ipBlock:
cidr: 172.17.0.0/16
except:
- 172.17.1.0/24
- namespaceSelector:
matchLabels:
project: myproject
- podSelector:
matchLabels:
role: frontend
ports: # 这是允许被连接到的端口,也就是入方向流量可以连接到的端口
- protocol: TCP
port: 6379
egress:
- to:
- ipBlock:
cidr: 10.0.0.0/24
ports:
- protocol: TCP
port: 5978

创建SA供别人访问

创建SA/role/rolebinding以及token

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
apiVersion: v1
kind: ServiceAccount
metadata:
name: default-admin
namespace: default
---
# 使用rolebinding绑定一个clusterrole: admin,权限依旧会限制在namespace之内
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: default-admin-rolebinding
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: admin
subjects:
- kind: ServiceAccount
name: default-admin
namespace: default
---
# sa的token以secret形式存储,关联并自动生成
apiVersion: v1
kind: Secret
metadata:
name: default-admin-token
annotations:
kubernetes.io/service-account.name: default-admin
type: kubernetes.io/service-account-token

获取SA的访问令牌

1
2
3
4
5
kubectl get secrets default-admin-token -o jsonpath="{.data.token}" | base64 --decode > default-admin.token
# 复制token文件到客户服务器
scp default-admin.token root@x.x.x.x:/path/to/token_file
# 复制ca根证书(公钥)到客户服务器
scp /etc/kubernetes/pki/ca.crt root@x.x.x.x:/path/to/ca_file

用户配置

1
2
3
4
5
6
7
8
# 创建cluster
kubectl config set-cluster peter-cluster --server="https://<api-server_ip>:<api-server_port>" --certificate-authority='/path/to/ca_file'
# 创建用户认证信息
kubectl config set-credentials default-admin --token=`cat /path/to/token_file`
# 创建上下文
kubectl config set-context default-admin-context --cluster="peter-cluster"
# 切换上下文
kubectl config use-context default-admin-context

kubeconfig

就是~/.kube/config文件,里面有两个重要参数:

client-certificate-data: 这个字段包含了编码后的客户端证书,它是由 Kubernetes 集群的 Certificate Authority (CA) 签发的,用于与 API 服务器通信时的客户端身份验证。这个证书表明客户端(用户或服务账户)的身份,并且在 TLS 握手过程中提供。(公钥)

client-key-data: 这个字段包含了编码后的客户端私钥。这个私钥用来与 client-certificate-data 字段中的公钥证书配对,确保通信的安全。私钥不应该共享或泄漏给其他人,因为它能证明客户端的身份。(私钥)

这两个字段用来设置特定用户与k8s API 服务器通信时使用的证书

定义集群信息

1
2
3
4
5
6
7
8
9
clusters:
- name: cluster1
cluster:
certificate-authority: /path/to/ca1.crt # 就是/etc/kubernetes/pki/下的ca根证书
server: https://cluster1.example.com
- name: cluster2
cluster:
certificate-authority: /path/to/ca2.crt
server: https://cluster2.example.com

定义用户信息

1
2
3
4
5
6
7
8
users:
- name: user1
user:
client-certificate: /path/to/user1.crt
client-key: /path/to/user1.key
- name: user2
user:
token: some-bearer-token

用户使用证书登录,这里只说个大概流程:

  1. 创建证书签名请求(Certificate Signing Request, CSR):首先,需要在用户的机器上生成一个私钥(client.key),然后使用这个私钥创建一个 CSR。CSR 里包含了用户的信息,如常用名称(Common Name,即用户名),以及可能的组织单位(Organization Unit)等。

  2. 提交CSR到Kubernetes集群:然后,将CSR提交给Kubernetes集群。在Kubernetes中,可以通过kubectl命令行工具或者API请求来完成这一步骤。

  3. 由CA签署证书:集群的管理员需要批准CSR,由 Kubernetes 的 CA 处理请求并签发证书。

  4. 生成客户端证书(client.crt):经 CA 签名后的客户端证书会被传回给申请者。这份证书包含了用户的公钥以及CA的签名。

  5. 在kubeconfig文件中引用证书和私钥:将签发的客户端证书及其对应的私钥的路径指定在 kubeconfig 文件的相应用户项中。

上下文

上下文是将用户和集群绑定在一起的设置.可以定义多个上下文,每个上下文都关联一个集群和一个用户,并可以指定一个默认的namespace

1
2
3
4
5
6
7
8
9
10
11
12
13
contexts:
- name: context1
context:
cluster: cluster1
user: user1
namespace: default
- name: context2
context:
cluster: cluster2
user: user2
namespace: default
# 指定默认上下文
current-context: context1

切换上下文

1
kubectl config use-context <context-name>

常用集群管理操作

怎么写yaml

1
2
3
4
5
6
# 查看支持的resources
kubectl api-resources
# 使用explain指令与'.'表达式获取帮助文档
kubectl explain <resource-name>.<sub-flag>.<sub-flag>...
# 比如想知道configmap的apiversion可以填什么
kubectl explain cm.apiVersion

RBAC

SA/role/RoleBinding都是命名空间级别的资源,所以操作它们时都要指定命名空间

ClusterRole和ClusterRoleBingding是集群级别的资源,操作它们时不需要指定命名空间

可以用RoleBinding绑定SA和ClusterRole,最终权限会限制在命名空间内

1
2
3
4
5
6
7
# 命令行的帮助菜单其实很好用
kubectl create [role|clusterrole|rolebinding|clusterrolebinding] --help
kubectl create sa <sa-name> -n <ns>
kubectl create clusterrole <cr-name> --verb=create --resource=deployments,statefulsets,daemonsets
kubectl create rolebinding <rb-name> --clusterrole=<cr-name> --serviceaccount=<ns>:<sa-name>
# 权限检查(不指定ns "-n" 则测试在集群范围内是否能执行该操作)
kubectl auth can-i create deployment --as system:serviceaccount:<namespace>:<sa-name> -n <ns-name>

根据label查看资源

1
kubectl top pod -l name=cpu-loader --sort-by=cpu -A

扩容deployment

1
2
kubectl scale deployment -h
kubectl scale deployment <dp-name> --replicas=<num>

pod的调度

调度主要通过label和taint来控制

1
2
3
4
5
6
7
8
9
10
# 打label
kubectl label [resource_type] [resource_name] [label_key]=[label_value]
# 删除label
kubectl label [resource_type] [resource_name] [label_key]-
# 打taint
kubectl taint nodes [node_name] [key]=[value]:[effect]
# 删除taint
kubectl taint nodes [node_name] [key]-
#
kubectl taint nodes [node_name] [key]=[value]-

关于taint的effect:

  • NoSchedule: 如果一个pod没有明确通过容忍声明来容忍此污点,它将不会被调度到有此污点的node上
  • PreferNoSchedule: NoSchedule的软化版,k8s会尽量避免将pod调度到存在该污点的node上,不过如果没得选,也会调度过去
  • NoExecute: 如果现有的pod没有容忍这个污点,则会被逐出node,新的pod没有容忍这个污点,则不会调度到该node上.主要用于需要驱逐节点pod的场景,比如节点维护,集群升级或策略改变.
1
2
# 通过污点来统计节点是否"可用"
kubectl describe nodes | grep -i Taints | grep -vc NoSchedule

SideCar

主要是某些日志收集的场景用得多,两个容器共享存储卷

官方文档

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
apiVersion: v1
kind: Pod
metadata:
name: counter
spec:
containers:
- name: count
image: busybox:1.28
args:
- /bin/sh
- -c
- >
i=0;
while true;
do
echo "$i: $(date)" >> /var/log/1.log;
echo "$(date) INFO $i" >> /var/log/2.log;
i=$((i+1));
sleep 1;
done
volumeMounts:
# 挂载
- name: varlog
mountPath: /var/log
- name: count-agent
image: registry.k8s.io/fluentd-gcp:1.30
env:
- name: FLUENTD_ARGS
value: -c /etc/fluentd-config/fluentd.conf
volumeMounts:
# 挂载
- name: varlog
mountPath: /var/log
- name: config-volume
mountPath: /etc/fluentd-config
volumes:
# 这个volumes同时被两个container挂载
- name: varlog
emptyDir: {}
- name: config-volume
configMap:
name: fluentd-config

PV和PVC

官方示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: task-pv-volume
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/mnt/data"
---
# PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: task-pv-claim
spec:
storageClassName: manual
accessModes:
- ReadWriteOnce # 单点读写
resources:
requests:
storage: 3Gi
---
# pod使用PVC
apiVersion: v1
kind: Pod
metadata:
name: task-pv-pod
spec:
volumes:
- name: task-pv-storage
persistentVolumeClaim:
claimName: task-pv-claim
containers:
- name: task-pv-container
image: nginx
ports:
- containerPort: 80
name: "http-server"
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: task-pv-storage

下面可以看出pv和pvc的关系.pv绑定具体的物理存储设备(本地,NFS,ceph等),PVC实际上是用户的存储请求,用户发起一个PVC,声明想请求多少容量的存储,k8s会根据请求绑定合适pv使用.

1
2
3
4
5
6
[root@k8s-master-1 ~]# kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
task-pv-volume 10Gi RWO Retain Bound default/task-pv-claim manual 46s
[root@k8s-master-1 ~]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
task-pv-claim Bound task-pv-volume 10Gi RWO manual 47s

集群升级

升级kubeadm管理的集群: 官方文档

以1.28->1.29为例

在control plane上操作

1
2
3
4
5
6
# 首先检查下是否有源
yum list --showduplicates kubeadm --disableexcludes=kubernetes | grep 1.29
# 安装新版本kubeadm
yum install -y kubeadm-'1.29.0-*' --disableexcludes=kubernetes
# 验证升级计划
kubeadm upgrade plan 1.29.0

kubeadm upgrade这个命令会分析当前集群版本以及目标升级的版本(这里是1.29.0),验证升级计划.

升级的同时也会对kubeadm管理的证书执行续约.

通过plan的输出,kubeadm主要负责升级:

  • kube-apiserver
  • kube-controller-manager
  • kube-scheduler
  • kube-proxy
  • CoreDNS
  • etcd (很多环境下,etcd是分开部署的,所以升级时可能需要跳过它)
1
2
3
4
# 升级
kubeadm upgrade apply 1.29.0 --etcd-upgrade=false
# 升级kubectl (命令行工具直接升级)
yum -y install kubectl-1.29.0

看到以下输出说明升级成功

1
2
3
[upgrade/successful] SUCCESS! Your cluster was upgraded to "v1.29.0". Enjoy!

[upgrade/kubelet] Now that your control plane is upgraded, please proceed with upgrading your kubelets if you haven't already done so

如果有多个控制平面节点,其他控制平面节点的升级命令有点不一样

1
2
# 直接执行
kubeadm upgrade node

然后升级kubelet,kubelet负责管控节点上pod的生命周期,所以需要先把节点上pod驱逐出去,要一个一个节点地操作(包括控制节点和工作节点)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 禁止调度
kubectl cordon <node-name>
# describe以下node可以看到以下输出
Normal NodeNotSchedulable 102s kubelet Node k8s-master-1 status is now: NodeNotSchedulable
# 驱逐节点上的pod(daemonsets除外)
kubectl drain <node-name> --ignore-daemonsets
# 安装新版kubelet
yum -y install kubelet-1.29.0
# 重启kubelet
systemctl restart kubelet
# 恢复调度
kubectl uncordon <node-name>
# describe以下看到以下输出
Normal NodeSchedulable 12s kubelet Node k8s-master-1 status is now: NodeSchedulable

某些情况下会驱逐失败:

  • 没有使用controller控制的pod
  • 使用了本地存储的pod(hostpath)
    • 可以通过--delete-emptydir-data --force强制删除数据(注意安全)

此时需要自行判断手动操作.

kubelet重启的影响: (chatgpt生成)

重启 kubelet 通常不会导致节点上运行的 Pod 被杀死或重新启动。不过,重启 kubelet 会暂时影响 Kubernetes 集群中控制平面与该节点的通信,包括调度器和控制器管理器。在 kubelet 重启并恢复正常运行之前,节点会被标记为 NotReady 状态。

以下是重启 kubelet 时可能发生的情况:

  1. 节点状态变化:当 kubelet 服务停止时,节点状态可能会在 Kubernetes API 中标记为 NotReady。一旦 kubelet 重启并与 API 服务器重新建立连接,它会更新节点的状态,如果一切正常,节点状态将改回 Ready

  2. Pod 状态信息丢失:由于重启 kubelet 期间本地的 pod 状态信息会丢失,因此当 kubelet 重启后,它需要重新同步现有 Pod 的状态信息。它将会查询容器运行时来确认现有 Pod 的运行情况,并将其反馈给 API 服务器。

  3. 工作负载调度:在 kubelet 不可用的期间,新的 Pods 将不会被调度到该节点上因为其标记为 NotReady。如果 kubelet 的断开时间较长,集群可能开始 Pod 重新调度的过程,将 Pod 迁移到其他健康的节点上。

  4. 服务中断最小化:通常情况下,重启 kubelet 对于正在节点上运行的 Pod 来说是无干扰的,因为容器是由 Docker 引擎或其他容器运行时独立管理的,并不直接依赖于 kubelet 的运行状态。

  5. DaemonSet Pod:对于 DaemonSet 管理的 Pod,由于它们保证了在每一个节点上有一个运行的 Pod 副本,kubelet 的重启不会影响其状态,因为它们不会因为节点的 NotReady 状态而被驱逐。

ETCD备份恢复

etcd 是一个高可用的键值存储系统,用于配置共享和服务发现。

在 Kubernetes 中,etcd 存储了所有的 Kubernetes 对象的状态,比如 pods、services、configmaps、secrets 等。控制平面的组件,如 kube-apiserver、调度器和控制器管理器,都会使用 etcd 来存储和检索其所需要的状态信息。

官方github

1
2
3
4
5
6
7
8
9
# 通过官方github下载最新的release包安装etcdctl
# 指定etcdctl工具的api版本为V3
export ETCDCTL_API=3
# 创建快照
etcdctl --endpoints=https://<etcd_ip:etcd_port> --cacert="/etc/kubernetes/pki/etcd/ca.crt" --cert="/etc/kubernetes/pki/etcd/peer.crt" --key="/etc/kubernetes/pki/etcd/peer.key" snapshot save /path/to/snapshot.db
# 检查快照,列出快照信息(快照大小、修订版本号、总键数等)
etcdctl snapshot status /path/to/snapshot.db -wtable
# 还原快照
etcdctl --endpoints=https://<etcd_ip:etcd_port> --cacert="/etc/kubernetes/pki/etcd/ca.crt" --cert="/etc/kubernetes/pki/etcd/peer.crt" --key="/etc/kubernetes/pki/etcd/peer.key" snapshot restore /path/to/snapshot.db

生产中,etcd一般都是独立部署集群,有可能以systemd方式运行.备份方式一样,还原时有些不一样.

1
2
3
4
5
6
7
8
9
10
# 查看etcd的数据存储目录,一般是/var/lib/etcd
ps -ef | grep etcd
# 停止etcd服务
systemctl stop etcd
# 备份原数据
mv /var/lib/etcd{,.bak}
# 还原(可以不加证书和密钥)
etcdctl --data-dir=/var/lib/etcd snapshot restore /path/to/snapshot.db
# 还原文件权限
chown -R etcd:etcd /var/lib/etcd

k8s-运维
http://example.com/2024/02/15/k8s-ops/
作者
Peter Pan
发布于
2024年2月15日
许可协议