Kubernetes-03 核心概念详解
Kubernetes 核心概念详解
系列第三篇。深入理解 K8s 的基本构建块,这些概念贯穿所有后续章节。
目录
1. Pod
Pod 是 K8s 中最小的可部署单元。
1.1 Pod 是什么
Pod 不是容器,而是一个或多个容器的集合,这些容器共享:
- 网络命名空间:同一个 Pod 中的容器共享 IP 和 Port,通过
localhost互相通信 - 存储卷(Volume):可以挂载相同的 Volume,实现数据共享
- Linux namespace 的部分:PID namespace(可配置)、IPC namespace
┌─────────────────────────────────────┐
│ Pod │
│ ┌──────────────┐ ┌─────────────┐ │
│ │ Container A │ │ Container B │ │
│ │ (主应用) │ │ (sidecar) │ │
│ └──────────────┘ └─────────────┘ │
│ │
│ 共享:IP(10.1.2.3) / Port / Volume │
│ │
│ ┌──────────────────────────────┐ │
│ │ Volume │ │
│ └──────────────────────────────┘ │
└─────────────────────────────────────┘
1.2 为什么是 Pod 而不是容器
这是 K8s 的核心设计决策。考虑这个场景:
Nginx + PHP-FPM:Nginx 把请求代理给 PHP-FPM,它们需要共享同一个 socket 文件。把它们放在同一个 Pod 中,通过共享 Volume 实现通信,比在不同容器间建立网络连接更高效。
主应用 + 日志 Agent:主容器写日志到共享 Volume,sidecar 容器读取并上报到日志系统,它们的生命周期一致,一起被调度、一起被销毁。
1.3 Pod 的生命周期
Pending → 已创建,等待调度或镜像拉取
Running → 至少一个容器在运行
Succeeded → 所有容器正常退出(exit 0)
Failed → 至少一个容器非正常退出
Unknown → 无法获取 Pod 状态(通常是 Node 失联)
容器状态:
Waiting → 等待某些条件(拉取镜像、等待 ConfigMap)
Running → 正在运行
Terminated → 已退出(exit code 可能为 0 或非 0)
重启策略(restartPolicy):
spec:
restartPolicy: Always # 默认,容器退出后总是重启(Deployment 使用)
# restartPolicy: OnFailure # 只有非 0 退出才重启(Job 使用)
# restartPolicy: Never # 不重启
1.4 完整 Pod YAML 示例
apiVersion: v1
kind: Pod
metadata:
name: go-app-pod
namespace: default
labels:
app: go-app
version: v1.2.0
env: production
annotations:
description: "Go HTTP 服务示例"
prometheus.io/scrape: "true"
prometheus.io/port: "9090"
spec:
# 调度到有 disktype=ssd 标签的节点
nodeSelector:
disktype: ssd
# 镜像拉取密钥(私有仓库需要)
imagePullSecrets:
- name: registry-secret
containers:
- name: go-app
image: myregistry.io/go-app:v1.2.0
imagePullPolicy: IfNotPresent # Always | IfNotPresent | Never
ports:
- name: http
containerPort: 8080
protocol: TCP
- name: metrics
containerPort: 9090
env:
- name: APP_ENV
value: "production"
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name # 注入 Pod 自身信息(Downward API)
- name: POD_IP
valueFrom:
fieldRef:
fieldPath: status.podIP
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
volumeMounts:
- name: config-volume
mountPath: /etc/config
readOnly: true
- name: data-volume
mountPath: /data
# 安全上下文(最小权限原则)
securityContext:
runAsNonRoot: true
runAsUser: 1000
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
volumes:
- name: config-volume
configMap:
name: go-app-config
- name: data-volume
emptyDir: {}
# Pod 级别安全上下文
securityContext:
fsGroup: 2000
1.5 Pod 常用调试命令
# 查看 Pod 列表
kubectl get pods
kubectl get pods -o wide # 显示 IP 和节点
kubectl get pods --sort-by='.status.startTime' # 按启动时间排序
# 查看详情(重点看 Events 部分)
kubectl describe pod <pod-name>
# 查看日志
kubectl logs <pod-name>
kubectl logs <pod-name> -c <container-name> # 多容器时指定容器
kubectl logs <pod-name> --previous # 查看上次崩溃的日志
# 进入容器调试
kubectl exec -it <pod-name> -- bash
kubectl exec -it <pod-name> -c <container-name> -- sh # 指定容器
# 临时调试容器(不修改原 Pod)
kubectl debug <pod-name> -it --image=busybox --target=<container-name>
# 复制文件
kubectl cp <pod-name>:/path/to/file ./local-file
kubectl cp ./local-file <pod-name>:/path/to/file
# 端口转发
kubectl port-forward pod/<pod-name> 8080:8080
2. Namespace
Namespace(命名空间)是 K8s 中逻辑隔离的机制,用于将一个集群划分为多个虚拟集群。
2.1 Namespace 的作用
- 资源隔离:不同 Namespace 的资源互不干扰(名字可以相同)
- 访问控制:RBAC 可以限制用户只能访问特定 Namespace
- 资源配额:通过 ResourceQuota 限制 Namespace 的资源使用量
- 多租户:一个集群为多个团队或环境(dev/staging/prod)服务
2.2 K8s 默认 Namespace
kubectl get namespaces
| Namespace | 用途 |
|---|---|
default |
未指定 Namespace 时的默认命名空间 |
kube-system |
K8s 系统组件(DNS、Dashboard 等) |
kube-public |
所有用户可读(包括未认证用户) |
kube-node-lease |
节点心跳续约,提升节点故障检测效率 |
2.3 创建和管理 Namespace
apiVersion: v1
kind: Namespace
metadata:
name: team-alpha
labels:
team: alpha
env: production
# 创建
kubectl create namespace team-alpha
# 或
kubectl apply -f namespace.yaml
# 在指定 Namespace 下操作
kubectl get pods -n team-alpha
kubectl apply -f pod.yaml -n team-alpha
# 设置当前上下文的默认 Namespace
kubectl config set-context --current --namespace=team-alpha
# 查看所有 Namespace 的 Pod
kubectl get pods --all-namespaces
kubectl get pods -A # 简写
2.4 ResourceQuota(资源配额)
限制 Namespace 内的资源总量:
apiVersion: v1
kind: ResourceQuota
metadata:
name: team-alpha-quota
namespace: team-alpha
spec:
hard:
# 计算资源
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
# 对象数量
pods: "20"
services: "10"
persistentvolumeclaims: "5"
secrets: "20"
configmaps: "20"
# 查看配额使用情况
kubectl describe resourcequota -n team-alpha
2.5 LimitRange(默认资源限制)
为 Namespace 中的 Pod/Container 设置默认资源:
apiVersion: v1
kind: LimitRange
metadata:
name: default-limits
namespace: team-alpha
spec:
limits:
- type: Container
default: # 未指定 limits 时的默认值
cpu: "200m"
memory: "256Mi"
defaultRequest: # 未指定 requests 时的默认值
cpu: "100m"
memory: "128Mi"
max: # 允许的最大值
cpu: "2"
memory: "2Gi"
min: # 允许的最小值
cpu: "50m"
memory: "64Mi"
2.6 哪些资源是 Namespace 级别的
Namespace 级别(有命名空间隔离):
- Pod、Deployment、StatefulSet、DaemonSet
- Service、Ingress
- ConfigMap、Secret
- PersistentVolumeClaim
- ServiceAccount、Role、RoleBinding
集群级别(无命名空间隔离):
- Node
- PersistentVolume(PV)
- StorageClass
- ClusterRole、ClusterRoleBinding
- Namespace 本身
3. Label 与 Selector
Label(标签)是附加在 K8s 资源上的键值对,用于标识和组织资源。Selector(选择器)用于根据 Label 过滤资源。
3.1 Label 的规则
metadata:
labels:
app: nginx # 应用名
version: "1.2.0" # 版本(值加引号避免被解析为数字)
env: production # 环境
tier: frontend # 层级
team: platform # 所属团队
release: stable # 发布通道
键名格式: [prefix/]name
- prefix 是可选的 DNS 子域名(如
app.kubernetes.io) - name 部分最长 63 字符,可以包含字母、数字、
-、_、.
K8s 推荐的标准标签(Recommended Labels):
labels:
app.kubernetes.io/name: mysql
app.kubernetes.io/instance: mysql-prod
app.kubernetes.io/version: "8.0"
app.kubernetes.io/component: database
app.kubernetes.io/part-of: my-app
app.kubernetes.io/managed-by: helm
3.2 kubectl 中使用 Label
# 查看 Label
kubectl get pods --show-labels
# 通过 Label 过滤
kubectl get pods -l app=nginx
kubectl get pods -l 'app=nginx,env=production'
kubectl get pods -l 'env in (staging, production)'
kubectl get pods -l 'app!=redis'
kubectl get pods -l '!deprecated' # 不含某个 key
# 添加 Label
kubectl label pod nginx-pod version=v2
# 修改 Label
kubectl label pod nginx-pod version=v3 --overwrite
# 删除 Label(key 后面加 -)
kubectl label pod nginx-pod version-
3.3 Selector 类型
等式型(Equality-based):
selector:
matchLabels:
app: nginx
env: production
集合型(Set-based,更灵活):
selector:
matchExpressions:
- key: app
operator: In
values: [nginx, apache]
- key: env
operator: NotIn
values: [development]
- key: tier
operator: Exists # 只检查 key 是否存在
- key: deprecated
operator: DoesNotExist
3.4 Label 的重要应用场景
Service → Pod 的流量路由:
# Service 通过 selector 选择后端 Pod
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx # 将流量路由到所有 app=nginx 的 Pod
ports:
- port: 80
targetPort: 8080
Deployment 管理 Pod:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx # Deployment 管理所有 app=nginx 的 Pod
template:
metadata:
labels:
app: nginx # Pod 的 Label,必须匹配 selector
spec:
containers:
- name: nginx
image: nginx:alpine
节点选择(nodeSelector):
# 给节点打标签
kubectl label node node-1 disktype=ssd gpu=true
spec:
nodeSelector:
disktype: ssd # 只调度到有此标签的节点
4. Annotation
Annotation(注解)也是键值对,但与 Label 不同:
- Label:用于选择和过滤,key/value 有格式限制
- Annotation:用于存储非标识性的元数据,value 可以是任意字符串(包括 JSON/YAML)
metadata:
annotations:
# 文档信息
description: "This is my Go web service"
owner: "platform-team@company.com"
documentation: "https://wiki.company.com/go-app"
# 部署信息
deployment.kubernetes.io/revision: "3"
kubernetes.io/change-cause: "Update image to v1.2.0"
# Prometheus 监控配置
prometheus.io/scrape: "true"
prometheus.io/port: "9090"
prometheus.io/path: "/metrics"
# Ingress 配置
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/proxy-body-size: "10m"
# 大型数据(如 kubectl apply 使用的 last-applied-configuration)
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"Pod",...}
实用场景:
- 存储 kubectl apply 的配置(
kubectl.kubernetes.io/last-applied-configuration) - 记录变更原因(
kubernetes.io/change-cause) - 工具集成配置(Prometheus、Istio、Ingress Controller 等通过 Annotation 读取配置)
- 自动化脚本的元数据
5. Node
Node 是 K8s 集群中的工作机器(物理机或虚拟机)。
5.1 查看节点信息
kubectl get nodes
kubectl get nodes -o wide # 显示更多信息
kubectl describe node <node-name>
describe 输出包含:
- 节点标签和 Annotation
- 系统信息(OS、内核版本、容器运行时)
- 资源容量(Capacity) vs 可分配量(Allocatable)
- 节点条件(Ready/MemoryPressure/DiskPressure 等)
- Pods(运行在该节点的所有 Pod)
- Allocated resources(已分配的资源汇总)
- Events
5.2 节点条件
Ready = True → 节点健康,可以调度 Pod
MemoryPressure = True → 内存不足
DiskPressure = True → 磁盘空间不足
PIDPressure = True → 进程数量接近上限
NetworkUnavailable = True → 网络配置异常
5.3 节点标签
K8s 为节点自动添加一些标签:
kubernetes.io/hostname=node-1
kubernetes.io/os=linux
kubernetes.io/arch=amd64
node.kubernetes.io/instance-type=m5.large # 云环境
topology.kubernetes.io/zone=us-east-1a # 可用区
topology.kubernetes.io/region=us-east-1 # 区域
5.4 节点维护:Cordon & Drain
# 停止调度新 Pod 到该节点(但不影响现有 Pod)
kubectl cordon node-1
# 驱逐节点上所有 Pod,并停止调度(用于维护前)
kubectl drain node-1 --ignore-daemonsets --delete-emptydir-data
# 维护完成后,恢复调度
kubectl uncordon node-1
6. 资源请求与限制
理解 requests 和 limits 是 K8s 资源管理的关键。
6.1 概念
resources:
requests: # 调度时的保证量(Scheduler 根据此值选择 Node)
cpu: "100m"
memory: "128Mi"
limits: # 运行时的上限(超出会被限速/OOMKilled)
cpu: "500m"
memory: "512Mi"
CPU:
1= 1 个 CPU 核心100m= 0.1 CPU(m = millicores,毫核)- CPU 超出 limits 时:被限速(throttled),不会被杀死
Memory:
Mi= Mebibytes(1Mi = 1024Ki)M= Megabytes(1M = 1000Ki)- 内存超出 limits 时:容器被 OOMKilled(Out Of Memory)
6.2 QoS 类别
K8s 根据 requests/limits 自动为 Pod 分配 QoS(Quality of Service)类别:
| QoS 类别 | 条件 | 含义 |
|---|---|---|
| Guaranteed | requests == limits(CPU 和 Memory 都设置且相等) | 最高优先级,Node 内存不足时最后被驱逐 |
| Burstable | requests < limits 或只设置了部分 | 中等优先级 |
| BestEffort | 没有设置任何 requests 和 limits | 最低优先级,最先被驱逐 |
# 查看 Pod 的 QoS
kubectl get pod <name> -o jsonpath='{.status.qosClass}'
生产建议:
- 生产环境核心服务:设置 Guaranteed(requests == limits)
- 开发/测试环境:可以使用 Burstable
- 永远不要使用 BestEffort(在生产中)
6.3 CPU 单位详解
# 这三种写法等价
cpu: "0.5"
cpu: "500m"
cpu: 0.5
# Node 有 4 个 CPU 核心,可以运行:
# 40 个 requests.cpu=100m 的容器
# 8 个 requests.cpu=500m 的容器
7. Init Container
Init Container(初始化容器)在主容器启动之前运行,且必须运行成功主容器才会启动。
7.1 使用场景
- 等待依赖服务就绪(等待数据库、等待某个服务启动)
- 下载配置文件或初始化数据
- 执行数据库迁移(配合主容器镜像中的 migrate 工具)
- 设置权限(修改 Volume 的文件权限)
7.2 示例
spec:
# Init Container:等待数据库就绪
initContainers:
- name: wait-for-db
image: busybox:1.36
command:
- sh
- -c
- |
until nc -z postgres-service 5432; do
echo "Waiting for database..."
sleep 2
done
echo "Database is ready!"
# Init Container:运行数据库迁移
- name: db-migrate
image: myapp:v1.0
command: ["/app/migrate", "--up"]
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-secret
key: url
# 主容器(Init Container 全部成功后才启动)
containers:
- name: go-app
image: myapp:v1.0
command: ["/app/server"]
注意:
- Init Container 顺序执行(一个完成后下一个才开始)
- Init Container 和主容器共享 Volume,但不共享端口
- Init Container 重启策略与主容器相同
8. Sidecar Container
Sidecar 是与主容器运行在同一 Pod 中的辅助容器,增强主容器的功能而不修改主容器代码。
8.1 常见 Sidecar 模式
日志采集(Log Agent):
spec:
containers:
- name: go-app
image: go-app:v1
volumeMounts:
- name: log-volume
mountPath: /var/log/app
- name: log-agent
image: fluent-bit:latest
volumeMounts:
- name: log-volume
mountPath: /var/log/app
readOnly: true
env:
- name: LOKI_URL
value: "http://loki:3100"
volumes:
- name: log-volume
emptyDir: {}
服务网格代理(Istio Envoy):
Istio 会自动注入 Envoy sidecar,实现流量管理、mTLS、可观测性,无需修改应用代码。
K8s 1.29+ 原生 Sidecar 支持:
spec:
initContainers:
- name: log-agent # 作为 sidecar 的 init container
image: fluent-bit:latest
restartPolicy: Always # 关键:设置 restartPolicy=Always 即变成 sidecar
containers:
- name: go-app
image: go-app:v1
原生 sidecar 的优势:
- 与主容器同时启动/停止
- 主容器结束后 sidecar 才结束(正确的生命周期管理)
- 在 Job 中也能正常工作
9. 静态 Pod
静态 Pod(Static Pod)是由 kubelet 直接管理的 Pod,不经过 kube-apiserver。
9.1 使用场景
K8s 自己的控制面组件(apiserver、scheduler、controller-manager、etcd)就是静态 Pod!
查看静态 Pod:
kubectl get pods -n kube-system
# kube-apiserver-master-node、etcd-master-node 等
静态 Pod 的配置文件位置:
ls /etc/kubernetes/manifests/
# etcd.yaml
# kube-apiserver.yaml
# kube-controller-manager.yaml
# kube-scheduler.yaml
kubelet 监控这个目录,文件变化时自动更新 Pod。
10. 小结
概念关系图
集群(Cluster)
└── Namespace(命名空间,逻辑隔离)
├── Pod(最小部署单元)
│ ├── Init Container(初始化容器)
│ ├── Container(主容器)
│ └── Sidecar Container(辅助容器)
├── Service(网络访问入口)
├── Deployment(管理 Pod 副本)
├── ConfigMap / Secret(配置)
└── ...
Node(实际运行 Pod 的机器)
└── Pod(被调度到此 Node 上的 Pod)
概念速查
| 概念 | 一句话描述 |
|---|---|
| Pod | K8s 最小部署单元,包含一个或多个容器 |
| Namespace | 逻辑隔离空间,同一集群多环境/多团队 |
| Label | 键值对标签,用于选择和组织资源 |
| Selector | 根据 Label 筛选资源的查询条件 |
| Annotation | 非标识性元数据,存储工具配置等信息 |
| Node | 运行 Pod 的工作节点(物理机/虚拟机) |
| requests | 调度时保证的资源量 |
| limits | 运行时最大可用资源量 |
| Init Container | 主容器启动前运行的初始化容器 |
| Sidecar | 与主容器共存的辅助容器 |
xingliuhua