Kubernetes overview

警告
本文最后更新于 2021-07-06,文中内容可能已过时。

Kubernetes 的主节点和工作节点都是集群中非常重要的组件。下面我们来更加详细地介绍一下它们的工作职能。

主节点:

  • API Server:作为 Kubernetes 的中央控制中心,API Server 负责所有组件之间的通信。API Server 接收到客户端的请求后,会将请求转发给相应的组件处理。
  • 集群存储:集群存储是整个控制层中唯一有状态(stateful)的部分,它持久化地存储了整个集群的配置与状态。集群存储在 Kubernetes 中扮演着至关重要的角色,可以为集群中的其他组件提供高效的存储和读取服务。
  • Controller 管理器:Controller 管理器是 Kubernetes 中的后台控制循环,它监控整个集群的状态,并根据预定义的操作执行相关的任务。Controller 管理器可以通过 API Server 与其他组件通信,以便更好地管理整个集群。
  • 调度器:Kubernetes 调度器的主要职责是监听 API Server 并启动新的工作任务,将任务分配到适合且正常运行的节点上。调度器可以根据容器的资源需求、亲和力、反亲和力等因素进行调度,并确保整个集群的负载均衡。

工作节点:

  • Kubelet:是每个工作节点上的重要代理端,它负责与主节点中的 API Server 通信,并根据主节点的指示来管理工作节点上的容器。Kubelet 还可以对容器的运行状况进行监控,并在容器故障时采取相应的措施。
  • 容器运行时:Kubelet 需要一个容器运行时(container runtime)来执行依赖容器才能执行的任务,例如拉取镜像并启动或停止容器。Docker 是 Kubernetes 最常用的容器运行时,但也可以使用其他容器运行时,例如 CRI-O、containerd 等。
  • kube-proxy:kube-proxy 是 Kubernetes 中用于管理网络代理的组件,它在每个工作节点上运行。kube-proxy 负责实现 Kubernetes 中的服务发现功能,为集群中的容器提供本地网络代理服务。

https://d33wubrfki0l68.cloudfront.net/2475489eaf20163ec0f54ddc1d92aa8d4c87c96b/e7c81/images/docs/components-of-kubernetes.svg

Deployment 是 Kubernetes 用来进行应用部署和更新的 API 对象之一,通过它可以控制 Pod 的副本数量、容器的升级等等。Deployment 对象通过定义 Pod 模板来创建管理 ReplicaSet,能够保证所需的 Pod 副本数与运行的 Pod 副本数保持一致。

ReplicaSet 是 Kubernetes 中用于控制 Pod 副本数量,保证用户指定的副本数始终已在集群中运行的 API 对象之一。一般情况下,我们使用 Deployment 来提供 ReplicaSet 和管理 Pod 的配置,而不会直接使用 ReplicaSet。这样,在 Deployment 进行滚动更新时,对应 ReplicaSet 也会自动更新 Pod 配置和个数。

https://image.linux88.com/2023/03/9/10c87c7b40fbe7b07a3f7d9d2843bb23.png

 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
apiVersion: apps/v1 #旧版 K8s 使用 apps/v1beta1
kind: Deployment
metadata:
  name: hello-deploy
  namespace: dev
spec:
  replicas: 2
  selector: # Pod 所必须具备的标签
    matchLabels:
      app: hello-world
  minReadySeconds: 10
  strategy: # Pod 的更新操作
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1 # 不允许出现比期望状态指定的 Pod 数量少超过一个的情况
      maxSurge: 1 # 不允许出现比期望状态指定的 Pod 数量多超过一个的情况
  template: # 管理的 Pod 模板
    metadata:
      labels:
        app: hello-world # 这个 Label 与 Service 的 Label 筛选器是匹配的
    spec:
      containers:
        - name: hello-pod
          image: nginx:latest
          ports:
            - containerPort: 80
          volumeMounts:
            - mountPath: "/usr/share/nginx/html"
              name: nginx-pv-storage
      volumes:
        - name: nginx-pv-storage
          persistentVolumeClaim:
            claimName: nfs-pvc
  • metadata 中的 labels 是用于标记和标识 Kubernetes 资源对象,Kubernetes 元数据。
  • template 中的 labels 则是用于标记和标识部署对象所创建的 Pod,Pod 元数据。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
kubectl apply -f deploy.yml --record

kubectl rollout status deployment hello-deploy

kubectl get deploy

# 查看历史记录
kubectl rollout history deployment hello-deploy

# 回滚到版本1
kubectl rollout undo deployment hello-deploy --to-revision=1

