前端也要懂点k8s-上篇

7,858 阅读9分钟

前言

最近在采用Jenkins实现前端项目自动化部署功能,其中有一个步骤用到了k8s, 这一块知识令我感到比较陌生,看不懂配置文件里的语句含义,以及如何被外部的bash指令串联起来,刚好假期有时间,决定学习一下k8s。学完目标是学完之后要了解k8s常用的操作。现在我们进入今天的主题:

一、Kubernetes 简介

Kubernetes(简称 K8s)是一个用于自动部署、扩展和管理容器化应用程序的开源系统。下图展示了Kubernetes集群的架构及其与外部系统的交互方式:

image.png

1.1 外部系统(External Systems)

  • kubectl: 这是Kubernetes的命令行工具,用户可以通过它与Kubernetes API服务器进行交互,执行各种操作如创建、删除和更新资源。
  • CI/CD Systems: 持续集成/持续部署系统可以使用Kubernetes API来自动化应用的部署和管理。
  • Apps Use SDK to connect to API server: 应用程序可以使用SDK连接到Kubernetes API服务器,以实现更复杂的集成和自动化。

1.2 Kubernetes 集群(Kubernetes Cluster)

Kubernetes集群采用的是主从架构(Master-Slave Architecture) ,主要由两个角色组成:

  • 控制平面(Control Plane) :负责集群的整体管理和调度。
  • 工作节点(Worker Node) :负责实际运行应用容器。

1.2.1 控制平面(Control Plane)

控制平面是 Kubernetes 的“大脑”,主要负责接收用户指令、调度任务、监控运行状态。它包含以下组件:

组件说明
kube-apiserverKubernetes API服务器,所有请求的统一入口,提供 HTTP REST 接口,处理认证、授权、通信等
etcd分布式 Key-Value 数据库,用于持久化存储集群所有状态数据
kube-scheduler调度器负责将新建 Pod 分配到合适的 Node
kube-controller-manager控制器管理器执行各种控制逻辑,比如运行多个控制器(副本控制器(ReplicaSet)、节点控制器、Job控制器等)
cloud-controller-manager云控制器管理器,管理与云服务平台的集成(如负载均衡、存储卷等)

所有这些组件通常运行在 Master 节点上。在生产环境中,控制平面可以做高可用部署(即多个 Master 节点):

  • 保证 apiserver 的可用性(通过负载均衡)
  • 保证 etcd 的数据冗余与高一致性(通常部署 3 个及以上节点)
  • 避免单点故障,增强容灾能力

1.2.2 工作节点(Worker Node)

每个 Node 是实际运行容器的机器(虚拟机或物理机),其核心组件包括:

组件说明
kubelet负责与 apiserver 通信,接收任务并在本地启动 Pod
kube-proxy维护服务与 Pod 之间的网络规则,实现负载均衡
Container Runtime运行容器的实际引擎,如 Docker、containerd、CRI-O

1.2.3 云提供商APIs

Kubernetes可以通过云提供商APIs与云服务进行集成,例如负载均衡器、存储卷和身份认证等。这使得Kubernetes能够利用云平台提供的各种服务来增强其功能。

1.3 k8s和docker的关系?

k8s和docker的用途都含有容器管理,初学者一般都搞不清楚两者之间的关系。可以理解为:Docker 负责造车,Kubernetes 负责调度车队跑起来并保持秩序

名称定义
Docker是一个容器引擎,用于打包、分发和运行容器化应用。
Kubernetes是一个容器编排平台,用于自动化管理大量容器的部署、调度、伸缩和维护。

Docker 管理单个容器,Kubernetes 管理容器的集群;它们各司其职,共同构成了现代云原生应用的基石。

维度DockerKubernetes
类型容器运行时容器编排平台
是否依赖对方不依赖早期依赖 Docker,后期依赖 CRI 接口
管理粒度单个容器多个服务或容器组成的集群
适用场景开发、测试、单机部署企业级生产环境的集群部署

