前言
最近在采用Jenkins实现前端项目自动化部署功能,其中有一个步骤用到了k8s, 这一块知识令我感到比较陌生,看不懂配置文件里的语句含义,以及如何被外部的bash指令串联起来,刚好假期有时间,决定学习一下k8s。学完目标是学完之后要了解k8s常用的操作。现在我们进入今天的主题:
一、Kubernetes 简介
Kubernetes(简称 K8s)是一个用于自动部署、扩展和管理容器化应用程序的开源系统。下图展示了Kubernetes集群的架构及其与外部系统的交互方式:
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-apiserver | Kubernetes 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 管理容器的集群;它们各司其职,共同构成了现代云原生应用的基石。
| 维度 | Docker | Kubernetes |
|---|---|---|
| 类型 | 容器运行时 | 容器编排平台 |
| 是否依赖对方 | 不依赖 | 早期依赖 Docker,后期依赖 CRI 接口 |
| 管理粒度 | 单个容器 | 多个服务或容器组成的集群 |
| 适用场景 | 开发、测试、单机部署 | 企业级生产环境的集群部署 |
1.4 工作流程
- 开发者通过 kubectl 提交 YAML 清单到 apiserver。
- apiserver 验证请求,并将信息存储到 etcd。
- scheduler 监听到新 Pod 创建请求,并根据调度算法分配到合适的 Node。
- 对应 Node 上的 kubelet 接收到任务,调用 Container Runtime 启动容器。
- 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
2.4 查看集群节点状态
kubectl get nodes
三、常用资源对象介绍
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 数量为 3selector: 用于匹配管理哪些 Podtemplate: 定义 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
- 如果数量不足
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 中进行流量转发的完整架构流程
-
用户访问
example.com/web; -
Ingress 中定义了
/web路径指向my-webService; -
Ingress Controller(如 nginx-ingress)读取 Ingress 规则;
-
Ingress Controller 接收到请求后,将其转发给
my-webService; -
Service 查找符合条件的 Pod(例如标签为
app=web); -
请求最终到达 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时:
- 请求被 Ingress Controller 捕获;
- 根据
/web路径匹配到规则;- 将请求转发到
my-webService;- Service 根据 selector 找到对应的 Pod(如
app=web);- 将请求转发给这些 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/hostsINGRESS_IP是你的 Ingress Controller 的外网 IP 地址。 -
浏览器访问:
https://example.com/
若配置无误,将自动跳转并看到你部署的 nginx 页面。
3.5 ConfigMap 与 Secret
在 Kubernetes 中,ConfigMap 和 Secret 是用于配置管理的两种核心资源类型,它们用于将配置和敏感数据(如密码、API 密钥)与容器解耦,让你的应用部署更加灵活、安全。
| 特性 | ConfigMap | Secret |
|---|---|---|
| 用途 | 存储普通配置(不敏感) | 存储敏感数据(如密码、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 里的资源彼此隔离,互不干扰。
- 比如你在
dev和prod中分别部署了两个nginx,它们不会冲突,因为在各自的命名空间中是唯一的。
2. 权限控制(RBAC)
可以基于 Namespace 分配不同的权限,比如:
张三只能管理dev命名空间;李四只能查看prod命名
便于企业多团队协作时的权限边界管理。
3. 资源配额限制(ResourceQuota)
可以为不同 Namespace 设置资源配额限制,比如:
devNamespace 最多使用 4 个 CPU、8G 内存;prodNamespace 可以使用更多资源;
这样可以避免某个项目“吃光”整个集群资源。
4. 便于环境分离
常见实践:按环境划分 Namespace:
dev:开发环境test:测试环境prod:生产环境
在一个集群中部署多套系统而互不干扰。此外Kubernetes 默认提供了几个内置命名空间:
| 命名空间 | 用途 |
|---|---|
default | 默认命名空间,用户不指定时资源会创建在这里 |
kube-system | Kubernetes 系统组件运行的地方(如 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
表示:用户 alice 在 dev 命名空间内,可以读取 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 | 按时间调度,周期性运行任务 |
Job | CronJob 每次触发都会生成一个 Job,它是一次性任务 |
Pod | Job 创建的 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 状态,直到有资源调度。举例说明:
- 集群中有 3 个 Node,每个 Node 有 2 核 CPU 和 4G 内存。
- 每个 Pod 要求
cpu: 500m。 - 初始状态运行了 6 个 Pod,正好占满资源(理论上最多能运行 12 个 Pod,但我们说6 个 Pod 就占满资源,是因为现实中不能这么理想化计算,系统组件也占资源,再预留一些 buffer 来应对波动、调度策略等,6~8 个 Pod 就可能接近极限了)。
- 负载升高,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 正常运行。
| 类别 | HPA | Cluster Autoscaler |
|---|---|---|
| 控制对象 | Pod 副本数量 | Node 数量(硬件资源) |
| 是否自动 | 是 | 是(需配置) |
| 是否立即生效 | 快速 | 云平台资源申请略慢 |
| 解决问题 | 应对应用层负载变化 | 应对物理资源不足 |
结语
肚子有点饿,今天先写到这里,下篇明天再续写。