Kubernetes权威指北

  • 你所不知道的事
  1. Service与其后端Pod副本集群之间则是通过Label Selector来实现“无缝对接”的
    在这里插入图片描述
    · 没有指定targetPort,则默认targetPort与port相同
    · Cluster IP无法被Ping,因为没有一个“实体网络对象”来响应。

  2. statefulSet (抄的)
    · 在Kubernetes系统中,Pod的管理对象RC、Deployment、DaemonSet和Job都面向无状态的服务。但现实中有很多服务是有状态的,特别是一些复杂的中间件集群,例如MySQL集群、MongoDB集群、Akka集群、ZooKeeper集群等,这些应用集群有4个共同点:
    (1)每个节点都有固定的身份ID,通过这个ID,集群中的成员可以相互发现并通信。
    (2)集群的规模是比较固定的,集群规模不能随意变动。
    (3)集群中的每个节点都是有状态的,通常会持久化数据到永久存储中。
    (4)如果磁盘损坏,则集群里的某个节点无法正常运行,集群功能受损。
    · 如果通过RC或Deployment控制Pod副本数量来实现上述有状态的集群,就会发现第1点是无法满足的,因为Pod的名称是随机产生的,Pod的IP地址也是在运行期才确定且可能有变动的,我们事先无法为每个Pod都确定唯一不变的ID。另外,为了能够在其他节点上恢复某个失败的节点,这种集群中的Pod需要挂接某种共享存储,为了解决这个问题,Kubernetes从1.4版本开始引入了PetSet这个新的资源对象,并且在1.5版本时更名为StatefulSet,StatefulSet从本质上来说,可以看作Deployment/RC的一个特殊变种,它有如下特性。

    1. StatefulSet里的每个Pod都有稳定、唯一的网络标识,可以用来发现集群内的其他成员。假设StatefulSet的名称为kafka,那么第1个Pod叫kafka-0,第2个叫kafka-1,以此类推。
    2. StatefulSet控制的Pod副本的启停顺序是受控的,操作第n个Pod时,前n-1个Pod已经是运行且准备好的状态。
    3. StatefulSet里的Pod采用稳定的持久化存储卷,通过PV或PVC来实现,删除Pod时默认不会删除与StatefulSet相关的存储卷(为了保证数据的安全)。

    · StatefulSet除了要与PV卷捆绑使用以存储Pod的状态数据,还要与Headless Service配合使用,即在每个StatefulSet定义中都要声明它属于哪个Headless Service。Headless Service与普通Service的关键区别在于,它没有Cluster IP,如果解析Headless Service的DNS域名,则返回的是该Service对应的全部Pod的Endpoint列表。StatefulSet在Headless Service的基础上又为StatefulSet控制的每个Pod实例都创建了一个DNS域名,这个域名的格式为:
    ${podname}.${headless service name}
    · 比如一个3节点的Kafka的StatefulSet集群对应的Headless Service的名称为kafka,StatefulSet的名称为kafka,则StatefulSet里的3个Pod的DNS名称分别为kafka-0.kafka、kafka-1.kafka、kafka-3.kafka,这些DNS名称可以直接在集群的配置文件中固定下来。

  3. pod调度过程
    在这里插入图片描述

  4. rbac
    饭粒1:RoleBinding将在default命名空间中把pod-reader角色授予用户jane,这一操作可以让jane读取default命名空间中的Pod

    kind: RoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: read-pods
      namespace: default
    subjects:
    - kind: User
      name: jane
      apiGroup: rbac.authorization.k8s.io
    roleRef:
      kind: Role
      name: pod-reader
      apiGroup: rbac.authorization.k8s.io
    

    饭粒2:虽然secret-reader是一个集群角色,但是因为使用了RoleBinding,所以dave只能读取development命名空间中的secret

    kind: RoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: read-secrets
      namespace: development
    subjects:
    - kind: User
      name: dave
      apiGroup: rbac.authorization.k8s.io
    roleRef:
      kind: ClusterRole
      name: secret-reader
      apiGroup: rbac.authorization.k8s.io
    

    饭粒3:允许manager组的用户读取任意Namespace中的secret

    kind: ClusterRoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: read-secrets-global
    subjects:
    - kind: Group
      name: manager
      apiGroup: rbac.authorization.k8s.io
    roleRef:
      kind: ClusterRole
      name: secret-reader
      apiGroup: rbac.authorization.k8s.io
    

    饭粒4:Pod是一个命名空间内的资源,log就是一个下级资源。要在一个RBAC角色中体现,就需要用斜线“/”来分隔资源和下级资源。若想授权让某个主体同时能够读取Pod和Pod log,则可以配置resources为一个数组

    kind: Role
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: pod-and-pod-logs-reader
    rules:
    - apiGroups: [""]
      resources: ["pods", "pods/log"]
      verbs: ["get", "list"]
    

    饭粒5:让一个主体只能对一个ConFigmap进行get和update操作

    kind: Role
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: configmap-updater
    rules:
    - apiGroups: [""]
      resources: ["configmap"]
      resourceNames: ["my-configmap"]
      verbs: ["update", "get"]
    

    常用的rbac角色示例

    1. 允许读取核心API组的Pod资源
    rules:
    - apiGroups: [""]
      resources: ["pods"]
      verbs: ["get", "list", "watch"]
    
    1. 允许读写extensions和apps两个API组中的deployment资源
    rules:
    - apiGroups: ["extensions", "apps"]
      resources: ["deployments"]
      verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
    
    1. 允许读取pods及读写jobs
    rules:
    - apiGroups: [""]
      resources: ["pods"]
      verbs: ["get", "list", "watch"]
    - apiGroups: ["batch", "extensions"]
      resources: ["jobs"]
      verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
    
    1. 允许读取一个名为my-config的ConfigMap(必须绑定到一个RoleBinding来限制到一个Namespace下的ConfigMap)
    rules:
    - apiGroups: [""]
      resources: ["configmaps"]
      resourceNames: ["my-config"]
      verbs: ["get"]
    
    1. 读取核心组的Node资源(Node属于集群级的资源,所以必须存在于ClusterRole中,并使用ClusterRoleBinding进行绑定)
    rules:
    - apiGroups: [""]
      resources: ["node"]
      verbs: ["get", "list", "watch"]
    
    1. 允许对非资源端点“/healthz”及其所有子路径进行GET和POST操作(必须使用ClusterRole和ClusterRoleBinding)
    rules:
    - nonResourceURLs: ["/healthz", "/healthz/*"]
      verbs: ["get", "post"]
    

    常见的rbac角色绑定

    1. 用户饭粒alice@example.com
    subjects:
    - kind: User
      name: "alice@example.com"
      apiGroup: rbac.authorization.k8s.io
    
    1. 用户组饭粒frontend-admins
    subjects:
    - kind: Group
      name: "frontend-admins"
      apiGroup: rbac.authorization.k8s.io
    
    1. kube-system命名空间中的默认Service Account
    subjects:
    - kind: ServiceAccount
      name: default
      namespace: kube-system
    
    1. qa命名空间中的所有Service Account
    subjects:
    - kind: Group
      name: system:serviceaccounts:qa
      apiGroup: rbac.authorization.k8s.io
    
    1. 所有Service Account
    subjects:
    - kind: Group
      name: system:serviceaccounts
      apiGroup: rbac.authorization.k8s.io
    
    1. 所有认证用户(Kubernetes 1.5以上版本)
    subjects:
    - kind: Group
      name: system:authenticated
      apiGroup: rbac.authorization.k8s.io
    
    1. 所有未认证用户(Kubernetes 1.5以上版本)
    subjects:
    - kind: Group
      name: system:unauthenticated
      apiGroup: rbac.authorization.k8s.io
    
    1. 全部用户(Kubernetes 1.5以上版本)
    subjects:
    - kind: Group
      name: system:authenticated
      apiGroup: rbac.authorization.k8s.io
    - kind: Group
      name: system:unauthenticated
      apiGroup: rbac.authorization.k8s.io
    

    可以在运行时进行调整,无须重新启动API Server。

  5. abac

  • 常见ABAC授权示例

    1. 允许用户alice对所有资源做任何操作
    {
    "apiVersion":"abac.authorization.kubernetes.io/v1beta1", 
    "kind": "Policy", 
    "spec": {"user": "alice", "namespace": "*", "resource": "*", "apiGroup": "*"}
    }
    
    1. kubelet可以读取任意Pod
    {
    "apiVersion":"abac.authorization.kubernetes.io/v1beta1", 
    "kind": "Policy", 
    "spec": {"user": "kubelet", "namespace": "*", "resource": "pods", "readonly": true}
    }
    
    1. kubelet可以读写Event对象
    {
    "apiVersion":"abac.authorization.kubernetes.io/v1beta1", 
    "kind": "Policy", 
    "spec": {"user": "kubelet", "namespace": "*", "resource": "events"}
    }
    
    1. 用户bob只能读取projectCaribou中的Pod
    {
    "apiVersion":"abac.authorization.kubernetes.io/v1beta1", 
    "kind": "Policy", 
    "spec": {"user": "bob", "namespace": "projectCaribou", "resource": "pod", "readonly": true}
    }
    
    1. 任何用户都可以对非资源类路径进行只读请求:
    {
    "apiVersion":"abac.authorization.kubernetes.io/v1beta1", 
    "kind": "Policy", 
    "spec": {"group": "system:authenticated",  "readonly": true, "nonResourcePath": "*"}
    }
    {
    "apiVersion":"abac.authorization.kubernetes.io/v1beta1", 
    "kind": "Policy", 
    "spec": {"group": "system:unauthenticated",  "readonly": true, "nonResourcePath": "*"}
    }
    

    如果添加了新的ABAC策略,则需要重启API Server以使其生效。

  1. Service Account也是一种账号,但它并不是给Kubernetes集群的用户(系统管理员、运维人员、租户用户等)用的,而是给运行在Pod里的进程用的,它为Pod里的进程提供了必要的身份证明。

  2. Docker支持的4类网络模式:
    - host模式:使用–net=host指定。
    - container模式:使用–net=container:NAME_or_ID指定。
    - none模式:使用–net=none指定。
    - bridge模式:使用–net=bridge指定,为默认设置。
    在Kubernetes管理模式下通常只会使用bridge模式。
    docker默认网桥模型:
    docker默认网桥模型
    在bridge模式下,Docker Daemon第1次启动时会创建一个虚拟的网桥,默认的名称是docker0,然后按照RPC1918的模型在私有网络空间中给这个网桥分配一个子网。针对由Docker创建的每一个容器,都会创建一个虚拟的以太网设备(Veth设备对),其中一端关联到网桥上,另一端使用Linux的网络命名空间技术,映射到容器内的eth0设备,然后从网桥的地址段内给eth0接口分配一个IP地址。

  3. API Server可能返回的状态码
    在这里插入图片描述

  4. kubernetes集群管理
    · 设置节点不可调度:

    1. kubectl patch node [node_name] -p '{"spec":{"unschedulable":true}}'
    2. kubectl cordon [node_name]
      将某个Node脱离调度范围时,在其上运行的Pod并不会自动停止,管理员需要手动停止在该Node上运行的Pod。

    · 集群加入新节点:
    在Kubernetes集群中,一个新Node的加入是非常简单的。在新的Node上安装Docker、kubelet和kube-proxy服务,然后配置kubelet和kube-proxy的启动参数,将Master URL指定为当前Kubernetes集群Master的地址,最后启动这些服务。通过kubelet默认的自动注册机制,新的Node将会自动加入现有的Kubernetes集群中。
    在这里插入图片描述
    · 标签管理:

    1. 添加标签
      kubectl label pod [pod_name] [label_key]=[label_value]
      eg: kubectl label pod myweb-gcq4v user=mine
      kubectl label node [node_name] [label_key]=[label_value]
    2. 删除标签(key后面加 -)
      kubectl label pod [pod_name] [label_key]-
    3. 修改标签(–overwrite)
      kubectl label pod [pod_name] [label_key]=[label_value] --overwrite
    4. 查看标签(–show-labels / -L[label_key])
      kubectl get po --show-labels
      eg: kubectl get po -Luser
      在这里插入图片描述

    · 资源管理 Requests/Limits
    CPU 是可压缩资源(当使用量超过限制值不会立刻杀死容器),而内存是不可压缩资源(只要使用量一超过阈值马上杀死容器)
    · QoS
    Kubernetes 支持了三种 QoS 级别,分别为BestEffort(尽力而为、不太可靠的)、Burstable(弹性波动、较可靠的) 和 Guranteed(完全可靠的)

    1. BestEffort表示 Pod 中没有一个容器设置了 Requests 或 Limits,它的优先级最低;(在容器未定义Limits时,Limits值默认等于节点资源容量的上限)
    2. Burstable表示 Pod 中每个容器至少定义了 CPU 或 Memory 的 Requests,或者 Requests 和 Limits 不相等,它属于中等优先级
    3. Guranteed则表示 Pod 中每个容器 Requests 和 Limits 都相等,这类 Pod 的运行优先级最高。简单来说就是cpu.limits = cpu.requests,memory.limits = memory.requests。容器可以不定义Requests,因为Requests值在未定义时默认等于Limits。

    当节点中某些Pod 使用的 CPU 和 Memory 越来越多,或者宿主机某些进程(例如 Kubelet、Docker)占用了 CPU 和 Memory,这个时候Kubernetes 就会根据 QoS 的优先级来选择 Kill 掉一部分 Pod。优先级最低的BestEffort类型的 Pod,占用的资源越多越优先被 Kill 掉。从另外一个角度来看,BestEffort Pod由于没有设置资源Limits,所以在资源充足时,它们可以充分使用所有的闲置资源。
    饭粒1:Burstable - OOM

    apiVersion: v1
    kind: Pod
    metadata:
      name: memory-burstable-demo
      namespace: demo
    spec:
      containers:
      - name: memory-demo
        image: polinux/stress
        resources:
          requests:
            memory: "50Mi"
          limits:
            memory: "100Mi"
        command: ["stress"]
        args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1"]
    

    饭粒2:Burstable - Out of CPU

    apiVersion: v1
    kind: Pod
    metadata:
      name: cpu-burstable-demo
      namespace: demo
    spec:
      containers:
      - name: cpu-demo
        image: vish/stress
        resources:
          limits:
            cpu: "1"
          requests:
            cpu: "0.5"
        args:
        - -cpus
        - "2"
    

    · LimitRange 设置默认资源防线

    apiVersion: v1
    kind: LimitRange
    metadata:
      name: mem-limit-range
      namespace: example
    spec:
      limits:
      - default:  # 默认 limit
          memory: 512Mi
          cpu: 2
        defaultRequest:  # 默认 request
          memory: 256Mi
          cpu: 0.5
        max:  # 最大 limit,pod容器可以设置的最大 Limits,default 字段不能高于此值
          memory: 800Mi
          cpu: 3
        min:  # 最小 request,Pod 中容器可以设置的最小 Requests,defaulRequest 字段不能低于此值
          memory: 100Mi
          cpu: 0.3
        maxLimitRequestRatio:  # limit/request 的最大比率
          memory: 2
          cpu: 2
        type: Container # 支持 Container / Pod / PersistentVolumeClaim 三种类型
    

    说明:

    1. 如果设置了max而又没有设置 default,那么所有未显式设置这些值的容器都将使用此处的最大值作为 Limits。
    2. 如果设置了min而又没有设置 defaulRequest,那么所有未显式设置这些值的容器都将使用此处的最小值作为 Requests。
    3. 参数必须满足以下关系:Min ≤ Default Request ≤ Default Limit ≤ Max
    4. 官文参考:
      如何配置每个命名空间最小和最大的 CPU 约束
      如何配置每个命名空间最小和最大的内存约束
      如何配置每个命名空间默认的 CPU 申请值和限制值
      如何配置每个命名空间默认的内存申请值和限制值
      如何配置每个命名空间最小和最大存储使用量

    · ResourceQuota 设置资源总量限制
    资源配额可以通过在kube-apiserver的--admission-control参数值中添加ResourceQuota参数进行开启

    apiVersion: v1
    kind: ResourceQuota 
    metadata: 
      name: compute-resources
      namespace: demo                  #在demo空间下
    spec: 
      hard:
        requests.cpu: "10"             #cpu预配置10
        requests.memory: 100Gi         #内存预配置100Gi
        limits.cpu: "40"               #cpu最大不超过40
        limits.memory: 200Gi           #内存最大不超过200Gi
        configmaps: "10"               #最多10个configmap
        pods: "20"                     #最多20个pod
        persistentvolumeclaims: "10"    #最多10个pvc
        replicationcontrollers: "20"   #最多20个rc
        secrets: "10"                  #最多10个secrets
        services: "10"                 #最多10个service
        services.loadbalancers: "10"    #最多10个lb类型的service
        requests.nvidia.com/gpu: 10        #最多10个GPU
    

    官文参考

  5. Kubernetes的GC机制(垃圾回收) 官文
    Kubernetes 默认开启了 GC 的能力,由kubelet负责,可以回收内部的各种资源对象,还可以回收 kubelet 节点上的冗余镜像以及退出的容器。
    · 容器镜像的 GC 参数:
    --minimum-image-ttl-duration表示一个镜像在清理前的最小存活时间;
    --image-gc-high-threshold表示磁盘使用率的上限阈值,默认值是 90%,即当磁盘使用率达到 90% 的时候会触发对镜像的 GC 操作;
    --image-gc-low-threshold表示磁盘使用率的下限阈值,默认值是 80%,即当磁盘使用率降到 80% 的时候,GC 操作结束。

    · 对容器的 GC 参数:
    --minimum-container-ttl-duration表示已停止的容器在被清理之前最小的存活时间,默认值是 1 分钟,即容器停止超过 1 分钟才会被标记可被 GC 清理;
    --maximum-dead-containers-per-container表示一个 Pod 内可以保留的已停止的容器数量,默认值是 2。Kubernetes 是以 Pod 为单位进行容器管理的。有时候 Pod 内运行失败的容器,比如容器自身的问题,或者健康检查失败,会被 kubelet 自动重启,这将产生一些停止的容器;
    --maximum-dead-containers表示在本节点上可以保留的已停止容器的最大数量,默认值是240。毕竟这些容器也会消耗额外的磁盘空间,所以超过这个上限阈值后,就会触发 Kubelet 的 GC 操作,来帮你自动清理这些已停止的容器,释放磁盘空间。
    注意:在有些场景中,容器的日志需要保留在本地,如果直接清理掉这些容器会丢失日志。所以这里我强烈建议你将–maximum-dead-containers-per-container设置为一个足够大的值,以便每个容器至少有一个退出的实例。

    · Kubernetes 内部对象的 GC
    *) 查看资源对象的从属关系:metadata.ownerReferences
    如:Deployment(owner) -> ReplicaSet (dependent) -> Pod (dependent)
    *) GC方式:
    通过 deleteOptions.propagationPolicy 这个字段,来控制删除的策略.

    • 级联删除
      后台(Background)模式:Kuberentes 会立即删除主对象,比如 Deployment,之后 Kubernetes 会在后台 GC 其附属的对象,比如 ReplicaSet。
      $ kubectl proxy --port=8080
      $ curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/replicasets/my-repset \
        -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
        -H "Content-Type: application/json"
      
      前台(Foreground)模式:先删除其所属的对象,然后再删除主对象。
      $ kubectl proxy --port=8080
      $ curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/replicasets/my-replicaset \
        -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \
        -H "Content-Type: application/json"
      
      注意:ownerReference.blockOwnerDeletion为true时才会组织删除主对象。
    • 非级联删除(孤立对象Orphaned)
      $ kubectl proxy --port=8080
      $ curl -X DELETE localhost:8080/apis/apps/v1/namespaces/default/replicasets/my-repset \
        -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
        -H "Content-Type: application/json"
      
      kubectl 命令行在删除操作的时候,默认是进行级联删除的,如果你不想级联删除,可以这么操作:
      $ kubectl delete replicaset my-repset --cascade=false
      
  6. pod抢占式资源调度(资源不足时优先级高的把优先级低的挤下线)
    PriorityClass 定义优先级

    apiVersion: scheduling.k8s.io/v1
    kind: PriorityClass
    metadata:
      name: high-priority
    value: 1000000
    globalDefault: false
    description: "This priority class should be used for XYZ service pods only."
    

    注意:
    这个对象是个集群级别的定义,并不属于任何 namespace,可以被全局使用,即各个 namespace 中创建的 Pod 都能使用 PriorityClass。
    globalDefault 用来表明是否将该 PriorityClass 的数值作为默认值,并将其应用在所有未设置 priorityClassName 的 Pod 上。如果没有任何一个 PriorityClass 对象的 globalDefault 被设置为 true 的话,就意味着所有未设置 spec.priorityClassName 的 Pod 的优先级为 0。即便你新建了某个 PriorityClass 对象,并将其 globalDefault 设置为 true,那么也不不影响集群中的存量 Pod,只会对新建的 Pod 生效。

    k8s定义了两个优先级值
    1. 自定义 PriorityClass 的时候,定义的优先级值是不能高于 HighestUserDefinablePriority 值 1000000000
    2. Kubernetes 在初始化的时候就自带了两个 PriorityClasses,即 system-cluster-critical 和 system-node-critical,优先级值为 2000000000,可以通过kubectl get priorityclass查看
      $ kubectl get priorityclass
      NAME                      VALUE        GLOBAL-DEFAULT   AGE
      system-cluster-critical   2000000000   false            59d
      system-node-critical      2000001000   false            59d
      

    pod设置系统优先级饭粒:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      ...
      name: coredns
      namespace: kube-system
      ...
    spec:
      ...
      template:
        ...
        spec:
          ...
          priorityClassName: system-cluster-critical
          ...
    status:
      ...
    
    $ kubectl describe pod coredns -n kube-system
    Name:                 coredns
    Namespace:            kube-system
    Priority:             2000000000
    Priority Class Name:  system-cluster-critical
    ...
    

    注意:在使用的时候不允许自己去设置 spec.priority 的数值,我们只能通过 spec.priorityClassName 来设置优先级。
    设置非抢占式,只优先调度不抢占(不推荐):

    1. PriorityClass定义时,在与globalDefault同级加上配置preemptionPolicy: Never
    2. kube-scheduler 的抢占能力是通过 disablePreemption 这个参数来控制的,该标志默认为 false。如果你还是坚持禁用抢占,可以将 disablePreemption 设置为true

    提高集群的资源利用率最常见的做法就是采用优先级的方案。在实际使用的时候,要避免恶意用户创建高优先级的 Pod,这样会导致其他 Pod 被驱逐或者无法调度,严重影响集群的稳定性和安全性。集群管理员可以为特定用户创建特定优先级级别,来防止他们恶意使用高优先级的 PriorityClass。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值