1.4 工作流程

  1. 开发者通过 kubectl 提交 YAML 清单到 apiserver。
  2. apiserver 验证请求,并将信息存储到 etcd。
  3. scheduler 监听到新 Pod 创建请求,并根据调度算法分配到合适的 Node。
  4. 对应 Node 上的 kubelet 接收到任务,调用 Container Runtime 启动容器。
  5. kube-proxy 设置好服务发现和访问规则,确保内部通信正常。

二、搭建 Kubernetes 环境

根据使用场景不同,k8s有三种搭建方式。三种搭建方式的优缺点如下:

搭建方式场景优点缺点
1. 使用 Minikube 或 kind学习和开发快速启动、资源占用少非真实生产环境
2. 使用 kubeadm 自建集群中小型生产环境或测试可控性强、接近生产配置复杂,需自行运维
3. 使用云厂商托管服务(如 ACK、GKE、EKS)生产简单可靠、高可用成本较高、依赖厂商

由于篇幅所限,本文只演示一下第一种搭建k8s环境的方式(以 macOS / Linux 为例):

2.1 安装 kubectl(Kubernetes 命令行工具)

curl -LO "https://dl.k8s.io/release/$(curl -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
chmod +x kubectl
sudo mv kubectl /usr/local/bin/
kubectl version --client

2.2 安装 Minikube

curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube

2.3 启动 Minikube 集群

minikube start

image.png

2.4 查看集群节点状态

kubectl get nodes

image.png

三、常用资源对象介绍

Kubernetes 中资源种类很多,常见的有:

类型说明
Pod最小部署单元
Deployment部署与版本控制
Service网络访问入口
ConfigMap / Secret配置和密钥
PersistentVolume / Claim存储
Namespace命名空间管理

3.1 Pod:最小部署单元

3.1.1 什么是Pod?

Pod 是 K8s 中最小的可调度单元。一个 Pod 包含一个或多个 容器(通常是 Docker 容器) ,这些容器共享:

  • 网络(IP 和端口空间)
  • 存储(Volume 卷)
  • 生命周期(被视为一个整体)

Pod 的典型用途是运行一个应用或服务的一个实例。一个 Pod 运行一个容器(最常见场景):

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
    - name: nginx
      image: nginx:1.24
      ports:
        - containerPort: 80

这个 Pod 会启动一个 Nginx 容器,并暴露 80 端口。

3.1.2 Pod 生命周期

Pod 的状态包括:

  • Pending: 等待调度资源
  • Running: 正在运行
  • Succeeded: 运行成功后退出
  • Failed: 运行失败
  • Unknown: 状态无法获取

3.1.3 Pod的创建,查看与删除

# 创建
kubectl apply -f nginx-pod.yaml
# 查看所有pod
kubectl get pods
# 查看某个pod
kubectl describe pod nginx-pod
# 删除
kubectl delete pod nginx-pod

上面给出的都是独立的pod的创建与管理方式,虽然你可以手动管理 Pod,但 更推荐使用 Deployment 控制器 ,创建Pod,自动管理 Pod 的副本数量、自愈能力和升级策略。

3.2 Deployment:无状态应用的部署控制器

Deployment 是 Kubernetes 中最常用的控制器之一,专门用于管理 无状态应用的生命周期。它确保你的 Pod 副本在集群中始终按预期运行,并具备以下功能:

  • 保证指定数量的 Pod 始终处于运行状态(副本控制)
  • 支持应用的滚动升级和回滚
  • 支持 declarative 式的配置和更新
  • 自动重建失败的 Pod(具备自愈能力)

3.2.1 典型 Deployment 示例

说明:

  • replicas: 设置运行的 Pod 数量为 3
  • selector: 用于匹配管理哪些 Pod
  • template: 定义 Pod 的内容(镜像、端口等)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:1.24
          ports:
            - containerPort: 80

3.2.2 Deployment 的工作逻辑

  • 寻找所有标签匹配 selector.matchLabels 的 Pod

