云计算百科
云计算领域专业知识百科平台

吃透 K8s 资源管控 + 健康探针 + RBAC 权限,面试 80% 考点全在这里!

📝摘要

本文完整讲解 K8s 命名空间资源配额 ResourceQuota、LimitRange 范围限制,详解 request/limits 原理,CPU 内存 OOM 现象;详解 Pod 三大探针 liveness/readiness/startupProbe,httpGet/exec/tcpSocket 探测方式;梳理 K8s API 访问链路:认证、鉴权、准入控制,实战 X509 证书用户、RBAC 角色与角色绑定。全部 YAML、命令集群实测,覆盖大量 CKA、云原生面试高频考点。

📖前言

在 K8s 生产环境中,资源失控导致节点雪崩、容器异常僵死不重启、权限越权是最常见三大故障。 本篇覆盖三大模块: 1.资源管控:ResourceQuota 命名空间总配额,LimitRange 单容器资源约束,搞懂 request 调度、limits 硬限制,理解 CPU 可压缩、内存 OOM 被杀底层逻辑; 2.Pod 健康检查:存活探针、就绪探针实战,搞懂探针在扩缩容、滚动更新中的生产价值; 3.K8s 安全体系:API 访问完整链路,身份认证、鉴权、准入控制,X509 自定义用户、RBAC 角色 / 集群角色全套实操。

📂目录

Quota and Limits

Kubernetes Health Check

Kubernetes 认证和授权

Quota and Limits

学习参考:

  • 资源配额

  • 限制范围

  • 为 Pod 和容器管理资源

