11.Quota and Limits、健康检查和认证与授权

2026-04-30

复习和预习

昨天课堂内容

  1. Pod Scheduler
  2. Metric Server and HPA

课前复习

默写

今天课堂内容

  1. Quota and Limits
  2. 健康检查
  3. 认证和授权

Quota and Limits

学习参考:

环境准备

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

    bash 复制代码
    [root@master30 ~]# kubectl create ns quota
    [root@master30 ~]# kubectl config set-context --current --namespace quota
  2. 提前部署好 Metric Server

ResourceQuota

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

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

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

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

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

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

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

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

  • 如果命名空间下的计算资源 (如 cpumemory)的配额被启用, 则用户必须为这些资源设定请求值(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一样

单位说明:

  • CPU1 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。

配额管理

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

创建 ResourceQuota 对象

bash 复制代码
[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 文件创建

yaml 复制代码
apiVersion: v1
kind: ResourceQuota
metadata:
  name: myquota
spec:
  hard:
    persistentvolumeclaims: "10"
    pods: "2"
    secrets: "5"
    services: "3"

测试配额

bash 复制代码
[root@master30 ~]# kubectl create deployment web --image=docker.io/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

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

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

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

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

测试-不指定计算资源

配额示例

bash 复制代码
[root@master30 ~]# vim resourcequota.yaml
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"
bash 复制代码
[root@master30 ~]# kubectl apply -f resourcequota.yaml

pod 示例

bash 复制代码
[root@master30 ~]# vim pod-without-quota.yaml
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: web
  labels:
    app: web
spec:
  containers:
  - name: web
    image: httpd
    imagePullPolicy: IfNotPresent
    ports:
    - name: web
      containerPort: 80
      protocol: TCP
bash 复制代码
[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

配额示例

bash 复制代码
[root@master30 ~]# vim resourcequota.yaml
yaml 复制代码
apiVersion: v1
kind: ResourceQuota
metadata:
  name: myquota
spec:
  hard:
    requests.cpu: 1000m
    requests.memory: "2048Mi"
bash 复制代码
[root@master30 ~]# kubectl apply -f resourcequota.yaml

pod 示例1:超上限

bash 复制代码
[root@master30 ~]# vim pod-request-1.yaml
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: web
  labels:
    app: web
spec:
  containers:
  - name: web
    image: docker.io/library/httpd
    imagePullPolicy: IfNotPresent
    resources:
      requests:
        cpu: 2000m
        memory: 4096Mi
    ports:
    - name: web
      containerPort: 80
      protocol: TCP
bash 复制代码
[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:未超上限

bash 复制代码
[root@master30 ~]# vim pod-request-2.yaml
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: web
  labels:
    app: web
spec:
  containers:
  - name: web
    image: docker.io/library/httpd
    imagePullPolicy: IfNotPresent
    resources:
      requests:
        cpu: 200m
        memory: 1024Mi
    ports:
    - name: web
      containerPort: 80
      protocol: TCP
bash 复制代码
[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

压力测试镜像

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

找讲师索取镜像。

bash 复制代码
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)

示例:

bash 复制代码
# 压力测试内存
$ docker run --name stress docker.io/progrium/stress -m 1 --vm-bytes 512M

# 压力测试CPU
$ docker run --name stress docker.io/progrium/stress -c 1

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

对于 pod:

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: stress
spec:
  containers:
  - name: stress
    image: docker.io/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']
配额示例
bash 复制代码
[root@master30 ~]# vim resourcequota.yaml
yaml 复制代码
apiVersion: v1
kind: ResourceQuota
metadata:
  name: myquota
spec:
  hard:
    limits.cpu: 1000m
    limits.memory: "2048Mi"
bash 复制代码
[root@master30 ~]# kubectl apply -f resourcequota.yaml
测试 CPU 资源

pod示例:

bash 复制代码
[root@master30 ~]# vim pod-limit-cpu.yaml
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: stress
spec:
  containers:
  - name: stress
    image: docker.io/progrium/stress
    imagePullPolicy: IfNotPresent
    args: ['-c','1']
    resources:
      limits:
        cpu: 200m
        memory: "256Mi"
bash 复制代码
[root@master30 ~]# kubectl apply -f pod-limit-cpu.yaml

打开一个终端监控

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

bash 复制代码
[root@master30 ~]# kubectl top pods
NAME     CPU(cores)   MEMORY(bytes)   
stress   201m         0Mi

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

bash 复制代码
# 删除 pod
[root@master30 ~]# kubectl delete pod stress --force
测试 MEMORY 资源

pod示例:

bash 复制代码
[root@master30 ~]# vim pod-limit-memory.yaml
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: stress
spec:
  containers:
  - name: stress
    image: docker.io/progrium/stress
    imagePullPolicy: IfNotPresent
    args: ['-m','1','--vm-bytes','512M']
    resources:
      limits:
        cpu: 200m
        memory: "256Mi"
bash 复制代码
[root@master30 ~]# kubectl apply -f pod-limit-memory.yaml

打开一个终端监控

bash 复制代码
[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。

bash 复制代码
# 删除 pod he 
[root@master30 ~]# kubectl delete pod stress --force
[root@master30 ~]# kubectl delete resourcequotas myquota
总结
  1. 计算资源的 limits 总和是否会超过节点上资源总和?

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

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

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

  2. 当计算资源的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 示例

bash 复制代码
[root@master30 ~]# vim limits.yaml
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

bash 复制代码
[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

bash 复制代码
[root@master30 ~]# vim pod-without-limits.yaml
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: stress
spec:
  containers:
  - name: stress
    image: docker.io/progrium/stress
    imagePullPolicy: IfNotPresent
    args: ['-c','1']

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

bash 复制代码
[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
yaml 复制代码
......
spec:
  containers:
    image: docker.io/progrium/stress
    imagePullPolicy: IfNotPresent
    name: stress
    resources:
      limits:
        cpu: 500m
        memory: 512Mi
      requests:
        cpu: 200m
        memory: 256Mi
......
bash 复制代码
# 清理资源
[root@master30 ~]# kubectl delete limitranges mylimit 
[root@master30 ~]# kubectl delete pod web --force 

只指定 limit 值

示例 2-1:limit 值大于 max 值
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  containers:
  - name: web
    image: docker.io/library/nginx
    resources:
      limits:
        cpu: 1.1
        memory: 1100Mi
bash 复制代码
[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 值
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  containers:
  - name: web
    image: docker.io/library/nginx
    resources:
      limits:
        cpu: 60m
        memory: 60Mi
bash 复制代码
[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 值
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  containers:
  - name: web
    image: docker.io/library/nginx
    resources:
      limits:
        cpu: 600m
        memory: 600Mi

结论:

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

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

    yaml 复制代码
    [root@master30 ~]# kubectl get pod web -o yaml
    ......
    spec:
      containers:
      - image: docker.io/library/nginx
        imagePullPolicy: Always
        name: web
        resources:
          limits:
            cpu: 600m
            memory: 600Mi
          requests:
            cpu: 600m
            memory: 600Mi
    ......

只指定 requests

示例 3-1:requests 大于 max 值
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  containers:
  - name: web
    image: docker.io/library/nginx
    resources:
      requests:
        cpu: 1600m
        memory: 600Mi
bash 复制代码
[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 值
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  containers:
  - name: web
    image: docker.io/library/nginx
    resources:
      requests:
        cpu: 60m
        memory: 60Mi
bash 复制代码
[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 值
yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  containers:
  - name: web
    image: docker.io/library/nginx
    resources:
      requests:
        cpu: 400m
        memory: 400Mi

结论:

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

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

    yaml 复制代码
    [root@master30 ~]# kubectl get pod web -o yaml
    ......
    spec:
      containers:
      - image: docker.io/library/nginx
        imagePullPolicy: Always
        name: web
        resources:
          limits:
            cpu: 500m
            memory: 512Mi
          requests:
            cpu: 400m
            memory: 400Mi
    ......

限定资源类型

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

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

LimitRange for PVC 示例:

yaml 复制代码
apiVersion: v1
kind: LimitRange
metadata:
  name: storagelimits
spec:
  limits:
  - type: PersistentVolumeClaim
    max:
      storage: 2Gi
    min:
      storage: 1Gi

环境清理

bash 复制代码
[root@master30 ~]# kubectl delete ns quota

Health Check

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

环境准备

bash 复制代码
[root@master30 ~]# kubectl create ns health
[root@master30 ~]# kubectl config set-context --current --namespace health

Health Check

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

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

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

bash 复制代码
# 创建一个普通 pod
[root@master30 ~]# kubectl run web --image=docker.io/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
bash 复制代码
[root@master30 ~]# vim deploy-httpGet-liveness.yaml
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: docker.io/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。
bash 复制代码
[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
bash 复制代码
[root@master30 ~]# vim deploy-httpGet-readiness.yaml
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: docker.io/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
bash 复制代码
# 创建应用
[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:检测容器自带文件

bash 复制代码
[root@master30 ~]# vim deploy-exec-liveness.yaml
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: docker.io/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
bash 复制代码
# 创建应用
[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:检测自定义文件

bash 复制代码
[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
yaml 复制代码
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

bash 复制代码
[root@master30 ~]# vim deploy-tcpSocket-liveness.yaml
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: docker.io/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会启动新副本, 然后发生了如下事件:

  1. 正常情况下新副本需要10秒钟完成准备工作, 在此之前无法响应业务请求。
  2. 由于人为配置错误, 副本始终无法完成准备工作(比如无法连接后端数据库)。

如果没有配置Health Check, 会出现怎样的情况?

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

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

环境清理

bash 复制代码
[root@master30 ~]# kubectl delete ns health

认证和授权

学习参考:API 访问控制

环境准备

bash 复制代码
[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。

json 复制代码
{
    "apiVersion": "abac.authorization.kubernetes.io/v1beta1",
    "kind": "Policy",
    "spec": {
        "user": "bob",
        "namespace": "projectCaribou",
        "resource": "pods",
        "readonly": true
    }
}
  • 如果 Bob 执行以下请求:读取 projectCaribou 名称空间中的对象清单,其鉴权请求将被允许。
json 复制代码
{
  "apiVersion": "authorization.k8s.io/v1beta1",
  "kind": "SubjectAccessReview",
  "spec": {
    "resourceAttributes": {
      "namespace": "projectCaribou",
      "verb": "get",
      "group": "unicorn.example.org",
      "resource": "pods"
    }
  }
}
  • 如果 Bob 在 projectCaribou 名字空间中请求写(createupdate)对象或在其它名字空间中请求读取(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-adminjane@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 参数。

bash 复制代码
[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 参数。
bash 复制代码
[root@master30 ~]# cat /etc/kubernetes/manifests/kube-apiserver.yaml |\
grep -- --token-auth-file
  • 文件为 csv格式,每行至少包括三列 token,username,user id。第四列为可选group 名项。如果有多个group名,列必须用""双引号包含其中,例如:
bash 复制代码
token,user,uid,"group1,group2,group3"
  • 默认未启用。

  • 启动引导令牌

    • 为了支持平滑地启动引导新的集群,Kubernetes 包含了一种动态管理的持有者令牌类型, 称作 启动引导令牌(Bootstrap Token) 。 这些令牌以 Secret 的形式保存在 kube-system 名字空间中,可以被动态管理和创建。 使用 kubeadm 引导和管理集群时,kubeadm 会自动完成这些设置。

    • 你必须在 API 服务器上设置 --enable-bootstrap-token-auth 标志来启用基于启动引导令牌的身份认证组件。

bash 复制代码
[root@master30 ~]# cat /etc/kubernetes/manifests/kube-apiserver.yaml |\
grep bootstrap
    - --enable-bootstrap-token-auth=true
  • 请参阅启动引导令牌, 以了解关于启动引导令牌身份认证组件详细信息。

  • 服务账号令牌

    • 服务账号(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工具。

bash 复制代码
[root@client ~]# apt install -y kubectl=1.30.2-00

准备申请材料

bash 复制代码
# 创建私钥
[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。

bash 复制代码
# 使用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,结果如下:

yaml 复制代码
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
bash 复制代码
# 设置 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.laoma.cloud   Ready    control-plane   40h   v1.30.2
worker31.laoma.cloud   Ready    <none>          40h   v1.30.2
worker32.laoma.cloud   Ready    <none>          40h   v1.30.2

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

bash 复制代码
# 获取文件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

删除账户

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

# 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

定集群

--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.laoma.cloud Ready control-plane 40h v1.30.2

worker31.laoma.cloud Ready 40h v1.30.2

worker32.laoma.cloud Ready 40h v1.30.2

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

```bash
# 获取文件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

删除账户

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

# 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
相关推荐
青山科技分享4 分钟前
跨境电商AI Agent哪个比较好用?剖析自动化运营工具的落地价值
运维·人工智能·自动化·ai智能体
莫陌尛.37 分钟前
StarRocks Iceberg MinIO S3 301报错完整修复文档(Docker环境)
java·docker·容器
再卷还是菜44 分钟前
Kubernetes(k8s) 控制器的详细介绍与总结
笔记·学习·kubernetes
天远Date Lab1 小时前
零信任架构实战:基于天远天远风控经营异常预警构建分布式企业合规监控网关
人工智能·分布式·架构
Henry-SAP1 小时前
AI芯片与具身智能双突破
人工智能·云原生·sap·erp
老郑聊AI业财智造1 小时前
从“思考-行动”到“知行合一”:ReActAgent的架构原理与工程实践全景剖析
人工智能·架构·系统架构·软件工程·软件构建
迁移科技2 小时前
3D视觉引导销轴上下料:单相机双工位高效方案
人工智能·自动化·视觉检测
AI行业说2 小时前
2026年家纺智能模板机品牌排名:六大品牌实测对比,枕套窗帘沙发垫工厂自动化选型指南
自动化·智能模板机·上橡筋机
戴西软件2 小时前
远程协同仿真是什么体验?
运维·jvm·人工智能·自动化·rpa
ZGIAI10 小时前
ZGI Skill Loop:给工具调用设边界
人工智能·架构