image.png

  • 如果数量不足 replicas,则新建 Pod
  • 如果数量过多,则删除多余的 Pod
  • 如果标签相同但镜像等配置不同,则更新 Pod
  • Deployment 不直接控制 Pod,而是通过创建一个 ReplicaSet,再由 ReplicaSet 具体去创建 Pod,维护副本数量,做滚动更新。

3.2.3 Deployment操作命令

# 创建 Deployment
kubectl apply -f nginx-deploy.yaml
# 查看状态
kubectl get deployments
kubectl describe deployment nginx-deploy
# 查看管理的 Pod
kubectl get pods -l app=nginx

修改镜像并滚动升级,将nginx从1.24升级到1.25

spec:
  containers:
    - name: nginx
      image: nginx:1.25

# 升级
kubectl apply -f nginx-deploy.yaml
# 查看历史记录
kubectl rollout history deployment nginx-deploy
# 回滚
kubectl rollout undo deployment nginx-deploy

3.3 Service:服务发现与负载均衡

在 Kubernetes 中,Pod 是会变化的 —— 当 Deployment 滚动更新、Pod 重启时,Pod 的 IP 会变。所以不能依赖 Pod 的 IP 地址来通信。

这就是 Service 出场的原因,它为一组 Pod 提供了一个 稳定的网络访问入口,实现了:

  • 服务发现(Pod 动态变动也能找到)
  • 负载均衡(多个 Pod 间自动分流请求)

3.3.1 Service实例

实例:为 nginx Pod 暴露一个 Service

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx  # 匹配被管理的 Pod(Deployment 创建的)
  ports:
    - protocol: TCP
      port: 80          # Service 对外暴露的端口
      targetPort: 80    # Pod 内部容器监听的端口
  type: ClusterIP       # 集群内访问(默认)

常见 Service 类型:

类型说明
ClusterIP默认类型,仅在集群内部通过虚拟 IP 访问
NodePort将 Service 暴露在每个 Node 的某个端口,外部可以通过 IP:Port 访问
LoadBalancer云环境下自动创建外部负载均衡器(阿里云、AWS 等)
ExternalName把请求重定向到外部 DNS 域名

3.3.2 Service 如何做服务发现?

Kubernetes 内置 DNS 服务,会为每个 Service 分配一个 DNS 名称: 例如

http://nginx-service.default.svc.cluster.local

容器中的其他 Pod 只需用这个 DNS 名称就能访问 nginx 服务,完全不需要关心 Pod IP。

3.3.3 创建并访问 Service 示例

# 创建 Deployment
kubectl apply -f nginx-deployment.yaml

# 创建 Service
kubectl apply -f nginx-service.yaml

# 查看 Service IP 和端口:
kubectl get svc

# 在集群中访问 Service:
curl http://nginx-service

3.4 Ingress

在 Kubernetes 中,Ingress是一种 API 对象,用于管理外部用户如何通过 HTTP 或 HTTPS 访问集群内的服务(Service) 。简而言之,Ingress 提供了一种统一的方式,将域名或路径映射到集群中的服务上,并支持负载均衡、SSL 终端和基于路径/主机的路由。

3.4.1 为什么需要 Ingress?

在没有 Ingress 的情况下,集群外部访问服务只能通过:

  • NodePort:每个 Service 暴露一个端口,访问地址为 NodeIP:Port,难管理。
  • LoadBalancer:为每个服务申请一个云负载均衡器,成本高。
  • Port-forward / kubectl proxy:临时调试用,不适合生产。

而 Ingress 通过一个统一的入口,根据域名或路径来转发请求,成本低、配置灵活、可维护性强。Ingress 功能点如下:

功能说明
域名路由根据主机名将请求转发到不同服务
路径路由根据路径将请求转发到不同服务
HTTPS 支持可以配置证书,实现 TLS 终端
负载均衡多个 Pod 间自动负载均衡
支持重定向与重写可以配置 URL 重定向或路径重写
身份验证、限速等借助 Ingress Controller 插件可实现更高级功能

3.4.2 组成结构

Ingress 本身不直接处理请求,它依赖 Ingress Controller 来工作。常见 Ingress Controller:

Controller 类型说明
Nginx最流行的开源选择,支持多数功能
Traefik轻量级、高性能,支持微服务和自动发现
HAProxy高性能、企业级选择
Istio Gateway用于服务网格场景
AWS/GCP/ALB云平台原生负载均衡集成

下面这张图展示了 Ingress 在 Kubernetes 中进行流量转发的完整架构流程

  1. 用户访问 example.com/web

  2. Ingress 中定义了 /web 路径指向 my-web Service;

  3. Ingress Controller(如 nginx-ingress)读取 Ingress 规则;

  4. Ingress Controller 接收到请求后,将其转发给 my-web Service;

  5. Service 查找符合条件的 Pod(例如标签为 app=web);

  6. 请求最终到达 Pod,得到业务响应。

       +--------------+
       |   Internet   |
       +------+-------+
              |
      +-------v--------+
      | Ingress        |  ← 配置路由规则的资源
      | (定义规则)     |
      +-------+--------+
              |
     +--------v---------+
     | Ingress Controller| ← 实际负责转发流量
     | (如 Nginx, Traefik)|
     +--------+---------+
              |
        +-----v------+
        | Kubernetes |
        |  Services  |
        +-----+------+
              |
           +--v--+
           | Pod |
           +-----+
    

3.4.3 配置一个简单的 Ingress

Ingress 如何连接 Service? 假设你有一个名为 my-web 的 Service,监听端口为 80:

service.yaml

apiVersion: v1
kind: Service
metadata:
  name: my-web
spec:
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 8080

service.yaml对应的my-web-deployment.yaml配置如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-web
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: web
          image: nginx:1.24
          ports:
            - containerPort: 8080

这个 Service 将流量从端口 80 转发到选中 Pod 的 8080 端口。Ingress 配置如下:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
spec:
  rules:
    - host: example.com
      http:
        paths:
          - path: /web
            pathType: Prefix
            backend:
              service:
                name: my-web        # 指向 Service 的名字
                port:
                  number: 80        # 指向 Service 的 port 字段

当用户访问 http://example.com/web 时:

  1. 请求被 Ingress Controller 捕获;
  2. 根据 /web 路径匹配到规则;
  3. 将请求转发到 my-web Service;
  4. Service 根据 selector 找到对应的 Pod(如 app=web);
  5. 将请求转发给这些 Pod 的 targetPort: 8080

3.4.4 配置 HTTPS Ingress

通过如下命令创建了一个包含 TLS 证书的 Secret:这个 Secret 包含公钥证书(CRT)和私钥(KEY),名称为 tls-secret,位于 default 命名空间中.

kubectl create secret tls tls-secret \
  --cert=example.com.crt \
  --key=example.com.key \
  -n default

在Ingress 配置启用 HTTPS

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  tls:
    - hosts:
        - example.com
      secretName: tls-secret  # 指向我们预先创建的 TLS Secret

  rules:
    - host: example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-web
                port:
                  number: 80

效果验证:

  • 本地配置 DNS:

    echo "INGRESS_IP  example.com" | sudo tee -a /etc/hosts
    

    INGRESS_IP 是你的 Ingress Controller 的外网 IP 地址。

  • 浏览器访问:

    https://example.com/
    

若配置无误,将自动跳转并看到你部署的 nginx 页面。

3.5 ConfigMap 与 Secret

在 Kubernetes 中,ConfigMap 和 Secret 是用于配置管理的两种核心资源类型,它们用于将配置和敏感数据(如密码、API 密钥)与容器解耦,让你的应用部署更加灵活、安全。

特性ConfigMapSecret
用途存储普通配置(不敏感)存储敏感数据(如密码、Token)
数据是否加密❌ 否(明文)✅ 是(Base64 编码,适合加密传输)
可挂载到 Pod✅ 是✅ 是
使用方式环境变量、挂载为文件、命令行参数等环境变量、挂载为文件、命令行参数等
推荐用途配置文件、环境变量、命令参数等密码、证书、数据库密钥、Token 等