每个工作节点中都运行相应服务的实例

  • 主要用于部署有状态应用,如MySQL。
  • 部署前需要 StorageClassheadless Service
  • 部署的应用之间是点对点发现的。
  • sts.spec.volumeClaimTemplates 在每次创建一个新的 Pod 副本的时候,自动创建一 个 PVC。
  • 删除 Pod, PVC会保留,恢复后会绑定原来的PVC。
  • sts.spec.podManagementPolicy:控 Pod 的启动和停止的顺序。
  • sts.spec.updateStrategy:升级操作总是从索引号最大的 Pod 开始,每次更新一个 Pod,直至最小索引号的 Pod。
  • kubectl scale sts tkb-sts --replicas=0:依次删除Pod
 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: apps/v1
kind: StatefulSet
metadata:
  name: tkb-sts
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  serviceName: "dullahan"  # 与 handless Service 绑定
  template:
    metadata:
      labels:
        app: web
    spec:
      terminationGracePeriodSeconds: 10
      containers:
      - name: ctr-web
        image: nginx:latest
        ports:
        - containerPort: 80
          name: web
        volumeMounts:
        - name: webroot
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates: # 用于在每次创建一个新的 Pod 副本的时候,自动创建一 个 PVC。
  - metadata:
      name: webroot
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "flash"
      resources:
        requests:
          storage: 1Gi
1
2
3
# StatefulSet 的应用是点对点发现的
# tkb-sts-0.dullahan.default.svc.cluster.local
<object-name>.<Service-name>.<namespace>.svc.cluster.local

不定期运行的临时任务则由定时任务

  • ClusterIP Service:拥有固定的 IP 地址和端口号,并且仅能够从集群内部访问得到。(默认类型)
  • NodePort Service:在 ClusterIP 的基础上增加 了从集群外部访问的可能。
  • LoadBalancer Service:能够与诸如 AWS、Azure、DO、IBM 云和 GCP 等云服务商提供的负载均衡服务集成。
  • ExternalName Service:能够将流量路由至 Kubernetes 集群之外的系统中去(所有其他类 型的 Service 都是在集群内部进行流量的路由)。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
apiVersion: v1
kind: Service
metadata:
  name: hello-svc # 集群 DNS 中注册的名称
  labels:
    app: hello-world
spec:
  type: NodePort
  ports:
    - port: 8080
      nodePort: 30001
      protocol: TCP
  selector:
    app: hello-world # # Service 查找带有 app=hello-world 的 Pod
1
2
3
4
5
6
7
8
# 查看 service
kubectl get svc

# 查看 service 后面的 endpoints
kubectl get ep

# 命令式方法部署Service
kubectl expose deployment web-deploy --name=hello-svc --target-port=8080 --type=NodePort

在一个 Pod 中,可以通过这个域名来访问另一个 Pod 中的服务,而无需使用 Pod 的 IP 地址。这个域名如 hello-svc.default.svc.cluster.local

  • hello-svc: 服务名称,即服务的 DNS 名称(如果服务未指定名称,则默认为 Kubernetes 中的 Pod 名称)。
  • default: 命名空间名称,即服务所属的命名空间(如果未指定,则为默认命名空间)。
  • svc: 服务类型,表示这是一个 Kubernetes 中的服务。
  • cluster.local: 集群域名,表示该服务所在的 Kubernetes 集群的域名。

headless Service 就是一个将 spec.clusterIP 设置为 None 的常规 Kubernetes Service 对象。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Headless Service for StatefulSet Pod DNS names
apiVersion: v1
kind: Service
metadata:
  name: dullahan   # 与 StatefulSet 的 ServiceName 关联
  labels:
    app: web
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: web

各种 Label 的组合

appzonever:应用名称,环境(测试,生产),版本

appcomponenttier:用于区分应用程序中的不同组件和层次。

  • app=webcomponent=frontendtier=web 用于前端应用程序
  • app=webcomponent=backendtier=api 用于 API 服务。

envstage:用于标识不同的环境和阶段。

  • env=devstage=test 用于开发测试环境
  • env=prodstage=prod 用于生产环境。

ownerteamcontact:用于标识应用程序或服务的所有者和维护者。

  • owner=devopsteam=infra[email protected] 用于 DevOps 团队维护的基础设施服务。

releasegit-commit:用于标识应用程序或服务的版本和发布信息。

  • release=1.0.0git-commit=abc123 用于标识应用程序的版本和发布信息。

regionzonedatacenter:用于标识服务或资源所在的区域、区域的子区域以及数据中心。

  • region=us-west-2zone=adatacenter=dc1 用于标识服务或资源所在的区域、区域的子区域以及数据中心。

cost-centerbudgetservice-level:用于标识服务或资源的成本、预算和服务级别。

  • cost-center=12345budget=100000service-level=gold 用于标识服务或资源的成本、预算和服务级别。