环境准备

  • 创建一个独立的名字空间quota,并切换到该ns

    root@master30:~# kubectl create ns quota
    root@master30:~# kubectl config set-context –current –namespace quota

  • 提前部署好 Metric Server

  • ResourceQuota

    **问题:**当多个用户或团队共享Kubernetes集群时,有人会使用超过其基于公平原则所分配到的资源量。

    **解决:**可以使用资源配额限制 Namespace 使用的资源。

    资源配额,通过 ResourceQuota 对象来定义,对每个命名空间的资源消耗总量提供限制。

    资源配额的工作方式如下:

    • 不同的团队在不同的命名空间下工作。这可以通过 RBAC 强制执行。

    • 集群管理员可以为每个命名空间创建一个或多个 ResourceQuota 对象。

    • 当用户在命名空间下创建资源(如 Pod、Service 等)时,Kubernetes 的配额系统会跟踪集群的资源使用情况, 以确保使用的资源用量不超过 ResourceQuota 中定义的硬性资源限额。

    • 如果资源创建或者更新请求违反了配额约束,那么该请求会报错(HTTP 403 FORBIDDEN), 并在消息中给出有可能违反的约束。

    • 如果命名空间下的计算资源 (如 cpu 和 memory)的配额被启用, 则用户必须为这些资源设定请求值(request)和约束值(limit),否则配额系统将拒绝 Pod 的创建。

      提示: 可使用 LimitRanger 准入控制器来为没有设置计算资源需求的 Pod 设置默认值。

    启用资源配额

    Kubernetes 默认启用了资源配额功能 。 当 API 服务器 的命令行标志 –enable-admission-plugins= 中包含 ResourceQuota 时, 资源配额会被启用。

    当命名空间中存在一个 ResourceQuota 对象时,对于该命名空间而言,资源配额就是开启的。

    配额类型

    Kubernetes可以限制两种类型资源:

    • 对象数量:Kubernetes 资源数量,例如pods,services等。

      实施资源数量配额可以提高kubernetes稳定性,避免Etcd数据库无限增长,还可以避免占用node中其他功能资源(例如ip地址服务)。

    • 计算资源:物理或者虚拟资源容量,例如 CPU,memory 和存储容量。

      实施计算资源配额可以避免消耗 kubernetes 集群中单个node所有计算资源,避免单个namespace中应用消耗所有集群资源,导致其他namespace中应用无法正常运行。

    **kubernetes 通过 ResourceQuota 类型资源实施配额。**一个namespace可以包含多个ResourceQuota对象,这些限制是累加的,一般情况,多个ResourceQuota对象不会限定同一个资源。

    • 对象数量:

      • persistentvolumeclaims
      • services
      • secrets
      • configmaps
      • replicationcontrollers
      • deployments.apps
      • replicasets.apps
      • statefulsets.apps
      • jobs.batch
      • cronjobs.batch
    • 计算资源

      资源名称描述
      limits.cpu 在所有处于非终止状态的 Pod 中,CPU 限制的总和不能超过此值。
      limits.memory 在所有处于非终止状态的 Pod 中,内存限制的总和不能超过这个值。
      requests.cpu 在所有处于非终止状态的 Pod 中,CPU 请求的总和不能超过此值。
      requests.memory 在所有处于非终止状态的 Pod 中,内存请求的总和不能超过这个值。
      requests.storage 在所有持久卷声明中,存储请求的总和不能超过此值。
      cpu 与 requests.cpu一样
      memory 与 requests.memory一样

    单位说明:

    • CPU:1 cpu 等于1000 m,默认单位是 cpu核心数量。
    • memory:支持两种格式。
      • Ki | Mi | Gi | Ti | Pi | Ei,进制是1024,例如1024 = 1Ki
      • k | M | G | T | P | E,进制是1000,例如1000 = 1k
      • 默认单位是 G,例如1.5,代表1500M。

    配额管理

    重要说明: 如果项目级别配额限定了 request 和 limit,那么创建pod的时候必须指定 request 和 limit。

    创建 ResourceQuota 对象

    root@master30:~# kubectl create quota myquota –hard=pods=2,services=3,secrets=5,persistentvolumeclaims=10

    root@master30:~# kubectl get resourcequotas
    NAME AGE REQUEST LIMIT
    my-quota 10s persistentvolumeclaims: 0/10, pods: 0/2, secrets: 1/5, services: 0/3

    root@master30:~# kubectl describe quota myquota
    Name: myquota
    Namespace: quota
    Resource Used Hard
    ——– —- —-
    persistentvolumeclaims 0 10
    pods 0 2
    secrets 1 5
    services 0 3

    通过 yaml 文件创建

    apiVersion: v1
    kind: ResourceQuota
    metadata:
    name: myquota
    spec:
    hard:
    persistentvolumeclaims: "10"
    pods: "2"
    secrets: "5"
    services: "3"

    测试配额

    root@master30:~# kubectl create deployment web –image=hub.laoma.cloud/library/nginx –replicas=3
    root@master30:~# kubectl get all
    NAME READY STATUS RESTARTS AGE
    pod/web-96d5df5c8-dl7qk 1/1 Running 0 40s
    pod/web-96d5df5c8-j7fhh 1/1 Running 0 40s

    NAME READY UP-TO-DATE AVAILABLE AGE
    deployment.apps/web 2/3 2 2 40s

    NAME DESIRED CURRENT READY AGE
    replicaset.apps/web-96d5df5c8 3 2 2 40s

    root@master30:~# kubectl describe rs web-96d5df5c8
    LAST SEEN TYPE REASON OBJECT MESSAGE
    ......
    33s Warning FailedCreate replicaset/web-96d5df5c8 Error creating: pods "web-96d5df5c8-xg6c9" is forbidden: exceeded quota: myquota, requested: pods=1, used: pods=2, limited: pods=2
    2s Warning FailedCreate replicaset/web-96d5df5c8 (combined from similar events): Error creating: pods "web-96d5df5c8-89p7j" is forbidden: exceeded quota: myquota, requested: pods=1, used: pods=2, limited: pods=2
    25s Normal SuccessfulCreate replicaset/web-96d5df5c8 Created pod: web-96d5df5c8-bkzmd
    34s Normal ScalingReplicaSet deployment/web Scaled up replica set web-96d5df5c8 to 3

    # 超过配额,创建失败

    # 修改配额 pod数量为10
    root@master30:~# kubectl patch resourcequotas myquota -p '{"spec":{"hard":{"pods":10}}}'

    # 此时重新扩展rs
    root@master30:~# kubectl scale rs web-96d5df5c8 –replicas 3

    # 再次验证pod数量
    root@master30:~# kubectl get pods
    NAME READY STATUS RESTARTS AGE
    pod/web-96d5df5c8-ajcz2 1/1 Running 0 2s
    pod/web-96d5df5c8-dl7qk 1/1 Running 0 60s
    pod/web-96d5df5c8-j7fhh 1/1 Running 0 60s

    # 清理环境
    root@master30:~# kubectl delete deployments.apps web
    root@master30:~# kubectl delete resourcequotas myquota

    思考: 如果一个用户可以管理多个 namespace,能否限定该用户配额呢?

    Request 和 Limits

    如果命名空间下的计算资源 (如 cpu 和 memory)的配额被启用, 则用户必须为这些资源设定请求值(request)和约束值(limit),否则配额系统将拒绝 Pod 的创建。

    pod.containers.resources 定义包含两部分:

    • requests,指明pod运行需要的最少计算资源,调度器查找具有充足计算资源的nodes。

    • limits,指明pod运行可以获得节点最多计算资源,用于阻止pod占用node太多计算资源。node使用Linux内核功能cgroup,限制pod资源使用。

    测试-不指定计算资源

    配额示例

    root@master30:~# vim resourcequota.yaml

    apiVersion: v1
    kind: ResourceQuota
    metadata:
    name: myquota
    spec:
    hard:
    persistentvolumeclaims: "10"
    pods: "2"
    secrets: "5"
    services: "3"
    requests.cpu: 1000m
    requests.memory: "2048Mi"
    limits.cpu: 1000m
    limits.memory: "2048Mi"

    root@master30:~# kubectl apply -f resourcequota.yaml

    pod 示例

    root@master30:~# vim pod-without-quota.yaml

    apiVersion: v1
    kind: Pod
    metadata:
    name: web
    labels:
    app: web
    spec:
    containers:
    name: web
    image: hub.laoma.cloud/library/httpd
    imagePullPolicy: IfNotPresent
    ports:
    name: web
    containerPort: 80
    protocol: TCP

    root@master30:~# kubectl apply -f pod-without-quota.yaml
    Error from server (Forbidden): error when creating "pod-without-quota.yaml": pods "web" is forbidden: failed quota: myquota: must specify limits.cpu for: web; limits.memory for: web; requests.cpu for: web; requests.memory for: web

    # 清理环境
    root@master30:~# kubectl delete resourcequotas myquota

    测试-Request

    配额示例

    root@master30:~# vim resourcequota.yaml

    apiVersion: v1
    kind: ResourceQuota
    metadata:
    name: myquota
    spec:
    hard:
    requests.cpu: 1000m
    requests.memory: "2048Mi"

    root@master30:~# kubectl apply -f resourcequota.yaml

    pod 示例1:超上限

    root@master30:~# vim pod-request-1.yaml

    apiVersion: v1
    kind: Pod
    metadata:
    name: web
    labels:
    app: web
    spec:
    containers:
    name: web
    image: hub.laoma.cloud/library/httpd
    imagePullPolicy: IfNotPresent
    resources:
    requests:
    cpu: 2000m
    memory: 4096Mi
    ports:
    name: web
    containerPort: 80
    protocol: TCP

    root@master30:~# kubectl apply -f pod-request-1.yaml
    Error from server (Forbidden): error when creating "pod-request-1.yaml": pods "web" is forbidden: exceeded quota: myquota, requested: requests.cpu=2,requests.memory=4Gi, used: requests.cpu=0,requests.memory=0, limited: requests.cpu=1,requests.memory=2Gi

    pod 示例2:未超上限

    root@master30:~# vim pod-request-2.yaml

    apiVersion: v1
    kind: Pod
    metadata:
    name: web
    labels:
    app: web
    spec:
    containers:
    name: web
    image: hub.laoma.cloud/library/httpd
    imagePullPolicy: IfNotPresent
    resources:
    requests:
    cpu: 200m
    memory: 1024Mi
    ports:
    name: web
    containerPort: 80
    protocol: TCP

    root@master30 ~# kubectl apply -f pod-request-2.yaml
    root@master30:~# kubectl get pod
    NAME READY STATUS RESTARTS AGE
    web 1/1 Running 0 43s

    # 验证使用情况
    root@master30:~# kubectl describe resourcequotas myquota
    Name: myquota
    Namespace: quota
    Resource Used Hard
    ——– —- —-
    requests.cpu 200m 1
    requests.memory 1Gi 2Gi

    # 删除pod和quota
    root@master30:~# kubectl delete pod web
    root@master30:~# kubectl delete resourcequotas myquota

    测试-Limits

    压力测试镜像

    可以直接使用镜像 hub.laoma.cloud/progrium/stress 进行压力测试,该镜像中运行stress命令。

    找讲师索取镜像。

    Usage: stress [OPTION [ARG]] ...
    -?, –help show this help statement
    –version show version statement
    -v, –verbose be verbose
    -q, –quiet be quiet
    -n, –dry-run show what would have been done
    -t, –timeout N timeout after N seconds
    –backoff N wait factor of N microseconds before work starts
    -c, –cpu N spawn N workers spinning on sqrt()
    -i, –io N spawn N workers spinning on sync()
    -m, –vm N spawn N workers spinning on malloc()/free()
    –vm-bytes B malloc B bytes per vm worker (default is 256MB)
    –vm-stride B touch a byte every B bytes (default is 4096)
    –vm-hang N sleep N secs before free (default none, 0 is inf)
    –vm-keep redirty memory instead of freeing and reallocating
    -d, –hdd N spawn N workers spinning on write()/unlink()
    –hdd-bytes B write B bytes per hdd worker (default is 1GB)

    Example: stress –cpu 8 –io 4 –vm 2 –vm-bytes 128M –timeout 10s

    Note: Numbers may be suffixed with s,m,h,d,y (time) or B,K,M,G (size).

    常用选项:

    • -c, –cpu N spawn N workers spinning on sqrt()

    • -m, –vm N spawn N workers spinning on malloc()/free()

      ​ –vm-bytes B malloc B bytes per vm worker (default is 256MB)

    • -d, –hdd N spawn N workers spinning on write()/unlink() –hdd-bytes B write B bytes per hdd worker (default is 1GB)

    示例:

    # 压力测试内存
    $ docker run –name stress hub.laoma.cloud/progrium/stress -m 1 –vm-bytes 512M

    # 压力测试CPU
    $ docker run –name stress hub.laoma.cloud/progrium/stress -c 1

    # 压力测试IO
    $ docker run –name stress hub.laoma.cloud/progrium/stress –d 1 –hdd-bytes 3G

    对于 pod:

    apiVersion: v1
    kind: Pod
    metadata:
    name: stress
    spec:
    containers:
    name: stress
    image: hub.laoma.cloud/progrium/stress
    imagePullPolicy: IfNotPresent
    command: ['sh','-c','sleep 3600']
    # 或者不用command,而是使用args作为参数传递给镜像的Entrypoint。
    #args: ['-m','1','–vm-bytes','512M']
    #args: ['-c','1']
    #args: ['-d','1','–hdd-bytes','3G']

    配额示例

    root@master30:~# vim resourcequota.yaml

    apiVersion: v1
    kind: ResourceQuota
    metadata:
    name: myquota
    spec:
    hard:
    limits.cpu: 1000m
    limits.memory: "2048Mi"

    root@master30:~# kubectl apply -f resourcequota.yaml

    测试 CPU 资源

    pod示例:

    root@master30:~# vim pod-limit-cpu.yaml

    apiVersion: v1
    kind: Pod
    metadata:
    name: stress
    spec:
    containers:
    name: stress
    image: hub.laoma.cloud/progrium/stress
    imagePullPolicy: IfNotPresent
    args: ['-c','1']
    resources:
    limits:
    cpu: 200m
    memory: "256Mi"

    root@master30:~# kubectl apply -f pod-limit-cpu.yaml

    打开一个终端监控

    kubectl top 命令需要提前部署Metrics-Server

    root@master30:~# kubectl top pods
    NAME CPU(cores) MEMORY(bytes)
    stress 201m 0Mi

    **可以发现:**CPU 使用率维持在 200m 左右。

    # 删除 pod
    root@master30:~# kubectl delete pod stress –force

    测试 MEMORY 资源

    pod示例:

    root@master30:~# vim pod-limit-memory.yaml

    apiVersion: v1
    kind: Pod
    metadata:
    name: stress
    spec:
    containers:
    name: stress
    image: hub.laoma.cloud/progrium/stress
    imagePullPolicy: IfNotPresent
    args: ['-m','1','–vm-bytes','512M']
    resources:
    limits:
    cpu: 200m
    memory: "256Mi"

    root@master30:~# kubectl apply -f pod-limit-memory.yaml

    打开一个终端监控

    root@master30:~# kubectl get pods -w
    NAME READY STATUS RESTARTS AGE
    stress 0/1 OOMKilled 1 (2s ago) 3s
    stress 0/1 CrashLoopBackOff 1 (2s ago) 4s

    可以发现: Pod 状态为 OOMKilled,并进行restart。

    # 删除 pod he
    root@master30:~# kubectl delete pod stress –force
    root@master30:~# kubectl delete resourcequotas myquota

    总结
  • 计算资源的 limits 总和是否会超过节点上资源总和?

    答案:可能会。 假设 node可用MEMORY为1G。

    每个pod内存 requests是256M,limit是512M。创建5个pod,pod实际占用内存也为256M(有可能小于256M)。

    node上大概可以创建4个pod,而此时的limits总和是2G。

  • 当计算资源的limits总和超过节点上资源总和时,kubernetes如何处理?

    • 对于 cpu,kubernetes 认为 cpu 是可被压缩的资源,在应用达到limits时,减少该容器的调度时间,并不会杀死应用。
    • 对于 memory,kubernetes 认为 memory 是无法被压缩的资源,此时k8s会杀死占用资源超过其request的应用(1.9版本之后的版本)。首当其冲的是没有指定request的container,然后是使用资源超过其request更多的container。同等情况下优先级更低的container更容易被杀死。
  • LimitRange

    kubernetes创建pod时,默认不指定资源请求和限制。如果namespace设置了配额,那么创建不指定资源请求和资源限制的pod是不允许的。为了在设定配额的namespace中使用pod,namespace还需要为pod资源请求设定默认范围。

    LimitRange 资源,也称为limits,定义了单个pod的资源请求和资源限制default、minimum、maximum值。pod的资源请求是其中所有容器请求的总和。

    LimitRange 资源用于限定特定 namespace。

    namespace设定了LimitRange,创建资源规则:

    • 如果项目中请求一个未提供计算资源的对象,那么此时namespace将使用limit范围default值创建该对象。
    • 如果项目中请求一个计算资源的对象,请求的资源小于limit最小值,那么该资源**无法创建**。
    • 如果项目中请求一个计算资源的对象,请求的资源大于limit最大值,那么该资源**无法创建**。

    LimitRange 示例

    root@master30:~# vim limits.yaml

    apiVersion: v1
    kind: LimitRange
    metadata:
    name: mylimit
    spec:
    limits:
    type: Container
    max:
    memory: 1024Mi
    cpu: 1
    min:
    memory: 128Mi
    cpu: 100m
    default:
    memory: 512Mi
    cpu: 500m
    defaultRequest:
    memory: 256Mi
    cpu: 200m

    说明:

    • name:只能使用小写字母,数字, ‘-’ 和 ‘.’,而且只能是数字或字母开头和结尾。
    • default:即该namespace配置resourceQuota时,创建container的默认limit上限
    • defaultRequest:即该namespace配置resourceQuota时,创建container的默认request上限
    • max:即该namespace下创建container的资源最大值
    • min:即该namespace下创建container的资源最小值

    其中: min <= defaultRequest <= default <= max

    root@master30:~# kubectl apply -f limits.yaml
    root@master30:~# kubectl get limitranges
    NAME CREATED AT
    mylimit 2021-09-09T04:09:15Z

    root@master30:~# kubectl describe limitranges mylimit
    Name: mylimit
    Namespace: quota
    Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
    —- ——– — — ————— ————- ———————–
    Container cpu 100m 1 200m 500m –
    Container memory 128Mi 1Gi 256Mi 512Mi –

    未指定 resources

    示例1:

    root@master30:~# vim pod-without-limits.yaml

    apiVersion: v1
    kind: Pod
    metadata:
    name: stress
    spec:
    containers:
    name: stress
    image: hub.laoma.cloud/progrium/stress
    imagePullPolicy: IfNotPresent
    args: ['-c','1']

    **结论:**创建出来的pod的resources 与 limitranage 指定的相关默认值一致。

    root@master30:~# kubectl apply -f pod-without-limits.yaml
    root@master30:~# kubectl top pods
    NAME CPU(cores) MEMORY(bytes)
    stress 501m 0Mi

    root@master30:~# kubectl get pod stress -o yaml


    spec:
    containers:
    image: hub.laoma.cloud/progrium/stress
    imagePullPolicy: IfNotPresent
    name: stress
    resources:
    limits:
    cpu: 500m
    memory: 512Mi
    requests:
    cpu: 200m
    memory: 256Mi

    # 清理资源
    root@master30:~# kubectl delete limitranges mylimit
    root@master30:~# kubectl delete pod web –force

    只指定 limit 值

    示例 2-1:limit 值大于 max 值

    apiVersion: v1
    kind: Pod
    metadata:
    name: web
    spec:
    containers:
    name: web
    image: hub.laoma.cloud/library/nginx
    resources:
    limits:
    cpu: 1.1
    memory: 1100Mi

    root@master30:~# kubectl apply -f limit.yml
    Error from server (Forbidden): error when creating "limit.yml": pods "web" is forbidden: [maximum cpu usage per Container is 1, but limit is 1100m, maximum memory usage per Container is 1Gi, but limit is 1181116006400m]

    示例 2-2:limit 值小于 min 值

    apiVersion: v1
    kind: Pod
    metadata:
    name: web
    spec:
    containers:
    name: web
    image: hub.laoma.cloud/library/nginx
    resources:
    limits:
    cpu: 60m
    memory: 60Mi

    root@master30:~# kubectl apply -f limit.yml
    Error from server (Forbidden): error when creating "limit.yml": pods "web" is forbidden: [minimum cpu usage per Container is 100m, but request is 60m, minimum memory usage per Container is 128Mi, but request is 60Mi]

    示例 2-3:min 值< limit 值< max 值

    apiVersion: v1
    kind: Pod
    metadata:
    name: web
    spec:
    containers:
    name: web
    image: hub.laoma.cloud/library/nginx
    resources:
    limits:
    cpu: 600m
    memory: 600Mi

    结论:

    • 创建的容器limits值必须满足条件:min值<指定的limit值<max值

    • 当只指定limits值时,requests值与limits值保持一致,而不是default request。

      root@master30:~# kubectl get pod web -o yaml

      spec:
      containers:
      image: hub.laoma.cloud/library/nginx
      imagePullPolicy: Always
      name: web
      resources:
      limits:
      cpu: 600m
      memory: 600Mi
      requests:
      cpu: 600m
      memory: 600Mi

    只指定 requests

    示例 3-1:requests 大于 max 值

    apiVersion: v1
    kind: Pod
    metadata:
    name: web
    spec:
    containers:
    name: web
    image: hub.laoma.cloud/library/nginx
    resources:
    requests:
    cpu: 1600m
    memory: 600Mi

    root@master30:~# kubectl apply -f limit4.yml
    The Pod "web" is invalid:
    * spec.containers[0].resources.requests: Invalid value: "1600m": must be less than or equal to cpu limit
    * spec.containers[0].resources.requests: Invalid value: "1600Mi": must be less than or equal to memory limit

    示例 3-2:requests 小于 min 值

    apiVersion: v1
    kind: Pod
    metadata:
    name: web
    spec:
    containers:
    name: web
    image: hub.laoma.cloud/library/nginx
    resources:
    requests:
    cpu: 60m
    memory: 60Mi

    root@master30:~# kubectl apply -f limit.yml
    Error from server (Forbidden): error when creating "limit.yml": pods "web" is forbidden: [minimum cpu usage per Container is 100m, but request is 60m, minimum memory usage per Container is 128Mi, but request is 60Mi]

    示例 3-3:min 值< request 值< max 值

    apiVersion: v1
    kind: Pod
    metadata:
    name: web
    spec:
    containers:
    name: web
    image: hub.laoma.cloud/library/nginx
    resources:
    requests:
    cpu: 400m
    memory: 400Mi

    结论:

    • 创建的容器requests值必须满足条件:min值<requests值<limits值

    • 当只指定requests值时,limits值与default值保持一致。

      root@master30:~# kubectl get pod web -o yaml

      spec:
      containers:
      image: hub.laoma.cloud/library/nginx
      imagePullPolicy: Always
      name: web
      resources:
      limits:
      cpu: 500m
      memory: 512Mi
      requests:
      cpu: 400m
      memory: 400Mi

    限定资源类型

    LimitRange 资源可以限定如下资源:

    TypeResource NameDescription
    container cpu、memory 限定容器 cpu、memroy
    Pod cpu、memory 限定 Pod 中所有容器cpu、memroy的总和
    PVC storage 限定PVC申请的存储空间大小

    LimitRange for PVC 示例:

    apiVersion: v1
    kind: LimitRange
    metadata:
    name: storagelimits
    spec:
    limits:
    type: PersistentVolumeClaim
    max:
    storage: 2Gi
    min:
    storage: 1Gi

    环境清理

    root@master30:~# kubectl delete ns quota

    Kubernetes Health Check

    学习参考:配置存活、就绪和启动探针

    环境准备

    root@master30:~# kubectl create ns health
    root@master30:~# kubectl config set-context –current –namespace health

    Health Check

    应用可能会因为各种问题,变的 unhealthy,例如临时连接断开,配置错误,应用本身错误。

    kubelet 使用 probes(探针),周期性地监控容器中应用是否为healthy状态,进一步决定什么时候要重启容器。 例如,当存活探针可以探测到应用死锁(应用在运行,但是无法继续执行后面的步骤)情况,进而重启pod,有助于提高应用的可用性,即使其中存在缺陷。

    没有探测的情况,看一个例子:

    # 创建一个普通 pod
    root@master30:~# kubectl run web –image=hub.laoma.cloud/library/httpd –image-pull-policy=IfNotPresent
    [root@laoma20 health]# kubectl describe pod web|grep '^IP:'
    IP: 10.224.73.16

    root@master30:~# curl 10.224.73.16
    <html><body><h1>It works!</h1></body></html>

    # 删除主页文件,即使pod中应用数据丢失,pod状态依然为Running
    root@master30:~# kubectl exec web — rm -f htdocs/index.html

    # 查看主页内容
    root@master30:~# curl 10.224.73.16
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
    <html>
    <head>
    <title>Index of /</title>
    </head>
    <body>
    <h1>Index of /</h1>
    <ul></ul>
    </body></html>
    root@master30:~# kubectl get pod
    NAME READY STATUS RESTARTS AGE
    web 1/1 Running 0 51s

    # 清理环境
    root@master30:~# kubectl delete pod web –force

    Probe Type

    kubelet 使用启动探针来了解应用容器何时启动。 如果配置了这类探针,存活探针和就绪探针成功之前不会重启,确保这些探针不会影响应用的启动。 启动探针可以用于对慢启动容器进行存活性检测,避免它们在启动运行之前就被杀掉。

    • LivenessProbe:用于确定pod中应用是否处于healthy状态。如果liveness probe检测的状态为unhealthy,则控制器将重新启动pod。

    • ReadinessProbe:用于确定pod中应用是否可以提供服务。如果返回失败状态,则**服务将从endpoints 中删除容器ip地址。**即使容器处于运行状态,也不接受代理发过来的请求。

    • StartupProbe:用于确定pod是否成功初始化。 如果指定,则在成功完成之前不会执行其他探测。如果此探测失败,Pod 将重新启动,就像 livenessProbe 失败一样。 这可用于在 Pod 生命周期开始时提供不同的探测参数,此时加载数据或预热缓存可能需要比稳态操作期间更长的时间。 这无法更新。

    我们这里不深入讨论StartupProbe。

    Checking Methods

    探针检查容器有四种不同的方法:

    • httpGet,对容器的 IP 地址上指定端口和路径执行 HTTP GET 请求。如果响应的状态码大于等于 200 且小于 400,则诊断被认为是成功的。
    • exec,在容器内执行指定命令。如果命令退出时返回码为 0,则认为诊断成功。
    • tcpSocket,对容器的 IP 地址上的指定端口执行 TCP 检查。如果端口打开,则诊断被认为是成功的。 如果远程系统(容器)在打开连接后立即将其关闭,这算作是健康的。
    • grpc,使用 gRPC 执行一个远程过程调用。 目标应该实现 gRPC 健康检查。 如果响应的状态是 “SERVING”,则认为诊断成功。

    我们这里不讨论 grpc 方法。

    HTTP Checks-httpGet

    当使用HTTP Checks,控制器使用webhoook判定容器健康情况。如果HTTP的响应码在200-399之间,判定check成功。适应范围:可以返回HTTP状态码应用。

    livenessProbe

    root@master30:~# vim deploy-httpGet-liveness.yaml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    labels:
    app: web
    name: web
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: web
    template:
    metadata:
    labels:
    app: web
    spec:
    containers:
    image: hub.laoma.cloud/library/httpd
    imagePullPolicy: IfNotPresent
    name: httpd
    # 添加livenessProbe部分
    livenessProbe:
    failureThreshold: 3
    initialDelaySeconds: 5
    periodSeconds: 5
    successThreshold: 1
    timeoutSeconds: 10
    httpGet:
    path: /index.html
    # port填写时间web端口
    port: 80
    # scheme指定协议,HTTP或者HTTPS
    scheme: HTTP

    probe选项说明:

    • initialDelaySeconds:必选。容器启动后多长时间,probe开始生效。
    • timeoutSeconds:必选。probe需要多长时间完成。如果超过该值,控制器判定probe失败。默认值1s,最小值是1秒。
    • periodSeconds:可选。检查频率。默认值10s,最小值是1秒。
    • successThreshold:可选,连续成功最少次数后判定probe成功。默认值1,最小值是1。
    • failureThreshold:可选。连续失败最少次数后判定probe失败。默认值3,最小值是1。

    root@master30:~# kubectl apply -f deploy-httpGet-liveness.yaml
    root@master30:~# kubectl get pod
    NAME READY STATUS RESTARTS AGE
    web-85c6ff748f-qwszz 1/1 Running 0 12m
    root@master30:~# kubectl describe pod web-85c6ff748f-j92jn|grep '^IP:'
    IP: 10.98.146.216

    # 删除主页文件
    root@master30:~# kubectl exec web-85c6ff748f-qwszz — bash -c 'rm htdocs/index.html'

    # 观察pod状态,RESTARTS次数变位1,再次访问
    root@master30:~# kubectl get pod
    NAME READY STATUS RESTARTS AGE
    web-85c6ff748f-qwszz 1/1 Running 1 13m

    # 容器删除需要一些时间,由参数terminationGracePeriodSeconds设定,默认值为30s。
    # 只有等容器删除,并创建完成后才会继续检测
    root@master30:~# curl 10.98.146.216
    <html><body><h1>It works!</h1></body></html>

    # 清理环境
    root@master30:~# kubectl delete deployments.apps web

    readinessProbe

    root@master30:~# vim deploy-httpGet-readiness.yaml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    labels:
    app: web
    name: web
    spec:
    replicas: 3
    selector:
    matchLabels:
    app: web
    template:
    metadata:
    labels:
    app: web
    spec:
    containers:
    image: hub.laoma.cloud/library/httpd
    imagePullPolicy: IfNotPresent
    name: httpd
    # 添加readinessProbe部分
    readinessProbe:
    failureThreshold: 3
    initialDelaySeconds: 5
    periodSeconds: 5
    successThreshold: 1
    timeoutSeconds: 10
    httpGet:
    path: /index.html
    port: 80
    scheme: HTTP

    # 创建应用
    root@master30:~# kubectl apply -f deploy-httpGet-readiness.yaml
    root@master30:~# kubectl expose deployment web –port=80 –target-port=80
    root@master30:~# kubectl get svc
    NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
    web ClusterIP 10.98.146.216 <none> 80/TCP 4m5s
    root@master30:~# kubectl get pod
    NAME READY STATUS RESTARTS AGE
    web-9479dc55c-6bpg7 1/1 Running 0 2m34s
    web-9479dc55c-d2gbn 1/1 Running 0 2m34s
    web-9479dc55c-hqh8q 1/1 Running 0 2m34s

    # 准备3个pod主页文件
    root@master30:~# for pod in $(kubectl get pods -o name|awk -F / '{print $2}'); do kubectl exec $pod — bash -c "echo $pod > htdocs/index.html"; done

    root@master30:~# for i in {1..90};do curl -s 10.96.180.30;done|sort |uniq -c
    24 web-9479dc55c-6bpg7
    33 web-9479dc55c-d2gbn
    33 web-9479dc55c-hqh8q

    root@master30:~# kubectl get endpoints web
    NAME ENDPOINTS AGE
    web 10.224.73.15:80,10.224.73.34:80,10.224.73.35:80 21m

    # 删除 web-9479dc55c-6bpg7主页文件
    root@master30:~# kubectl exec -it web-9479dc55c-6bpg7 — rm -f htdocs/index.html

    # web 服务的后端没有pod的ip
    root@master30:~# kubectl get endpoints web
    NAME ENDPOINTS AGE
    web 10.224.73.15:80,10.224.73.34:80 23m

    # 访问svc,后端无法看到 web-9479dc55c-6bpg7
    root@master30:~# for i in {1..90};do curl -s 10.96.180.30;done|sort |uniq -c
    50 web2
    40 web3

    # 观察web1状态,READY为0,RESTARTS数量为0
    root@master30:~# kubectl get pod
    NAME READY STATUS RESTARTS AGE
    web-9479dc55c-6bpg7 0/1 Running 0 8m49s
    web-9479dc55c-d2gbn 1/1 Running 0 8m49s
    web-9479dc55c-hqh8q 1/1 Running 0 8m49s

    # 清理环境
    root@master30:~# kubectl delete deployments.apps web

    Execution Checks-exec

    当使用容器执行检测,kubelet代理将在容器内执行命令。返回值是0,代表check成功。

    示例1:检测容器自带文件

    root@master30:~# vim deploy-exec-liveness.yaml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    labels:
    app: web
    name: web
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: web
    template:
    metadata:
    labels:
    app: web
    spec:
    containers:
    image: hub.laoma.cloud/library/httpd
    imagePullPolicy: IfNotPresent
    name: httpd
    # 添加livenessProbe部分
    livenessProbe:
    failureThreshold: 3
    initialDelaySeconds: 5
    periodSeconds: 5
    successThreshold: 1
    timeoutSeconds: 10
    exec:
    command:
    cat
    /usr/local/apache2/htdocs/index.html

    # 创建应用
    root@master30:~# kubectl apply -f deploy-exec-liveness.yaml
    root@master30:~# kubectl get pods
    NAME READY STATUS RESTARTS AGE
    web-8c9ff9b76-nm6s2 1/1 Running 1 (2s ago) 18s

    # 删除主页文件
    root@master30:~# kubectl exec web-8c9ff9b76-nm6s2 — bash -c 'rm htdocs/index.html'

    # 观察pod状态,RESTARTS次数变位1
    root@master30:~# kubectl get pod
    NAME READY STATUS RESTARTS AGE
    web 1/1 Running 1 4m5s

    示例2:检测自定义文件

    root@master30:~# kubectl run busybox –image=busybox –image-pull-policy=IfNotPresent -o yaml –dry-run=client > busybox.yml
    root@master30:~# vim deploy-exec-busybox.yml

    apiVersion: v1
    kind: Pod
    metadata:
    creationTimestamp: null
    labels:
    run: busybox
    name: busybox
    spec:
    containers:
    image: busybox
    imagePullPolicy: IfNotPresent
    name: busybox

    # 添加args参数
    args:
    /bin/sh
    c
    touch /tmp/healthy; sleep 10; rm rf /tmp/healthy; sleep 100

    #添加livenessProbe参数
    livenessProbe:
    failureThreshold: 3
    initialDelaySeconds: 5
    periodSeconds: 5
    successThreshold: 1
    timeoutSeconds: 10
    exec:
    command:
    ls
    /tmp/healthy
    dnsPolicy: ClusterFirst
    restartPolicy: Always

    TCP Socket Checks-tcpSocket

    当使用TCP socket checks,kubelet代理尝试打开容器socket。如果check可以建立连接,判定check成功。

    示例:liveness probe使用TCP Socket check

    root@master30:~# vim deploy-tcpSocket-liveness.yaml

    apiVersion: apps/v1
    kind: Deployment
    metadata:
    labels:
    app: web
    name: web
    spec:
    replicas: 1
    selector:
    matchLabels:
    app: web
    template:
    metadata:
    labels:
    app: web
    spec:
    containers:
    image: hub.laoma.cloud/library/httpd
    imagePullPolicy: IfNotPresent
    name: httpd
    # 添加livenessProbe部分
    livenessProbe:
    failureThreshold: 3
    initialDelaySeconds: 5
    periodSeconds: 5
    successThreshold: 1
    timeoutSeconds: 10
    tcpSocket:
    port: 80

    Health Check Case

    Health Check 在 Scale Up 中的应用

    对于多副本应用, 当执行Scale Up操作时, 新副本会作为backend被添加到Service的负载均衡中, 与已有副本一起处理客户的请求。考虑到应用启动通常都需要一个准备阶段, 比如加载缓存数据、 连接数据库等, 从容器启动到真正能够提供服务是需要一段时间的。 我们可以通过Readiness探测判断容器是否就绪, 避免将请求发送到还没有准备好的backend。

    Health Check 在滚动更新中的应用

    Health Check另一个重要的应用场景是Rolling Update。 试想一下, 现有一个正常运行的多副本应用, 接下来对应用进行更新(比如使用更高版本的image) , Kubernetes会启动新副本, 然后发生了如下事件:

  • 正常情况下新副本需要10秒钟完成准备工作, 在此之前无法响应业务请求。
  • 由于人为配置错误, 副本始终无法完成准备工作(比如无法连接后端数据库)。
  • 如果没有配置Health Check, 会出现怎样的情况?

    因为新副本本身没有异常退出, 默认的Health Check机制会认为容器已经就绪, 进而会逐步用新副本替换现有副本, 其结果就是: 当所有旧副本都被替换后, 整个应用将无法处理请求, 无法对外提供服务。 如果这是发生在重要的生产系统上, 后果会非常严重。

    如果正确配置了Health Check, 新副本只有通过了探测才会被添加到Service; 如果没有通过探测, 现有副本不会被全部替换, 业务仍然正常进行。

    环境清理

    root@master30:~# kubectl delete ns health

    Kubernetes 认证和授权

    学习参考:API 访问控制

    环境准备

    root@master30:~# kubectl create ns auth
    root@master30:~# kubectl config set-context –current –namespace auth

    Kubernetes API 访问控制

    学习参考:Kubernetes API 访问控制

    当用户使用User 或 服务账号访问Kubernetes API时,每个请求都会经过多阶段的访问控制之后才会被接受,包括身份认证、鉴权以及准入控制(Admission Control)。

    如下图所示:

    传输安全

    默认情况下,Kubernetes API 服务器在第一个非 localhost 网络接口的 6443 端口上进行监听, 受 TLS 保护。在一个典型的 Kubernetes 生产集群中,API 使用 443 端口。 该端口可以通过 –secure-port 进行变更,监听 IP 地址可以通过 –bind-address 标志进行变更。

    客户端向 Kubernetes API 服务器发起请求时,**API 服务器出示证书。**该证书可以使用私有证书颁发机构(CA)签名,也可以基于链接到公认的 CA 的公钥基础架构签名。 该证书和相应的私钥可以通过使用 –tls-cert-file 和 –tls-private-key-file 标志进行设置。

    如果你的集群使用私有证书颁发机构,你需要在客户端的 ~/.kube/config 文件中提供该 CA 证书的副本, 以便你可以信任该连接并确认该连接没有被拦截。

    身份认证

    如上图步骤 ① 所示:Kubernetes 操作前首先进行身份认证(Authentication)。

    Kubernetes 使用认证模块进行认证,认证模块包含客户端证书、密码、普通令牌、引导令牌和 JSON Web 令牌(JWT,用于服务账号)等。如果 Kubernetes 指定多个认证模块,服务器依次尝试每个验证模块,直到其中一个成功。

    • 如果请求认证通过,下一步对该用户名进行鉴权。
    • 如果请求认证不通过,服务器将以 HTTP 状态码 401 拒绝该请求。

    身份认证组件在认证节中有更详细的描述。

    鉴权

    如上图的步骤 ② 所示,将请求验证为来自特定的用户后,请求必须被鉴权(Authorization)。请求必须包含请求者的用户名、请求的行为以及受该操作影响的对象。 如果现有策略声明用户有权完成请求的操作,那么该请求被鉴权通过。

    示例: 以下策略,Bob 只能在 projectCaribou 名称空间中读取 Pod。

    {
    "apiVersion": "abac.authorization.kubernetes.io/v1beta1",
    "kind": "Policy",
    "spec": {
    "user": "bob",
    "namespace": "projectCaribou",
    "resource": "pods",
    "readonly": true
    }
    }

    • 如果 Bob 执行以下请求:读取 projectCaribou 名称空间中的对象清单,其鉴权请求将被允许。

    {
    "apiVersion": "authorization.k8s.io/v1beta1",
    "kind": "SubjectAccessReview",
    "spec": {
    "resourceAttributes": {
    "namespace": "projectCaribou",
    "verb": "get",
    "group": "unicorn.example.org",
    "resource": "pods"
    }
    }
    }

    • 如果 Bob 在 projectCaribou 名字空间中请求写(create 或 update)对象或在其它名字空间中请求读取(get)对象,其鉴权请求会被拒绝。

    **注意:**Kubernetes 鉴权要求使用公共 REST 属性与现有的组织范围或云提供商范围的访问控制系统进行交互。 使用 REST 格式很重要,因为这些控制系统可能会与 Kubernetes API 之外的 API 交互。

    Kubernetes 支持多种鉴权模块,例如 ABAC 模式、RBAC 模式和 Webhook 模式等。 管理员创建集群时,他们配置应在 API 服务器中使用的鉴权模块。 如果配置了多个鉴权模块,则 Kubernetes 会检查每个模块,任意一个模块鉴权该请求,请求即可继续; 如果所有模块拒绝了该请求,请求将会被拒绝(HTTP 状态码 403)。

    要了解更多有关 Kubernetes 鉴权的更多信息,包括有关使用支持鉴权模块创建策略的详细信息, 请参阅鉴权。

    准入控制

    这一操作如上图的步骤 ③ 所示。

    • 准入控制器对创建、修改、删除或(通过代理)连接对象的请求进行操作。 当有多个准入控制器被配置时,服务器将依次调用它们。准入控制器不会对仅读取对象的请求起作用。准入控制模块是可以修改或拒绝请求的软件模块。 除鉴权模块可用的属性外,准入控制模块还可以访问正在创建或修改的对象的内容。

    • 与身份认证和鉴权模块不同,如果任何准入控制器模块拒绝某请求,则该请求将立即被拒绝。除了拒绝对象之外,准入控制器还可以为字段设置复杂的默认值。

    • 请求通过所有准入控制器后,将使用检验例程检查对应的 API 对象,然后将其写入对象存储(如步骤 4 所示)。

    可用的准入控制模块参考 准入控制器。

    审计

    Kubernetes 审计提供了一套与安全相关的、按时间顺序排列的记录,其中记录了集群中的操作序列。 集群对用户、使用 Kubernetes API 的应用程序以及控制平面本身产生的活动进行审计。

    更多信息请参考 审计。

    认证管理

    学习参考:认证

    Kubernetes 中的用户

    Kubernetes 集群有两类用户:

    • 普通用户,Kubernetes 中普通用户不是由 kubernetes 直接提供,而是身份认证插件提供,Kubernetes 并不包含用来代表普通用户账号的对象。 普通用户的信息无法通过 API 调用添加到集群中,Kubernetes 认为:能够提供由集群的证书机构签名的合法证书的用户是通过身份认证的用户。 基于这样的机制,Kubernetes 使用证书中的 ‘subject’ 的通用名称(Common Name)字段 (例如,“/CN=bob”)来确定用户名。 接下来,基于角色访问控制(RBAC)子系统会确定用户是否有权针对某资源执行特定的操作。
    • 服务账号,Kubernetes 中服务账号是 Kubernetes API 所管理的用户。它们被绑定到特定的名字空间, 或者由 API 服务器自动创建,或者通过 API 调用创建。服务账号与一组以 Secret 保存的凭据相关,这些凭据会被挂载到 Pod 中,从而允许集群内的进程访问 Kubernetes API。

    每个 API 请求必须包含一个用户:普通用户相关或者服务账号,客户端也可以发起匿名请求。这意味着集群内外的每个进程在向 API 服务器发起请求时都必须通过身份认证,否则会被视作匿名用户。

    身份认证策略

    Kubernetes 通过身份认证插件认证 API 请求的身份。HTTP 请求发给 API 服务器时,插件会将以下属性关联到请求本身:

    • 用户名:用来辩识最终用户的字符串。常见的值可以是 kube-admin 或 jane@example.com。
    • 用户 ID:用来辩识最终用户的字符串,旨在比用户名有更好的一致性和唯一性。
    • 用户组:取值为一组字符串,其中各个字符串用来标明用户是某个命名的用户逻辑集合的成员。 常见的值可能是 system:masters 或者 devops-team 等。
    • 附加字段:一组额外的键-值映射,键是字符串,值是一组字符串; 用来保存一些鉴权组件可能觉得有用的额外信息。

    所有(属性)值对于身份认证系统而言都是不透明的, 只有被鉴权组件解释过之后才有意义。

    可以同时启用多种身份认证方法,通常至少使用两种方法:

    • 针对服务账号使用服务账号令牌。
    • 至少另外一种方法对用户的身份进行认证,例如X509客户证书。

    Kubernetes 默认使用的是服务账号和X509客户证书。本课程深入探讨以上两种方法。

    认证插件

    Kubernetes支持同时开启多个认证插件,只要有一个认证通过即可。如果认证成功,则用户的username会被传入鉴权模块做进一步鉴权验证;而对于认证失败的请求则返回HTTP 401。

    常用认证插件:

    • X509 客户证书

      • 客户端用户与Kubernetes交互时候,使用的认证凭据文件.kube/config就是使用X509证书。

      • API Server启动时配置 –client-ca-file=SOMEFILE 参数。

    root@master30:~# cat /etc/kubernetes/manifests/kube-apiserver.yaml |\\
    grep — –client-ca-file
    – –client-ca-file=/etc/kubernetes/pki/ca.crt

    • 静态令牌文件

      • API Server启动时配置 –token-auth-file=SOMEFILE 参数。默认未启用。
      • 文件为 csv格式,每行至少包括三列 token,username,user id。第四列为可选group 名项。如果有多个group名,列必须用””双引号包含其中,例如:token,user,uid,"group1,group2,group3"
    • 启动引导令牌

      • 为了支持平滑地启动引导新的集群,Kubernetes 包含了一种动态管理的持有者令牌类型, 称作 启动引导令牌(Bootstrap Token)。 这些令牌以 Secret 的形式保存在 kube-system 名字空间中,可以被动态管理和创建。 使用 kubeadm 引导和管理集群时,kubeadm 会自动完成这些设置。
      • 你必须在 API 服务器上设置 –enable-bootstrap-token-auth 标志来启用基于启动引导令牌的身份认证组件。
      • 请参阅启动引导令牌, 以了解关于启动引导令牌身份认证组件详细信息。
    • 服务账号令牌

      • 服务账号(Service Account)是一种自动被启用的用户认证机制,使用经过签名的持有者令牌来验证请求。

      • 服务账号通常由 API 服务器自动创建并通过 ServiceAccount 准入控制器关联到集群中运行的 Pod 上。 持有者令牌会挂载到 Pod 中可预知的位置,允许集群内进程与 API 服务器通信。

      • 服务账号也可以使用 Pod 规约的 serviceAccountName 字段显式地关联到 Pod 上。

    • Webhook 令牌身份认证

      Webhook 身份认证是一种用来验证持有者令牌的回调机制。

    • 身份认证代理

      API 服务器可以配置成从请求的头部字段值(如 X-Remote-User)中辩识用户。 这一设计是用来与某身份认证代理一起使用 API 服务器,代理负责设置请求的头部字段值。

    • basic-auth-file认证

      在kubernetes 1.19及之后的版本中,kubernetes放弃了 basic-auth-file 认证方式。

    匿名请求

    如果请求没有被已配置的身份认证方法拒绝, 则被视作匿名请求(Anonymous Requests)。这类请求获得用户名 system:anonymous 和对应的用户组 system:unauthenticated。

    • 在 1.5.1-1.5.x 版本中,匿名访问默认情况下是被禁用的,可以通过为 API 服务器设定 –anonymous-auth=true 来启用。

    • 在 1.6 及之后版本中,如果所使用的鉴权模式不是 AlwaysAllow,则匿名访问默认是被启用的。 从 1.6 版本开始,ABAC 和 RBAC 鉴权模块要求对 system:anonymous 用户或者 system:unauthenticated 用户组执行显式的权限判定,所以之前的为用户 * 或用户组 * 赋予访问权限的策略规则都不再包含匿名用户。

    **例如,**在一个配置了令牌身份认证且启用了匿名访问的服务器上,如果请求提供了非法的持有者令牌, 则会返回 401 Unauthorized 错误。如果请求没有提供持有者令牌,则被视为匿名请求。

    创建账户

    以下探讨使用 **X509客户证书 **插件管理用户。

    客户端准备

    客户端要想访问集群,必须安装与集群版本一致的kubectl工具。

    root@client:~# apt install -y kubectl=1.30.2-1.1

    准备申请材料

    # 创建私钥
    root@client:~# openssl genrsa -out laoma.key 2048

    # 根据私钥,创建请求证书
    root@client:~# openssl req -new -key laoma.key -out laoma.csr -subj '/CN=laoma/O=kubernets'
    # 参数说明:
    ## C,Country,代表国家
    ## ST,STate,代表省份
    ## L,Location,代表城市
    ## O,Organization,代表组织,公司
    ## OU,Organization Unit,代表部门
    ## CN,Common Name,代表服务器域名
    ## emailAddress,代表联系人邮箱地址。

    # 其他示例:
    root@client:~# openssl req -new -key servera.key -out servera.csr -subj "/C=CHINA/ST=JS/L=NJ/O=LM/OU=DEVOPS/CN=servera.lab.example.com/emailAddress=laoma@lab.example.com"

    # 客户端将自己请求证书发给kubernetes管理员
    root@client:~# scp laoma.csr root@master30:

    创建用户凭据

    管理员使用以下资源文件创建用户的kubeconfig。

    # 使用ca.crt和ca.key签名laoma.csr,得到laoma.crt证书
    root@master30:~# openssl x509 -req -in laoma.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out laoma.crt -days 1095

    # 导出kubeconfig模版
    root@master30:~# kubectl config view > config.tpl

    # 将kubeconfig模板、laoma.crt和kubernetes的ca证书发给客户端
    root@master30:~# scp config.tpl laoma.crt /etc/kubernetes/pki/ca.crt root@client:~

    创建 kubeconfig

    kubeconfig创建方法:

    • **方法一:**使用kubectl config命令创建。

    修改模版config.tpl,结果如下:

    apiVersion: v1
    clusters:
    cluster:
    server: https://10.1.8.30:6443
    name: kubernetes
    contexts:
    context:
    cluster: kubernetes
    namespace: default
    user: laoma
    name: laoma@kubernetes
    current-context: laoma@kubernetes
    kind: Config
    users:
    name: laoma

    # 设置 cluster
    root@client:~# mv config.tpl config
    root@client:~# kubectl config set-cluster kubernetes –kubeconfig=config –certificate-authority=ca.crt –embed-certs

    # –kubeconfig指定kubeconfig文件
    # –server指定kubernetes服务器认证地址
    # –certificate-authority选项指定ca证书
    # –embed-certs选项作用是将ca.crt的内容添加到config文件中,
    # 如果没有该选项,则添加 –certificate-authority 选项指定的路径,也就是ca.crt

    # 设置credentials
    root@client:~# kubectl config set-credentials laoma –kubeconfig=config –client-key=laoma.key –client-certificate=laoma.crt –embed-certs

    # –client-key 指定用户私钥
    # –client-certificate 指定服务器为用户生成的证书

    # 设置context
    root@client:~# kubectl config set-context laoma –kubeconfig=config –namespace=default –cluster=kubernetes –user=laoma
    # –namespace指定Namespace
    # –cluster指定集群
    # –user指定用户

    # 授权用户laoma集群管理员角色,后续详细讲解角色管理
    root@master30:~# kubectl create clusterrolebinding laoma-admin –clusterrole=cluster-admin –user=laoma

    # 验证结果
    root@client:~# kubectl get nodes –kubeconfig=config
    NAME STATUS ROLES AGE VERSION
    master30.cai.cloud Ready control-plane 40h v1.30.2
    worker31.cai.cloud Ready <none> 40h v1.30.2
    worker32.cai.cloud Ready <none> 40h v1.30.2

    • **方法二:**使用文本编辑器创建(不推荐)。

    # 获取文件ca.crt base64编码,填充到certificate-authority-data
    root@client:~# cat ca.crt | base64 | tr -d '\\n'

    # 获取文件laoma.key base64编码,填充到client-key-data
    root@client:~# cat laoma.key | base64 | tr -d '\\n'

    # 获取文件laoma.crt base64编码,填充到client-certificate-data
    root@client:~# cat laoma.crt | base64 | tr -d '\\n'

    # 使用上面的base64编码修改配置文件对应值
    root@master30:~# kubectl config view
    apiVersion: v1
    clusters:
    – cluster:
    certificate-authority-data: DATA+OMITTED
    server: https://10.1.8.30:6443
    name: kubernetes
    contexts:
    – context:
    cluster: kubernetes
    user: kubernetes-laoma
    name: kubernetes-laoma@kubernetes
    current-context: kubernetes-admin@kubernetes
    kind: Config
    preferences: {}
    users:
    – name: kubernetes-laoma
    user:
    client-certificate-data: REDACTED
    client-key-data: REDACTED

    删除账户

    # 通过删除证书进行删除账户即可,为了后续操作方便,该账户不删除

    # k8s删除用户csr资源后,客户端用户仍可以访问集群。
    # 解释:用户认证功能由x509提供,与k8s无关。
    # 如果不予许用户登录,应该从x509认证机制方面下手,例如ca.crt将相应客户端csr加入黑名单。

    # 删除权限
    root@master30:~# kubectl delete clusterrolebindings.rbac.authorization.k8s.io laoma-admin

    # 验证权限
    root@client:~# kubectl get nodes
    Error from server (Forbidden): nodes is forbidden: User "laoma" cannot list resource "nodes" in API group "" at the cluster scope

    授权管理

    学习参考:鉴权、使用 RBAC 鉴权

    鉴权概述

    Kubernetes API 服务器对 API 请求进行鉴权。 它根据所有策略评估所有请求属性来决定允许或拒绝请求。 一个 API 请求的所有部分都必须被某些策略允许才能继续。 这意味着默认情况下拒绝权限。

    当系统配置了多个鉴权模块时,Kubernetes 将按顺序使用每个模块。

    • 如果任何鉴权模块批准或拒绝请求,则立即返回该决定,并且不会与其他鉴权模块协商。
    • 如果所有模块对请求没有意见,则拒绝该请求。 被拒绝响应返回 HTTP 状态代码 403。

    鉴权模式

    鉴权模式定义认证成功的用户对集群的操作权限,由kube-apiserver配置文件指定:

    root@master30:~# cat /etc/kubernetes/manifests/kube-apiserver.yaml |grep mode
    – –authorization-mode=Node,RBAC

    我们这里使用RBAC和Node模式。

    支持的模式:

    • Node,是节点专用的鉴权模式,根据调度到 kubelet 上运行的 Pod 为 kubelet 授予权限。 要了解有关使用节点鉴权模式的更多信息,请参阅节点鉴权。

    • ABAC,基于属性的访问控制(ABAC)定义了一种访问控制范型,通过使用将属性组合在一起的策略, 将访问权限授予用户。策略可以使用任何类型的属性(用户属性、资源属性、对象,环境属性等)。 要了解有关使用 ABAC 模式的更多信息,请参阅 ABAC 模式。

    • RBAC,基于角色的访问控制(RBAC) 是一种基于企业内个人用户的角色来管理对计算机或网络资源的访问的方法。要了解有关使用 RBAC 模式的更多信息,请参阅 RBAC 模式。

      • 被启用之后,RBAC(基于角色的访问控制)使用 rbac.authorization.k8s.io API 组来驱动鉴权决策,从而允许管理员通过 Kubernetes API 动态配置权限策略。
      • 要启用 RBAC,请使用 –authorization-mode = RBAC 启动 API 服务器。
    • Webhook —— WebHook 是一个 HTTP 回调:发生某些事情时调用的 HTTP POST; 通过 HTTP POST 进行简单的事件通知。 实现 WebHook 的 Web 应用程序会在发生某些事情时将消息发布到 URL。 要了解有关使用 Webhook 模式的更多信息,请参阅 Webhook 模式。

    • AlwaysAllow,允许用户所有请求。

      # 前面我们删除了用户laoma权限,更改为AlwaysAllow模式,测试laoma用户权限。
      root@master30:~# vim /etc/kubernetes/manifests/kube-apiserver.yaml
      ......
      # 在spec.containers下的command中添加参数- –basic-auth-file=/etc/kubernets/pki/aa.csv
      spec:
      containers:
      – command:
      – –authorization-mode=AlwaysAllow
      ......

      # 更改完成后,kubernetes会自动重启pod/kube-apiserver,等该pod状态为running再次验证。
      root@client:~# kubectl get nodes
      NAME STATUS ROLES AGE VERSION
      master30.cai.cloud Ready control-plane 12d v1.30.2
      worker31.cai.cloud Ready <none> 12d v1.30.2
      worker32.cai.cloud Ready <none> 12d v1.30.2

    • AlwaysDeny,拒绝用户所有请求,不管用户是否具有权限,但不限制admin用户。

    role 管理

    kubernetes 方便管理权限,将一组特定权限赋予角色,然后将角色赋予用户,那么用户将继承该角色具有的权限。

    角色分类
    • role,namespace 角色,限定用户访问特定namespace。role绑定给用户,称之为rolebinding。

    • clusterrole,cluster 角色,可以管理集群,包括所有namespace中资源。clusterrole绑定给用户,称之为clusterrolebinding。

    权限由kubernetes系统预定义的,clusterroles/admin中包涵系统中全部权限列表。

    root@master30:~# kubectl describe clusterroles admin
    Name: admin
    Labels: kubernetes.io/bootstrapping=rbac-defaults
    Annotations: rbac.authorization.kubernetes.io/autoupdate: true
    PolicyRule:
    Resources Non-Resource URLs Resource Names Verbs
    ——— —————– ————– —–
    rolebindings.rbac.authorization.k8s.io [] [] [create delete deletecollection get list patch update watch]
    roles.rbac.authorization.k8s.io [] [] [create delete deletecollection get list patch update watch]
    configmaps [] [] [create delete deletecollection patch update get list watch]
    endpoints [] [] [create delete deletecollection patch update get list watch]
    ......

    输出说明:

    • Resources:代表系统中资源类型,例如Secret,Configmap等。

    • Resource Names:代表特定资源。如果Resources是Secret,那么这里就指特定Secret。

    • Non-Resource URLs: 被称为非资源URL或虚拟URL对象,是k8s中所需要的特殊动作(不需要关注)。

    • Verbs:代表针对资源执行的动作,包括操作get、list、create、delete、update、edit、watch、exec。

      • get,用于获得特定资源信息,例如,针对pod,可以执行GET /api/v1/namespaces/{namespace}/pods/{podname}。

    root@client:~# kubectl get pod -n kube-system
    Error from server (Forbidden): pods is forbidden: User "laoma" cannot list resource "pods" in API group "" in the namespace "kube-system"

    root@client:~# kubectl get pod kube-proxy-8kp8w -n kube-system
    NAME READY STATUS RESTARTS AGE
    kube-proxy-8kp8w 1/1 Running 4 52d

    • list,用户查看某一类型资源清单,例如针对pod,可以执行GET /api/v1/namespaces/{namespace}/pods。

    root@client:~# kubectl get pod -n kube-system
    NAME READY STATUS RESTARTS AGE
    calico-kube-controllers-6dfcd885bf-lq4n5 1/1 Running 4 52d
    calico-node-44cf4 1/1 Running 4 52d
    calico-node-48sm4 1/1 Running 4 52d
    .....

    root@client:~# kubectl get pod kube-proxy-8kp8w -n kube-system
    Error from server (Forbidden): pods "kube-proxy-8kp8w" is forbidden: User "laoma" cannot get resource "pods" in API group "" in the namespace "kube-system"

    更多API信息参考:https://kubernetes.io/docs/reference/kubernetes-api/

    创建 role

    root@master30:~# kubectl create role -h
    Create a role with single rule.

    Usage:
    kubectl create role NAME –verb=verb –resource=resource.group/subresource
    [–resource-name=resourcename] [–dry-run=server|client|none] [options]

    示例1:可以对项目中所有pods执行get、list、watch操作

    root@master30:~# kubectl create role pod-role –verb=get,list,watch –resource=pods -n default –dry-run=client -o yaml

    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
    creationTimestamp: null
    name: podrole
    namespace: default
    rules:
    apiGroups:
    ""
    resources:
    pods
    verbs:
    get
    list
    watch

    root@master30:~# kubectl create role pod-role –verb=get,list,watch –resource=pods -n default

    root@master30:~# kubectl get roles pod-role -n default
    NAME CREATED AT
    pod-role 2021-08-24T10:24:36Z

    root@master30:~# kubectl describe roles pod-role -n default
    Name: pod-role
    Labels: <none>
    Annotations: <none>
    PolicyRule:
    Resources Non-Resource URLs Resource Names Verbs
    ——— —————– ————– —–
    pods [] [] [get list watch]

    示例2:访问特定资源pods/readablepod

    root@master30:~# kubectl create role pod-role –verb=get –resource=pods \\
    –resource-name=readablepod –resource-name=anotherpod

    示例3:可以对项目中所有replicasets执行get list watch操作

    root@master30:~# kubectl create role foo –verb=get,list,watch –resource=replicasets

    修改 role

    # 增加create权限
    root@master30:~# kubectl edit roles -n default pod-role
    ......
    rules:
    – apiGroups:
    ""
    resources:
    – pods
    verbs:
    # 在verbs下添加相应权限
    – list
    – get
    watch
    – create

    apiGroups
    • 角色的 rules 属性中 apiGroups 默认为空。

    • pod、service 资源的 apiVersion 是v1,apiGroups为""。

    • Deployment、DaemonSet 资源的 apiVersion 是apps/v1,apiGroups为"apps"。如下:

    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
    creationTimestamp: null
    name: deploymentsrole
    namespace: default
    rules:
    apiGroups:
    "apps"
    resources:
    deployments
    verbs:
    get
    list
    watch

    **示例1:**定义角色,无法操作deployments,因为apiGroups未指定apps。

    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
    creationTimestamp: null
    name: deploymentsrole
    namespace: default
    rules:
    apiGroups:
    ""
    resources:
    deployments
    verbs:
    get
    list
    watch

    **示例2:**定义一个可以 scale deployments 的角色。

    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
    creationTimestamp: null
    name: deploymentsrole
    namespace: default
    rules:
    apiGroups:
    "apps"
    resources:
    deployments
    # 额外添加以下资源
    deployments/scale
    verbs:
    get
    list
    watch
    # 额外添加以下权限
    patch

    **示例3:**定义一个对不同类型资源赋予不同权限的角色。

    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
    creationTimestamp: null
    name: allrole
    namespace: default
    rules:
    apiGroups:
    ""
    resources:
    pods
    verbs:
    get
    list
    watch
    apiGroups:
    "apps"
    resources:
    deployments
    deployments/scale
    verbs:
    get
    list
    watch
    patch

    常见apiGroups

    TypeapiVersionapiGroups
    Pod、Service、PersistentVolume、PersistentVolumeClaim v1 “”
    Deployment、DaemonSet、StatefulSets apps/v1 apps
    Job batch/v1 batch
    CronJob batch/v1beta1 batch
    Role RoleBinding 、ClusterRole ClusterRoleBinding rbac.authorization.k8s.io/v1 rbac.authorization.k8s.io
    NetworkPolicy networking.k8s.io/v1 networking.k8s.io

    每种类型资源的 apiVersion 都可以通过以下命令查询:

    root@master30:~# kubectl explain deployment|grep VERSION
    VERSION: apps/v1

    root@master30:~# kubectl explain networkpolicy|grep VERSION
    VERSION: networking.k8s.io/v1
    # 或者
    root@master30:~/auth# kubectl api-resources |grep -i deploy
    deployments deploy apps/v1 true Deployment

    role 绑定

    将 role 绑定给用户。

    root@master30:~# kubectl create rolebinding default-pod-laoma -n default –role=pod-role –user=laoma –dry-run=client -o yaml

    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
    creationTimestamp: null
    name: defaultpodlaoma
    namespace: default
    roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: Role
    name: podrole
    subjects:
    apiGroup: rbac.authorization.k8s.io
    kind: User
    name: laoma

    # 绑定 ns/default 中角色 pod-role 给 laoma
    root@master30:~# kubectl create rolebinding default-pod-laoma -n default –role=pod-role –user=laoma
    # 角色绑定完成后,角色的权限发生变化,用户获得的权限也会跟着动态变化。

    root@master30:~# kubectl get rolebindings -n default default-pod-laoma
    NAME ROLE AGE
    default-pod-laoma Role/pod-role 2m15s

    root@master30:~# kubectl describe rolebindings -n default default-pod-laoma
    Name: default-pod-laoma
    Labels: <none>
    Annotations: <none>
    Role:
    Kind: Role
    Name: pod-role
    Subjects:
    Kind Name Namespace
    —- —- ———
    User laoma

    # 验证
    root@client:~# kubectl run web –image=hub.laoma.cloud/library/httpd –image-pull-policy=IfNotPresent -n default

    root@client:~# kubectl get pod -n default
    NAME READY STATUS RESTARTS AGE
    web 1/1 Running 0 2m30s

    root@client:~# kubectl get pod -n default -w
    NAME READY STATUS RESTARTS AGE
    web 1/1 Running 0 2m42s

    role 回收

    root@master30:~# kubectl delete rolebindings default-pod-laoma -n default
    rolebinding.rbac.authorization.k8s.io "default-pod-laoma" deleted

    # 再次验证
    root@client:~# kubectl get pod -n default
    Error from server (Forbidden): pods is forbidden: User "laoma" cannot list resource "pods" in API group "" in the namespace "default"

    role 删除

    root@master30:~# kubectl delete roles pod-role -n default

    📝全文总结

  • 资源管控:ResourceQuota 管控命名空间总资源上限,LimitRange 管控单个容器资源范围,填充默认 request/limits;request 用于调度,limits 通过 cgroup 硬限制资源;CPU 可压缩节流,内存超限 OOMKilled。
  • Pod 探针:Liveness 异常重启容器;Readiness 失败摘除 Service 后端端点,保障扩缩容、滚动更新业务稳定性,web 业务生产必须配置。
  • K8s 安全体系:API 访问经过 TLS、认证、鉴权、准入控制;X509 证书实现外部用户;RBAC 实现细粒度权限,区分命名空间 Role 和集群 ClusterRole。
  • 赞(0)
    未经允许不得转载:网硕互联帮助中心 » 吃透 K8s 资源管控 + 健康探针 + RBAC 权限,面试 80% 考点全在这里!
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!