3.5.1 ConfigMap:存储非敏感配置

创建 ConfigMap 的方式

方法 1:使用 kubectl 命令行创建

kubectl create configmap my-config --from-literal=color=blue --from-literal=lang=zh

方法 2:使用 YAML 创建

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config
data:
  color: blue
  lang: zh
使用 ConfigMap 的方式

方法 1:作为环境变量注入容器

env:
  - name: COLOR
    valueFrom:
      configMapKeyRef:
        name: my-config
        key: color

方法 2:挂载为文件

volumeMounts:
  - name: config-volume
    mountPath: /etc/config
volumes:
  - name: config-volume
    configMap:
      name: my-config

3.5.2 Secret:存储敏感配置

Secret 的数据会以 Base64 编码存储(可以结合加密存储后端实现更高安全性)。

创建 Secret 的方式

方法 1:命令行直接创建

kubectl create secret generic my-secret --from-literal=password=123456

方法 2:YAML 文件创建(注意 Base64 编码)

apiVersion: v1
kind: Secret
metadata:
  name: my-secret
type: Opaque
data:
  password: MTIzNDU2  # Base64 编码后的 "123456"

可以用如下命令手动编码:

echo -n "123456" | base64
使用 Secret 的方式

方法 1:作为环境变量注入

env:
  - name: DB_PASSWORD
    valueFrom:
      secretKeyRef:
        name: my-secret
        key: password

方法 2:挂载为文件

volumeMounts:
  - name: secret-volume
    mountPath: /etc/secret
volumes:
  - name: secret-volume
    secret:
      secretName: my-secret

3.6 PersistentVolumeClaim

PersistentVolumeClaim(PVC) 是一种资源对象,用于申请持久化存储空间(PersistentVolume,PV) 。简单来说,它是 Pod 与底层存储之间的桥梁,用户通过 PVC 来请求磁盘,而不是直接绑定硬盘资源。

3.6.1 什么是 PersistentVolume 与 PersistentVolumeClaim?

  • PersistentVolume(PV) :由管理员创建或自动创建的存储资源,类似“硬盘”。
  • PersistentVolumeClaim(PVC) :用户申请使用 PV 的方式,类似“租用硬盘”。

🧩 类比理解:

  • PV = 房东提供的房子
  • PVC = 租客发出的租房申请
  • Kubernetes 匹配 PVC 与 PV,实现租房动作

为什么需要 PVC?在容器运行时,容器内的数据是临时的(临时存储) ,容器重启或迁移后会丢失。如果需要保存数据库、文件上传等数据,就必须使用 PVC 来绑定到稳定的硬盘。

3.6.2 PVC 使用流程

  • 管理员配置 StorageClass 或 PV
  • 开发者在 Pod 中声明 PVC
  • 系统自动匹配合适的 PV 给 PVC
  • Pod 使用 PVC 提供的存储挂载路径

3.6.3 PVC 使用示例

Step1:定义 PVC

申请一个 1Gi 的存储空间

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce      # 只允许一个 Pod 挂载读写
  resources:
    requests:
      storage: 1Gi        # 请求 1Gi 存储空间

访问模式说明:

模式说明
ReadWriteOnce只能被单个 Node 上的一个 Pod 读写(最常用)
ReadOnlyMany多个 Pod 可读,但不可写
ReadWriteMany多个 Pod 可读写(需特定存储支持,如 NFS)
Step 2:Pod 中使用 PVC
apiVersion: v1
kind: Pod
metadata:
  name: nginx-with-pvc
spec:
  containers:
    - name: nginx
      image: nginx
      volumeMounts:
        - mountPath: "/usr/share/nginx/html"
          name: web-data
  volumes:
    - name: web-data
      persistentVolumeClaim:
        claimName: my-pvc

这样,Pod 就能把 /usr/share/nginx/html 目录的数据存储到持久化卷中。也可以用 PVC 搭配 StorageClass,让 K8s 自动向云厂商(如 AWS、GCP)动态创建磁盘资源,无需管理员手动创建 PV。

