跳转至

配置

Taint/Toleration

默认情况下,Master节点是不允许运行用户Pod的。通过Taint/Toleration机制,可以在Master节点部署用户Pods。

原理:节点被加上一个Taint(染上“污点“),如果节点未声明自己能够容忍该”污点”(Toleration),则Pod不能在上面运行。

节点加上“污点”的命令:

  • NoSchedule意味着该Taint只会在调度新的Pod时产生作用,不会影响node1上已经运行的Pods
$ kubectl taint nodes node1 foo=bar:NoSchedule

Pod声明Toleartion:

# 能够容忍所有键值对为foo=bar的Taint
apiVersion: v1
kind: Pod
...
spec:
  toleartions:
    - key: "foo"
      operation: "Equal"
      value: "bar"
      effect: "NoSchedule"

节点删除“污点”的命令:让Master节点可以运行Pod

# 删除所有节点的node-role.kubernetes.io/master的Taint(最后的减号表示删除)
$ kubectl taint nodes --all node-role.kubernetes.io/master -

Yaml说明

资源yaml的构成:

  • TypeMeta:Kind,ApiVersion;
  • ObjectMeta:即对应的.metadata;
  • Spec:对应的 .spec;
  • Status:对应的 .status;

ResourceVersion

同一个版本的并发修改,只能有一个成功,两一个再更改时会发现版本号不一致。

  • 其 CAS 原子性操作是 etcd 的特性?

全局唯一的版本号(metadata.resourceVersion),防止基于同一个版本的并发修改的覆盖问题。

每个资源对象从创建开始就会有一个版本号,而后每次被修改(不管是 update 还是 patch 修改),版本号都会发生变化。

官方文档告诉我们,这个版本号是一个 K8s 的内部机制,用户不应该假设它是一个数字或者通过比较两个版本号大小来确定资源对象的新旧,唯一能做的就是通过比较版本号相等来确定对象是否是同一个版本(即是否发生了变化)。

  • 如果两个用户同时对一个资源对象做 update,不管操作的是对象中同一个字段还是不同字段,都存在版本控制的机制确保两个用户的 update 请求不会发生覆盖

Generation

  • 对所有变更请求,除非改变是针对 .metadata.status.metadata.generation 的取值都会增加。

Finalizers

Finalizers 是由字符串组成的数组,当 Finalizers 字段中存在元素时,相关资源不允许被删除

每当删除 namespace 或 pod 等一些 Kubernetes 资源时,有时资源状态会卡在 Terminating,很长时间无法删除,甚至有时增加 --force flag 之后还是无法正常删除。这时就需要 edit 该资源,将 finalizers 字段设置为 [],之后 Kubernetes 资源就正常删除了。

字段属于 Kubernetes GC 垃圾收集器,是一种删除拦截机制,能够让控制器实现异步的删除前(Pre-delete)回调,存在于资源对象的 Meta中。

对带有 Finalizer 的对象的第一个删除请求会为其 metadata.deletionTimestamp 设置一个值,但不会真的删除对象。一旦此值被设置,finalizers 列表中的值就只能被移除。

metadata.deletionTimestamp 字段被设置时,负责监测该对象的各个控制器会通过轮询对该对象的更新请求来执行它们所要处理的所有 Finalizer。当所有 Finalizer 都被执行过,资源被删除。

metadata.deletionGracePeriodSeconds 的取值控制对更新的轮询周期。

每个控制器要负责将其 Finalizer 从列表中去除。

每执行完一个就从 finalizers 中移除一个,直到 finalizers 为空,之后其宿主资源才会被真正的删除。

Owner References 属主与附属

ReplicaSet 是一组 Pod 的属主,具有属主的对象是属主的附属(Dependent)。附属对象有一个 metadata.ownerReferences 字段,用于引用其属主对象。在 Kubernetes 中不允许跨 namespace 指定属主。

delete 策略

Foreground策略:先删除附属对象,再删除属主对象。将对象的metadata.finalizers字段值设置为foregroundDeletion,控制器需要主动处理foregroundDeletion的finalizers。

Background策略(默认):删除一个对象同时会删除它的附属对象。

Orphan策略:不会自动删除它的附属对象,这些残留的依赖被称为原对象的孤儿对象。

SecurityContext

三种级别的设置:

  • Container级别:Container-level Security Context
  • 单Pod内所有容器和Volume:Pod-level Security Context
  • 集群内部所有Pod和Volume:Pod Security Policies

配置安全上下文可以

  • 访问权限控制:指定容器中运行进程的用户和用户组(通过uid和gid);
  • 阻止容器使用 root 户运行(容器的默认运行用户通常在其镜像中指定,所以可能需要阻止容器 root 用户运行;
  • 使用特权模式运行容器,使其对宿主节点的内核具有完全的访问权限;
  • 与以上相反,通过添加或禁用内核功能,配置细粒度的内核访问权限;
  • 设 SELinux C Security aced Linux 安全增强型 Linux )边项,加强对容器的限制;
  • 阻止进程写入容器的根文件系统
kubectl explain 'pods.spec.securityContext'

Pod的设置:

apiVersion: v1 
kind: Pod 
metadata: 
  name: pod-as-user-guest 
spec: 
  containers: 
  - name: main
    image: alpine 
    command: ["/bin/sleep","99999"]
    securityContext: 
      # 特定用户,只能指定用户Id
      runAsUser: 405
      # 特定用户组
      runAsGroup: 1000
      #
      fsGroup:

      # 阻止容器使用 root 用户运行
      runAsNonRoot: true

修改NodePort范围

默认范围是 30000-32767。

使用 kubeadm 安装 K8S 集群的情况下,修改/etc/kubernetes/manifests/kube-apiserver.yaml文件,向其中添加 --service-node-port-range=20000-22767 (定义需要的端口范围)

重启kube-apiserver

# 获得 apiserver 的 pod 名字
export apiserver_pods=$(kubectl get pods --selector=component=kube-apiserver -n kube-system --output=jsonpath={.items..metadata.name})
# 删除 apiserver 的 pod
kubectl delete pod $apiserver_pods -n kube-system

验证结果

  • 执行以下命令查看相关pod
kubectl describe pod $apiserver_pods -n kube-system

注意:

  • 对于已经创建的NodePort类型的Service,需要删除重新创建
  • 如果集群有多个 Master 节点,需要逐个修改每个节点上的 /etc/kubernetes/manifests/kube-apiserver.yaml 文件,并重启 apiserver

本地磁盘限制

防止将宿主机的磁盘撑满,导致宿主机不可用。

ephemeral-storage

ephemeral-storage 包括:

  • emptyDir volumes, except tmpfs emptyDir volumes
  • directories holding node-level logs
  • writeable container layers

在每个Kubernetes的节点上,kubelet的根目录(默认是/var/lib/kubelet)和日志目录(/var/log)保存在节点的主分区上,这个分区同时也会被Pod的EmptyDir类型的volume、容器日志、镜像的层、容器的可写层所占用

  • kubelet会统计当前节点的主分区的可分配的磁盘资源,或者可以覆盖节点上kubelet的配置来自定义可分配的资源。
  • 在创建Pod时会根据存储需求调度到满足存储的节点,在Pod使用超过限制的存储时会对其做驱逐的处理来保证不会耗尽节点上的磁盘空间。

注意事项:

  • 如果k8s的根目录(kubelet root-dir)跟容器镜像存储根目录(/var/lib/{docker})是单独挂载的磁盘(非root盘),则通过 kubectl 查看 node 的 ephemeral-storage 只会显示根分区(/) 的存储空间。
  • The kubelet will only track the root filesystem for ephemeral storage. OS layouts that mount a separate disk to /var/lib/kubelet or /var/lib/containers will not report ephemeral storage correctly.
  • 在申请资源的时候,可能会出问题(因为总的资源量结果不对)

  • K8s 1.22 版本及之后,允许容器镜像存储根目录(/var/lib/{docker})单独挂载盘,如果镜像可写层超过限制,可以正常被驱除;

使用示例 Pod:

resources:
  requests:
    cpu: 1
    memory: 2048Mi
    # k8s 1.8开始引入的特性,限制容器存储空间的使用
    ephemeral-storage: 2Gi
  limits:
    cpu: 2
    memory: 2048Mi
    ephemeral-storage: 5Gi

当ephemeral-storage超出限制时,kublet会驱除当前容器

Pod 内的重启不会被重启(不会受 restartPolicy 影响,也不会受存活等探针影响),因此需要配合 deployment 等使用,由 deployment 重新创建 Pod;

  • 已经 restart 过,但是有错误信息,reason状态导致不会继续重启(k8s 1.22版本),参考Pod驱除
  • get pods -o yaml信息如下:
status:
  - lastProbeTime: null
    lastTransitionTime: "2024-02-04T09:31:31Z"
    reason: PodFailed
    status: "False"
    type: Ready
  - ...
  containerStatuses:
  - image: nginx
    ...
    ready: false
    restartCount: 1
    started: false
    state:
      terminated:
        exitCode: 137
        finishedAt: null
        message: The container could not be located when the pod was terminated
        reason: ContainerStatusUnknown
        startedAt: null
  message: 'Pod ephemeral local storage usage exceeds the total limit of containers 1Gi. '
  phase: Failed
  qosClass: Burstable
  reason: Evicted

查看事件时如下:

  Warning  Evicted    27s    kubelet            Pod ephemeral local storage usage exceeds the total limit of containers 1Gi.
  Normal   Killing    27s    kubelet            Stopping container nginx

网络

CoreDNS 添加域名映射

kubectl edit configmap coredns -n kube-system

  • hosts 中 添加主机名到 ip 的映射;
data:
  Corefile: |
    .:53 {
        ... 
        # 添加主机名到 ip 的映射
        hosts {
          172.16.1.129 apiserver.cluster.local
          172.16.2.135   node135
          172.16.2.136   node136
          172.16.2.137   node137
          fallthrough
        }

        ...

        forward . /etc/resolv.conf {
           max_concurrent 1000
        }
    }
    # 特定DNS服务器解析特定域名
    *.baidu.com:53 {
        errors
        cache 30
        forward . 192.168.8.132
    }