容器存储接口(The Container Storage Interface, CSI)是 存储 和 Kubernetes 的中间层。

持久化卷(Persistent Volume,PV),持久化卷申请(Persistent Volume Claim,PVC),存储类(Storage Class,SC)是 Kunbernetes 的 持久化卷子系统。

  • PV 代表的是 Kubernetes 中的存储;
  • PVC 就像许可证,赋予 Pod 访问 PV 的 权限;
  • CS 则使分配过程是动态的。
 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
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
  labels:
    release: stable
spec:
  capacity:
    storage: 1024Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Retain
  storageClassName: nfs
  mountOptions:
    - hard
    - nfsvers=4.1
  nfs:
    path:  "/data/k8s_data"
    server: 192.168.0.100
    readOnly: false
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
spec:
  storageClassName: nfs
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1024Gi

spec.accessModes 定义了 PV 是如何被挂载的。

  • ReadWriteOnce(RWO):限制一个 PV 只能以读写方式被挂载或绑定到一个 PVC。尝试将其绑定到多个 PVC 的话会失败。块存储通常只支持 RWO。
  • ReadWriteMany(RWM):允许一个 PV 能够以读写方式被绑定到多个 PVC 上。这种模式通常只支持诸如 NFS 这样的文件或对象存储。
  • ReadOnlyMany(ROM):允许 PV 以只读方式绑定到多个 PVC。

如果 PV 和 PVC 需要绑定 accessModesstorageClassNamestorage 需要一致。

spec.persistentVolumeReclaimPolicy 定义在 PVC 被释放 之后,如何处理对应的 PV

  • Delete
  • Retain

在 Kubernetes 中,存储类(Storage Class)是一种抽象层,用于定义 Kubernetes 中的不同存储技术,例如本地存储、网络存储和云存储等。通过使用存储类,可以将存储资源动态分配给 Kubernetes 集群中的不同应用程序和服务,并且可以根据应用程序和服务的需求进行灵活配置和管理。

存储类定义了动态存储分配策略,包括存储资源的类型、容量、访问模式和重试策略等。它们还可以定义存储类参数,例如数据复制策略、数据恢复选项和 QoS 类型等,以确保存储资源的高可用性和性能。

开发只需要创建PVC(只关心容量和速度),存储工程师只需要定义 SC(设置各种存储参数),PV 根据 PVC 和 SC 关联自动创建,这样就做到了存储工程师和开发工程师之间的分离。

  • StorageClass:对象是不可变的,这意味着它在部署之后无法进行修改。
  • metadata.name:应当是有意义的,因为其他对象可能会使用它来代指某个存储类。
  • provisioner 和 plugin 两个术语可以互相替换使用。
  • parameters:定义了与插件相关的值,每个插件可以支持其特有的一组参数。
 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
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: slow  # 由 PVC 引用
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: kubernetes.io/gce-pd
parameters:
  type: pd-standard
reclaimPolicy: Retain
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pv-ticket  # 由 PodSpec 引用
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: slow  # 匹配 SC 名称
  resources:
    requests:
      storage: 25Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: class-pod
spec:
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: pv-ticket  # 匹配 PVC 名称
  containers:
  - name: ubuntu-ctr
    image: ubuntu:latest
    command:
    - /bin/bash
    - "-c"
    - "sleep 60m"
    volumeMounts:
    - mountPath: /data
      name: data

删除操作

1
2
3
4
# 删除顺序为 Pod,PVC,SC
kubectl delete Pod class-Pod
kubectl delete pvc pv-ticket
kubectl delete sc slow
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# 通过命令创建 configMap
kubectl create cm testmap1 \
--from-literal shortname=msb.com \
--from-literal longname=magicsandbox.com

kubectl create cm testmap2 --from-file cmfile.txt

# 通过声明创建 configMap
kind: ConfigMap
apiVersion: v1
metadata:
	name: test-conf
data:
	test.conf: |
		env = plex-test
		endpoint = 0.0.0.0:31001
		char = utf8
		vault = PLEX/test
		log-size = 512M
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: v1
kind: Pod
metadata:
  labels:
    chapter: configmaps
  name: envpod
spec:
  restartPolicy: OnFailure
  containers:
    - name: ctr1
      image: busybox
      # 通过作为容器启动命令的参数
      command: [ "/bin/sh", "-c", "echo First name $(FIRSTNAME) last name $(LASTNAME)" ]
      env:
        - name: FIRSTNAME
          valueFrom:
            configMapKeyRef:
              name: multimap
              key: given
        - name: LASTNAME
          valueFrom:
            configMapKeyRef:
              name: multimap
              key: family