3.7 Namespace

Namespace(命名空间) 是一种用于对集群中的资源进行逻辑隔离和分组管理的机制。可以把它理解为集群中的「虚拟子集群」,用于将资源划分为多个相互独立的空间。并非所有的资源都可以用命名空间进行隔离。

特性是否作用于 Namespace
Pod、Service✅ 是,属于某个命名空间
Node、PV❌ 否,全局资源
Role、Quota✅ 是,作用于指定命名空间
ClusterRole❌ 否,作用于全集群

顺便说一下Node和Pod的区别:

类目Node(节点)Pod
定义集群中的一台工作机器(物理机或虚拟机)Kubernetes 中可调度的最小计算单元(通常是一个或多个容器)
层级关系Node 是运行 Pod 的宿主机Pod 运行在 Node 上
数量集群中通常只有少数几个 Node(如3个、5个)可以调度成千上万个 Pod
作用提供计算资源(CPU、内存、网络)封装应用容器及其运行环境
组成部分kubelet、kube-proxy、容器运行时(如 containerd)一个或多个容器、共享网络和存储卷

通俗理解Node 是宿舍楼,里面住着多个 Pod(宿舍间) 一个 Node 可以运行多个 Pod,但 Pod 不能脱离 Node 独立存在。

3.7.1 Namespace 有什么用?

1. 资源隔离
  • 每个 Namespace 里的资源彼此隔离,互不干扰。
  • 比如你在 devprod 中分别部署了两个 nginx,它们不会冲突,因为在各自的命名空间中是唯一的。
2. 权限控制(RBAC)

可以基于 Namespace 分配不同的权限,比如:

  • 张三 只能管理 dev 命名空间;
  • 李四 只能查看 prod 命名

便于企业多团队协作时的权限边界管理。

3. 资源配额限制(ResourceQuota)

可以为不同 Namespace 设置资源配额限制,比如:

  • dev Namespace 最多使用 4 个 CPU、8G 内存;
  • prod Namespace 可以使用更多资源;

这样可以避免某个项目“吃光”整个集群资源。

4. 便于环境分离

常见实践:按环境划分 Namespace:

  • dev:开发环境
  • test:测试环境
  • prod:生产环境

在一个集群中部署多套系统而互不干扰。此外Kubernetes 默认提供了几个内置命名空间:

命名空间用途
default默认命名空间,用户不指定时资源会创建在这里
kube-systemKubernetes 系统组件运行的地方(如 kube-dns)
kube-public所有人都可访问,主要用于公开信息
kube-node-lease节点状态心跳相关

3.7.2 创建命名空间并部署资源示例

# 创建命名空间
kubectl create namespace dev

# 在 dev 命名空间部署 nginx
kubectl run nginx --image=nginx -n dev

# 查看 dev 命名空间下的 Pod
kubectl get pods -n dev

命名空间的逻辑隔离:

+------------------------+
|     Kubernetes 集群     |
|                        |
| +--------+  +--------+ |
| | dev    |  | prod   | |
| |        |  |        | |
| | nginx  |  | nginx  | |
| | redis  |  | mysql  | |
| +--------+  +--------+ |
+------------------------+

3.8 RBAC

RBAC(基于角色的访问控制,Role-Based Access Control) 是一种权限管理机制,用来控制谁可以对哪些资源执行哪些操作。RBAC 就像公司中的权限系统:不同的岗位(角色)有不同的权限,不同的员工(用户)只能做他们被授权的事情。

3.8.1 RBAC 的核心组件

RBAC 一共由 4 个关键对象组成:

对象说明
Role定义在某个 Namespace 中能进行哪些操作(比如:可以查看 Pod)
ClusterRole类似 Role,但作用于所有命名空间或集群级资源(如节点、存储等)
RoleBinding将 Role 绑定到具体用户、组或 ServiceAccount(限某命名空间)
ClusterRoleBinding将 ClusterRole 绑定到用户、组或服务账号(全局作用)

常见的操作:

