Kubernetes & Docker 核心面试题整理
Kubernetes & Docker 核心面试题整理
1. 基础概念 (Basic Concepts)
1. K8s 中常见类型的资源介绍和区别?
Kubernetes 中的资源对象(API Objects)主要分为以下几类,核心区别在于用途和管理方式:
- 工作负载型 (Workloads):用于运行应用。
- Pod:最小调度单元,包含一个或多个紧密耦合的容器,共享网络和存储。
- Deployment:管理无状态应用。负责维护 Pod 副本数,支持滚动更新和回滚。底层通过 ReplicaSet 实现。
- StatefulSet:管理有状态应用(如数据库)。Pod 有固定的网络标识(hostname)和稳定的存储绑定,启动/删除有序。
- DaemonSet:确保集群中每个节点(或指定节点)都运行一个 Pod 副本(如日志收集 fluentd、监控 node-exporter)。
- Job / CronJob:运行一次性任务或定时任务,任务完成后 Pod 终止。
- 服务发现与负载均衡 (Services & Networking):
- Service:定义一组 Pod 的访问策略(ClusterIP, NodePort, LoadBalancer),提供稳定的 IP 和 DNS 名称,实现负载均衡。
- Ingress:管理外部访问集群服务的规则(主要是 HTTP/HTTPS),通常配合 Ingress Controller 使用,提供七层路由。
- 配置与存储 (Config & Storage):
- ConfigMap:存储非敏感的配置数据(环境变量、配置文件)。
- Secret:存储敏感数据(密码、Token、密钥),经过 Base64 编码(需注意并非加密)。
- PV (PersistentVolume) / PVC (PersistentVolumeClaim):持久化存储的抽象层,解耦存储供给与使用。
- 集群资源 (Cluster):
- Namespace:逻辑隔离集群资源,用于多租户或环境隔离。
- Node:集群中的工作节点。
- ServiceAccount:为 Pod 内的进程提供访问 API Server 的身份标识。
2. K8s 中 Pod 服务健康检查方式有哪两种?
严格来说有三种探针(Probe),但最核心的两种是:
- Liveness Probe(存活探针):
- 作用:判断容器是否“活着”。如果检测失败,Kubelet 会杀死容器并根据重启策略(RestartPolicy)进行重启。
- 场景:解决死锁、进程挂起但未退出等“假死”情况。
- Readiness Probe(就绪探针):
- 作用:判断容器是否“准备好接收流量”。如果检测失败,Endpoints 控制器会将该 Pod 从 Service 的负载均衡列表中剔除,不再转发流量,但不会重启容器。
- 场景:应用启动加载数据、依赖服务未就绪时,避免用户请求失败。
(注:还有一种 Startup Probe,用于处理启动缓慢的应用,启动成功后不再执行)
3. K8s 认证方式有几种?
Kubernetes API Server 支持多种认证插件,常见的有:
- 客户端证书 (Client Certificates):基于 TLS 双向认证,最常用且安全,用于组件间通信和管理员访问。
- Bearer Token:
- Service Account Tokens:Pod 内部访问 API Server 的标准方式。
- Static Token File:静态文件定义的 Token(不推荐生产使用)。
- Bootstrap Token:用于节点加入集群时的临时认证。
- OIDC (OpenID Connect):集成第三方身份提供商(如 Google, GitHub, Keycloak)。
- Webhook Token:调用外部服务进行认证。
- Anonymous:匿名访问(通常默认禁用或权限极低)。
- Basic Auth:用户名密码(已废弃,新版不再支持)。
机制:API Server 可以启用多种,只要有一种通过即认证成功。
4. K8s 中的证书和私钥种类有哪些?
在基于 PKI 的集群中(如 kubeadm 部署),主要证书包括:
- CA 根证书 (
ca.crt,ca.key):集群的信任锚点,用于签发其他所有证书。 - API Server 服务端证书 (
apiserver.crt,apiserver.key):用于 API Server 对外提供 HTTPS 服务。 - API Server 连接 Kubelet 的客户端证书 (
apiserver-kubelet-client.crt,.key):API Server 访问 kubelet 接口时使用。 - Kubelet 服务端证书 (
kubelet.crt,.key):每个节点上的 Kubelet 对外提供服务使用。 - Controller Manager / Scheduler 客户端证书:这些组件作为客户端访问 API Server 时使用。
- Etcd 证书:包括 Etcd 服务端证书和 Etcd 客户端证书(用于 API Server 访问 Etcd)。
- Front Proxy 证书:用于聚合层(Aggregation Layer)的认证。
- Service Account 密钥 (
sa.key,sa.pub):用于签名和验证 Service Account 的 JWT Token,不属于 X.509 证书体系但属于密钥对。
5. K8s 中各个主要组件有哪些?各自作用是什么?
分为控制平面 (Control Plane) 和 节点 (Node) 组件:
- kube-apiserver:集群的唯一入口和大脑。处理 REST 操作,验证请求,更新 Etcd,调度决策的协调者。
- etcd:高可用的键值存储数据库,保存集群的所有状态数据(配置、状态、元数据)。
- kube-scheduler:负责调度。监听新创建的 Pod,根据资源空闲情况、策略约束将其分配到合适的 Node 上。
- kube-controller-manager:运行各种控制器(如 ReplicaSet 控制器、Node 控制器、Endpoint 控制器),确保集群实际状态向期望状态收敛(自愈)。
- cloud-controller-manager:对接云厂商 API,管理云特有的控制器(如路由、负载均衡器、节点生命周期)。
- kubelet:运行在每个节点上。管理 Pod 生命周期(启停容器)、上报节点状态、执行健康检查。
- kube-proxy:网络代理。维护节点上的网络规则(iptables/IPVS),实现 Service 的负载均衡和网络转发。
- Container Runtime (如 containerd, Docker):真正负责运行容器的软件。
sequenceDiagram
autonumber
participant User as 用户 (kubectl)
participant API as kube-apiserver
participant DB as etcd
participant Sch as kube-scheduler
participant CCM as kube-controller-manager
participant Klet as kubelet (Node)
participant Runtime as Container Runtime
participant Proxy as kube-proxy
Note over User, DB: 阶段一:提交请求与持久化
User->>API: 1. 发送 POST 请求 (创建 Pod YAML)
API->>API: 2. 验证请求 (鉴权/准入控制)
API->>DB: 3. 将 Pod 信息写入 etcd (状态: Pending)
DB-->>API: 4. 确认写入成功
API-->>User: 5. 返回 "Pod created"
Note over Sch, API: 阶段二:调度决策
Sch->>API: 6. 监听 (Watch) 到新的 Pending Pod
Sch->>Sch: 7. 执行调度算法 (过滤 + 评分)
Sch->>API: 8. 提交绑定结果 (Binding: Pod -> Node-A)
API->>DB: 9. 更新 Pod 信息 (nodeName: Node-A)
Note over Klet, Runtime: 阶段三:节点执行
Klet->>API: 10. 监听 (Watch) 到分配给自己的 Pod
Klet->>Runtime: 11. 调用 CRI 接口 (创建 Pause 容器 + 业务容器)
Runtime->>Runtime: 12. 拉取镜像,启动容器
Runtime-->>Klet: 13. 返回容器启动成功
Klet->>API: 14. 上报状态 (Status: Running)
API->>DB: 15. 更新 etcd 中的 Pod 状态
Note over CCM, API: 阶段四:状态自愈 (持续运行)
CCM->>API: 16. 监听 Pod 状态变化
CCM->>CCM: 17. 对比期望状态 (Replicas) 与实际状态
opt 如果 Pod 意外崩溃
CCM->>API: 18. 发现实际数量 < 期望数量
CCM->>API: 19. 触发重建逻辑 (创建新 Pod)
end
Note over Proxy, API: 阶段五:网络连通
Proxy->>API: 20. 监听 Service/Endpoint 变化
Proxy->>Proxy: 21. 更新 iptables/IPVS 规则
Note right of Proxy: 外部流量现在可以访问该 Pod
6. K8s 集群中有没有高可用?你们公司的高可用架构是什么?
- 有没有高可用:原生支持,但需要手动配置多主节点。
- 通用高可用架构方案:
- 多 Master 节点:部署 3 个或以上的 Master 节点(奇数),防止单点故障。
- 负载均衡 (LB):在 Master 节点前架设负载均衡器(如 Keepalived + HAProxy,或云厂商的 SLB/ELB),提供一个统一的 VIP (虚拟 IP) 供 Worker 节点和 kubectl 访问 API Server。
- Etcd 高可用:Etcd 集群通常部署为 3 或 5 节点,采用 Raft 协议保证数据一致性。可以是堆叠在 Master 上,也可以是独立的外部集群。
- Worker 节点多副本:应用通过 Deployment 设置多副本并配合反亲和性策略,分散在不同节点。
(注:作为 AI,我没有具体的“公司”,以上是业界标准的 HA 架构实践。)
7. K8s 中镜像下载策略(ImagePullPolicy)有哪几种?
- Always:每次启动 Pod 时都尝试从仓库拉取最新镜像。如果标签是
latest,默认也是此行为。 - IfNotPresent(默认):只有当本地节点没有该镜像时才拉取。如果本地已有,直接使用本地缓存。
- Never:只使用本地镜像,如果本地没有则报错,绝不尝试联网拉取。
8. K8s 中 Pod 故障重启策略(RestartPolicy)有哪几种?
该策略定义在 Pod Spec 中,作用于 Pod 内所有容器:
- Always(默认):无论容器是正常退出(exit code 0)还是异常退出,都会重启。Deployment 等控制器管理的 Pod 必须使用此策略。
- OnFailure:仅当容器异常退出(exit code 非 0)时重启。常用于 Job。
- Never:无论何种情况都不重启。常用于调试或一次性任务。
9. K8s 中 PV 有几种访问模式(Access Modes)?
- ReadWriteOnce (RWO):读写权限,只能被单个节点挂载(最常见,如云盘)。
- ReadOnlyMany (ROX):只读权限,可以被多个节点同时挂载。
- ReadWriteMany (RWX):读写权限,可以被多个节点同时挂载(通常需要 NFS、CephFS 等共享存储)。
- ReadWriteOncePod (RWOP) (K8s 1.23+ Alpha/Beta):读写权限,只能被单个 Pod 挂载(比 RWO 更严格,即使在同一节点的不同 Pod 也不行)。
10. K8s 中 PV 和 PVC 的作用是什么?PV、PVC 和底层存储的关系?
你总结的关于 PV (PersistentVolume)、PVC (PersistentVolumeClaim) 以及它们与底层存储的关系非常准确,核心逻辑(解耦、绑定、使用、回收)完全正确。
为了让你对 StorageClass 的理解更加透彻,并补全“动态供给”这一现代 K8s 存储的核心场景,我将基于你的总结进行深化和补充,重点理清 StorageClass 在其中的桥梁作用。
1. 核心角色深化
PV (PersistentVolume) - “仓库”
- 定义:集群中的一块具体存储资源。它是集群级别的资源(不属于任何 Namespace)。
- 状态:
Available:空闲,未被绑定。Bound:已绑定到某个 PVC。Released:PVC 已删除,但 PV 中的资产还未被清理(取决于回收策略)。Failed:自动回收失败。
- 关键点:它屏蔽了底层细节(是 NFS、Ceph RBD、还是 AWS EBS),对 Pod 来说,它就是一个挂载点。
PVC (PersistentVolumeClaim) - “订单”
- 定义:用户对存储资源的请求。它是 Namespace 级别的资源。
- 内容:声明需要的容量(Size)、访问模式(ReadWriteOnce, ReadOnlyMany, ReadWriteMany)以及存储类(StorageClassName)。
- 行为:K8s 控制平面会尝试寻找一个满足要求的 PV 进行绑定。如果找不到且配置了动态供给,则会触发创建新的 PV。
StorageClass (SC) - “自动化采购经理/模板”
- 作用:这是连接 PVC 和底层存储动态创建的关键。
- 解决的问题:在没有 SC 之前,管理员必须手动预先创建好所有 PV(静态供给)。有了 SC,用户只需在 PVC 中指定
storageClassName,K8s 就会自动调用云厂商 API 或存储插件去动态创建对应的 PV 和底层存储卷。 - 组成:
- Provisioner:驱动程序(如
kubernetes.io/aws-ebs,rook-ceph.rbd.csi.ceph.com),决定由哪个插件来创建存储。 - Parameters:创建存储时的参数(如磁盘类型 SSD/HDD、IOPS、副本数等)。
- ReclaimPolicy:回收策略(Delete 或 Retain)。
- VolumeBindingMode:
Immediate:PVC 创建时立即创建 PV 和底层存储。WaitForFirstConsumer:直到有 Pod 使用该 PVC 时,才在 Pod 所在的节点对应位置创建存储(常用于本地存储或特定拓扑约束场景)。
- Provisioner:驱动程序(如
2. 三者与底层存储的完整关系图谱
我们可以将整个过程看作一个供应链流程:
场景 A:静态供给 (Static Provisioning) - 传统模式
- 管理员手动在云控制台或存储设备上创建一块磁盘/文件系统。
- 管理员在 K8s 中编写 YAML 创建 PV,指向这块具体的存储。
- 开发者编写 PVC,请求特定大小的存储。
- K8s 发现有一个未绑定的 PV 满足 PVC 要求,执行 绑定 (Binding)。
- Pod 引用 PVC,挂载成功。
- 缺点:PV 用完了需要管理员手动介入扩容或新建,效率低。
场景 B:动态供给 (Dynamic Provisioning) - 现代主流模式 (引入 StorageClass)
- 管理员创建一个 StorageClass (例如名为
fast-ssd),配置好 Provisioner 和参数。 - 开发者编写 PVC,指定
storageClassName: fast-ssd和所需大小(此时集群中可能并没有对应的 PV)。 - K8s 控制平面 监听到这个 PVC:
- 发现没有现成的 PV 匹配。
- 检查 PVC 指定的 StorageClass。
- 调用 StorageClass 中定义的 Provisioner。
- Provisioner 调用底层存储 API(如 AWS API, Ceph Monitor),动态创建 一块新的物理/网络存储卷。
- Provisioner 随即在 K8s 中自动创建一个 PV 对象,指向这块新创建的底层存储,并立即将该 PV 与 PVC 绑定。
- Pod 引用 PVC,挂载成功。
- 优点:按需分配,无需管理员预先准备 PV,实现了真正的自助服务。
3. 生命周期与回收策略 (Reclaim Policy)
当 PVC 被删除时,PV 和底层存储的命运由 PV (或 StorageClass 默认) 的回收策略决定:
| 策略 | 行为描述 | 适用场景 |
|---|---|---|
| Retain (保留) | PVC 删除后,PV 变为 Released 状态,底层存储数据保留,PV 不会自动删除。需要管理员手动清理数据和 PV 对象。 |
生产环境重要数据,防止误删导致数据丢失。 |
| Delete (删除) | PVC 删除后,PV 对象和底层存储资产(如云盘、Ceph 卷)都会被自动删除。 | 开发/测试环境,临时数据,追求资源自动回收。 |
| Recycle (回收) | 已过时。执行 rm -rf /volume/* 清除数据,PV 变回 Available 供再次使用。 |
现代 K8s 版本已不再推荐使用,通常由 CSI 驱动自行实现类似逻辑或直接使用 Delete/Retain。 |
4. 总结图示化理解
[开发者]
|
| 1. 提交 PVC (需求: 10Gi, Class: fast-ssd)
v
[K8s Control Plane]
|
|-- 查找现有 PV? -> 无匹配
|
|-- 2. 读取 StorageClass "fast-ssd" (模板/规则)
| - Provisioner: ebs.csi.aws.com
| - Type: gp3
|
|-- 3. 调用 Provisioner -> [底层存储系统 (AWS EBS/Ceph/NFS)]
| (动作: 创建真实的 10Gi 磁盘)
|
|-- 4. 创建 PV 对象 (指向新磁盘)
|
|-- 5. 绑定 PV <-> PVC
|
v
[Pod] --(引用 PVC)--> [挂载点] --> [底层真实数据]
关键结论
- PV 是资源的抽象表示。
- PVC 是用户的使用接口。
- StorageClass 是自动化引擎,它定义了“如何创建 PV”以及“创建什么样的底层存储”。
- 底层存储 是最终的物理载体。
加上 StorageClass 后,K8s 的存储体系从“手动预分配”进化到了“按需自动供给”,极大地提升了云原生应用的弹性和运维效率。
flowchart TD
A[开发者创建 PVC
请求: 10Gi, StorageClass: fast-ssd] --> B{K8s 控制平面
查找匹配 PV?}
B -- 有匹配 PV --> C[直接绑定 PV <-> PVC]
B -- 无匹配 PV --> D[读取 StorageClass
fast-ssd 配置]
D --> E[调用 Provisioner
e.g., ebs.csi.aws.com]
E --> F[底层存储系统
AWS EBS/Ceph/NFS
动态创建实际存储卷]
F --> G[自动创建 PV 对象
指向新存储卷]
G --> H[绑定 PV <-> PVC]
C --> I[Pod 挂载 PVC
访问存储]
H --> I
I --> J{PVC 被删除?}
J -- 是 --> K{PV 回收策略?}
K -- Delete --> L[自动删除 PV +
底层存储卷]
K -- Retain --> M[PV 变为 Released
保留底层数据
需手动清理]
style A fill:#e6f3ff,stroke:#333
style D fill:#fff2cc,stroke:#333
style F fill:#d5e8d4,stroke:#333
style J fill:#f8cecc,stroke:#333
11. 客户端访问 K8s 资源需要经过几关?分别是什么?
客户端请求到达 kube-apiserver 后,依次经过三道关卡(任意一关失败即拒绝):
- 认证 (Authentication):确认“你是谁”?(校验证书、Token 等)。
- 授权 (Authorization):确认“你有权限做这件事吗”?(校验 RBAC 角色绑定、ABAC 策略等)。
- 准入控制 (Admission Control):确认“你的请求符合集群规范吗”?(执行 Mutating 修改请求或 Validating 校验请求,如检查镜像策略、资源配额 LimitRange 等)。
通过后才会执行请求并将数据存入 Etcd。
12. K8s 集群中的数据是存储在哪个位置?
- 集群状态元数据:所有的资源对象定义(Pod, Service, Deployment 等)和集群状态都存储在 Etcd 数据库中。这是 K8s 的唯一真实数据源(Source of Truth)。
- 容器数据:
- 临时数据:存储在节点的容器运行时目录中(随 Pod 删除而丢失)。
- 持久数据:通过 PV 挂载,存储在后端存储系统中(如 NFS 服务器、云厂商的云盘、Ceph 集群等),独立于 K8s 集群节点存在。
- 日志:默认在节点的文件系统中(
/var/log/pods),通常建议通过日志采集系统(EFK/ELK)输出到外部存储。
13. 什么是 Headless(无头)Service?
- 定义:一种特殊的 Service,其 YAML 中
spec.clusterIP字段被显式设置为None。 - 特点:
- 不分配 Cluster IP:K8s 不会为该 Service 分配虚拟 IP,也不会通过 kube-proxy 做负载均衡。
- DNS 解析:当客户端查询该 Service 的域名时,DNS 服务器(CoreDNS)会直接返回后端所有 Pod 的 IP 地址列表(A 记录),而不是一个 VIP。
- 用途:
- 主要用于有状态应用(配合 StatefulSet),让客户端能直接发现并连接特定的 Pod(如
pod-0.service,pod-1.service)。 - 用于需要客户端自己实现负载均衡或直接感知后端拓扑的场景(如 Zookeeper, Kafka 集群内部通信)。
- 主要用于有状态应用(配合 StatefulSet),让客户端能直接发现并连接特定的 Pod(如
2. Docker 相关 (Docker Related)
14. Docker 怎么用 Dockerfile 文件构建镜像?具体命令是什么?
步骤:
- 编写
Dockerfile文件,定义构建指令。 - 在包含
Dockerfile的目录下执行构建命令。
具体命令:
docker build -t <镜像名称>:<标签> <上下文路径>
-t(tag):指定生成的镜像名称和标签(例如myapp:v1)。<上下文路径>:通常是当前目录.,Docker 会将该目录下的所有文件发送给 Docker 守护进程作为构建上下文。
示例:
docker build -t my-python-app:1.0 .
15. Docker 怎么用镜像运行一个容器?如何设置在后台运行?
基本命令:
docker run [选项] <镜像名称> [命令]
后台运行设置:
使用 -d (detach) 参数让容器在后台运行,不占用当前终端。通常还会配合 --name 指定容器名,以及 -p 映射端口。
示例:
# 以后台模式运行 nginx,命名为 my-nginx,将宿主机的 8080 端口映射到容器的 80 端口
docker run -d --name my-nginx -p 8080:80 nginx:latest
-d: Detached mode (后台运行)。--name: 指定容器名称。-p host_port:container_port: 端口映射。
16. Docker Harbor 是怎么安装的?有哪几种安装方式?
Harbor 是一个开源的企业级 Docker 镜像仓库。
主要安装方式:
- 离线安装包安装 (最常用):
- 从 GitHub 下载
.tgz离线包。 - 解压后修改
harbor.yml配置文件(设置 hostname, https 证书路径,密码等)。 - 运行
./install.sh脚本。该脚本会调用 Docker Compose 启动所有组件(Core, Registry, Database, Redis, Nginx 等)。
- 从 GitHub 下载
- Helm Chart 安装 (K8s 环境推荐):
- 在 Kubernetes 集群中,使用 Helm 添加 Harbor 仓库。
- 自定义
values.yaml配置。 - 执行
helm install部署到 K8s 集群中,利用 K8s 的存储和高可用特性。
- Docker Compose 手动编排:
- 不通过 install.sh,直接编写或修改
docker-compose.yml文件来启动服务(适合深度定制或调试)。
- 不通过 install.sh,直接编写或修改
17. Dockerfile 中都有哪些关键字?各自的作用是什么?
- FROM: 指定基础镜像(必须是第一行,除了 ARG)。
- LABEL: 为镜像添加元数据(作者、版本等)。
- ENV: 设置环境变量,后续指令和运行时可用。
- ARG: 定义构建时的变量(仅在
docker build过程中有效,运行时不可见,除非转为 ENV)。 - RUN: 执行命令并创建新的镜像层(用于安装软件、编译代码)。
- COPY: 将宿主机文件复制到镜像中。
- ADD: 类似 COPY,但支持自动解压压缩包和下载 URL(一般推荐用 COPY)。
- WORKDIR: 设置工作目录,后续指令在此目录下执行。
- EXPOSE: 声明容器运行时监听的端口(文档作用,不自动映射)。
- VOLUME: 创建挂载点,用于持久化数据或共享数据。
- ENTRYPOINT: 配置容器启动时执行的可执行程序(难以被覆盖)。
- CMD: 提供容器启动时的默认参数(可被
docker run后面的参数覆盖)。 - USER: 指定运行后续指令和容器进程的用户。
- HEALTHCHECK: 定义健康检查指令。
- STOPSIGNAL: 设置停止容器时发送的系统信号。
- ONBUILD: 当此镜像作为其他镜像的基础镜像时,触发执行的指令。
🔍 深度解析:ENTRYPOINT vs CMD
1. 核心区别
ENTRYPOINT: 定义容器启动时必须执行的主程序。它让容器表现得像一个可执行文件。CMD: 提供主程序的默认参数。如果用户在docker run时提供了参数,这些参数会覆盖CMD的内容,并作为参数传递给ENTRYPOINT。
2. 场景演示
场景 A:只使用 CMD (传统方式)
这种方式下,整个命令都可以被替换。
FROM ubuntu:latest
CMD ["echo", "Hello World"]
docker run my-image-> 输出:Hello Worlddocker run my-image ls -l-> 输出: 执行ls -l(完全覆盖了echo "Hello World")- 缺点:如果你想保留
echo但修改内容,必须重写整个命令。
- 缺点:如果你想保留
场景 B:只使用 ENTRYPOINT (强制模式)
这种方式下,主程序固定,用户只能传递参数,或者必须用 --entrypoint 强制覆盖。
FROM ubuntu:latest
ENTRYPOINT ["echo", "Hello"]
docker run my-image-> 输出:Hello(无额外参数)docker run my-image World-> 输出:Hello World(World被追加为参数)docker run my-image ls -l-> 输出:Hello ls -l(注意:它不会执行 ls,而是把 ls 当作 echo 的参数打印出来)- 缺点:灵活性稍差,如果想运行其他命令比较麻烦。
场景 C:ENTRYPOINT + CMD 组合 (最佳实践 ⭐)
这是最常用的模式。ENTRYPOINT 固定主程序,CMD 提供默认参数。
FROM ubuntu:latest
# 主程序是 echo,默认参数是 "Hello World"
ENTRYPOINT ["echo"]
CMD ["Hello World"]
docker run my-image- 执行逻辑:
echo+Hello World - 输出:
Hello World
- 执行逻辑:
docker run my-image "Goodbye"- 执行逻辑:
echo+Goodbye(CMD 被覆盖) - 输出:
Goodbye
- 执行逻辑:
docker run my-image "A" "B" "C"- 执行逻辑:
echo+A+B+C - 输出:
A B C
- 执行逻辑:
💡 关键点:在这种组合下,
docker run后面跟的所有内容都会替换掉CMD的内容,并拼接到ENTRYPOINT后面。
3. 实战案例:Nginx 镜像
Nginx 官方镜像就是典型的使用了这种组合,允许用户轻松覆盖启动参数(如开启 debug 模式或加载不同配置),而不用重新指定 nginx 二进制文件的路径。
FROM nginx:alpine
# 固定主程序路径
ENTRYPOINT ["nginx", "-g", "daemon off;"]
# 默认不带额外参数,如果需要可以传入 -c 指定配置文件
CMD []
- 正常启动:
docker run nginx-> 执行nginx -g daemon off; - 自定义配置:
docker run nginx -c /etc/nginx/my.conf-> 执行nginx -g daemon off; -c /etc/nginx/my.conf
📝 格式重要提示
在使用 ENTRYPOINT 和 CMD 时,强烈推荐使用 Exec 格式(JSON 数组格式),而不是 Shell 格式。
- ✅ 推荐 (Exec 格式):
ENTRYPOINT ["executable", "param1"]- 信号量(如 Ctrl+C)能正确传递给进程。
- 参数拼接逻辑清晰。
- ❌ 不推荐 (Shell 格式):
ENTRYPOINT executable param1- 实际会以
/bin/sh -c包裹执行,导致 PID 1 是 shell 而不是你的应用,可能引起信号处理问题(容器停不下来)。
- 实际会以
总结对照表
| 特性 | ENTRYPOINT | CMD |
|---|---|---|
| 主要用途 | 定义容器的主程序/入口点 | 提供默认参数或默认命令 |
被 docker run 覆盖 |
不容易 (需用 --entrypoint 标志) |
容易 (直接跟在镜像名后的参数即覆盖) |
| 组合使用效果 | 接收 CMD 的内容作为参数 | 内容被替换并传给 ENTRYPOINT |
| 典型场景 | Web 服务器 (nginx, apache), 数据库 (mysql) | 设置默认启动参数,或作为纯命令行工具 |
18. 如何使用 Docker 快速运行相关服务?(例如 Docker 安装 MySQL/Redis 等)
利用官方镜像和预设的环境变量快速启动。
MySQL 示例:
docker run -d \
--name mysql-db \
-e MYSQL_ROOT_PASSWORD=my-secret-pw \
-e MYSQL_DATABASE=testdb \
-p 3306:3306 \
-v mysql-data:/var/lib/mysql \
mysql:8.0
-e: 传递环境变量配置 root 密码和初始数据库。-v: 挂载卷持久化数据。
Redis 示例:
docker run -d \
--name redis-cache \
-p 6379:6379 \
-v redis-data:/data \
redis:latest --appendonly yes
--appendonly yes: 开启 AOF 持久化(作为 CMD 参数传入)。
19. 使用过 Docker Compose 吗?比 Docker 来讲,有什么优势?
是的,广泛使用。
优势:
- 多容器编排:Docker 命令一次只能运行一个容器。Compose 可以通过一个 YAML 文件定义和管理多个相互关联的服务(如 Web + DB + Cache),一键启动/停止整个应用栈。
- 配置即代码:所有启动参数、网络、卷映射都写在
docker-compose.yml中,便于版本控制和团队协作,避免冗长的命令行。 - 依赖管理:可以定义服务启动顺序(
depends_on),确保数据库先于应用启动。 - 环境隔离:可以为开发、测试、生产定义不同的 Compose 文件(或 override 文件)。
- 简化网络:自动创建一个专属网络,服务间可以通过服务名直接互通,无需手动配置 link 或 IP。
20. 会编写 Docker Compose 的 YAML 文件吗?如何编写?
会。 文件名为 docker-compose.yml (或 .yaml)。
基本结构:
version: '3.8' # 版本号
services: # 定义服务列表
web:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html
depends_on:
- db
networks:
- app-net
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: example
volumes:
- db-data:/var/lib/mysql
networks:
- app-net
volumes: # 定义外部卷
db-data:
networks: # 定义网络
app-net:
driver: bridge
关键点: 缩进必须严格(通常 2 空格),层级关系为 services -> service_name -> 配置项。
21. Docker 有几种网络模式?分别是哪些?各自作用是什么?
Docker 主要有 4 种网络驱动模式:
- Bridge (桥接模式):默认模式。
- 作用:创建一个虚拟网桥(docker0),容器连接到网桥上。容器拥有独立的 IP,通过 NAT 与宿主机通信。容器间可通过 IP 通信,默认无法通过容器名解析(除非在自定义 bridge 网络或使用了 link)。
- 场景:单机多容器通信,需要端口映射到宿主机。
- Host (主机模式):
- 作用:容器不使用独立的 Network Namespace,直接使用宿主机的网络栈。容器没有独立 IP,端口直接占用宿主机端口。
- 场景:对网络性能要求极高,或需要绑定特定宿主机端口的场景(如监控 agent)。
- None (无网络模式):
- 作用:容器有自己的 Network Namespace,但不进行任何网络配置(只有 lo 回环接口)。
- 场景:高度安全的封闭环境,或完全自定义网络配置。
- Container (共享网络模式):
- 作用:新创建的容器不创建自己的 Network Namespace,而是使用一个已存在容器的网络(IP、端口等完全共享)。
- 场景:Kubernetes 中的 Pod 就是基于此概念(Sidecar 模式),或者某些特殊的调试场景。
(注:还有 Overlay 网络用于 Swarm 集群跨主机通信,Macvlan 用于让容器拥有物理网络 IP)
22. 你们用的 K8s 的版本是什么?
(作为 AI,我没有实体的“公司”或正在运行的集群。但在实际面试或生产环境中,这是一个考察你对版本迭代关注度的问题。)
参考回答策略:
“在生产环境中,我们通常遵循‘落后最新稳定版 1-2 个小版本’的策略,以确保稳定性并获得安全补丁。目前主流生产环境多使用 v1.26 到 v1.29 之间的版本。
具体选择取决于:
- 云厂商支持:如果使用托管 K8s (EKS, ACK, GKE),通常跟随云厂商的支持周期。
- 特性需求:是否需要特定的新特性(如 Sidecar 容器原生支持在 1.29+ 成熟)。
- 生态兼容性:确保使用的 Helm Charts、CSI 插件、CNI 插件与该版本兼容。
如果是模拟回答,可以说:‘我们目前集群主要运行在 v1.28 版本,计划在下个季度升级到 v1.29。’”
23. Dockerfile 中 RUN、CMD、ENTRYPOINT 的区别?
- RUN:
- 时机:镜像构建时执行。
- 作用:执行命令并提交结果到新的镜像层(如安装软件
apt-get install)。 - 结果:不产生容器进程,只改变文件系统。
- CMD:
- 时机:容器启动时执行。
- 作用:提供默认的启动命令或参数。
- 覆盖性:可以被覆盖。如果用户在
docker run后面加了命令,CMD 的内容会被完全替换。 - 格式:推荐使用 Exec 格式
["cmd", "param"],若用 Shell 格式/bin/sh -c会导致信号传递问题。
- ENTRYPOINT:
- 时机:容器启动时执行。
- 作用:配置容器的主执行程序(Executable)。
- 覆盖性:很难被覆盖。
docker run后面的参数会作为参数追加给 ENTRYPOINT,而不是替换它(除非使用--entrypoint强制覆盖)。 - 最佳实践:通常组合使用,
ENTRYPOINT指定主程序(如python或java),CMD指定默认参数(如app.py或-jar app.jar)。
24. Dockerfile 中 ADD 和 COPY 的区别?
- COPY:
- 功能:单纯地将本地文件/目录复制到镜像中。
- 来源:仅限构建上下文(本地)的文件。
- 推荐度:官方推荐。行为透明,易于维护。
- ADD:
- 功能:除了复制文件外,还有两个额外特性:
- 如果源文件是压缩包(tar, gzip 等),会自动解压到目标路径。
- 支持通过 URL 下载远程文件到镜像中。
- 缺点:隐式行为(自动解压)可能导致意外;下载大文件会增大镜像层且无法利用构建缓存的高效机制。
- 建议:除非明确需要自动解压或下载 URL,否则始终使用 COPY。如果需要解压,建议在 RUN 指令中显式执行
tar -xf。
- 功能:除了复制文件外,还有两个额外特性:
25. Docker 中的镜像分层(Layering)是怎么样的?
- 原理:Docker 镜像是由一系列只读层 (Read-only Layers) 叠加而成的。
- 构建过程:Dockerfile 中的每一条指令(
FROM,RUN,COPY,ENV等,除MAINTAINER外)都会创建一个新的层。- 每一层只包含该指令相对于上一层的变更内容(新增、修改、删除的文件)。
- 层是缓存的单位。如果某一层及其之前的层没有变化,构建时会直接使用缓存,加速构建。
- 联合文件系统 (UnionFS):启动容器时,Docker 会在所有只读镜像层之上,挂载一个可写层 (Container Layer / Read-Write Layer)。
- 容器的所有写入操作(新建文件、修改文件)都发生在这个顶层。
- 读取文件时,采用“向上查找”策略,如果在可写层没找到,就去下面的镜像层找。
- 删除文件时,实际上是在可写层创建一个“白out”文件(标记删除),底层文件依然存在。
- 优势:
- 共享存储:多个容器可以共享相同的底层镜像层,节省磁盘空间。
- 快速分发:推送/拉取镜像时,只需传输变化的层。
- 版本控制:每一层都有唯一的 ID,便于追踪变更。
3. Pod 和服务 (Pod & Service)
26. K8s 中 Pod 是如何实现代理和负载均衡的?
K8s 本身不直接在 Pod 内部做负载均衡,而是通过 Service 资源配合节点上的 kube-proxy 组件来实现。
- 机制:
- Service 定义:用户创建一个 Service,定义一组 Pod 的选择器(Selector)和虚拟 IP(ClusterIP)。
- Endpoints:K8s 控制平面监控到符合 Selector 的 Pod,将其 IP 列表更新到 Endpoints 对象中。
- kube-proxy 监听:每个节点上的
kube-proxy监听到 Service 和 Endpoints 的变化。 - 规则下发:
kube-proxy根据配置的模式(iptables 或 IPVS),在节点内核中生成相应的网络规则。- iptables 模式:生成一系列 NAT 规则。当流量访问 ClusterIP 时,内核 netfilter 模块根据概率随机将流量转发到后端某个 Pod IP。
- IPVS 模式:调用内核 IPVS 模块,创建虚拟服务器(VIP)和真实服务器(Pod IP),利用内核的高效负载均衡算法(轮询、最少连接等)转发流量。
- 结果:客户端访问 Service 的 VIP 时,流量被自动负载均衡到后端的任意一个健康 Pod 上。
27. K8s 中创建 Pod 的过程或流程是怎么样的?
这是一个典型的异步控制循环过程:
- 提交请求:用户通过
kubectl或 API 调用向 API Server 发送创建 Pod 的请求。 - 验证与存储:API Server 进行认证、授权和准入控制,验证通过后,将 Pod 信息写入 Etcd。
- 调度决策:kube-scheduler 监听到有新的 Pod 处于
Pending状态且未绑定节点,根据资源需求、亲和性、污点等策略,选择一个最合适的 Node,并将绑定结果(Binding)通过 API Server 更新回 Etcd。 - 节点执行:目标节点上的 kubelet 监听到分配给自己的 Pod 任务:
- 调用容器运行时(如 containerd)拉取镜像。
- 创建容器沙箱(Pause 容器)和业务容器。
- 挂载卷、配置网络(调用 CNI 插件)。
- 启动容器进程。
- 状态上报:kubelet 将 Pod 的运行状态(Running, Failed 等)定期上报给 API Server,并更新到 Etcd。
- 完成:用户查询时看到 Pod 状态变为
Running。
flowchart TD
%% --- 节点定义 ---
Start([用户发起创建])
APIServer[API Server]
Validation{验证通过?}
Error[返回错误]
EtCD[(Etcd)]
Scheduler[kube-scheduler]
NodeSelect[选定 Node]
Kubelet[kubelet]
CRI["容器运行时 (containerd/CRI-O)"]
ImagePull[下载镜像]
PauseContainer["Pause 容器 (持有 Network/PID Namespace)"]
CNI["CNI 插件 (分配 IP/路由)"]
VolumeMount[挂载 Volumes]
CheckHook{有 PostStart?}
RunPostStart["执行 PostStart (异步/不阻塞)"]
StartApp[13. 启动业务容器]
StatusCheck{运行正常?}
Running[状态: Running]
Restart[重启容器]
StopTrigger[触发停止]
CheckPreStop{有 PreStop?}
RunPreStop["执行 PreStop (同步/阻塞)"]
StopContainer[停止容器]
End([Pod 就绪])
%% --- 样式定义 ---
style Start fill:#e6f3ff,stroke:#333,stroke-width:2px
style APIServer fill:#fff2cc,stroke:#d6b656,stroke-width:2px
style Scheduler fill:#d5e8d4,stroke:#82b366,stroke-width:2px
style Kubelet fill:#f8cecc,stroke:#b85450,stroke-width:2px
style CRI fill:#dae8fc,stroke:#6c8ebf,stroke-width:2px
style PauseContainer fill:#dae8fc,stroke:#6c8ebf,stroke-width:2px
style RunPostStart fill:#ffe6cc,stroke:#d79b00,stroke-width:2px,stroke-dasharray: 5 5
style CheckPreStop fill:#ffe6cc,stroke:#d79b00,stroke-width:2px,stroke-dasharray: 5 5
style RunPreStop fill:#ffe6cc,stroke:#d79b00,stroke-width:2px,stroke-dasharray: 5 5
style End fill:#e6f3ff,stroke:#333,stroke-width:2px
style Validation fill:#ffffff,stroke:#333
style CheckHook fill:#ffffff,stroke:#333
style StatusCheck fill:#ffffff,stroke:#333
%% --- 流程连线 ---
Start -->|1. kubectl create pod| APIServer
APIServer -->|2. 认证/授权| Validation
Validation -- 否 --> Error
Validation -- 是 --> EtCD
EtCD -->|3. 写入 Pod Pending| APIServer
APIServer -.->|监听 Pending| Scheduler
Scheduler -->|4. 调度算法| NodeSelect
NodeSelect -->|5. 提交 Binding| APIServer
APIServer -->|更新 Etcd| EtCD
APIServer -.->|6. 监听已分配| Kubelet
Kubelet -->|7. 调用 CRI| CRI
CRI -->|8. 拉取镜像| ImagePull
ImagePull -->|9. 创建 Pause 容器| PauseContainer
PauseContainer -->|10. 配置网络| CNI
CNI -->|11. 挂载卷| VolumeMount
VolumeMount -->|12. 检查| CheckHook
CheckHook -- 是 --> RunPostStart
CheckHook -- 否 --> StartApp
RunPostStart -.-> StartApp
StartApp -->|14. 监控| StatusCheck
StatusCheck -- 是 --> Running
StatusCheck -- 否 --> Restart
Restart --> StartApp
StartApp -.->|收到终止信号| StopTrigger
StopTrigger --> CheckPreStop
CheckPreStop -- 是 --> RunPreStop
CheckPreStop -- 否 --> StopContainer
RunPreStop --> StopContainer
Running -->|16. 上报状态| APIServer
Running -->|17. 用户查询| End
28. K8s 中如何批量删除 Pod?
有多种方式,取决于筛选条件:
- 按标签删除(最常用):
kubectl delete pod -l app=my-app -n default - 按名称匹配删除:
kubectl delete pod $(kubectl get pod -n default | grep "my-prefix" | awk '{print $1}') - 删除命名空间下所有 Pod(慎用):
kubectl delete pod --all -n default - 强制删除(处理 Terminating 状态卡住的 Pod):
kubectl delete pod <pod-name> --grace-period=0 --force
29. Kubeadm 初始化的 K8s 集群,Token 过期后,集群中节点无法加入怎么办?
Kubeadm 生成的 bootstrap token 默认有效期为 24 小时。过期后需重新生成。
解决步骤(在 Master 节点执行):
- 生成新的 Token:
kubeadm token create - 获取 CA 证书的 Hash 值(用于安全校验):
(注:较新版本的 kubeadm 可以直接在 token create 命令中输出完整命令)openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //' - 使用完整命令拼接:
或者直接运行以下命令让 kubeadm 自动打印完整的 join 命令:kubeadm token create --print-join-command - 在 Worker 节点执行:复制输出的完整
kubeadm join ...命令并在 Worker 节点运行即可。
30. K8s 运维过程中遇到过哪些问题,如何解决的?(开放性问题)
(面试参考回答,列举常见痛点,涵盖 Pod 全生命周期状态)
-
问题 1:Pod 一直处于
CrashLoopBackOff- 排查:
kubectl logs查看应用日志,发现配置文件缺失、代码 Panic 或数据库连接失败;kubectl describe pod查看事件,发现 Liveness 探针配置过严(启动慢于探测时间)。 - 解决:修正 ConfigMap/Secret 配置,修复代码逻辑,或调整探针的
initialDelaySeconds(初始延迟)和failureThreshold(失败阈值)。
- 排查:
-
问题 2:节点
NotReady- 排查:登录节点,发现
kubelet服务停止或 CNI 插件(如 Calico/Flannel)Pod 崩溃。查看/var/log/messages或journalctl -u kubelet,常见原因为磁盘空间满(触发DiskPressure)、证书过期或网络插件异常。 - 解决:清理无用镜像/日志释放空间并重启 kubelet;若是证书过期,使用
kubeadm renew certs更新并重启相关组件;若是 CNI 问题,重启 CNI DaemonSet。
- 排查:登录节点,发现
-
问题 3:Service 访问不通
- 排查:检查
Endpoints是否为空(通常因 Deployment 的 Label 与 Service 的 Selector 不匹配);检查kube-proxy日志;测试节点内部iptables/IPVS规则是否丢失。 - 解决:修正 Deployment 的 Label 确保匹配,重启
kube-proxyDaemonSet 刷新规则,确认 Pod 已通过 Readiness 探针(未通过不会加入 Endpoint)。
- 排查:检查
-
问题 4:Pod 被
OOMKilled- 排查:
kubectl get pod看到状态为OOMKilled或重启原因包含 OOM,说明容器内存使用超过limits.memory限制被内核杀死。 - 解决:短期调大 YAML 中
resources.limits.memory;长期需优化代码减少内存泄漏,或调整 JVM/Go 的 GC 参数以适配容器限制。
- 排查:
-
问题 5:Pod 一直处于
Pending- 排查:
kubectl describe pod查看 Events。常见原因:集群资源不足(Insufficient cpu/memory)、节点污点(Taints)且 Pod 无容忍度、亲和性(Affinity)配置无匹配节点、或 PVC 存储卷未绑定。 - 解决:扩容节点或调小 Pod
requests;添加tolerations容忍污点;修正亲和性配置;检查 StorageClass 及底层存储状态。
- 排查:
-
问题 6:Pod 处于
ImagePullBackOff/ErrImagePull- 排查:
kubectl describe pod查看具体错误。404表示镜像名/Tag 错误;401/403表示私有仓库认证失败(缺imagePullSecrets);Timeout表示网络不通或 DNS 解析失败。 - 解决:修正镜像地址;创建并绑定
imagePullSecrets;配置节点网络代理或镜像加速器;检查节点 DNS 配置。
- 排查:
-
问题 7:Pod 处于
Evicted- 排查:
kubectl describe pod显示节点资源不足(The node was low on resource...)。通常是节点磁盘 ephemeral-storage 满(日志未轮转)或内存压力过大。 - 解决:清理节点无用镜像和容器日志;配置日志轮转(Log Rotation);设置合理的
ephemeral-storage请求/限制;非核心业务可部署 PDB (Pod Disruption Budget) 防止被误驱逐。
- 排查:
-
问题 8:Pod 卡在
ContainerCreating- 排查:
kubectl describe pod查看 Events。常见报错:MountVolume.SetUp failed(ConfigMap/Secret 不存在或 PVC 挂载超时)、Network plugin not ready(CNI 分配 IP 失败)。 - 解决:补全缺失的配置对象;修复存储后端(如 NFS 宕机);重启 CNI 插件或检查节点网络配置。
- 排查:
-
问题 9:Pod 显示
Running但频繁重启(隐蔽故障)- 排查:观察
RESTARTS计数持续增加。使用kubectl logs <pod> --previous查看上一次崩溃前的日志(关键步骤),常发现应用死锁或被 Liveness 探针误杀。 - 解决:根据历史日志修复应用 Bug;优化探针逻辑(区分“启动中”和“假死”),避免过于激进的 restart 策略。
- 排查:观察
31. 执行 kubectl get node 命令后看不到某些节点的原因?
- 命名空间误解:Node 是集群级资源,不属于任何 Namespace,不需要加
-n,但如果用了错误的 context 可能连错集群。 - 节点未加入集群:Worker 节点从未成功执行
kubeadm join,或者 join 后网络不通导致心跳丢失。 - 标签过滤:如果不小心使用了
kubectl get node -l ...且标签不匹配。 - 权限不足:当前使用的 ServiceAccount 或 User 没有
list nodes的 RBAC 权限。 - 节点被删除:节点已被管理员手动删除或自动伸缩组缩容。
- 显示问题:节点存在但状态极差,尝试加
-o wide查看详细信息。
32. 执行 kubectl get cs 查看集群状态不正常,显示 Unhealthy 的原因?
- 背景:
cs(ComponentStatus) 是旧版 API,依赖 kube-controller-manager 和 kube-scheduler 向 API Server 汇报自身状态。 - 常见原因:
- 版本废弃:在 K8s v1.22+ 版本中,ComponentStatus API 已被弃用 (Deprecated) 并移除,不再可靠。现代集群不应依赖此命令判断健康度。
- 组件配置错误:在旧版本中,如果 scheduler 或 controller-manager 启动参数中
--port=0(禁用了不安全端口)或未正确配置向 API Server 汇报的地址,会导致显示 Unhealthy。 - 网络隔离:API Server 无法连接到 scheduler/cm 的状态端口。
- 正确做法:直接检查组件 Pod 的状态 (
kubectl get pods -n kube-system) 或查看系统日志,而不是依赖get cs。
33. Kubectl 命令中 create 和 apply 创建资源的区别?
kubectl create:- 命令式:意图是“创建这个资源”。
- 行为:如果资源已存在,会报错
AlreadyExists。不支持更新现有资源。 - 场景:脚本初始化、一次性创建、确保资源不存在时创建。
kubectl apply:- 声明式:意图是“确保集群状态与 YAML 文件一致”。
- 行为:如果资源不存在则创建;如果已存在,则计算差异并进行补丁更新 (Patch)。支持记录最后应用的配置注解 (
last-applied-configuration)。 - 场景:CI/CD 流水线、日常运维、GitOps,推荐作为标准操作方式。
34. Pod 资源共享机制如何实现?即:如何实现 Pod 中两个容器共享数据?
Pod 的核心设计就是共享上下文。
- 共享网络:
- Pod 内所有容器共享同一个 Network Namespace。
- 它们拥有相同的 IP 地址、端口空间。
- 容器间可以通过
localhost+ 端口号直接通信。 - 通过 Pause 容器(Infra Container)持有网络栈,业务容器加入该 Namespace。
- 共享存储:
- 通过定义 Volume(如
emptyDir,hostPath,persistentVolumeClaim)。 - 在 Pod spec 的
volumes字段定义卷。 - 在不同容器的
volumeMounts字段中挂载同一个卷名到各自的路径。 - 这样多个容器可以读写同一份文件系统数据。
- 通过定义 Volume(如
- 共享 IPC/PID (可选):
- 通过设置
shareProcessNamespace: true,容器间可以看到彼此的进程 ID,甚至进行信号通信。
- 通过设置
35. 容器之间是通过什么进行隔离的?
主要依赖 Linux 内核的两大特性:
- Namespaces (命名空间):实现资源视图隔离。
- 让进程以为自己是系统中唯一的进程,拥有独立的网络、主机名、用户 ID、文件系统挂载点等。
- 类型:PID, Net, IPC, Mnt, UTS, User。
- Cgroups (Control Groups):实现资源用量限制。
- 限制、记录和隔离进程组所使用的物理资源(CPU 时间片、内存上限、IO 带宽等)。
- 防止单个容器耗尽宿主机资源。
(辅助技术:Capabilities 能力集限制,Seccomp 系统调用过滤,SELinux/AppArmor 安全模块)
36. Pod 常用的状态有哪些?
- Pending:API Server 已接受请求,但 Pod 尚未调度成功,或镜像正在下载中。
- Running:Pod 已绑定到节点,所有容器已创建,至少有一个容器正在运行或即将启动。
- Succeeded:所有容器都成功终止(退出码 0),且不会重启(常用于 Job)。
- Failed:所有容器都已终止,且至少有一个容器是非正常退出(退出码非 0)。
- Unknown:由于通信问题(如节点失联),无法获取 Pod 状态。
- (常见中间状态) ContainerCreating, Terminating, CrashLoopBackOff (重启等待中), ErrImagePull。
37. 节点选择器(Node Selector)都有什么?各自的区别是什么?
主要有三种机制,灵活度递增:
- nodeSelector:
- 形式:简单的键值对 (
key: value)。 - 逻辑:必须匹配所有标签(AND 关系)。
- 缺点:功能单一,无法表达复杂逻辑(如 OR, NOT)。
- 形式:简单的键值对 (
- Node Affinity (节点亲和性):
- 形式:在
affinity字段中定义,支持表达式。 - 类型:
requiredDuringSchedulingIgnoredDuringExecution:硬约束,必须满足,否则不调度。preferredDuringSchedulingIgnoredDuringExecution:软约束,尽量满足,打分制。
- 优势:支持
In,NotIn,Exists,Gt,Lt等操作符,可组合逻辑。
- 形式:在
- Taints and Tolerations (污点和容忍):
- 区别:前两者是 Pod“主动选择”节点;这是节点“拒绝”Pod,除非 Pod 有“容忍度”。用于将特定 Pod 独占到特定节点,或阻止普通 Pod 调度到特殊节点(如 Master)。
38. 污点(Taint)和容忍度(Toleration)是什么?两者是如何配合使用的?
- Taint (污点):打在 Node 上。表示“别惹我”,默认排斥所有不带相应容忍度的 Pod。
- 格式:
Key=Value:Effect - Effect 类型:
NoSchedule:新 Pod 不能调度上来(已有的不管)。PreferNoSchedule:尽量不调度(软限制)。NoExecute:新 Pod 不能调度,且已运行的不匹配 Pod 会被驱逐。
- 格式:
- Toleration (容忍度):写在 Pod Spec 中。表示“我能忍受这个污点”。
- 配合流程:
- 管理员给 Master 节点打上污点:
kubectl taint nodes master node-role.kubernetes.io/master:NoSchedule。 - 普通 Pod 没有容忍度 -> 调度失败。
- 系统组件 Pod(如 CNI, kube-proxy)在 Spec 中配置了 toleration 匹配该 key/effect -> 允许调度到 Master。
- 管理员给 Master 节点打上污点:
39. Service 的 4 种类型?
- ClusterIP(默认):仅在集群内部暴露一个虚拟 IP。用于内部微服务互访。
- NodePort:在 ClusterIP 基础上,在每个节点的指定端口(30000-32767)暴露服务。外部可通过
NodeIP:NodePort访问。 - LoadBalancer:在 NodePort 基础上,请求云厂商创建一个外部负载均衡器(ELB/SLB),将流量转发到 NodePort。用于公有云环境对外暴露。
- ExternalName:不涉及代理。将服务映射到 DNS 名称(如
my.db.example.com)。Pod 访问该 Service 时,DNS 解析直接返回外部域名。用于访问集群外部的数据库或服务。
40. Service 的两种代理模式(iptables/IPVS)?
由 kube-proxy 实现:
- iptables:
- 原理:利用 Linux Netfilter 框架,为每个 Service 生成大量的 NAT 规则链。
- 优点:稳定,几乎所有 Linux 内核默认支持。
- 缺点:规则是线性的。当 Service 和 Endpoint 数量巨大时(成千上万),规则链变长,流量匹配延迟增加,性能下降明显。更新规则需全量刷新,可能有短暂中断。
- IPVS:
- 原理:利用 Linux 内核的 IP Virtual Server 模块,在内核态维护哈希表。
- 优点:高性能。查找复杂度为 O(1),适合大规模集群。支持更多负载均衡算法(轮询、最小连接、源地址哈希等)。
- 要求:节点内核需加载
ip_vs模块。K8s v1.11+ 成熟支持。 - 现状:大规模生产环境推荐使用 IPVS 模式。
41. K8s 提供了哪几种对外暴露访问方式?
从简单到复杂,主要有以下几种:
- NodePort:最简单,直接利用节点 IP+ 高位端口。适合测试或无 LB 环境。
- LoadBalancer Service:利用云厂商 LB。适合公有云,成本较高,每个 Service 对应一个 LB IP。
- Ingress(最常用):
- 七层负载均衡(HTTP/HTTPS)。
- 只需一个 LB IP(入口),通过域名和路径路由到集群内不同的 Service。
- 支持 SSL 终止、重写规则等。需部署 Ingress Controller (Nginx, Traefik, ALB Ingress)。
- Gateway API:Ingress 的继任者,更通用、更强大的标准,支持 TCP/UDP/gRPC 等多种协议和更细粒度的路由控制(逐渐普及中)。
- HostNetwork + HostPort:直接使用宿主机网络(不推荐,耦合度高,端口易冲突)。
4. 监控和日志 (Monitoring & Logging)
42. K8s 的监控(Prometheus)常用监控组件有哪些?各自作用?
🏗️ Prometheus K8s 监控架构流程图
graph TD
%% 定义样式
classDef source fill:#e1f5fe,stroke:#01579b,stroke-width:2px;
classDef core fill:#fff3e0,stroke:#e65100,stroke-width:2px;
classDef alert fill:#ffebee,stroke:#b71c1c,stroke-width:2px;
classDef viz fill:#e8f5e9,stroke:#1b5e20,stroke-width:2px;
classDef k8s fill:#f3e5f5,stroke:#4a148c,stroke-width:2px,stroke-dasharray: 5 5;
subgraph K8s_Cluster [Kubernetes 集群内部]
direction TB
subgraph Data_Sources [数据源层]
Node[🖥️ 节点 Node]:::source
Kubelet["⚙️ Kubelet (内置 cAdvisor)"]:::source
API_Server["📡 API Server"]:::k8s
App[📦 业务应用/Pod]:::source
end
subgraph Exporters [采集器层]
NodeExp["📊 Node Exporter (宿主机指标)"]:::core
KSM["🔍 Kube-State-Metrics (对象状态)"]:::core
AppExp["🔌 Blackbox/自定义 Exporter"]:::core
end
subgraph Core_Prom [核心服务层]
PromServer[("🔴 Prometheus Server (存储/计算)")]:::core
end
end
subgraph External_Systems [外部/辅助系统]
AlertMgr["🔔 Alertmanager (告警处理)"]:::alert
Grafana["📈 Grafana (仪表盘)"]:::viz
HPA["🔄 HPA (自动伸缩)"]:::k8s
Adapter["🔌 Prometheus Adapter"]:::core
Notify["📧 通知渠道 (钉钉/邮件)"]:::alert
end
%% 数据流向
Node -->|暴露端口 9100| NodeExp
Kubelet -->|容器资源指标| PromServer
NodeExp -->|硬件指标| PromServer
KSM --- API_Server
KSM -->|K8s 对象状态| PromServer
App -->|暴露 /metrics| PromServer
App -.->|可选扩展| AppExp
AppExp -->|业务指标| PromServer
PromServer -->|1. 触发告警规则| AlertMgr
AlertMgr -->|2. 路由通知| Notify
PromServer -->|3. 查询展示| Grafana
PromServer -->|4. 提供自定义指标| Adapter
Adapter -->|5. 转换 Metrics API| HPA
HPA -->|6. 扩缩容调度| API_Server
%% 布局优化
linkStyle default stroke:#333,stroke-width:1.5px;
📝 架构组件详细解读
1. 数据源层 (Data Sources)
- Kubelet (cAdvisor): 每个节点上的 Kubelet 内置了 cAdvisor,自动采集容器级别的资源数据(CPU、内存、网络、文件系统),无需额外部署 Exporter。
- Node: 物理机或虚拟机本身,需要安装 Node Exporter 来采集宿主机层面的硬件和 OS 指标。
- API Server: K8s 的核心大脑,存储所有对象的状态信息。
- Applications: 运行在 Pod 中的业务程序,通过代码埋点暴露
/metrics接口。
2. 采集器层 (Exporters)
- Node Exporter: DaemonSet 部署,将宿主机的硬件指标转化为 Prometheus 格式。
- Kube-State-Metrics (KSM): 关键组件。它不关心资源用了多少,只关心状态对不对。例如:Pod 是 Running 还是 Pending?它将 API Server 的状态转化为指标。
- Custom Exporters: 针对特定中间件(如 MySQL, Redis)或黑盒监控(Blackbox Exporter)的采集器。
3. 核心服务层 (Core)
- Prometheus Server:
- Pull 模型: 主动去抓取上述所有 Exporter 暴露的指标。
- TSDB: 将数据存储在本地时间序列数据库中。
- PromQL: 提供强大的查询语言进行数据分析。
- Rule Manager: 评估告警规则,触发时发送给 Alertmanager。
4. 告警处理层 (Alerting)
- Alertmanager:
- 接收 Prometheus 发出的原始告警。
- 去重/分组/静默: 减少告警轰炸,合并同类项,并在维护期间屏蔽特定告警。
- 路由: 根据标签将告警发送给对应渠道(钉钉、邮件、Slack 等)。
5. 展示与应用层 (Visualization & Action)
- Grafana: 仪表盘展示,连接 Prometheus 数据源。
- Prometheus Adapter + HPA:
- Adapter 将 Prometheus 指标转换为 K8s 能够识别的 Metrics API。
- HPA 根据这些自定义指标(如 QPS)实现自动伸缩。
💡 核心区别总结
- cAdvisor vs Node Exporter: 前者看容器,后者看宿主机。
- KSM 的特殊性: 它监控的是 K8s 对象的生命周期状态(如副本数是否匹配),而不是 CPU 这种瞬时资源用量。
43. cAdvisor、node-exporter、metrics-server 的区别和联系?
- cAdvisor:
- 来源:Google 开发,已集成到 Kubelet 二进制文件中,无需单独部署。
- 作用:采集单个节点上所有容器的资源使用数据(CPU, Memory, Network, FS)。
- 数据粒度:容器级。
- Node Exporter:
- 来源:Prometheus 社区项目,需作为 DaemonSet 单独部署。
- 作用:采集**宿主机(Node)**本身的硬件和 OS 指标(如物理 CPU 负载、磁盘剩余空间、系统 uptime)。
- 数据粒度:节点级(不含容器内部细节)。
- Metrics Server:
- 来源:K8s 官方组件。
- 作用:聚合器。它从每个节点的 Kubelet(调用 cAdvisor 接口)收集数据,进行汇总,并通过 K8s Metrics API (
kubectl top) 提供短期、实时的资源使用数据。 - 用途:主要用于
kubectl top命令和 HPA (Horizontal Pod Autoscaler) 的自动伸缩决策。 - 区别:它不存储历史数据,重启后数据丢失;而 Prometheus 用于长期存储和历史趋势分析。
- 联系:Metrics Server 的数据源头很大程度上依赖 Kubelet 中的 cAdvisor;而 Prometheus 可以同时抓取 cAdvisor (通过 Kubelet)、Node Exporter 和 KSM 的数据进行全方位监控。
44. Pod 常见的状态有哪些?(结合生命周期回答)
Pod 的状态(Phase)反映了其在生命周期中的位置:
- Pending:API Server 已创建对象,但 Pod 尚未调度到节点,或者正在下载镜像。
- 生命周期阶段:调度前或初始化中。
- Running:Pod 已绑定节点,所有容器已创建,至少有一个容器正在运行、即将启动或重启中。
- 生命周期阶段:正常运行中。
- Succeeded:所有容器都成功终止(退出码 0),且不会重启。
- 生命周期阶段:任务完成(常见于 Job)。
- Failed:所有容器都已终止,且至少有一个容器是非正常退出(退出码非 0)。
- 生命周期阶段:任务失败。
- Unknown:由于节点通信故障,无法获取 Pod 状态。
- 生命周期阶段:状态丢失。
- 常见中间/异常状态(Status 字段显示):
ContainerCreating:正在拉取镜像或挂载卷。ErrImagePull/ImagePullBackOff:镜像拉取失败。CrashLoopBackOff:容器反复崩溃重启,K8s 在等待冷却期。OOMKilled:容器因内存超限被内核杀死。Terminating:Pod 正在被删除,等待优雅终止。
45. Node 节点不能工作的处理流程?
当发现节点异常(如 NotReady 或无响应)时:
- 查看状态:
kubectl get nodes确认状态(NotReady, Unknown)。 - 检查 Pod:
kubectl get pods -n kube-system -o wide | grep <node-name>查看该节点上的系统组件(CNI, kube-proxy)是否正常运行。 - 登录节点:SSH 登录到故障节点。
- 检查系统资源:
top,free -m,df -h查看 CPU、内存、磁盘是否满载(磁盘满会导致 kubelet 停止工作)。 - 检查关键服务:
systemctl status kubelet:查看 kubelet 是否存活,journalctl -u kubelet -f查看日志报错(如证书过期、配置错误、CNI 插件报错)。systemctl status docker或containerd:检查容器运行时。
- 检查网络:Ping Master 节点 API Server IP,检查防火墙规则,检查 CNI 插件配置。
- 检查证书:
/etc/kubernetes/pki/下的证书是否过期。 - 尝试重启:
systemctl restart kubelet。 - 极端情况:如果节点彻底失联且无法恢复,可能需要
kubectl drain驱逐业务,然后kubectl delete node移除节点,重新初始化加入。
46. K8s 常见健康检查的探针(Probe)有几种?
主要有三种,作用于容器级别:
- Liveness Probe(存活探针):
- 作用:判断容器是否“死锁”或“假死”。
- 失败动作:重启容器(Restart)。
- 场景:程序死循环、线程池耗尽但进程未退出。
- Readiness Probe(就绪探针):
- 作用:判断容器是否“准备好接收流量”。
- 失败动作:从 Service 的 Endpoints 中移除 IP(切断流量),不重启。
- 场景:应用启动加载大文件、依赖的 DB 尚未连通。
- Startup Probe(启动探针) (K8s 1.16+ Beta, 1.18+ Stable):
- 作用:专门用于处理启动缓慢的应用。在它成功之前,Liveness 和 Readiness 都不会执行。
- 失败动作:无(直到成功或达到失败阈值导致 Pod 重启)。
- 场景:遗留应用启动需要几分钟,避免 Liveness 探针过早杀掉正在启动的容器。
47. K8s 中网络通信类型有几种?
K8s 网络模型要求满足以下四种通信场景:
- Pod 与 Pod 之间(同一节点或不同节点):直接通过 IP 通信,无需 NAT。
- Pod 与 Service 之间:通过 Service VIP 和 kube-proxy 规则进行负载均衡通信。
- 外部用户与 Service 之间:通过 NodePort, LoadBalancer 或 Ingress 访问集群内部服务。
- 节点与 Pod 之间:节点上的组件(如 kubelet, prometheus)访问本地或其他节点的 Pod。
48. K8s 中网络插件(CNI)有哪些?各自特点是什么?
CNI (Container Network Interface) 是标准接口,常见插件:
- Flannel:
- 特点:简单、轻量、易部署。Overlay 网络(VXLAN 模式)。
- 缺点:功能单一,不支持 NetworkPolicy(网络策略),性能一般(VXLAN 有封装损耗)。
- 场景:小型集群、测试环境、对网络策略无要求的场景。
- Calico:
- 特点:高性能(支持 BGP 路由模式,无封装损耗),功能强大(支持严格的 NetworkPolicy),生态成熟。
- 缺点:BGP 模式对底层网络有一定要求(需支持 BGP 或 IPIP 穿透)。
- 场景:生产环境首选,特别是需要网络隔离和大规模集群。
- Cilium:
- 特点:基于 eBPF 技术,性能极高,可观测性强(Hubble),支持七层网络策略(HTTP/gRPC)。
- 场景:对性能、安全、可观测性有极高要求的现代化集群。
- Weave Net:
- 特点:自动加密(sleeve 模式),部署极其简单。
- 场景:对安全性有基础要求且不想复杂配置的场景。
- Cloud Provider CNI (如 AWS VPC CNI, Aliyun Terway):
- 特点:直接将 Pod 分配到云厂商的 VPC 子网中,Pod 拥有真实云内网 IP。
- 场景:公有云托管集群,追求原生网络性能和兼容性。
49. Pod 网络连接超时的几种情况?
- CNI 插件故障:节点上的 CNI 组件未运行或配置错误,导致 Pod 网卡未正确分配 IP 或路由不通。
- NetworkPolicy 拦截:配置了默认拒绝(Deny All)的策略,且未放行特定流量。
- 目标 Pod 未就绪:目标 Pod 的 Readiness Probe 失败,流量未被转发(如果是通过 Service 访问)。
- 防火墙/安全组:云厂商的安全组或节点内部的
iptables/firewalld阻断了端口。 - IP 冲突或路由缺失:跨节点通信时,底层物理网络路由不可达,或 Overlay 隧道建立失败。
- DNS 解析超时:如果是通过域名访问,CoreDNS 故障或配置错误导致解析慢或失败。
- 应用自身问题:目标应用处理请求过慢、死锁或监听地址错误(如只监听了 localhost)。
50. 访问 Pod 的 IP:端口 或 Service 的 IP 显示超时的处理思路?
排查步骤:
- 确认目标状态:
kubectl get pod/svc确认 Pod 是 Running,Service 有 Endpoints。- 关键点:如果 Service 的 Endpoints 为空,说明没有后端 Pod,流量无处转发。
- 同节点测试:登录到 Pod 所在的节点,使用
curl <Pod_IP>:<Port>测试。- 如果通:说明 Pod 正常,问题在跨节点网络或 Service 规则。
- 如果不通:说明 Pod 应用未启动、监听端口错误或节点本地防火墙/CNI 问题。
- 检查 NetworkPolicy:
kubectl get networkpolicy查看是否有策略限制了源或目的。 - 检查 kube-proxy:查看
kube-proxy日志,确认 iptables/IPVS 规则是否生成。在节点执行iptables-save | grep <Service_IP>查看规则是否存在。 - 抓包分析:在源 Pod 或节点上使用
tcpdump抓包,看 SYN 包是否发出,是否有 RST 或 DROP。 - DNS 检查:如果是域名访问超时,先试 IP。如果 IP 通域名不通,排查 CoreDNS。
- MTU 问题:跨节点大包不通可能是 MTU 设置不一致(Overlay 网络需预留头部空间)。
51. Pod 的生命周期阶段?
从创建到销毁的标准流程:
- Pending:创建申请提交,等待调度。
- ContainerCreating:调度完成,正在拉取镜像、挂载存储、配置网络。
- Running:
- Init Containers 执行(如果有)。
- Main Containers 启动。
- Probes 开始工作(Startup -> Readiness -> Liveness)。
- Succeeded / Failed:任务型 Pod 的最终状态。
- Terminating:
- 收到删除指令。
- 发送
SIGTERM信号给容器进程(优雅退出)。 - 等待
terminationGracePeriodSeconds(默认 30s)。 - 若未退出,发送
SIGKILL强制杀死。 - 清理资源(网络、存储挂载)。
- Deleted:从 Etcd 和 API 中移除。
52. Pod 处于 Running,但应用不正常的几种情况?
Running 仅代表容器进程在运行,不代表业务正常:
- 应用内部报错:代码逻辑错误、配置文件错误、依赖服务连不上(需看
kubectl logs)。 - 死锁/假死:进程在跑,但无法处理请求(需靠 Liveness Probe 发现并重启)。
- 未通过就绪检查:应用启动慢或依赖未好,流量被切断(需看 Readiness Probe 状态,
kubectl describe pod)。 - 资源限制:CPU 被节流(Throttling)导致响应极慢,或内存接近 Limit 导致频繁 GC。
- 端口监听错误:进程启动了,但监听在错误的 IP(如 127.0.0.1 而不是 0.0.0.0)或错误端口。
- 持久化存储满:磁盘写满导致应用无法写入日志或数据而卡住。
- 时钟不同步:节点时间偏差导致 TLS 握手失败或逻辑判断错误。
53. 当遇到 CoreDNS 经常重启和报错,这种故障如何排查?
CoreDNS 是集群 DNS 核心,不稳定会影响全网。
排查思路:
- 查看日志:
kubectl logs -n kube-system -l k8s-app=kube-dns。- 常见错误:
plugin/loop: Loop in Hints(通常是因为节点 hosts 文件配置不当或上游 DNS 配置环路)。 - OOMKilled:内存不足,需调整
limits.memory。
- 常见错误:
- 检查配置 (ConfigMap):
kubectl edit cm coredns -n kube-system。- 检查
forward插件指向的上游 DNS 是否可达。 - 检查是否有语法错误。
- 检查
- 检查网络插件兼容性:某些 CNI 插件(如早期版本的 Calico/Flannel)与 CoreDNS 的 IP 分配或网络策略冲突。
- 检查节点 DNS 配置:CoreDNS 依赖宿主机的
/etc/resolv.conf进行上游转发,如果宿主机 DNS 配置错误,CoreDNS 也会失效。 - 资源竞争:节点负载过高导致 CoreDNS 被误杀或调度不均,建议设置亲和性让 CoreDNS 分散在不同节点。
- 版本问题:K8s 版本升级后,CoreDNS 配置格式可能变化(如
proxy改为forward)。
54. K8s 集群节点状态为 NotReady 的都有哪些情况?
NotReady 意味着 Kubelet 无法向 API Server 上报“我准备好了”的状态。
常见原因:
- Kubelet 服务挂掉:
systemctl status kubelet显示 inactive 或 failed。 - 容器运行时故障:Docker/Containerd 未运行或无响应,Kubelet 无法检查容器状态。
- CNI 插件未就绪:节点上的 CNI 配置缺失或 Pod 网络未打通,Kubelet 会认为节点未准备好(
NetworkPluginNotReady)。 - 资源耗尽:
- 磁盘压力 (
DiskPressure):日志或镜像占满磁盘,Kubelet 进入保护模式。 - 内存压力 (
MemoryPressure)。 - PID 耗尽 (
PIDPressure)。
- 磁盘压力 (
- 证书过期:Kubelet 连接 API Server 的客户端证书过期,导致认证失败,心跳中断。
- 时间不同步:节点时间与集群其他节点偏差过大,导致 TLS 握手失败。
- 网络中断:节点与 Master 节点之间的网络不通,心跳包丢失。
- Swap 未关闭:K8s 默认要求关闭 Swap,如果开启且 Kubelet 配置未允许,可能导致启动失败或状态异常。
5. 调度和资源管理 (Scheduling & Resources)
55. K8s 的几种调度方式?
Kubernetes 的调度不仅仅是“自动”,它提供了多种策略来控制 Pod 落在哪个节点上:
- 自动调度 (Default Scheduler):
- 由
kube-scheduler根据节点的剩余资源(CPU/Mem)、亲和性、污点等默认策略,自动选择最优节点。
- 由
- 指定节点调度 (nodeName):
- 在 Pod Spec 中直接指定
nodeName: <node-name>。 - 特点:跳过调度器,强制绑定。如果该节点资源不足或不存在,Pod 会一直 Pending。
- 在 Pod Spec 中直接指定
- 节点选择器 (nodeSelector):
- 基于简单的键值对标签匹配 (
key: value)。节点必须拥有该标签才能被调度。
- 基于简单的键值对标签匹配 (
- 节点亲和性 (Node Affinity):
- 硬策略 (required...):必须满足条件,否则不调度。支持复杂的逻辑运算(In, NotIn, Exists 等)。
- 软策略 (preferred...):尽量满足,打分制,不满足也能调度。
- 污点与容忍 (Taints and Tolerations):
- 排斥机制。节点设置污点(Taint),Pod 设置容忍度(Toleration)。只有容忍了污点的 Pod 才能调度到该节点。常用于专用节点(如 GPU 节点)或 Master 节点隔离。
- Pod 亲和性与反亲和性 (Pod Affinity/Anti-Affinity):
- 根据其他 Pod的位置来调度。
- 亲和:让 Pod 尽量靠近某些 Pod(如同一服务的不同组件)。
- 反亲和:让 Pod 尽量远离某些 Pod(如将同一应用的副本分散到不同节点/可用区,实现高可用)。
- 拓扑分布约束 (Topology Spread Constraints):
- 更精细的控制,确保 Pod 在指定的拓扑域(如可用区、主机名、区域)中均匀分布,避免倾斜。
56. K8s 中一个 Node 节点突然断电,恢复后上面的 Pod 无法启动怎么办?
这种情况通常是因为节点状态异常或资源冲突。
排查与解决步骤:
- 检查节点状态:
kubectl get nodes。如果节点仍为NotReady,先修复节点(参考第 54 题:检查 kubelet、CNI、证书、资源等)。
- 检查 Pod 状态:
kubectl get pods -o wide | grep <node-name>。- 如果 Pod 状态是
Terminating且卡住:说明节点失联,API Server 收不到删除确认。需强制删除:kubectl delete pod <pod-name> --grace-period=0 --force。控制器(Deployment)会自动在其他健康节点重建新 Pod。 - 如果 Pod 状态是
Pending:可能是原节点资源未释放,或者调度器认为原节点不可用但还没触发驱逐逻辑。
- 检查驱逐逻辑:
- K8s 有
pod-eviction-timeout(默认 5 分钟)。如果节点失联超过此时间,控制器管理器会将 Pod 标记为终止并重新调度。如果刚恢复,可能还在等待期内。
- K8s 有
- 资源冲突:
- 如果节点恢复后,原来的 Pod 试图启动但失败,检查是否因为挂载的卷(Volume)具有
ReadWriteOnce(RWO) 属性,且未被正确卸载(例如云盘还挂载在旧的网络命名空间或认为仍被占用)。可能需要手动介入解除挂载或重启 kubelet。
- 如果节点恢复后,原来的 Pod 试图启动但失败,检查是否因为挂载的卷(Volume)具有
- 最终手段:
- 如果节点数据损坏严重,最稳妥的方式是:
kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data(如果节点可达) 或直接kubectl delete node <node-name>,然后重置该节点并重新加入集群,让 Pod 调度到其他节点。
- 如果节点数据损坏严重,最稳妥的方式是:
57. Pod 超过节点资源限制的故障情况有哪些?
这里指 Pod 请求/限制超过了节点能提供的能力,或运行时超出了 Limit。
- 调度失败 (Pending):
- 原因:Pod 的
requests(请求值) 大于任何可用节点的剩余资源。 - 现象:Pod 一直处于
Pending状态,事件显示FailedScheduling: Insufficient cpu/memory。
- 原因:Pod 的
- OOMKilled (内存超限):
- 原因:容器进程使用的内存超过了
limits.memory。 - 现象:Pod 状态变为
Running但容器反复重启,kubectl get pod显示OOMKilled,退出码 137。
- 原因:容器进程使用的内存超过了
- CPU 节流 (Throttling):
- 原因:容器使用的 CPU 超过了
limits.cpu。 - 现象:Pod 不会重启,但应用响应变慢、卡顿。可以通过监控看到
cpu_cfs_throttled_seconds_total指标升高。
- 原因:容器使用的 CPU 超过了
- Evicted (被驱逐):
- 原因:节点整体资源不足(如磁盘满、内存压力),Kubelet 主动驱逐优先级较低(QoS 为 BestEffort 或 Burstable)的 Pod。
- 现象:Pod 状态变为
Failed,理由为Evicted。
- 创建失败 (CreateContainerConfigError):
- 原因:极少见,但如果配置的 Limit 小于 Request,或者数值格式错误,会导致无法创建。
58. Pod 的自动扩容和缩容的方法有哪些?(HPA/VPA)
- HPA (Horizontal Pod Autoscaler,水平自动伸缩):
- 原理:增加或减少 Pod 的副本数量。
- 指标:基于 CPU 使用率、内存使用率,或通过 Metrics Server/Prometheus Adapter 获取自定义指标(如 QPS、消息队列长度)。
- 适用:无状态应用(Deployment),最常用的扩缩容方式。
- 命令:
kubectl autoscale deployment <name> --cpu-percent=50 --min=1 --max=10。
- VPA (Vertical Pod Autoscaler,垂直自动伸缩):
- 原理:调整 单个 Pod 的资源请求 (requests) 和限制 (limits)(即加大/减小 CPU/内存配额)。
- 代价:调整资源通常需要重启 Pod 才能生效(因为容器启动时已确定 cgroup 限制)。
- 适用:有状态应用或无法简单通过增加副本来扩展的应用。注意:HPA 和 VPA 通常不建议同时用于同一个资源的同一个维度(如都控制 CPU),以免冲突。
- Cluster Autoscaler (CA,集群自动伸缩):
- 原理:当 Pod 因资源不足无法调度(Pending)时,自动增加节点;当节点利用率低时,自动减少节点。
- 依赖:需要云厂商支持或底层基础设施支持动态添加机器。
- 关系:通常配合 HPA 使用。HPA 增加 Pod -> 资源不足 -> CA 增加 Node。
59. K8s 中 Service 访问异常的常见问题有哪些?如何处理?
- Endpoints 为空:
- 原因:Service 的
selector标签与 Pod 的labels不匹配。 - 处理:
kubectl get endpoints <svc-name>查看是否为空。修正 Deployment 或 Service 的标签。
- 原因:Service 的
- 目标 Pod 未就绪:
- 原因:Pod 虽然 Running,但 Readiness Probe 失败,导致 IP 被从 Endpoints 移除。
- 处理:
kubectl describe pod查看探针失败原因,修复应用启动逻辑或调整探针参数。
- 网络插件 (CNI) 问题:
- 原因:跨节点通信失败,iptables/IPVS 规则未生成。
- 处理:检查 CNI 插件 Pod 状态,重启 kube-proxy,检查节点间网络连通性。
- 端口映射错误:
- 原因:Service 的
targetPort与容器实际监听端口不一致。 - 处理:核对 YAML 配置。
- 原因:Service 的
- NetworkPolicy 拦截:
- 原因:存在默认拒绝的 NetworkPolicy。
- 处理:
kubectl get networkpolicy,检查入站/出站规则,添加允许规则。
- DNS 解析失败:
- 原因:CoreDNS 故障。
- 处理:尝试直接用 IP 访问。如果 IP 通域名不通,排查 CoreDNS(参考第 53 题)。
60. K8s 中 Pod 删除失败,有哪些情况?和如何解决?
Pod 卡在 Terminating 状态无法删除:
- 节点失联 (Node Unreachable):
- 原因:Pod 所在的节点宕机或网络中断,API Server 发送删除指令后,Kubelet 无法接收并执行,也无法上报状态。
- 解决:强制删除。
kubectl delete pod <pod-name> --grace-period=0 --force。这会直接从 Etcd 移除记录,但需注意如果是有状态应用,可能需要人工清理残留资源。
- Finalizers (终结器) 阻塞:
- 原因:Pod 或其他关联资源(如 PVC)上有
finalizers字段,控制器逻辑未完成清理工作(例如外部存储卷正在卸载中,或自定义控制器卡死)。 - 解决:
- 先排查关联控制器日志。
- 若确认安全,可手动编辑资源移除 finalizer:
kubectl edit pod <pod-name>,删除metadata.finalizers列表中的内容,保存后 K8s 会立即完成删除。
- 原因:Pod 或其他关联资源(如 PVC)上有
- 存储卷挂载无法卸载:
- 原因:底层存储(如 NFS、云盘)繁忙或驱动 bug,导致 Volume 无法 Detach。
- 解决:检查 CSI 驱动日志,必要时在节点上手动 umount,或重启该节点上的 kubelet。
- API Server 负载过高:
- 原因:集群并发量大,删除请求处理延迟。
- 解决:等待或扩容 API Server。
61. Pause 容器的概念和作用?
Pause 容器(也称为 Infra Container 或 Sandbox Container)是 K8s Pod 设计的核心基石。
- 概念:每个 Pod 在启动业务容器之前,都会先启动一个极小的镜像(
k8s.gcr.io/pause或registry.k8s.io/pause),这个容器就是 Pause 容器。 - 核心作用:
- 持有命名空间 (Hold Namespaces):
- Pause 容器负责创建并持有 Pod 共享的 Network Namespace(IP 地址、端口范围)和 IPC Namespace。
- 业务容器加入(Join)Pause 容器的网络命名空间,从而共享 IP 和 localhost 通信能力。
- 作为 PID 1 (Init Process):
- 在 Linux 中,PID 1 负责回收僵尸进程。Pause 容器作为一个极简的 init 进程运行,负责回收 Pod 内业务容器产生的僵尸进程,防止资源泄漏。
- 生命周期管理:
- 只要 Pause 容器活着,Pod 的网络环境就存在。
- 如果业务容器崩溃重启,Pause 容器不受影响,IP 地址保持不变,保证服务连续性。
- 只有当 Pause 容器退出时,整个 Pod 才会销毁。
- 持有命名空间 (Hold Namespaces):
- 为什么需要它?:如果没有 Pause 容器,当主业务容器重启时,其网络命名空间可能会重建,导致 IP 变化,破坏 K8s “Pod IP 固定”的承诺。
6. 网络和通信 (Networking)
62. 同一个节点多个 Pod 之间通信示意图及原理?
原理:
在同一个节点(Node)上,所有 Pod 都连接到同一个虚拟网桥(通常是 cni0 或 docker0,取决于 CNI 插件)。
- 网络命名空间隔离但连通:每个 Pod 有自己的 Network Namespace,拥有独立的 IP。
- 网桥转发:CNI 插件会在宿主机创建一个虚拟网桥,并将每个 Pod 的虚拟网卡(veth pair 的一端)插入到这个网桥中。
- 二层通信:当 Pod A 访问 Pod B 的 IP 时,数据包从 Pod A 发出 -> 经过 veth pair -> 到达宿主机网桥 -> 网桥根据 MAC 地址表直接转发给 Pod B 的 veth pair -> 进入 Pod B。
- 无需 NAT:同节点通信通常不需要经过 iptables 的 NAT 规则(除非有 NetworkPolicy 限制),直接通过二层交换完成,速度极快。
通信示意图:
+-----------------------+ Node (Host)
| |
| +-------+ |
| | Pod A |---(veth)--+
| | 10.244.1.2 | +---------+
| +-------+ +------| cni0 | (Virtual Bridge)
| +--| /172.17 |
| +-------+ +----| |
| | Pod B |---(veth)--+ +---------+
| | 10.244.1.3 | ^
| +-------+ | | (Direct L2 Forwarding)
| | v
+-----------------------+ (No NAT, No Routing needed usually)
63. 跨主机之间的多个 Pod 之间通信示意图及原理?
原理:
跨节点通信依赖于 CNI 插件实现的 Overlay 网络(如 VXLAN, IPIP)或路由模式(如 BGP)。以最常见的 Flannel VXLAN 为例:
- 路由查找:Pod A (Node 1) 发送数据包给 Pod B (Node 2)。Node 1 的路由表知道 Pod B 的网段属于 Node 2 的 IP。
- 封装 (Encapsulation):
- 数据包到达 Node 1 的网桥。
flanneld守护进程(或内核 VXLAN 模块)拦截数据包。- 将原始数据包(源 IP: Pod A, 目的 IP: Pod B)作为载荷,封装在一个新的 UDP 包中。
- 新包头:源 IP = Node 1 IP, 目的 IP = Node 2 IP, 目的端口 = 8472 (VXLAN 默认)。
- 物理传输:封装后的包通过物理网络发送到 Node 2。
- 解封装 (Decapsulation):
- Node 2 收到 UDP 包,识别是 VXLAN 流量。
- 剥离外层包头,还原出原始数据包。
- 根据内部目的 IP (Pod B),通过本地网桥转发给 Pod B。
通信示意图:
Node 1 Node 2
+------------+ +------------+
| Pod A | | Pod B |
| 10.244.1.2 | | 10.244.2.5 |
+-----+------+ +-----+------+
| veth ^ veth
v |
+-----+------+ +-----+------+
| cni0 | | cni0 |
| (Bridge) | | (Bridge) |
+-----+------+ +-----+------+
| ^
| [Original Pkt: Src=A, Dst=B] |
v |
+-----+------+ +-----+------+
| flannel.1 | (VXLAN Device) | flannel.1 |
| (Encap) | | (Decap) |
+-----+------+ +-----+------+
| ^
| [Outer Pkt: Src=Node1, Dst=Node2, Port=8472]
+-------------------------------------------+
Physical Network (Underlay)
(注:如果是 Calico BGP 模式,则不需要封装,直接通过路由协议将 Pod 网段广播到物理网络,性能更高)
64. K8s 中同一个命名空间下服务间是怎么调用的?
在同一个 Namespace 内,服务发现非常简洁,依赖 CoreDNS。
- DNS 解析:
- 应用 A 想要访问应用 B 的 Service,只需使用 Service 的名称,例如
http://my-service。 - Pod 内的
/etc/resolv.conf配置了搜索域为当前 Namespace。 - DNS 查询请求发送给 CoreDNS,CoreDNS 解析
my-service为对应的 ClusterIP。
- 应用 A 想要访问应用 B 的 Service,只需使用 Service 的名称,例如
- 流量转发:
- 应用 A 向 ClusterIP 发起请求。
- 节点上的
kube-proxy监听到该 ClusterIP 的流量,根据 iptables 或 IPVS 规则,将流量负载均衡转发到后端某个具体的 Pod IP。
- 简称调用:直接使用
ServiceName即可。
示例:
# App A 访问 App B
url: "http://backend-service:8080"
# DNS 解析 backend-service -> 10.96.x.x (ClusterIP)
65. K8s 中不同命名空间下服务是怎么调用的?
跨 Namespace 调用需要使用 FQDN (Fully Qualified Domain Name) 格式。
- DNS 格式:
- 格式:
<ServiceName>.<NamespaceName>.svc.cluster.local - 通常简写为:
<ServiceName>.<NamespaceName>(因为svc.cluster.local是默认搜索后缀)。
- 格式:
- 流程:
- 应用 A (NS:
dev) 访问 应用 B (NS:prod)。 - 调用地址:
http://db-service.prod。 - CoreDNS 解析
db-service.prod.svc.cluster.local得到prod命名空间下db-service的 ClusterIP。 - 后续流量转发逻辑同单命名空间(通过 kube-proxy 转发)。
- 应用 A (NS:
- 注意:NetworkPolicy 可能会默认禁止跨 Namespace 流量,需确认策略允许。
示例:
# 在 dev 命名空间的 Pod 中 curl prod 命名空间的 service
curl http://redis-master.production
# 完整域名:redis-master.production.svc.cluster.local
66. ExternalName 类型的 Service 的概念深入理解?
概念:
ExternalName 是 Service 的一种特殊类型,它不创建 ClusterIP,也不设置 iptables/IPVS 规则,更不进行代理。
它的唯一作用是将 Service 映射到一个外部的 DNS 名称(CNAME 记录)。
工作原理:
-
定义:
apiVersion: v1 kind: Service metadata: name: my-db namespace: default spec: type: ExternalName externalName: db.example.com # 外部真实域名 -
调用过程:
- 当 Pod 内应用访问
my-db.default.svc.cluster.local时。 - CoreDNS 拦截请求,发现这是一个
ExternalName类型的 Service。 - CoreDNS 直接返回 配置中的
db.example.com域名(作为 CNAME 记录)。 - 客户端(Pod 内的应用)收到 CNAME 后,会再次发起 DNS 查询去解析
db.example.com的真实 IP。 - 客户端直接向
db.example.com解析出的 IP 发起连接。
- 当 Pod 内应用访问
-
关键特点:
- 无代理:流量不经过 kube-proxy,也不经过 Service 的虚拟 IP。它是直连外部服务的。
- 依赖 DNS:完全依赖集群内部的 DNS 解析能力。
- 用途:
- 将集群外的数据库、消息队列抽象为集群内的 Service 名称,使应用代码无需修改(代码里写
my-db,实际连的是外部 AWS RDS 或自建 MySQL)。 - 实现服务迁移的透明化(先指向旧 IP,后期修改 Service 指向新 IP,应用无感知)。
- 将集群外的数据库、消息队列抽象为集群内的 Service 名称,使应用代码无需修改(代码里写
- 局限性:不支持端口映射(
externalName本身不带端口,依赖 DNS 解析后的默认端口或应用指定端口),不支持 Session Affinity,不支持选择器。
深入理解总结:
它本质上是一个 DNS 别名(CNAME),而不是一个真正的负载均衡器或代理。它解决了“如何让集群内应用通过统一的 Service 名称访问集群外资源”的问题,实现了内外网服务寻址的统一接口。
7. 日志和配置 (Logging & Config)
67. Docker 镜像的优化方法有哪些?
优化目标:减小体积、加快构建速度、提高安全性。
- 选择合适的基础镜像:
- 使用 Alpine 或 Distroless 镜像(体积极小,仅包含运行所需库,无 shell,安全性高)。
- 避免使用
ubuntu或centos等全量发行版,除非必须。
- 多阶段构建 (Multi-stage Builds):
- 在第一个阶段编译代码(需要 GCC, Maven 等重型工具)。
- 在第二个阶段只复制编译好的二进制文件/产物到干净的基础镜像中。
- 效果:最终镜像不包含编译工具和源代码,体积可减少 90% 以上。
- 优化 Dockerfile 指令顺序:
- 将变化频率低的指令(如安装系统依赖、复制
package.json)放在前面。 - 将变化频率高的指令(如复制源代码
COPY . .)放在最后。 - 原理:充分利用 Docker 的层缓存 (Layer Cache),加速构建。
- 将变化频率低的指令(如安装系统依赖、复制
- 合并 RUN 指令:
- 将多个
RUN命令合并为一个,用&&连接,并清理缓存(如apt-get clean,rm -rf /var/cache/apk/*)。 - 效果:减少镜像层数(Layer),减小体积。
- 将多个
- 使用
.dockerignore:- 排除不需要上传到 Docker 守护进程的文件(如
.git,node_modules,logs,*.md)。 - 效果:加快
docker build上下文传输速度,避免敏感信息泄露。
- 排除不需要上传到 Docker 守护进程的文件(如
- 移除无用文件:
- 删除文档、man pages、临时文件。
- 对于 Python/Node 应用,安装依赖时使用
--no-cache-dir或production模式。
68. K8s 中针对标准化输出方式(stdout/stderr)的日志,如何进行收集?
这是 K8s 推荐的日志处理方式(Cloud-Native 方式)。
- 原理:容器进程将日志打印到标准输出(stdout)和标准错误(stderr)。Docker/Containerd 捕获这些流,并将其写入节点上的 JSON 文件(通常位于
/var/log/pods/<pod_uid>/<container_name>/<run_id>.log)。 - 收集方案:
- DaemonSet 模式(主流):
- 在每个节点部署一个日志采集 Agent(如 Filebeat, Fluentd, Fluent Bit, Logstash)。
- Agent 以 DaemonSet 运行,挂载宿主机的
/var/log/pods目录。 - Agent 实时监控日志文件变化,解析 JSON,添加 Pod 元数据(Namespace, Pod Name, Labels),然后发送到中央存储(如 Elasticsearch, Kafka, S3)。
- Sidecar 模式(不推荐用于纯 stdout 日志,资源开销大):
- 在每个 Pod 中伴生一个日志容器,共享空目录卷,主容器将日志重定向到文件,Sidecar 收集发送。
- 直接推送:
- 应用 SDK 直接将日志推送到日志后端(侵入性强,不推荐)。
- DaemonSet 模式(主流):
69. K8s 中针对容器内部的日志文件,如何进行收集?
很多传统应用会将日志写入容器内的文件(如 /var/log/app/access.log),而非 stdout。
- 挑战:容器重启后,内部文件会丢失(如果是 emptyDir 或未挂载持久卷)。
- 收集方案:
- Sidecar 模式(经典方案):
- 在 Pod 中定义一个专门的日志 Sidecar 容器。
- 主容器和 Sidecar 共享一个
emptyDir或hostPath卷。 - 主容器将日志写入该卷中的文件。
- Sidecar 容器运行日志采集 agent(如 filebeat),监控该卷中的文件并发送到后端。
- 缺点:每个 Pod 多跑一个容器,资源消耗大,管理复杂。
- DaemonSet + 宿主机路径映射(推荐方案):
- 主容器将日志文件挂载到宿主机的特定目录(通过
hostPath或特定的卷插件)。 - 节点上的 DaemonSet 日志 Agent 监控宿主机上的这些特定目录。
- 注意:K8s 默认不推荐随意使用
hostPath,需规划好目录结构(如/var/log/myapp/<namespace>/<pod>)。
- 主容器将日志文件挂载到宿主机的特定目录(通过
- Log-Pilot / Filebeat 自动发现:
- 利用采集工具的自动发现机制,识别容器内的日志路径配置,直接从容器文件系统读取(需挂载
/var/lib/docker或/run/containerd等,较复杂且依赖运行时)。 - 更常见的做法是:修改应用配置,将日志路径指向一个挂载出来的 Volume,让外部 Agent 能访问到。
- 利用采集工具的自动发现机制,识别容器内的日志路径配置,直接从容器文件系统读取(需挂载
- Sidecar 模式(经典方案):
70. 什么是标准输出日志?什么是容器内部日志?
- 标准输出日志 (Standard Output/Stdout & Stderr):
- 定义:应用程序将日志信息打印到操作系统的标准输出流(文件描述符 1)或标准错误流(文件描述符 2)。
- 特点:
- 无状态:日志内容不保存在容器文件系统中,由容器运行时(Docker/Kubelet)接管并写入宿主机的日志文件。
- 生命周期:容器销毁后,日志仍保留在宿主机的日志文件中(直到被轮转清理)。
- 最佳实践:12-Factor App 原则推荐的方式,便于平台统一收集。
- 容器内部日志 (Container Internal Log Files):
- 定义:应用程序将日志写入容器文件系统内的具体文件路径(如
/app/logs/error.log)。 - 特点:
- 有状态(易失):如果日志文件所在的目录没有被挂载为持久卷(PVC)或 HostPath,容器重启或销毁后,日志文件会随容器一起消失。
- 收集困难:需要进入容器内部或通过特殊挂载才能读取。
- 传统习惯:传统虚拟机部署应用的遗留习惯。
- 定义:应用程序将日志写入容器文件系统内的具体文件路径(如
71. K8s 中阿里云开源软件 Log-Pilot 如何收集标准化输出的日志?
Log-Pilot 是阿里云开源的智能日志采集工具(底层基于 Filebeat),现已逐渐演进为更通用的方案,但其核心逻辑依然适用。
- 收集机制:
- DaemonSet 部署:Log-Pilot 以 DaemonSet 形式运行在每个节点。
- 监听 Docker/Containerd 事件:Log-Pilot 监听容器启动/停止事件。
- 自动挂载日志目录:它会自动挂载宿主机的
/var/log/pods(或 Docker 的 json-log 路径)。 - 标签过滤与解析:
- 通过读取容器的 Labels 或 Annotations(例如
aliyun.logs.stdout=stdout)。 - 识别出哪些容器是输出到 stdout 的。
- 通过读取容器的 Labels 或 Annotations(例如
- 采集与发送:
- 直接读取运行时生成的 JSON 日志文件。
- 解析 JSON,提取时间戳、日志内容。
- 自动注入 K8s 元数据(Pod Name, Namespace, Container Name)。
- 根据配置输出到 Elasticsearch、Kafka 等。
- 配置示例(通过 Annotation):
metadata: annotations: aliyun.logs.stdout: "stdout" # 告诉 Log-Pilot 采集该容器的标准输出 aliyun.logs.tags: "app=nginx" # 添加自定义标签
72. K8s 中阿里云开源软件 Log-Pilot 如何收集容器内的日志?
- 收集机制:
- 文件路径发现:Log-Pilot 支持通过环境变量或 Annotation 指定容器内部的日志文件路径。
- 挂载点映射:
- Log-Pilot 容器启动时,通常会挂载宿主机的整个文件系统根目录(或特定目录,如
/挂载到/host),或者利用 Docker 的驱动信息找到容器层的可读写层。 - 它能够“穿透”到容器内部的文件系统视图中去读取文件。
- Log-Pilot 容器启动时,通常会挂载宿主机的整个文件系统根目录(或特定目录,如
- 配置方式:
- 通过 Annotation 指定:
aliyun.logs.<name>=<path>。 - 例如:
aliyun.logs.access=/var/log/nginx/access.log。
- 通过 Annotation 指定:
- 工作流程:
- Log-Pilot 扫描到该 Annotation。
- 定位到对应容器的文件系统路径(例如
/var/lib/docker/overlay2/.../merged/var/log/nginx/access.log)。 - 像读取本地文件一样 Tail 该文件。
- 解析日志内容(支持正则、JSON、分隔符等格式)。
- 添加元数据并发送。
- 优势:无需在业务 Pod 中配置 Sidecar,也无需业务容器修改挂载卷,实现了无侵入式的容器内文件日志采集。
73. K8s 中 Pod 的亲和性(Affinity)和反亲和性(Anti-Affinity)的概念?如何配置?
概念:
- 亲和性 (Affinity):一种调度规则,表示 Pod 倾向于 或 必须 调度到满足特定条件的节点上(或靠近其他 Pod)。
- 反亲和性 (Anti-Affinity):一种调度规则,表示 Pod 尽量避免 或 禁止 调度到满足特定条件的节点上(或远离其他 Pod)。
- 目的:实现高可用(分散部署)、性能优化(就近部署)、硬件专用(GPU 节点)等。
类型:
- Node Affinity:基于节点标签的亲和/反亲和。
- Pod Affinity/Anti-Affinity:基于已运行 Pod 的标签的亲和/反亲和。
硬性 vs 软性:
requiredDuringSchedulingIgnoredDuringExecution(硬策略):必须满足,否则不调度。preferredDuringSchedulingIgnoredDuringExecution(软策略):尽量满足,打分制,不满足也能调度。
配置示例 (YAML):
apiVersion: v1
kind: Pod
metadata:
name: my-app
spec:
affinity:
# 1. 节点亲和性 (Node Affinity)
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd # 必须调度到有 disktype=ssd 标签的节点
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: zone
operator: In
values:
- cn-hangzhou-a # 优先调度到 A 区
# 2. Pod 反亲和性 (Pod Anti-Affinity) - 常用于高可用
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- my-app # 匹配自身标签
topologyKey: kubernetes.io/hostname
# 含义:同一个节点 (hostname) 上,不能运行两个 app=my-app 的 Pod
# 这样会强制将副本分散到不同节点
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- database
topologyKey: topology.kubernetes.io/zone
# 含义:尽量不和 database 类型的 Pod 在同一个可用区 (Zone)
关键点总结:
topologyKey:定义“在一起”或“分开”的范围(如kubernetes.io/hostname指同一节点,topology.kubernetes.io/zone指同一可用区)。- IgnoredDuringExecution:意味着一旦 Pod 调度成功,即使后续标签变化导致不再
8. 存储和持久化 (Storage)
以下是针对 Kubernetes 存储(PV)、Etcd 特性及 Raft 一致性算法的详细解答:
74. 简述 Kubernetes 中 PV 生命周期内的阶段有哪些?
PersistentVolume (PV) 的生命周期主要包含以下五个阶段(Phase):
- Available(可用):
- PV 已创建并存在于集群中,但尚未被任何 PersistentVolumeClaim (PVC) 绑定。
- 此时 PV 处于空闲状态,等待匹配。
- Bound(已绑定):
- PV 已成功与某个 PVC 绑定。
- 此时 PV 专属于该 PVC,其他 PVC 无法再使用此 PV。
- Released(已释放):
- 关联的 PVC 已被用户删除。
- PV 对象本身仍存在,但资源已被释放。
- 注意:此时数据仍保留在底层存储中,PV 不会 立即变为
Available,因为需要等待回收策略(Reclaim Policy)执行完毕(如删除数据或保留数据)。
- Failed(失败):
- PV 的自动回收过程失败(例如:云厂商 API 调用失败、存储后端故障、权限不足等)。
- 需要管理员手动介入干预(修复存储问题或手动删除 PV)。
- Recycled / Terminating(回收中/终止中):
- 注:
Recycled策略在较新版本 K8s 中已废弃,但在旧版本中存在。 - 当 PVC 删除后,根据
persistentVolumeReclaimPolicy的不同(Retain,Delete,Recycle),PV 会经历清理数据或删除底层存储资源的过程,最终回到Available或被彻底删除。
- 注:
75. K8s 中 Etcd 的特点?
Etcd 是 Kubernetes 的核心数据库,存储集群的所有状态数据。其核心特点包括:
- 强一致性 (Strong Consistency):
- 基于 Raft 共识算法,保证集群中所有节点的数据在任何时刻都是一致的。读取操作默认也是线性的(Linearizable),确保读到最新数据。
- 高可用性 (High Availability):
- 采用集群部署(通常奇数个节点,如 3, 5, 7),允许部分节点故障而不影响服务。只要超过半数节点存活,集群即可正常工作。
- 键值存储 (Key-Value Store):
- 数据结构简单,基于路径的层级键值对(类似文件系统目录结构),非常适合存储配置信息和状态元数据。
- Watch 机制 (监听/通知):
- 支持客户端对特定 Key 或目录进行监听。当数据发生变化时,Etcd 会主动推送通知给客户端。这是 K8s Controller 模式(控制循环)的基础。
- 轻量级与高性能:
- 用 Go 语言编写,编译为单一二进制文件,部署简单。针对读写优化,但在高并发写场景下性能会有瓶颈(K8s 主要是读多写少,适合 Etcd)。
- 安全性:
- 支持 TLS 加密通信和基于角色的访问控制 (RBAC)。
- TTL (Time To Live):
- 支持键的过期时间,常用于实现分布式锁或临时注册信息(K8s 中 Node 的心跳检测依赖此机制)。
76. 简述 Etcd 适应的场景?
Etcd 的设计目标决定了它适用的场景:
- 服务发现与服务注册:
- 利用其 Key-Value 结构和 Watch 机制,服务启动时注册 IP,客户端监听变化获取最新服务列表(K8s 的核心功能)。
- 配置管理与共享:
- 存储应用的配置信息,支持动态更新配置并实时通知应用生效(如 K8s 的 ConfigMap 底层存储)。
- 分布式锁与选举:
- 利用 TTL 和原子操作(Compare-And-Swap),实现分布式环境下的互斥锁和 Leader 选举。
- 集群状态存储:
- 存储整个集群的“真实状态”(Source of Truth),如 Pod 定义、Node 状态、Secret 等(K8s 的主要用途)。
- 不适用场景:
- 海量数据存储:Etcd 不适合存储大量非结构化数据或大文件(建议 Value 大小控制在 1MB 以内,总数据量建议在 GB 级别,不宜过大)。
- 高频写入:由于 Raft 协议需要多数派确认,写性能受限,不适合高吞吐的日志存储或消息队列场景。
77. Etcd 集群节点之间是怎么同步数据的?
Etcd 集群通过 Raft 协议 进行数据同步,核心流程如下:
- 角色划分:
- Leader (领导者):集群中唯一能处理写请求的节点。所有写操作必须先发给 Leader。
- Follower (跟随者):被动接收 Leader 的日志复制,处理读请求(取决于一致性级别)。
- Candidate (候选人):当 Leader 挂掉或超时,Follower 转变为 Candidate 发起选举。
- 写同步流程:
- 接收请求:Client 发送写请求给 Leader。
- 追加日志:Leader 将操作作为一条日志条目(Log Entry)追加到自己的本地日志中。
- 复制日志:Leader 并行地将该日志条目发送给所有 Follower。
- 多数派确认:Follower 收到日志后写入本地,并回复 ACK。当 Leader 收到超过半数 (Quorum) 节点的 ACK 后,认为该日志已提交(Committed)。
- 应用状态:Leader 将日志应用到状态机(更新内存中的数据树),并通知 Follower 应用该日志。
- 返回结果:Leader 向 Client 返回成功。
- 心跳机制:
- Leader 定期向 Follower 发送心跳包(空日志),维持领导地位并防止 Follower 发起选举。
- 快照 (Snapshot):
- 当日志文件过大时,Leader 会生成快照,将当前状态压缩保存,并发送给落后的 Follower,以加快同步速度并截断旧日志。
78. Raft 一致性算法核心解析(顺便介绍下)
Raft 是一种易于理解的一致性算法,旨在替代复杂的 Paxos。它的核心思想是将一致性问题分解为三个子问题:Leader 选举、日志复制、安全性。
1. 节点状态
每个节点处于以下三种状态之一:
- Follower:被动状态,只响应 Leader 和 Candidate 的请求。
- Candidate:选举过程中的临时状态。
- Leader:处理所有客户端请求,负责日志复制。
2. 核心机制
A. Leader 选举 (Leader Election)
- 触发:系统启动时所有节点都是 Follower。如果 Follower 在随机超时时间(Election Timeout)内没收到 Leader 的心跳,就转变为 Candidate。
- 拉票:Candidate 增加当前任期号(Term),向其他节点发送
RequestVoteRPC。 - 投票:其他节点如果在该任期内还没投过票,且 Candidate 的日志比自己新(或至少一样新),就投赞成票。
- 当选:Candidate 获得多数派选票后,成为 Leader,并开始发送心跳。其他 Candidate 退回到 Follower。
- 分裂投票:如果多个节点同时超时成为 Candidate,导致票数分散,无人当选。它们会等待新的随机超时时间后再次尝试,概率上总会有一方先超时从而赢得选举。
B. 日志复制 (Log Replication)
- 唯一入口:只有 Leader 能接收写请求。
- 流程:
- Leader 接收命令,追加到本地日志。
- 并行发送给所有 Follower。
- 一旦多数派节点成功写入日志,Leader 提交(Commit)该条目。
- Leader 通知 Follower 提交,并应用到状态机。
- 一致性保证:Raft 保证如果一条日志被提交,那么它一定存在于大多数节点的日志中,且未来的 Leader 必然包含这条日志。
C. 安全性 (Safety)
- 选举限制:Candidate 必须拥有“至少和其他节点一样新”的日志才能当选 Leader。这保证了已提交的日志不会丢失。
- Leader 完整性:一旦某条日志被提交,它将永远存在于后续的 Leader 中。
- 状态机安全:如果两个节点在同一个索引位置应用了日志,那么这两条日志一定是相同的。
3. 为什么 K8s 选择 Raft 而不是 Paxos?
- 易理解性:Raft 将复杂的一致性逻辑拆解得非常清晰,工程实现和调试更容易。
- 强 Leader 模型:简化了日志复制流程,避免了 Paxos 多主或多阶段提交的复杂性,虽然写性能受限于 Leader,但对于 K8s 这种“读多写少”且强依赖一致性的场景非常合适。
总结图示逻辑:
[Client] --> [Leader] --(Replicate Log)--> [Follower 1]
| [Follower 2] (Majority)
|<--(Ack)------------^
|<--(Ack)------------^
[Leader] Commits Log --> Applies to State Machine
9. 综合问题 (Comprehensive)
79. 简述 Kubernetes 和 Docker 的关系和区别?
- 关系:
- 互补而非竞争:Docker 是容器运行时(负责打包、构建镜像、运行单个容器),Kubernetes 是容器编排平台(负责管理成百上千个容器的生命周期、调度、 networking、存储)。
- 历史演变:早期 K8s 强依赖 Docker Engine 作为运行时。但从 v1.20 起,K8s 弃用了 Docker Shim,转而直接使用符合 CRI (Container Runtime Interface) 标准的运行时(如 containerd, CRI-O)。现在 Docker 更多用于本地开发和镜像构建,而生产环境 K8s 节点通常直接运行 containerd。
- 区别:
- 层级:Docker 是工具/引擎;K8s 是操作系统/集群管理系统。
- 范围:Docker 关注单机容器;K8s 关注多机集群协调。
- 功能:Docker 提供
docker build/run;K8s 提供自动扩缩容、自愈、服务发现、负载均衡、滚动更新等高级功能。
80. 简述 Kubernetes 的 CNI 模型?
- CNI (Container Network Interface) 是 CNCF 制定的标准接口规范,用于配置容器网络。
- 核心机制:
- 插件化:K8s 本身不实现网络,而是调用 CNI 插件(如 Calico, Flannel, Cilium, Weave)。
- 调用时机:当 Kubelet 创建 Pod 时,会调用 CNI 插件为 Pod 分配 IP 地址并配置网络接口(veth pair)。
- 输入输出:Kubelet 将包含容器 ID、网络命名空间路径等信息的 JSON 配置文件传给 CNI 插件,插件执行网络配置后返回结果(主要是 IP 地址)。
- IPAM:CNI 通常配合 IPAM (IP Address Management) 插件来管理 IP 池的分配。
- 目标:实现“每个 Pod 一个 IP”,且所有 Pod 无需 NAT 即可互相通信。
81. 简述 Kubernetes 如何实现集群管理?
K8s 采用 控制平面 (Control Plane) 与 工作节点 (Worker Nodes) 分离的架构,基于 声明式 API 和 控制循环 (Control Loop) 进行管理:
- API Server:集群的统一入口,所有组件通过 REST API 交互。
- Etcd:存储集群所有状态数据(Source of Truth)。
- Controller Manager:运行各种控制器(如 Deployment Controller, Node Controller),不断对比 期望状态(用户定义的 YAML)和 实际状态(Etcd 中的数据),驱动集群向期望状态收敛。
- Scheduler:负责将未调度的 Pod 分配到合适的节点。
- Kubelet:运行在每个节点上,监听 API Server,负责启动/停止容器,汇报节点状态。
- Kube-Proxy:维护节点网络规则,实现 Service 的负载均衡。
- 核心逻辑:用户提交 YAML -> API Server 写入 Etcd -> 控制器检测到变化 -> 执行操作(如调用 Scheduler 或通知 Kubelet)-> Kubelet 调用 CRI/CNI -> 状态更新回 Etcd。
82. 简述 Kubernetes 的优势、适应场景及其特点?
- 优势:
- 高可用与自愈:节点故障自动迁移 Pod,容器崩溃自动重启。
- 弹性伸缩:支持 HPA(Pod 级)和 CA(节点级)自动扩缩容。
- 服务发现与负载均衡:内置 Service 和 DNS。
- 声明式配置:基础设施即代码 (IaC),版本可控。
- 生态丰富:拥有庞大的 CNCF 生态系统。
- 适应场景:
- 微服务架构应用。
- 需要频繁发布、回滚的应用。
- 混合云/多云部署。
- 大数据、AI 训练任务调度。
- 特点:轻量级(相对虚拟机)、可移植性强、自动化程度高。
83. 同一节点上的 Pod 通信原理?
- 原理:通过 虚拟网桥 (Bridge) 进行二层转发。
- 流程:
- CNI 插件在节点上创建一个网桥(如
cni0)。 - 每个 Pod 通过 veth pair 连接到该网桥。
- Pod A 发送数据包 -> veth -> 网桥 -> 网桥根据 MAC 地址表直接转发给 Pod B 的 veth -> Pod B。
- 特点:不走 iptables NAT,延迟极低,类似同一交换机下的通信。
- CNI 插件在节点上创建一个网桥(如
84. 不同节点上的 Pod 通信原理?
- 原理:依赖 CNI 插件实现的 Overlay 网络 (如 VXLAN, IPIP) 或 路由模式 (如 BGP)。
- 流程 (以 VXLAN 为例):
- Pod A (Node 1) 发送包给 Pod B (Node 2)。
- Node 1 的 CNI 组件拦截包,将其封装在 UDP 包中(外层 IP 为 Node 1 和 Node 2 的 IP)。
- 物理网络传输到 Node 2。
- Node 2 解封装,还原原始包,通过本地网桥交给 Pod B。
- 特点:对应用透明,应用看到的始终是 Pod IP,底层由 CNI 处理跨机路由。
85. 简述 Kubernetes Scheduler 使用哪两种算法将 Pod 调度到 Node?
调度过程分为两个阶段:
- 预选 (Predicates / Filtering):
- 作用:过滤掉不满足条件的节点。
- 策略:资源充足性(CPU/Mem)、端口冲突、节点亲和性/污点容忍、卷绑定等。
- 结果:得到一个合格节点列表。
- 优选 (Priorities / Scoring):
- 作用:对合格节点进行打分,选择得分最高的。
- 策略:资源均衡度(避免倾斜)、节点亲和性权重、Pod 反亲和性(分散部署)、拓扑分布约束等。
- 结果:选出最优节点进行绑定 (Bind)。
86. 简述 Kubernetes 如何保证集群的安全性?
- 认证 (Authentication):确认用户身份(x509 证书、Bearer Token、ServiceAccount)。
- 授权 (Authorization):确认用户权限(RBAC - 基于角色的访问控制,ABAC, Webhook)。
- 准入控制 (Admission Control):请求落地前的最后检查(如限制特权容器、强制镜像签名、资源配额 LimitRange/ResourceQuota)。
- 网络安全:NetworkPolicy 限制 Pod 间流量,TLS 加密组件间通信。
- 秘密管理:Secret 对象加密存储敏感信息(建议开启 Etcd 静态加密)。
- 镜像安全:扫描漏洞,使用可信仓库,禁止 root 运行。
87. K8s 中 Namespace 的作用?
- 逻辑隔离:将集群资源划分为多个虚拟子集群。
- 用途:
- 多租户:不同团队/项目使用不同 Namespace,互不干扰。
- 环境隔离:dev, test, prod 环境分开。
- 资源配额:可在 Namespace 级别设置 ResourceQuota 和 LimitRange。
- 权限隔离:RBAC 角色绑定通常限定在特定 Namespace。
- 注意:Namespace 不是严格的.security 边界(默认网络互通,需 NetworkPolicy 隔离),主要是管理边界。
88. Pod 是什么?
- 定义:K8s 中最小的调度单元和部署单元。
- 特点:
- 一个 Pod 可以包含一个或多个紧密耦合的容器(共享网络、存储、IPC)。
- 拥有独立的 IP 地址。
- 生命周期短暂,不可变(不可直接修改,需重建)。
- 由控制器(Deployment, StatefulSet 等)管理,而非直接创建。
89. 什么是静态 Pod(Static Pod)?
- 定义:不由 API Server 管理,而是由 Kubelet 直接监控特定目录(如
/etc/kubernetes/manifests)下的 YAML 文件创建和管理的 Pod。 - 特点:
- 无法通过
kubectl删除/修改(只能修改文件或删文件)。 - 高可用关键:通常用于部署控制平面组件(API Server, Etcd, Scheduler, Controller Manager),确保即使 API Server 挂了,这些核心组件也能由 Kubelet 维持运行。
- 可见性:会在 API Server 中创建一个“镜像”Pod 供查看,状态为 Pending(实际上由 Kubelet 运行)。
- 无法通过
90. 简述 K8s 中 Pod 的常见调度方式?
- 自动调度:默认调度器根据资源和服务策略自动选择。
- 指定节点 (nodeName):强制指定具体节点名。
- 节点选择器 (nodeSelector):基于标签简单匹配。
- 节点亲和性 (Node Affinity):基于标签的复杂逻辑匹配(硬/软)。
- 污点与容忍 (Taints & Tolerations):节点排斥,Pod 需容忍才能调度。
- Pod 亲和/反亲和:根据其他 Pod 的位置调度。
- 拓扑分布约束:跨域均匀分布。
91. 简述一下在 K8s 中删除 Pod 的流程?
- 接收请求:用户执行
kubectl delete,API Server 接收请求。 - 更新状态:API Server 将 Pod 标记为
Terminating,记录deletionTimestamp。 - 移除端点:Endpoint Controller 检测到状态变化,将该 Pod IP 从 Service 的 Endpoints 列表中移除(切断流量)。
- PreStop 钩子:如果定义了
preStop生命周期钩子,Kubelet 执行它(用于优雅关闭)。 - 发送 SIGTERM:Kubelet 向容器主进程发送
SIGTERM信号,应用开始清理工作。 - 等待宽限期:等待
terminationGracePeriodSeconds(默认 30s)。 - 强制杀死:若超时仍未退出,发送
SIGKILL强制终止。 - 清理资源:Kubelet 清理容器、网络、挂载卷等资源。
- 最终删除:Kubelet 通知 API Server,API Server 从 Etcd 中彻底删除 Pod 对象。
92. Pod 的资源请求(Request)和限制(Limit)如何定义?
在 Pod Spec 的 containers 字段中定义:
- requests:调度依据。K8s 保证节点至少有这么多资源可用。用于计算 QoS 等级。
- limits:运行上限。容器不能超过此限制,否则会被 OOMKilled (内存) 或 Throttled (CPU)。
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
93. 标签(Labels)及标签选择器(Label Selectors)是什么,作用是什么?
- Labels:键值对元数据(Key=Value),附加在对象(Pod, Node, Service 等)上。用于标识对象的属性(如
app=nginx,env=prod)。 - Label Selectors:查询语句,用于筛选具有特定标签的对象。
- 等值:
app=nginx - 集合:
env in (prod, dev) - 存在性:
env(只要存在该 key)
- 等值:
- 作用:
- 关联对象:Service 通过 Selector 找到后端 Pod;Deployment 通过 Selector 管理 ReplicaSet。
- 调度:Node Selector/Affinity 基于标签调度。
- 监控/日志:筛选特定组别的资源进行采集。
- 批量操作:
kubectl delete pods -l app=nginx。
94. Service 的域名解析格式?
K8s 内部通过 CoreDNS 解析,格式遵循:
<ServiceName>.<Namespace>.svc.cluster.local
- 同命名空间:可直接用
<ServiceName>。 - 跨命名空间:需用
<ServiceName>.<Namespace>。 - 完整 FQDN:上述长格式,确保全局唯一。
95. Pod 与 Service 的通信信息是怎么样的?
- 虚拟 IP (ClusterIP):Pod 访问 Service 时,目标是 Service 的 ClusterIP 和端口。
- iptables/IPVS 规则:节点上的 Kube-Proxy 监听该 ClusterIP,通过内核网络规则将流量 NAT/DNAT 转发到后端某个具体的 Pod IP。
- 负载均衡:转发策略通常是轮询(iptables 随机,IPVS 支持多种算法)。
- 会话保持:默认无状态,若需会话保持需配置
sessionAffinity: ClientIP。
96. 在 K8s 集群内的应用如何访问外部的服务?
- ExternalName Service:将 Service 映射为外部域名(CNAME),应用访问 Service 域名,DNS 解析到外部 IP。
- 直接 IP/域名访问:应用代码直接配置外部服务的 IP 或公网域名(需节点能通外网)。
- Egress Gateway:通过 Istio 等网格组件或专用网关统一出口,进行流量控制和审计。
- NAT Gateway:节点通过云厂商的 NAT 网关访问公网。
97. Service、Endpoint、Kube-Proxy 三者的关系是什么?
- Service:定义了一组 Pod 的逻辑访问入口(VIP + 端口 + 选择器)。
- Endpoint:Service 的“后端列表”。Endpoint Controller 监听 Service 和 Pod 变化,将符合 Service Selector 的 Pod IP:Port 实时更新到 Endpoint 对象中。
- Kube-Proxy:监听 Endpoint 的变化。一旦 Endpoint 更新,Kube-Proxy 就在节点上刷新 iptables/IPVS 规则,确保发往 Service VIP 的流量能被正确转发到最新的 Pod IP 列表。
- 总结:Service 是抽象定义,Endpoint 是实时状态,Kube-Proxy 是执行者。
98. Pod 创建/删除时,Service、Endpoint、Kube-Proxy 三者发生了什么变化?
- Pod 创建 (且标签匹配 Service):
- Endpoint Controller 发现新 Pod,将其 IP 添加到对应的 Endpoint 列表中。
- Kube-Proxy 监听到 Endpoint 变更,在所有节点的 iptables/IPVS 中添加一条转发规则,指向新 Pod IP。
- Service 本身定义不变,但后端容量增加。
- Pod 删除:
- Endpoint Controller 发现 Pod 终止,将其 IP 从 Endpoint 列表中移除。
- Kube-Proxy 监听到变更,删除对应的转发规则,流量不再发往该 Pod。
- 若 Pod 正在终止,Service 会先停止向其分发新流量(优雅下线)。
99. Deployment 怎么扩容或缩容?
- 命令方式:
kubectl scale deployment <name> --replicas=5
- 修改 YAML:
- 编辑
spec.replicas字段,apply 生效。
- 编辑
- 自动扩缩容 (HPA):
- 配置 HorizontalPodAutoscaler,根据 CPU/内存或自定义指标自动调整 replicas 数量。
- 原理:Deployment 控制器检测到 replicas 数变化,创建或删除对应的 ReplicaSet,进而创建或终止 Pod。
100. K8s 数据持久化的方式有哪些?
- EmptyDir:临时存储,随 Pod 销毁而消失(用于缓存、临时交换空间)。
- HostPath:挂载宿主机文件系统,风险高,仅限单节点测试或特权系统组件。
- NFS / GlusterFS / CephFS:网络文件系统,支持多节点读写,适合共享存储。
- 云厂商块存储 (Cloud Volumes):
- AWS EBS, GCP PD, Azure Disk, 阿里云云盘等。
- 通常通过 CSI (Container Storage Interface) 驱动动态供给 PV。
- 特性:高性能,通常支持 ReadWriteOnce (RWO)。
- 对象存储 (S3/OSS):通过挂载工具(如 s3fs)或应用 SDK 访问,适合非结构化数据。
- StatefulSet + PVC:有状态应用的标准持久化方案,保证 Pod 重启后挂载相同的 PV。
10. 高级主题 (Advanced Topics)
101. 什么是 Kubernetes?它的主要目标是什么?
- 定义:Kubernetes (K8s) 是一个开源的容器编排引擎,用于自动化部署、扩展和管理容器化应用程序。它由 Google 设计并捐赠给 CNCF。
- 主要目标:
- 自动化部署与回滚:自动发布应用,若失败则自动回滚。
- 服务发现与负载均衡:无需修改应用代码,自动分配 IP 和 DNS。
- 存储编排:自动挂载本地或云存储。
- 自动扩缩容:根据负载自动调整 Pod 数量或节点数量。
- 自愈能力:自动重启失败的容器,替换不可用的节点。
- 密钥与配置管理:安全地管理敏感信息和配置文件。
102. 什么是 ReplicaSet?
- 定义:ReplicaSet 是 K8s 的控制器,用于确保在任何时候都有指定数量 (replicas) 的相同 Pod 副本在运行。
- 作用:维持期望状态。如果 Pod 崩溃或被删除,ReplicaSet 会自动创建新的 Pod 来补足数量。
- 关系:通常不直接创建 ReplicaSet,而是通过 Deployment 来管理 ReplicaSet,从而获得滚动更新等高级功能。
103. 什么是 Deployment?
- 定义:Deployment 是管理无状态应用的高级控制器。它在 ReplicaSet 之上提供了一层抽象。
- 核心功能:
- 声明式更新:支持滚动更新(Rolling Update),零停机发布新版本。
- 回滚:支持一键回滚到之前的版本。
- 扩缩容:方便地调整副本数量。
- 暂停/继续:支持暂停更新过程进行调试。
- 原理:Deployment 创建和管理多个版本的 ReplicaSet,通过控制 ReplicaSet 的副本数来实现版本切换。
104. 什么是 Service?
- 定义:Service 是一种抽象,定义了一组逻辑上的 Pod 集合以及访问它们的策略(微服务)。
- 作用:
- 服务发现:为一组动态变化的 Pod 提供稳定的 IP 地址 (ClusterIP) 和 DNS 名称。
- 负载均衡:将流量分发到后端健康的 Pod。
- 类型:ClusterIP (集群内), NodePort (节点端口), LoadBalancer (云负载均衡), ExternalName (外部域名)。
105. 什么是命名空间 (Namespace)?
- 定义:Namespace 是 K8s 中资源的逻辑隔离机制。
- 作用:
- 将集群资源划分为多个虚拟集群(如
dev,test,prod或按团队划分)。 - 不同 Namespace 中的资源名称可以重复。
- 用于实施资源配额 (ResourceQuota) 和访问控制 (RBAC)。
- 将集群资源划分为多个虚拟集群(如
- 注意:默认情况下,不同 Namespace 的网络是互通的(除非配置 NetworkPolicy)。
106. 如何进行应用程序的水平扩展?
水平扩展指增加 Pod 的副本数量。
- 手动扩展:
- 命令:
kubectl scale deployment <name> --replicas=5 - 修改 YAML 中的
spec.replicas字段并 apply。
- 命令:
- 自动扩展 (HPA):
- 创建 HorizontalPodAutoscaler 对象,基于 CPU、内存或自定义指标自动调整副本数。
- 命令:
kubectl autoscale deployment <name> --cpu-percent=50 --min=2 --max=10
107. 如何在 Kubernetes 中进行滚动更新 (Rolling Update)?
滚动更新允许在不中断服务的情况下更新应用。
- 方法:
- 修改 Deployment 的 YAML 文件(如更改镜像版本
image: nginx:1.21)。 - 执行
kubectl apply -f deployment.yaml。 - 或者使用命令:
kubectl set image deployment/<name> <container>=<new-image>。
- 修改 Deployment 的 YAML 文件(如更改镜像版本
- 过程:K8s 会逐步创建新版本的 Pod,待其就绪(Readiness Probe 通过)后,再逐步终止旧版本的 Pod,始终保持可用的副本数满足要求。
108. 如何在 Kubernetes 中进行滚动回滚 (Rollback)?
当新版本出现 bug 时,快速恢复到上一个稳定版本。
- 查看历史:
kubectl rollout history deployment/<name> - 回滚到上一版本:
kubectl rollout undo deployment/<name> - 回滚到特定版本:
kubectl rollout undo deployment/<name> --to-revision=2 - 原理:Deployment 会保留旧的 ReplicaSet,回滚只是将旧 ReplicaSet 的副本数调大,新版本的调小。
109. 什么是 Kubernetes 的水平自动扩展 (Horizontal Pod Autoscaler, HPA)?
- 定义:HPA 是一个控制器,根据观测到的指标(如 CPU 利用率、内存或自定义指标)自动调整 Deployment 或 ReplicaSet 中的 Pod 副本数量。
- 工作流程:
- Metrics Server 收集指标。
- HPA 定期查询指标。
- 如果指标高于阈值,增加 Pod;低于阈值,减少 Pod。
- 限制:仅适用于可以通过增加副本来提升性能的应用(无状态应用)。
110. 如何进行存储卷 (Volume) 的使用?
- 定义 Volume:在 Pod 的
spec.volumes中定义存储来源(如emptyDir,hostPath,persistentVolumeClaim,configMap等)。 - 挂载 Volume:在容器的
spec.containers.volumeMounts中指定挂载点 (mountPath) 和对应的 volume 名称。 - 持久化流程 (推荐):
- 创建 PV (PersistentVolume)。
- 创建 PVC (PersistentVolumeClaim) 请求存储。
- 在 Pod 中引用 PVC。
- K8s 自动绑定 PV 和 PVC,并将存储挂载到 Pod。
111. 什么是 Init 容器 (Init Container)?
- 定义:在主应用容器启动之前运行的专用容器。
- 特点:
- 可以包含多个,按顺序依次执行。
- 必须成功退出(Exit Code 0),主容器才会启动;若失败,Pod 会重启。
- 拥有独立的文件系统(但可共享 EmptyDir 卷与主容器交换数据)。
- 用途:等待依赖服务(如数据库)就绪、初始化配置文件、执行权限设置等。
112. 如何在 Kubernetes 中进行配置文件的安全管理(Secret/ConfigMap)?
- ConfigMap:
- 存储非敏感配置(键值对)。
- 使用方式:环境变量注入、命令行参数、挂载为文件。
- Secret:
- 存储敏感信息(密码、Token、Key)。
- 安全性:数据在 Etcd 中以 Base64 编码存储(建议开启 Etcd 静态加密),传输和使用过程中比 ConfigMap 更受控。
- 使用方式:同 ConfigMap,但 K8s 会将其挂载为内存临时文件系统(tmpfs),避免落盘。
- 最佳实践:结合 RBAC 限制访问权限,使用 External Secrets Operator 从云厂商密钥管理服务同步 Secret。
113. 如何监控 Kubernetes 集群?
主流方案是 Prometheus + Grafana:
- 数据采集:
- Metrics Server:提供基础资源指标(CPU/Mem),供 HPA 和
kubectl top使用。 - Prometheus:通过 Service Discovery 自动发现 K8s 组件(Node, Pod, Service)和中间件,拉取指标数据。
- Exporters:节点导出器 (Node Exporter)、Kube-State-Metrics (监控 K8s 对象状态)。
- Metrics Server:提供基础资源指标(CPU/Mem),供 HPA 和
- 可视化:Grafana 连接 Prometheus 数据源,展示仪表盘。
- 日志监控:ELK (Elasticsearch, Logstash, Kibana) 或 EFK (Fluentd/Fluent Bit) 栈。
- 告警:Alertmanager 配置规则,发送通知到邮件/Slack/钉钉。
114. 如何进行跨集群部署和管理?
- 联邦集群 (KubeFed):CNCF 项目,允许在一个控制平面管理多个 K8s 集群,实现配置同步和故障转移(目前成熟度一般)。
- GitOps (推荐):使用 ArgoCD 或 Flux。
- 将多个集群的配置存储在 Git 仓库。
- ArgoCD 在每个集群中运行,监听 Git 变化并自动同步应用到对应集群。
- 多集群管理平台:如 Rancher, OpenShift ACM, Google Anthos,提供统一的 UI 和策略管理。
- 服务网格 (Istio):通过 Istio Multi-Cluster 实现跨集群的服务发现和流量治理。
115. 什么是 Kubernetes 的生命周期钩子 (Lifecycle Hooks)?
允许容器在特定生命周期节点执行命令。
- postStart:容器创建后立即执行。若失败,容器会被杀死。注意:不能保证在容器 ENTRYPOINT 之前运行。
- preStop:容器被终止前执行(收到 SIGTERM 之前)。常用于优雅下线(如刷新缓冲区、通知注册中心下线)。
- 执行方式:执行 Shell 命令 (
exec) 或 HTTP 请求 (httpGet)。
116. 什么是 Pod 的探针 (Probe)?(Liveness, Readiness, Startup)
探针用于检测容器状态,Kubelet 据此采取行动。
- Liveness Probe (存活探针):
- 作用:检测容器是否死锁或无法恢复。
- 失败动作:重启容器。
- 场景:应用死循环、线程池耗尽。
- Readiness Probe (就绪探针):
- 作用:检测容器是否准备好接收流量。
- 失败动作:从 Service 的 Endpoints 中移除 IP(切断流量),但不重启。
- 场景:应用正在加载大文件、依赖服务未连通。
- Startup Probe (启动探针):
- 作用:用于启动缓慢的容器。在它成功之前,Liveness 和 Readiness 都不会生效。
- 场景:遗留应用启动需要几分钟,避免被 Liveness 误杀。
117. 什么是 Kubernetes 的安全性措施?
- 认证 (AuthN):x509 证书、ServiceAccount Token、OIDC。
- 授权 (AuthZ):RBAC (Role-Based Access Control) 是最常用的授权模式。
- 准入控制 (Admission Control):Mutating/Validating Webhook,强制安全策略(如禁止特权容器、强制镜像签名)。
- 网络策略 (NetworkPolicy):限制 Pod 间的进出流量(白名单机制)。
- Pod 安全标准 (PSS):替代旧的 PSP,限制 Pod 的安全上下文(如禁止 root 用户、禁止挂载宿主机目录)。
- 秘密管理:Secrets 加密存储,集成外部密钥管理系统。
- 镜像扫描:集成 Trivy/Clair 等工具扫描漏洞。
118. 什么是容器资源限制 (Resource Limit) 和容器资源请求 (Resource Request)?
- Request (请求):
- 调度器依据此值判断节点是否有足够资源来放置 Pod。
- 保证 Pod 至少能获得的资源量。
- Limit (限制):
- 容器运行时(Docker/containerd)依据此值限制容器能使用的最大资源。
- CPU 超限:会被节流 (Throttled),变慢但不会被杀。
- 内存 超限:会被 OOMKilled (Out Of Memory) 直接杀死并重启。
- QoS 等级:根据 Request 和 Limit 的设置,Pod 分为 Guaranteed, Burstable, BestEffort 三个等级,影响被驱逐的优先级。
119. 什么是 Kubernetes 中的水平和垂直扩展?
- 水平扩展 (Scale Out/In):
- 增加或减少 Pod 的副本数量。
- 由 HPA 或手动操作完成。
- 适用于无状态应用,是最常用的扩展方式。
- 垂直扩展 (Scale Up/Down):
- 增加或减少 单个 Pod 的资源配额 (CPU/Memory)。
- 由 VPA (Vertical Pod Autoscaler) 建议或自动执行(通常需要重启 Pod 才能生效)。
- 适用于有状态应用或无法简单拆分的应用。
120. 什么是 Kubernetes 的事件 (Event)?
- 定义:Event 是 K8s 对象(如 Pod, Node, Deployment)状态变化或发生重要事情时的记录。
- 内容:包含时间、涉及的对象、原因 (Reason)、消息 (Message)、类型 (Normal/Warning)。
- 作用:
- 故障排查的核心依据(如
FailedScheduling,OOMKilling,BackOff)。 - 查看命令:
kubectl get events --sort-by=.lastTimestamp或kubectl describe pod <name>。
- 故障排查的核心依据(如
- 注意:Event 默认保留 1 小时,长期存储需导出到外部系统。
121. 什么是 Helm?
- 定义:Kubernetes 的包管理器。
- 核心概念:
- Chart:打包好的应用描述文件集合(包含 templates, values.yaml, Chart.yaml)。
- Release:Chart 在集群中运行的实例。
- Repository:存放 Chart 的仓库。
- 优势:
- 模板化:通过
values.yaml定制配置,一套 Chart 适配多环境。 - 版本管理:支持 Release 的升级、回滚。
- 依赖管理:可管理复杂应用的子图表依赖。
- 模板化:通过
122. 如何进行 Kubernetes 集群的高可用性配置?
高可用 (HA) 旨在消除单点故障。
- 控制平面 (Control Plane) HA:
- 多 Master 节点:部署 3 个或更多奇数个 API Server / Controller Manager / Scheduler。
- Etcd 集群:部署奇数个节点(3, 5, 7),跨可用区分布,利用 Raft 协议保证数据一致性。
- 负载均衡:在 Master 节点前架设负载均衡器 (LB),指向所有 API Server。
- 工作节点 (Worker Nodes) HA:
- 多节点部署,配合 Pod 反亲和性,确保关键应用分散在不同节点/可用区。
- 使用集群自动伸缩组 (Auto Scaling Group) 自动替换故障节点。
- 网络与存储 HA:
- CNI 插件高可用配置。
- 存储后端采用多副本机制(如 Ceph, 云厂商多副本云盘)。
123. 什么是 K8s 的配置管理工具?
除了原生的 ConfigMap/Secret,还有第三方工具:
- Helm:最流行的包管理工具,基于模板。
- Kustomize:K8s 原生集成 (
kubectl kustomize),基于补丁 (Patch) 和叠加 (Overlay) 机制,无需模板语法,更适合纯 YAML 管理。 - Ansible/Terraform:基础设施即代码工具,用于集群搭建和初始配置。
- ArgoCD/Flux:GitOps 工具,将 Git 仓库作为配置源,自动同步集群状态。
- External Secrets Operator:将外部密钥系统(AWS Secrets Manager, Vault)同步为 K8s Secret。
124. 什么是 K8s 的网络模型?
K8s 网络模型遵循以下核心原则(CNI 规范):
- Pod IP 唯一性:每个 Pod 拥有一个唯一的 IP 地址。
- 无 NAT 通信:所有 Pod 可以在无需 NAT 的情况下相互通信(无论是否在同一节点)。
- 节点与 Pod 互通:节点上的 Agent(如 Kubelet)可以与该节点或其他节点上的 Pod 通信。
- 实现:通过 CNI 插件(Calico, Flannel, Cilium 等)构建 Overlay 网络或 BGP 路由网络来实现上述模型。
125. Kubernetes 的升级策略有哪些?
主要指集群版本升级和应用升级。
- 应用升级 (Deployment):
- 滚动更新 (RollingUpdate):默认策略,逐步替换,零停机。
- 重建 (Recreate):先杀光旧 Pod,再建新 Pod,会有短暂停机。
- 蓝绿部署 (Blue/Green):部署全新版本环境,切换 Service 流量,旧环境保留以备回滚。
- 金丝雀发布 (Canary):先将少量流量导入新版本,验证无误后全量切换(常结合 Istio 或 Ingress 控制器实现)。
- 集群升级 (Kubeadm/Managed):
- 原地升级:逐个升级 Master 和 Worker 节点(先控制面,后工作节点)。
- 蓝绿集群升级:新建一套新版集群,迁移应用和数据,切换流量,销毁旧集群(风险最低,适合生产环境)。
126. 什么是 Kubernetes 的监控和日志记录解决方案?
- 监控 (Monitoring):
- 核心栈:Prometheus (数据采集与存储) + Grafana (可视化) + Alertmanager (告警)。
- 组件:
Metrics Server:提供基础资源指标(CPU/Mem),供kubectl top和 HPA 使用。Node Exporter:采集节点硬件指标。Kube-State-Metrics:采集 K8s 对象状态(Pod 相位、Deployment 副本数等)。cAdvisor:集成在 Kubelet 中,采集容器级指标。
- 日志 (Logging):
- 架构模式:通常采用 Node-Level Agent 模式(DaemonSet)。
- 主流方案:
- EFK:Elasticsearch (存储/搜索) + Fluentd/Fluent Bit (采集) + Kibana (可视化)。
- PLG:Promtail (采集) + Loki (存储,轻量级) + Grafana (可视化)。
- 商业/云原生:Datadog, Splunk, 阿里云 SLS, AWS CloudWatch。
- 原理:Agent 挂载宿主机的
/var/log/pods,实时收集 stdout/stderr 或文件日志,添加元数据后发送至后端。
127. 怎样从一个镜像创建一个 Pod?
虽然生产环境通常使用 Deployment,但可以直接创建 Pod 用于测试:
- 生成 YAML:
kubectl run my-pod --image=nginx --restart=Never --dry-run=client -o yaml > pod.yaml - 编辑 YAML:确保
kind: Pod,配置镜像、端口等。 - 应用:
kubectl apply -f pod.yaml - 直接命令:
kubectl run my-pod --image=nginx --restart=Never(交互式创建)。
注意:直接创建的 Pod 不会被自动重启或扩缩容,适合调试。
128. 如何将应用程序部署到 Kubernetes?
标准流程是通过控制器(如 Deployment):
- 编写 manifests:创建
deployment.yaml(定义副本、镜像、资源) 和service.yaml(定义暴露方式)。 - 应用配置:
kubectl apply -f deployment.yaml -f service.yaml。 - 验证:
kubectl get pods查看状态,kubectl logs查看日志。 - 包管理 (可选):使用 Helm Chart (
helm install my-app ./chart)。 - CI/CD 集成:流水线自动执行
kubectl apply或helm upgrade。
129. 如何水平扩展 Deployment?
- 命令方式:
kubectl scale deployment <name> --replicas=10 - 自动方式 (HPA):
创建 HPA 对象:kubectl autoscale deployment <name> --cpu-percent=50 --min=2 --max=20 - 修改 YAML:
更新spec.replicas字段并执行kubectl apply。
130. 怎样在 Kubernetes 中进行服务发现?
K8s 内置了强大的服务发现机制:
- 环境变量:当 Pod 启动时,K8s 会自动将当前 Namespace 内所有 Service 的信息注入为环境变量(如
MY_SERVICE_SERVICE_HOST,MY_SERVICE_SERVICE_PORT)。 - DNS (推荐):
- 集群内运行 CoreDNS (或 kube-dns)。
- 每个 Service 都有 DNS 记录:
<service-name>.<namespace>.svc.cluster.local。 - 同 Namespace 下可直接通过
<service-name>访问。 - 应用只需配置域名,无需硬编码 IP。
131. 怎样进行容器间通信?
- 同一 Pod 内:
- 通过
localhost+ 端口通信。 - 共享网络命名空间,IP 相同。
- 可通过共享 Volume 交换文件。
- 通过
- 同一节点不同 Pod:
- 通过 Pod IP 直接通信(CNI 插件保证二层互通)。
- 不同节点 Pod:
- 通过 Pod IP 直接通信(CNI 插件通过 Overlay 网络或路由实现跨节点互通)。
- 或通过 Service (ClusterIP) 进行负载均衡访问。
- 外部访问:
- 通过 Service (NodePort/LoadBalancer) 或 Ingress。
132. 如何进行安全访问控制 (RBAC)?
RBAC 通过四个核心对象实现:
- Role / ClusterRole:定义权限规则(能做什么,如
get,list,create哪些资源)。Role:限定在特定 Namespace。ClusterRole:集群范围或所有 Namespace。
- RoleBinding / ClusterRoleBinding:将角色绑定给用户/组/ServiceAccount。
- 定义谁(Subject)拥有什么权限(RoleRef)。
- User/Group/ServiceAccount:身份主体。
- 配置示例:
# 创建 Role kind: Role rules: - apiGroups: [""] resources: ["pods"] verbs: ["get", "list"] --- # 绑定给 ServiceAccount kind: RoleBinding subjects: - kind: ServiceAccount name: my-sa namespace: default roleRef: kind: Role name: pod-reader apiGroup: rbac.authorization.k8s.io
133. 怎样进行热更新 (Hot Deployment)?
K8s 原生支持滚动更新 (Rolling Update),实现业务零停机:
- 配置策略:在 Deployment 中设置
strategy.type: RollingUpdate。maxSurge:更新过程中允许超出期望副本数的最大数量。maxUnavailable:更新过程中允许不可用的最大数量。
- 执行更新:修改镜像版本 (
kubectl set image ...或apply)。 - 配合探针:必须配置
readinessProbe,确保新 Pod 完全启动并准备好接收流量后,才销毁旧 Pod。 - 应用层要求:应用需支持优雅停机(监听 SIGTERM,处理完现有请求再退出)。
134. 如何在 Prometheus 中定义监控指标?
Prometheus 本身不“定义”指标,而是抓取 (Scrape) 目标暴露的指标。
- 指标格式:目标应用需暴露 HTTP 接口(默认
/metrics),遵循 Prometheus 文本格式:# HELP http_requests_total Total number of HTTP requests. # TYPE http_requests_total counter http_requests_total{method="POST",handler="/api"} 1024 - 客户端库:应用可使用 Prometheus 官方客户端库(Go, Java, Python 等)在代码中注册 Counter, Gauge, Histogram, Summary 类型的指标。
135. 如何配置 Prometheus 进行目标抓取 (Scrape Config)?
在 prometheus.yml 中配置 scrape_configs:
scrape_configs:
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
# 只抓取带有 prometheus.io/scrape=true 注解的 Pod
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
# 动态替换抓取端口
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
target_label: __address__
regex: (.+)
replacement: ${1}
- 静态配置:直接指定
static_configs中的 targets。 - 服务发现:利用
kubernetes_sd_configs,consul_sd_configs等自动发现目标。
136. Prometheus 如何处理数据存储和保留策略?
- 本地存储:默认将时间序列数据存储在本地磁盘(TSDB 格式)。
- 保留策略:通过
--storage.tsdb.retention.time(如15d) 或--storage.tsdb.retention.size(如50GB) 参数控制。 - 清理机制:后台进程定期删除超过保留期限的数据块 (Blocks)。
- 长期存储:原生 Prometheus 不适合长期海量存储,通常配合 Thanos 或 Cortex 将数据卸载到对象存储 (S3/GCS)。
137. 如何设置警报规则并配置 Alertmanager?
- 定义规则 (rules.yml):
groups: - name: example rules: - alert: HighMemoryUsage expr: container_memory_usage_bytes / container_spec_memory_limit_bytes > 0.9 for: 5m labels: severity: critical annotations: summary: "High memory usage detected" - 加载规则:在
prometheus.yml中引用rule_files。 - 配置 Alertmanager (
alertmanager.yml):- 定义 Receiver (接收器):Email, Slack, Webhook (钉钉/企微), PagerDuty。
- 定义 Route (路由):根据标签将告警分发到不同接收器。
- 配置 抑制 (Inhibition) 和 分组 (Grouping)。
138. Prometheus 支持哪些查询操作和聚合函数 (PromQL)?
- 选择器:
http_requests_total,http_requests_total{job="api"}. - 范围向量:
http_requests_total[5m](过去 5 分钟的数据)。 - 聚合函数:
sum(),avg(),max(),min(),count().rate()(计算每秒增长率,最常用),irate(),increase().histogram_quantile()(计算分位数,如 P99)。
- 数学运算:加减乘除,布尔比较。
- 连接操作:
on,ignoring,group_left/right(类似 SQL Join)。
139. 什么是 Prometheus 的服务发现机制?
Prometheus 支持动态发现目标,无需硬编码 IP:
- Kubernetes SD:自动发现 Node, Pod, Service, Endpoint, Ingress。可根据 Label/Annotation 过滤。
- Consul/Etcd SD:从注册中心拉取服务列表。
- File SD:监控文件变化,自动重载目标列表。
- DNS SD:通过 DNS SRV/A 记录发现目标。
- EC2/GCE SD:自动发现云厂商的实例。
- 优势:适应云环境动态变化的 IP,实现自动化监控。
140. Prometheus 的可视化和查询界面是什么 (Grafana/PromUI)?
- PromUI (Expression Browser):
- Prometheus 自带的简单界面 (
/graph)。 - 功能:执行 PromQL 查询,查看原始数据表格和简单图表。
- 缺点:功能简陋,不适合生产大屏展示。
- Prometheus 自带的简单界面 (
- Grafana:
- 行业标准可视化平台。
- 功能:连接 Prometheus 数据源,创建丰富的仪表盘(Dashboard),支持多种图表、变量插值、模板化、告警面板。
- 生态:拥有大量社区预制的 K8s/Prometheus 模板。
141. 什么是 Prometheus 的推模式 (Push) 和拉模式 (Pull) 抓取?
- 拉模式 (Pull - 默认):
- Prometheus Server 主动去 Target 的
/metrics接口抓取数据。 - 优点:控制端掌握节奏,易于监控 Target 是否存活,防火墙配置简单(只需 Target 对 Server 开放)。
- 适用:大多数长期运行的服务。
- Prometheus Server 主动去 Target 的
- 推模式 (Push):
- Target 主动将数据推送到 Pushgateway。
- Prometheus 再从 Pushgateway 拉取。
- 适用:短作业 (Batch Jobs)、临时任务,这些任务运行时间短,可能在 Prometheus 来抓取前就结束了。
- 注意:Pushgateway 不是长期存储,仅作为中转。
142. 如何在 Prometheus 中配置持久化存储?
- K8s 环境:
- 使用 StatefulSet 部署 Prometheus。
- 配置
volumeClaimTemplates,动态申请 PVC (对接云盘或 Ceph/NFS)。 - 示例:
volumeClaimTemplates: - metadata: name: prometheus-data spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 50Gi
- 单机环境:启动时指定
--storage.tsdb.path=/data/prometheus并挂载磁盘。
143. Prometheus 是否支持高可用性 (HA) 部署?
原生 Prometheus 不支持 集群模式(多主写入),但可通过架构实现 HA:
- 多副本独立运行:部署两套完全相同的 Prometheus 实例,抓取相同的目标。
- 查询时通过 Grafana 配置 PromQL Federation 或使用 Thanos Query / Cortex 进行合并查询。
- 只要有一套存活,数据就不丢失(数据会有重复,查询层去重)。
- Thanos/Cortex 架构:
- Sidecar 模式:多个 Prometheus 将数据上传到对象存储 (S3)。
- Query 层:从对象存储和各 Prometheus 实例统一查询,实现全局视图和高可用。
- 这是生产环境推荐的 HA 方案。
144. 什么是 Prometheus 的持续查询 (Recording Rules)?
- 定义:预先计算复杂的 PromQL 表达式,并将结果保存为新的时间序列指标。
- 目的:
- 优化性能:将昂贵的查询(如大范围
rate或多表join)提前算好,查询时直接读取结果,加快 Dashboard 加载速度。 - 简化查询:将复杂逻辑封装为简单的指标名(如
job:http_requests:rate5m)。
- 优化性能:将昂贵的查询(如大范围
- 配置:在
rules.yml中定义record规则。
145. K8s 中 RBAC (Role-Based Access Control) 详解?
- 核心逻辑:基于角色的权限控制,解耦了“用户”和“权限”。
- 四大资源:
- Role:Namespaced 级别的权限集合(定义动词 verbs + 资源 resources + API 组 apiGroups)。
- ClusterRole:Cluster 级别的权限集合(可访问所有 Namespace 或集群级资源如 Node, PV)。
- RoleBinding:将 Role 授予特定 Namespace 内的 Subject (User/Group/SA)。
- ClusterRoleBinding:将 ClusterRole 授予集群范围的 Subject。
- 聚合 ClusterRole:可以通过
aggregationRule自动聚合带有特定 Label 的其他 ClusterRole 的权限,方便插件扩展。 - 默认行为:默认拒绝所有未明确允许的请求。
146. K8s 中如何安全地传递敏感信息 (如密码、密钥等)?
- 使用 Secret 对象:
- 创建:
kubectl create secret generic my-secret --from-literal=password=123。 - 使用方式:
- 环境变量:
valueFrom.secretKeyRef。 - 挂载卷:以文件形式挂载到容器内(推荐,避免环境变量泄露给子进程或日志)。
- 环境变量:
- 创建:
- 加密存储 (Encryption at Rest):
- 配置 API Server 的
EncryptionConfiguration,使 Etcd 中存储的 Secret 数据经过加密(使用 AES-CBC 或 aescbc 提供者),即使 Etcd 文件被盗也无法解密。
- 配置 API Server 的
- 外部密钥管理 (最佳实践):
- 使用 External Secrets Operator 或 Sealed Secrets。
- 将密钥存储在专业的密钥管理系统(AWS Secrets Manager, HashiCorp Vault, Azure Key Vault)中,同步到 K8s。
- 避免将明文 Secret YAML 提交到 Git 仓库。
147. Kubernetes 中如何管理容器的安全性?可以列举几点?
- Pod Security Standards (PSS):启用 PSS (Baseline, Restricted),禁止特权容器、宿主机网络/PID 命名空间、Root 用户运行。
- 非 Root 运行:在
securityContext中设置runAsNonRoot: true和runAsUser。 - 只读文件系统:设置
readOnlyRootFilesystem: true,防止恶意篡改二进制文件。 - 能力丢弃 (Drop Capabilities):默认丢弃所有 Linux Capabilities (
drop: ["ALL"]),仅添加必要的(如NET_BIND_SERVICE)。 - 镜像扫描:在 CI/CD 流水线中集成 Trivy/Clair,阻止有高危漏洞的镜像上线。
- 网络策略 (NetworkPolicy):默认拒绝所有流量,仅放行必要的 Pod 间通信。
- ServiceAccount 最小权限:不为 Pod 绑定默认的
defaultSA(尤其不要绑定 cluster-admin),创建专用的 SA 并绑定最小权限 Role。
148. 如何查看和分析 Pod 的日志?有哪些工具可以帮助实现?
- 基础命令:
kubectl logs <pod-name>:查看单容器日志。kubectl logs <pod-name> -c <container-name>:查看多容器 Pod 中指定容器日志。kubectl logs -f <pod-name>:实时跟踪 (Follow)。kubectl logs --previous <pod-name>:查看崩溃重启前的日志。kubectl logs -l app=nginx:查看匹配标签的所有 Pod 日志。
- 高级工具:
- Stern:同时 tail 多个 Pod 的日志,支持正则高亮 (
stern -l app=nginx)。 - Kubetail:类似的 Bash 脚本工具。
- K9s:终端 UI 工具,可交互式查看日志。
- ELK/Loki + Grafana:集中式日志平台,支持全文检索、聚合分析和可视化。
- Stern:同时 tail 多个 Pod 的日志,支持正则高亮 (
149. 如何使用 Kubernetes 进行多环境部署(如开发、测试、生产)?
- Namespace 隔离 (轻量级):
- 创建
dev,test,prodNamespace。 - 配合 Kustomize 或 Helm Values 区分配置(如 replica 数、资源限制、镜像 tag)。
- 优点:简单,资源共享。缺点:隔离性较弱(噪声邻居问题)。
- 创建
- 独立集群 (重量级/推荐用于 Prod):
- 为 Dev/Test/Prod 建立完全独立的 K8s 集群。
- 通过 CI/CD 流水线将应用部署到不同集群。
- 优点:故障隔离彻底,安全性高,可定制不同版本的 K8s。
- GitOps 管理:
- 使用 ArgoCD,在 Git 仓库中维护不同目录(
overlays/dev,overlays/prod),分别同步到对应的 Namespace 或集群。
- 使用 ArgoCD,在 Git 仓库中维护不同目录(
150. 如何在 Kubernetes 中实现应用程序的配置管理?
- ConfigMap:存储非敏感配置(配置文件、环境变量)。
- 挂载为文件:适用于传统应用读取配置文件。
- 注入环境变量:适用于云原生应用。
- Secret:存储敏感配置。
- 外部配置中心:
- 应用启动时从 Apollo, Nacos, Consul 拉取配置。
- 配合 Sidecar 或 Init Container 同步配置到本地文件。
- Helm/Kustomize:在部署阶段通过模板渲染生成具体的 ConfigMap/Secret,实现“一次构建,多处部署”。
- 动态更新:
- 挂载 ConfigMap 为文件时,应用需支持热重载或配合 Sidecar (如 Reloader) 重启 Pod。
- 环境变量方式通常需要重启 Pod 才能生效。
151. Kubernetes 与 CI/CD (如 Jenkins, GitLab CI) 如何集成?
- Kubectl 方式:
- CI 环境中安装
kubectl,配置 kubeconfig。 - 脚本执行
kubectl apply -f ...或kubectl set image ...。 - 缺点:命令式,难以回滚,状态管理弱。
- CI 环境中安装
- Helm 方式:
- CI 执行
helm upgrade --install。 - 优点:版本管理,回滚方便,参数化配置。
- CI 执行
- GitOps 方式 (现代最佳实践):
- CI 只负责构建镜像、推送镜像、更新 Git 仓库中的 Manifest (镜像 tag)。
- ArgoCD/Flux (运行在 K8s 内) 监听 Git 变化,自动同步集群状态。
- 优点:声明式,审计性强,集群权限无需暴露给 CI。
- Jenkins Kubernetes Plugin:
- Jenkins Master 动态在 K8s 中创建 Agent Pod 来执行构建任务,用完即毁。
152. 如何实现 Kubernetes 集群的备份(特别是 Etcd)?
- Etcd 备份 (核心):
- 快照命令:
etcdctl snapshot save backup.db --endpoints=<ip>:2379 ... - 定时任务:使用 CronJob 定期执行快照并上传到对象存储 (S3)。
- 恢复:停止 API Server,执行
etcdctl snapshot restore,重启 Etcd 和 API Server。
- 快照命令:
- 资源清单备份:
- 使用 Velero (推荐):
- 备份 K8s 资源对象 (YAML) 到对象存储。
- 备份 PV 数据 (通过云厂商快照插件或 Restic/Kopia)。
- 支持灾难恢复、集群迁移、定时备份。
- 使用 Velero (推荐):
- 配置即代码:最根本的备份是 Git 仓库中的 Manifest/Helm Chart。
153. Kubernetes 中如何管理和优化资源 (如 CPU、内存)?
- 合理设置 Request/Limit:
- 基于实际压测数据设置,避免过大浪费或过小导致 OOM/节流。
- 利用 QoS 等级 (Guaranteed/Burstable) 保障关键业务。
- 垂直自动伸缩 (VPA):
- 分析历史用量,自动推荐或调整 Request/Limit 值(注意:修改 Limit 通常需要重启 Pod)。
- 水平自动伸缩 (HPA):
- 根据负载动态增减副本,提高资源利用率。
- 集群自动伸缩 (CA):
- 当节点资源不足时自动增加节点,空闲时缩容节点。
- 资源配额 (ResourceQuota):
- 限制 Namespace 总资源使用,防止单一团队耗尽集群资源。
- 调度优化:
- 使用亲和性/反亲和性、拓扑分布约束,平衡节点负载,避免热点。
154. Kubernetes 中如何管理和更新容器的安全补丁?
- 基础镜像更新:
- 定期重建基础镜像(OS 层补丁),触发应用镜像重新构建。
- 自动化扫描与修复:
- 集成 Trivy/Grype 在 CI 中扫描。
- 使用 Renovate 或 Dependabot 自动检测基础镜像漏洞并提 PR 更新 Dockerfile。
- 滚动更新策略:
- 发布新镜像版本,利用 Deployment 滚动更新替换旧 Pod。
- 运行时防护:
- 使用 Falco 等工具监控异常行为。
- 对于无法立即重启的关键应用,考虑热补丁技术(较少见,通常还是重启)。
- K8s 组件升级:
- 定期升级 Kubelet, Kube-Proxy 及控制平面组件以修复 CVE。
155. Kubernetes 中如何实现故障转移和自动恢复?
- Pod 级别自愈:
- Restart Policy:容器崩溃自动重启。
- Liveness Probe:检测到死锁/无响应,自动重启 Pod。
- Controller (Deployment/StatefulSet):Pod 意外删除或节点故障导致 Pod 丢失时,控制器会自动在新节点创建新 Pod。
- 节点级别故障转移:
- Node Controller:检测到 Node 失联 (NotReady) 超过阈值,将该节点上的 Pod 标记为终止,并在其他健康节点重新调度。
- Pod Disruption Budget (PDB):确保在自愿干扰(如节点维护)期间,始终有最小数量的 Pod 可用。
- 多可用区 (Multi-AZ) 部署:
- 配置 Topology Spread Constraints 或 Pod Anti-Affinity,强制 Pod 分散在不同的可用区 (Zone)。
- 当某个 AZ 整体故障时,其他 AZ 的 Pod 继续服务,配合 LoadBalancer 流量切换。
- 控制平面 HA:
- 多 Master + Etcd 集群,单点故障不影响集群管理功能。
- Kubernetes & Docker 核心面试题整理
- 1. 基础概念 (Basic Concepts)
- 1. K8s 中常见类型的资源介绍和区别?
- 2. K8s 中 Pod 服务健康检查方式有哪两种?
- 3. K8s 认证方式有几种?
- 4. K8s 中的证书和私钥种类有哪些?
- 5. K8s 中各个主要组件有哪些?各自作用是什么?
- 6. K8s 集群中有没有高可用?你们公司的高可用架构是什么?
- 7. K8s 中镜像下载策略(ImagePullPolicy)有哪几种?
- 8. K8s 中 Pod 故障重启策略(RestartPolicy)有哪几种?
- 9. K8s 中 PV 有几种访问模式(Access Modes)?
- 10. K8s 中 PV 和 PVC 的作用是什么?PV、PVC 和底层存储的关系?
- 11. 客户端访问 K8s 资源需要经过几关?分别是什么?
- 12. K8s 集群中的数据是存储在哪个位置?
- 13. 什么是 Headless(无头)Service?
- 2. Docker 相关 (Docker Related)
- 14. Docker 怎么用 Dockerfile 文件构建镜像?具体命令是什么?
- 15. Docker 怎么用镜像运行一个容器?如何设置在后台运行?
- 16. Docker Harbor 是怎么安装的?有哪几种安装方式?
- 17. Dockerfile 中都有哪些关键字?各自的作用是什么?
- 🔍 深度解析:ENTRYPOINT vs CMD
- 18. 如何使用 Docker 快速运行相关服务?(例如 Docker 安装 MySQL/Redis 等)
- 19. 使用过 Docker Compose 吗?比 Docker 来讲,有什么优势?
- 20. 会编写 Docker Compose 的 YAML 文件吗?如何编写?
- 21. Docker 有几种网络模式?分别是哪些?各自作用是什么?
- 22. 你们用的 K8s 的版本是什么?
- 23. Dockerfile 中 RUN、CMD、ENTRYPOINT 的区别?
- 24. Dockerfile 中 ADD 和 COPY 的区别?
- 25. Docker 中的镜像分层(Layering)是怎么样的?
- 3. Pod 和服务 (Pod & Service)
- 26. K8s 中 Pod 是如何实现代理和负载均衡的?
- 27. K8s 中创建 Pod 的过程或流程是怎么样的?
- 28. K8s 中如何批量删除 Pod?
- 29. Kubeadm 初始化的 K8s 集群,Token 过期后,集群中节点无法加入怎么办?
- 30. K8s 运维过程中遇到过哪些问题,如何解决的?(开放性问题)
- 31. 执行
kubectl get node命令后看不到某些节点的原因? - 32. 执行
kubectl get cs查看集群状态不正常,显示 Unhealthy 的原因? - 33. Kubectl 命令中
create和apply创建资源的区别? - 34. Pod 资源共享机制如何实现?即:如何实现 Pod 中两个容器共享数据?
- 35. 容器之间是通过什么进行隔离的?
- 36. Pod 常用的状态有哪些?
- 37. 节点选择器(Node Selector)都有什么?各自的区别是什么?
- 38. 污点(Taint)和容忍度(Toleration)是什么?两者是如何配合使用的?
- 39. Service 的 4 种类型?
- 40. Service 的两种代理模式(iptables/IPVS)?
- 41. K8s 提供了哪几种对外暴露访问方式?
- 4. 监控和日志 (Monitoring & Logging)
- 42. K8s 的监控(Prometheus)常用监控组件有哪些?各自作用?
- 43. cAdvisor、node-exporter、metrics-server 的区别和联系?
- 44. Pod 常见的状态有哪些?(结合生命周期回答)
- 45. Node 节点不能工作的处理流程?
- 46. K8s 常见健康检查的探针(Probe)有几种?
- 47. K8s 中网络通信类型有几种?
- 48. K8s 中网络插件(CNI)有哪些?各自特点是什么?
- 49. Pod 网络连接超时的几种情况?
- 50. 访问 Pod 的 IP:端口 或 Service 的 IP 显示超时的处理思路?
- 51. Pod 的生命周期阶段?
- 52. Pod 处于 Running,但应用不正常的几种情况?
- 53. 当遇到 CoreDNS 经常重启和报错,这种故障如何排查?
- 54. K8s 集群节点状态为 NotReady 的都有哪些情况?
- 5. 调度和资源管理 (Scheduling & Resources)
- 6. 网络和通信 (Networking)
- 7. 日志和配置 (Logging & Config)
- 8. 存储和持久化 (Storage)
- 9. 综合问题 (Comprehensive)
- 79. 简述 Kubernetes 和 Docker 的关系和区别?
- 80. 简述 Kubernetes 的 CNI 模型?
- 81. 简述 Kubernetes 如何实现集群管理?
- 82. 简述 Kubernetes 的优势、适应场景及其特点?
- 83. 同一节点上的 Pod 通信原理?
- 84. 不同节点上的 Pod 通信原理?
- 85. 简述 Kubernetes Scheduler 使用哪两种算法将 Pod 调度到 Node?
- 86. 简述 Kubernetes 如何保证集群的安全性?
- 87. K8s 中 Namespace 的作用?
- 88. Pod 是什么?
- 89. 什么是静态 Pod(Static Pod)?
- 90. 简述 K8s 中 Pod 的常见调度方式?
- 91. 简述一下在 K8s 中删除 Pod 的流程?
- 92. Pod 的资源请求(Request)和限制(Limit)如何定义?
- 93. 标签(Labels)及标签选择器(Label Selectors)是什么,作用是什么?
- 94. Service 的域名解析格式?
- 95. Pod 与 Service 的通信信息是怎么样的?
- 96. 在 K8s 集群内的应用如何访问外部的服务?
- 97. Service、Endpoint、Kube-Proxy 三者的关系是什么?
- 98. Pod 创建/删除时,Service、Endpoint、Kube-Proxy 三者发生了什么变化?
- 99. Deployment 怎么扩容或缩容?
- 100. K8s 数据持久化的方式有哪些?
- 10. 高级主题 (Advanced Topics)
- 101. 什么是 Kubernetes?它的主要目标是什么?
- 102. 什么是 ReplicaSet?
- 103. 什么是 Deployment?
- 104. 什么是 Service?
- 105. 什么是命名空间 (Namespace)?
- 106. 如何进行应用程序的水平扩展?
- 107. 如何在 Kubernetes 中进行滚动更新 (Rolling Update)?
- 108. 如何在 Kubernetes 中进行滚动回滚 (Rollback)?
- 109. 什么是 Kubernetes 的水平自动扩展 (Horizontal Pod Autoscaler, HPA)?
- 110. 如何进行存储卷 (Volume) 的使用?
- 111. 什么是 Init 容器 (Init Container)?
- 112. 如何在 Kubernetes 中进行配置文件的安全管理(Secret/ConfigMap)?
- 113. 如何监控 Kubernetes 集群?
- 114. 如何进行跨集群部署和管理?
- 115. 什么是 Kubernetes 的生命周期钩子 (Lifecycle Hooks)?
- 116. 什么是 Pod 的探针 (Probe)?(Liveness, Readiness, Startup)
- 117. 什么是 Kubernetes 的安全性措施?
- 118. 什么是容器资源限制 (Resource Limit) 和容器资源请求 (Resource Request)?
- 119. 什么是 Kubernetes 中的水平和垂直扩展?
- 120. 什么是 Kubernetes 的事件 (Event)?
- 121. 什么是 Helm?
- 122. 如何进行 Kubernetes 集群的高可用性配置?
- 123. 什么是 K8s 的配置管理工具?
- 124. 什么是 K8s 的网络模型?
- 125. Kubernetes 的升级策略有哪些?
- 126. 什么是 Kubernetes 的监控和日志记录解决方案?
- 127. 怎样从一个镜像创建一个 Pod?
- 128. 如何将应用程序部署到 Kubernetes?
- 129. 如何水平扩展 Deployment?
- 130. 怎样在 Kubernetes 中进行服务发现?
- 131. 怎样进行容器间通信?
- 132. 如何进行安全访问控制 (RBAC)?
- 133. 怎样进行热更新 (Hot Deployment)?
- 134. 如何在 Prometheus 中定义监控指标?
- 135. 如何配置 Prometheus 进行目标抓取 (Scrape Config)?
- 136. Prometheus 如何处理数据存储和保留策略?
- 137. 如何设置警报规则并配置 Alertmanager?
- 138. Prometheus 支持哪些查询操作和聚合函数 (PromQL)?
- 139. 什么是 Prometheus 的服务发现机制?
- 140. Prometheus 的可视化和查询界面是什么 (Grafana/PromUI)?
- 141. 什么是 Prometheus 的推模式 (Push) 和拉模式 (Pull) 抓取?
- 142. 如何在 Prometheus 中配置持久化存储?
- 143. Prometheus 是否支持高可用性 (HA) 部署?
- 144. 什么是 Prometheus 的持续查询 (Recording Rules)?
- 145. K8s 中 RBAC (Role-Based Access Control) 详解?
- 146. K8s 中如何安全地传递敏感信息 (如密码、密钥等)?
- 147. Kubernetes 中如何管理容器的安全性?可以列举几点?
- 148. 如何查看和分析 Pod 的日志?有哪些工具可以帮助实现?
- 149. 如何使用 Kubernetes 进行多环境部署(如开发、测试、生产)?
- 150. 如何在 Kubernetes 中实现应用程序的配置管理?
- 151. Kubernetes 与 CI/CD (如 Jenkins, GitLab CI) 如何集成?
- 152. 如何实现 Kubernetes 集群的备份(特别是 Etcd)?
- 153. Kubernetes 中如何管理和优化资源 (如 CPU、内存)?
- 154. Kubernetes 中如何管理和更新容器的安全补丁?
- 155. Kubernetes 中如何实现故障转移和自动恢复?
- 1. 基础概念 (Basic Concepts)