动作含义
get获取资源
list列出资源列表
watch监听资源变化
create创建资源
update更新资源
delete删除资源

3.8.2 创建一个只读角色

创建 Role:只能查看 Pod 和 Service

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: pod-reader
  namespace: dev
rules:
  - apiGroups: [""]
    resources: ["pods", "services"]
    verbs: ["get", "list", "watch"]

创建 RoleBinding:把这个权限绑定给某个用户

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

表示:用户 alicedev 命名空间内,可以读取 Pod 和 Service,但不能创建、删除、修改。

常用命令:

# 查看所有 ClusterRole
kubectl get clusterroles

# 查看绑定关系
kubectl get rolebindings -n dev

# 授予某用户集群管理员权限(示例)
kubectl create clusterrolebinding admin-binding \
  --clusterrole=cluster-admin \
  --user=alice@example.com

3.9 CronJob

CronJob 是用来按计划周期性运行任务的资源类型,类似于 Linux 中的 crontab。它适用于那些需要定时执行的任务,例如数据库备份、定期数据清理、定时邮件发送等。

配置字段说明:

名称说明
CronJob按时间调度,周期性运行任务
JobCronJob 每次触发都会生成一个 Job,它是一次性任务
PodJob 创建的 Pod 执行任务脚本
restartPolicy通常设置为 OnFailure,失败时重试
suspend可设为 true 暂停 CronJob 执行

示例:每天午夜运行一次任务

apiVersion: batch/v1
kind: CronJob
metadata:
  name: hello-cronjob
spec:
  schedule: "0 0 * * *"  # crontab 格式:每天0点
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: hello
              image: busybox
              args:
                - /bin/sh
                - -c
                - echo "Hello from CronJob at $(date)"
          restartPolicy: OnFailure

schedule 使用的是类 Unix 的 cron 表达式,格式如下:

分 时 日 月 星期
示例含义
*/5 * * * *每 5 分钟执行一次
0 0 * * *每天午夜 0 点执行
0 9 * * 1每周一早上 9 点执行

CronJob 的执行过程:

时间触发器 (schedule)
        ↓
   +-----------+
   |  CronJob  | ← 负责按照 schedule 触发 Job
   +-----------+
        ↓
   +-----------+
   |   Job     | ← 一次性任务(控制器)
   +-----------+
        ↓
   +-----------+
   |   Pod     | ← 实际执行任务的容器
   +-----------+

常用命令:

# 获取集群中所有CronJob资源的列表
kubectl get cronjob
# 查看名为 hello-cronjob 的 CronJob 资源的详细信息
kubectl describe cronjob hello-cronjob
# 列出所有的 Job 资源
kubectl get jobs
# 查看与指定 Job 相关的 Pod 的日志
kubectl logs <job-created-pod-name>

四、自动伸缩(HPA)

HPA(Horizontal Pod Autoscaler,水平 Pod 自动扩缩容) 是一个控制器,它会根据CPU、内存或自定义指标,自动调整 Pod 的副本数量,确保应用在不同负载情况下都能平稳运行。

4.1 HPA 的工作原理

  • HPA 监测目标 Pod 资源使用情况(默认监测 CPU)。
  • 如果 CPU 或其他指标高于设定阈值,就自动增加 Pod 副本数。
  • 如果 CPU 或其他指标低于设定阈值,就自动减少 Pod 副本数。

4.2 如何使用 HPA?

4.2.1 确保 Metrics Server 已安装

HPA 需要 metrics-server 提供 Pod 资源使用数据。可以使用以下命令检查:

kubectl get apiservices | grep metrics

如果 metrics.k8s.io 没有运行,需要安装:

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

4.2.2 创建一个 Deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: php-apache
spec:
  replicas: 1
  selector:
    matchLabels:
      app: php-apache
  template:
    metadata:
      labels:
        app: php-apache
    spec:
      containers:
        - name: php-apache
          image: k8s.gcr.io/hpa-example
          ports:
            - containerPort: 80
          resources:
            requests:
              cpu: 200m
            limits:
              cpu: 500m

注意:HPA 需要 resources.requests.cpu 进行判断,因此 Pod 必须指定 cpu requests 值,否则 HPA 不会生效。

4.2.3 创建 HPA 规则(基于 CPU 自动扩缩)

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: php-apache   # 关联的 Deployment
  minReplicas: 1        # 最少 1 个副本
  maxReplicas: 10       # 最多 10 个副本
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 50  # CPU 使用率超过 50% 时扩容

4.2.4 应用与查看 HPA 规则

kubectl apply -f hpa.yaml
kubectl get hpa

示例输出:

NAME            REFERENCE            TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
php-apache-hpa  Deployment/php-apache  60%/50%  1         10        3         5m
  • TARGETS 60%/50%:当前 CPU 使用率 60%,HPA 目标是 50%。
  • REPLICAS 3:HPA 自动扩展了 3 个 Pod。

4.2.5 模拟高负载(测试 HPA)

可以使用 busybox 持续压测 Pod 的 CPU:

kubectl run -i --tty busybox --image=busybox -- sh
# 在 BusyBox 终端里执行
while true; do wget -q -O- http://php-apache; done

观察 HPA 变化:

kubectl get hpa -w

4.2.6 进阶-基于自定义指标扩缩容

HPA 也可以基于内存使用量Prometheus 自定义指标进行扩缩容,例如:

metrics:
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 70  # 当内存使用率超过 70% 时扩容

或者基于 Prometheus 监控指标 进行扩容:

metrics:
  - type: External
    external:
      metric:
        name: requests_per_second 
      target:
        type: AverageValue
        averageValue: 1000 # 每秒请求超过1000次扩容

4.3 怎么解决资源不足问题?

HPA 扩展的 Pod 所需的硬件资源,来自集群中已有的 Node(节点)资源池。如果 Node上没有足够资源容纳新的 Pod,Pod 会处于 Pending 状态,直到有资源调度。举例说明:

  1. 集群中有 3 个 Node,每个 Node 有 2 核 CPU 和 4G 内存。
  2. 每个 Pod 要求 cpu: 500m
  3. 初始状态运行了 6 个 Pod,正好占满资源(理论上最多能运行 12 个 Pod,但我们说6 个 Pod 就占满资源,是因为现实中不能这么理想化计算,系统组件也占资源,再预留一些 buffer 来应对波动、调度策略等,6~8 个 Pod 就可能接近极限了)。
  4. 负载升高,HPA 触发扩容为 8 个 Pod。

结果:新创建的 2 个 Pod 会 Pending(等待) ,因为没有 Node 有足够资源运行它们。

怎么解决资源不足问题?有两种方式:

4.3.1 手动添加节点(扩容集群)

如果你使用的是物理机或虚拟机搭建的集群,可以手动加入更多 Node。

# 添加新节点后,kubelet 会将其注册进集群
kubectl get nodes

4.3.2 使用 Cluster Autoscaler(集群自动扩容)

Cluster Autoscaler 是 Kubernetes 官方提供的自动添加/移除 Node 的组件

  • 当 Pod 无法调度时,Cluster Autoscaler 会自动向云服务申请添加 Node。
  • 当某些 Node 上没有运行任何 Pod 并维持一段时间,自动释放这些 Node。

支持的云平台:

  • GKE(Google)
  • EKS(AWS)
  • AKS(Azure)
  • 阿里云、腾讯云等也有类似组件

4.3.3 最佳方案

最佳实践:HPA + Cluster Autoscaler 联用 是生产环境最常见做法:

  • HPA 根据 CPU/内存/自定义指标自动调整 Pod 数量。
  • 如果资源不足,Cluster Autoscaler 自动申请节点,保障 Pod 正常运行。
类别HPACluster Autoscaler
控制对象Pod 副本数量Node 数量(硬件资源)
是否自动是(需配置)
是否立即生效快速云平台资源申请略慢
解决问题应对应用层负载变化应对物理资源不足

结语

肚子有点饿,今天先写到这里,下篇明天再续写。