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),但最核心的两种是:

  1. Liveness Probe(存活探针)
    • 作用:判断容器是否“活着”。如果检测失败,Kubelet 会杀死容器并根据重启策略(RestartPolicy)进行重启。
    • 场景:解决死锁、进程挂起但未退出等“假死”情况。
  2. Readiness Probe(就绪探针)
    • 作用:判断容器是否“准备好接收流量”。如果检测失败,Endpoints 控制器会将该 Pod 从 Service 的负载均衡列表中剔除,不再转发流量,但不会重启容器
    • 场景:应用启动加载数据、依赖服务未就绪时,避免用户请求失败。
      (注:还有一种 Startup Probe,用于处理启动缓慢的应用,启动成功后不再执行)

3. K8s 认证方式有几种?

Kubernetes API Server 支持多种认证插件,常见的有:

  1. 客户端证书 (Client Certificates):基于 TLS 双向认证,最常用且安全,用于组件间通信和管理员访问。
  2. Bearer Token
    • Service Account Tokens:Pod 内部访问 API Server 的标准方式。
    • Static Token File:静态文件定义的 Token(不推荐生产使用)。
  3. Bootstrap Token:用于节点加入集群时的临时认证。
  4. OIDC (OpenID Connect):集成第三方身份提供商(如 Google, GitHub, Keycloak)。
  5. Webhook Token:调用外部服务进行认证。
  6. Anonymous:匿名访问(通常默认禁用或权限极低)。
  7. 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 集群中有没有高可用?你们公司的高可用架构是什么?

  • 有没有高可用:原生支持,但需要手动配置多主节点。
  • 通用高可用架构方案
    1. 多 Master 节点:部署 3 个或以上的 Master 节点(奇数),防止单点故障。
    2. 负载均衡 (LB):在 Master 节点前架设负载均衡器(如 Keepalived + HAProxy,或云厂商的 SLB/ELB),提供一个统一的 VIP (虚拟 IP) 供 Worker 节点和 kubectl 访问 API Server。
    3. Etcd 高可用:Etcd 集群通常部署为 3 或 5 节点,采用 Raft 协议保证数据一致性。可以是堆叠在 Master 上,也可以是独立的外部集群。
    4. Worker 节点多副本:应用通过 Deployment 设置多副本并配合反亲和性策略,分散在不同节点。
      (注:作为 AI,我没有具体的“公司”,以上是业界标准的 HA 架构实践。)

7. K8s 中镜像下载策略(ImagePullPolicy)有哪几种?

  1. Always:每次启动 Pod 时都尝试从仓库拉取最新镜像。如果标签是 latest,默认也是此行为。
  2. IfNotPresent(默认):只有当本地节点没有该镜像时才拉取。如果本地已有,直接使用本地缓存。
  3. Never:只使用本地镜像,如果本地没有则报错,绝不尝试联网拉取。

8. K8s 中 Pod 故障重启策略(RestartPolicy)有哪几种?

该策略定义在 Pod Spec 中,作用于 Pod 内所有容器:

  1. Always(默认):无论容器是正常退出(exit code 0)还是异常退出,都会重启。Deployment 等控制器管理的 Pod 必须使用此策略。
  2. OnFailure:仅当容器异常退出(exit code 非 0)时重启。常用于 Job
  3. Never:无论何种情况都不重启。常用于调试或一次性任务。

9. K8s 中 PV 有几种访问模式(Access Modes)?

  1. ReadWriteOnce (RWO):读写权限,只能被单个节点挂载(最常见,如云盘)。
  2. ReadOnlyMany (ROX):只读权限,可以被多个节点同时挂载。
  3. ReadWriteMany (RWX):读写权限,可以被多个节点同时挂载(通常需要 NFS、CephFS 等共享存储)。
  4. 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 所在的节点对应位置创建存储(常用于本地存储或特定拓扑约束场景)。

2. 三者与底层存储的完整关系图谱

我们可以将整个过程看作一个供应链流程

场景 A:静态供给 (Static Provisioning) - 传统模式
  1. 管理员手动在云控制台或存储设备上创建一块磁盘/文件系统。
  2. 管理员在 K8s 中编写 YAML 创建 PV,指向这块具体的存储。
  3. 开发者编写 PVC,请求特定大小的存储。
  4. K8s 发现有一个未绑定的 PV 满足 PVC 要求,执行 绑定 (Binding)
  5. Pod 引用 PVC,挂载成功。
    • 缺点:PV 用完了需要管理员手动介入扩容或新建,效率低。
场景 B:动态供给 (Dynamic Provisioning) - 现代主流模式 (引入 StorageClass)
  1. 管理员创建一个 StorageClass (例如名为 fast-ssd),配置好 Provisioner 和参数。
  2. 开发者编写 PVC,指定 storageClassName: fast-ssd 和所需大小(此时集群中可能并没有对应的 PV)。
  3. K8s 控制平面 监听到这个 PVC:
    • 发现没有现成的 PV 匹配。
    • 检查 PVC 指定的 StorageClass
    • 调用 StorageClass 中定义的 Provisioner
  4. Provisioner 调用底层存储 API(如 AWS API, Ceph Monitor),动态创建 一块新的物理/网络存储卷。
  5. Provisioner 随即在 K8s 中自动创建一个 PV 对象,指向这块新创建的底层存储,并立即将该 PV 与 PVC 绑定
  6. 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 后,依次经过三道关卡(任意一关失败即拒绝):

  1. 认证 (Authentication):确认“你是谁”?(校验证书、Token 等)。
  2. 授权 (Authorization):确认“你有权限做这件事吗”?(校验 RBAC 角色绑定、ABAC 策略等)。
  3. 准入控制 (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 集群内部通信)。

14. Docker 怎么用 Dockerfile 文件构建镜像?具体命令是什么?

步骤:

  1. 编写 Dockerfile 文件,定义构建指令。
  2. 在包含 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 镜像仓库。
主要安装方式:

  1. 离线安装包安装 (最常用)
    • 从 GitHub 下载 .tgz 离线包。
    • 解压后修改 harbor.yml 配置文件(设置 hostname, https 证书路径,密码等)。
    • 运行 ./install.sh 脚本。该脚本会调用 Docker Compose 启动所有组件(Core, Registry, Database, Redis, Nginx 等)。
  2. Helm Chart 安装 (K8s 环境推荐)
    • 在 Kubernetes 集群中,使用 Helm 添加 Harbor 仓库。
    • 自定义 values.yaml 配置。
    • 执行 helm install 部署到 K8s 集群中,利用 K8s 的存储和高可用特性。
  3. Docker Compose 手动编排
    • 不通过 install.sh,直接编写或修改 docker-compose.yml 文件来启动服务(适合深度定制或调试)。

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 World
  • docker 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

📝 格式重要提示

在使用 ENTRYPOINTCMD 时,强烈推荐使用 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 来讲,有什么优势?

是的,广泛使用。
优势:

  1. 多容器编排:Docker 命令一次只能运行一个容器。Compose 可以通过一个 YAML 文件定义和管理多个相互关联的服务(如 Web + DB + Cache),一键启动/停止整个应用栈。
  2. 配置即代码:所有启动参数、网络、卷映射都写在 docker-compose.yml 中,便于版本控制和团队协作,避免冗长的命令行。
  3. 依赖管理:可以定义服务启动顺序(depends_on),确保数据库先于应用启动。
  4. 环境隔离:可以为开发、测试、生产定义不同的 Compose 文件(或 override 文件)。
  5. 简化网络:自动创建一个专属网络,服务间可以通过服务名直接互通,无需手动配置 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 种网络驱动模式:

  1. Bridge (桥接模式)默认模式
    • 作用:创建一个虚拟网桥(docker0),容器连接到网桥上。容器拥有独立的 IP,通过 NAT 与宿主机通信。容器间可通过 IP 通信,默认无法通过容器名解析(除非在自定义 bridge 网络或使用了 link)。
    • 场景:单机多容器通信,需要端口映射到宿主机。
  2. Host (主机模式)
    • 作用:容器不使用独立的 Network Namespace,直接使用宿主机的网络栈。容器没有独立 IP,端口直接占用宿主机端口。
    • 场景:对网络性能要求极高,或需要绑定特定宿主机端口的场景(如监控 agent)。
  3. None (无网络模式)
    • 作用:容器有自己的 Network Namespace,但不进行任何网络配置(只有 lo 回环接口)。
    • 场景:高度安全的封闭环境,或完全自定义网络配置。
  4. Container (共享网络模式)
    • 作用:新创建的容器不创建自己的 Network Namespace,而是使用一个已存在容器的网络(IP、端口等完全共享)。
    • 场景:Kubernetes 中的 Pod 就是基于此概念(Sidecar 模式),或者某些特殊的调试场景。

(注:还有 Overlay 网络用于 Swarm 集群跨主机通信,Macvlan 用于让容器拥有物理网络 IP)

22. 你们用的 K8s 的版本是什么?

(作为 AI,我没有实体的“公司”或正在运行的集群。但在实际面试或生产环境中,这是一个考察你对版本迭代关注度的问题。)

参考回答策略:
“在生产环境中,我们通常遵循‘落后最新稳定版 1-2 个小版本’的策略,以确保稳定性并获得安全补丁。目前主流生产环境多使用 v1.26 到 v1.29 之间的版本。
具体选择取决于:

  1. 云厂商支持:如果使用托管 K8s (EKS, ACK, GKE),通常跟随云厂商的支持周期。
  2. 特性需求:是否需要特定的新特性(如 Sidecar 容器原生支持在 1.29+ 成熟)。
  3. 生态兼容性:确保使用的 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 指定主程序(如 pythonjava),CMD 指定默认参数(如 app.py-jar app.jar)。

24. Dockerfile 中 ADD 和 COPY 的区别?

  • COPY:
    • 功能:单纯地将本地文件/目录复制到镜像中。
    • 来源:仅限构建上下文(本地)的文件。
    • 推荐度官方推荐。行为透明,易于维护。
  • ADD:
    • 功能:除了复制文件外,还有两个额外特性:
      1. 如果源文件是压缩包(tar, gzip 等),会自动解压到目标路径。
      2. 支持通过 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 组件来实现。

  • 机制
    1. Service 定义:用户创建一个 Service,定义一组 Pod 的选择器(Selector)和虚拟 IP(ClusterIP)。
    2. Endpoints:K8s 控制平面监控到符合 Selector 的 Pod,将其 IP 列表更新到 Endpoints 对象中。
    3. kube-proxy 监听:每个节点上的 kube-proxy 监听到 Service 和 Endpoints 的变化。
    4. 规则下发kube-proxy 根据配置的模式(iptables 或 IPVS),在节点内核中生成相应的网络规则。
      • iptables 模式:生成一系列 NAT 规则。当流量访问 ClusterIP 时,内核 netfilter 模块根据概率随机将流量转发到后端某个 Pod IP。
      • IPVS 模式:调用内核 IPVS 模块,创建虚拟服务器(VIP)和真实服务器(Pod IP),利用内核的高效负载均衡算法(轮询、最少连接等)转发流量。
  • 结果:客户端访问 Service 的 VIP 时,流量被自动负载均衡到后端的任意一个健康 Pod 上。

27. K8s 中创建 Pod 的过程或流程是怎么样的?

这是一个典型的异步控制循环过程:

  1. 提交请求:用户通过 kubectl 或 API 调用向 API Server 发送创建 Pod 的请求。
  2. 验证与存储:API Server 进行认证、授权和准入控制,验证通过后,将 Pod 信息写入 Etcd
  3. 调度决策kube-scheduler 监听到有新的 Pod 处于 Pending 状态且未绑定节点,根据资源需求、亲和性、污点等策略,选择一个最合适的 Node,并将绑定结果(Binding)通过 API Server 更新回 Etcd。
  4. 节点执行:目标节点上的 kubelet 监听到分配给自己的 Pod 任务:
    • 调用容器运行时(如 containerd)拉取镜像。
    • 创建容器沙箱(Pause 容器)和业务容器。
    • 挂载卷、配置网络(调用 CNI 插件)。
    • 启动容器进程。
  5. 状态上报:kubelet 将 Pod 的运行状态(Running, Failed 等)定期上报给 API Server,并更新到 Etcd。
  6. 完成:用户查询时看到 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?

有多种方式,取决于筛选条件:

  1. 按标签删除(最常用):
    kubectl delete pod -l app=my-app -n default
    
  2. 按名称匹配删除
    kubectl delete pod $(kubectl get pod -n default | grep "my-prefix" | awk '{print $1}')
    
  3. 删除命名空间下所有 Pod(慎用):
    kubectl delete pod --all -n default
    
  4. 强制删除(处理 Terminating 状态卡住的 Pod)
    kubectl delete pod <pod-name> --grace-period=0 --force
    

29. Kubeadm 初始化的 K8s 集群,Token 过期后,集群中节点无法加入怎么办?

Kubeadm 生成的 bootstrap token 默认有效期为 24 小时。过期后需重新生成。
解决步骤(在 Master 节点执行):

  1. 生成新的 Token
    kubeadm token create
    
  2. 获取 CA 证书的 Hash 值(用于安全校验):
    openssl x509 -pubkey -in /etc/kubernetes/pki/ca.crt | openssl rsa -pubin -outform der 2>/dev/null | openssl dgst -sha256 -hex | sed 's/^.* //'
    
    (注:较新版本的 kubeadm 可以直接在 token create 命令中输出完整命令)
  3. 使用完整命令拼接
    或者直接运行以下命令让 kubeadm 自动打印完整的 join 命令:
    kubeadm token create --print-join-command
    
  4. 在 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/messagesjournalctl -u kubelet,常见原因为磁盘空间满(触发 DiskPressure)、证书过期或网络插件异常。
    • 解决:清理无用镜像/日志释放空间并重启 kubelet;若是证书过期,使用 kubeadm renew certs 更新并重启相关组件;若是 CNI 问题,重启 CNI DaemonSet。
  • 问题 3:Service 访问不通

    • 排查:检查 Endpoints 是否为空(通常因 Deployment 的 Label 与 Service 的 Selector 不匹配);检查 kube-proxy 日志;测试节点内部 iptables/IPVS 规则是否丢失。
    • 解决:修正 Deployment 的 Label 确保匹配,重启 kube-proxy DaemonSet 刷新规则,确认 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 命令后看不到某些节点的原因?

  1. 命名空间误解:Node 是集群级资源,不属于任何 Namespace,不需要加 -n,但如果用了错误的 context 可能连错集群。
  2. 节点未加入集群:Worker 节点从未成功执行 kubeadm join,或者 join 后网络不通导致心跳丢失。
  3. 标签过滤:如果不小心使用了 kubectl get node -l ... 且标签不匹配。
  4. 权限不足:当前使用的 ServiceAccount 或 User 没有 list nodes 的 RBAC 权限。
  5. 节点被删除:节点已被管理员手动删除或自动伸缩组缩容。
  6. 显示问题:节点存在但状态极差,尝试加 -o wide 查看详细信息。

32. 执行 kubectl get cs 查看集群状态不正常,显示 Unhealthy 的原因?

  • 背景cs (ComponentStatus) 是旧版 API,依赖 kube-controller-manager 和 kube-scheduler 向 API Server 汇报自身状态。
  • 常见原因
    1. 版本废弃:在 K8s v1.22+ 版本中,ComponentStatus API 已被弃用 (Deprecated) 并移除,不再可靠。现代集群不应依赖此命令判断健康度。
    2. 组件配置错误:在旧版本中,如果 scheduler 或 controller-manager 启动参数中 --port=0(禁用了不安全端口)或未正确配置向 API Server 汇报的地址,会导致显示 Unhealthy。
    3. 网络隔离:API Server 无法连接到 scheduler/cm 的状态端口。
  • 正确做法:直接检查组件 Pod 的状态 (kubectl get pods -n kube-system) 或查看系统日志,而不是依赖 get cs

33. Kubectl 命令中 createapply 创建资源的区别?

  • kubectl create:
    • 命令式:意图是“创建这个资源”。
    • 行为:如果资源已存在,会报错 AlreadyExists。不支持更新现有资源。
    • 场景:脚本初始化、一次性创建、确保资源不存在时创建。
  • kubectl apply:
    • 声明式:意图是“确保集群状态与 YAML 文件一致”。
    • 行为:如果资源不存在则创建;如果已存在,则计算差异并进行补丁更新 (Patch)。支持记录最后应用的配置注解 (last-applied-configuration)。
    • 场景:CI/CD 流水线、日常运维、GitOps,推荐作为标准操作方式。

34. Pod 资源共享机制如何实现?即:如何实现 Pod 中两个容器共享数据?

Pod 的核心设计就是共享上下文。

  1. 共享网络
    • Pod 内所有容器共享同一个 Network Namespace
    • 它们拥有相同的 IP 地址、端口空间。
    • 容器间可以通过 localhost + 端口号直接通信。
    • 通过 Pause 容器(Infra Container)持有网络栈,业务容器加入该 Namespace。
  2. 共享存储
    • 通过定义 Volume(如 emptyDir, hostPath, persistentVolumeClaim)。
    • 在 Pod spec 的 volumes 字段定义卷。
    • 在不同容器的 volumeMounts 字段中挂载同一个卷名到各自的路径。
    • 这样多个容器可以读写同一份文件系统数据。
  3. 共享 IPC/PID (可选):
    • 通过设置 shareProcessNamespace: true,容器间可以看到彼此的进程 ID,甚至进行信号通信。

35. 容器之间是通过什么进行隔离的?

主要依赖 Linux 内核的两大特性:

  1. Namespaces (命名空间):实现资源视图隔离
    • 让进程以为自己是系统中唯一的进程,拥有独立的网络、主机名、用户 ID、文件系统挂载点等。
    • 类型:PID, Net, IPC, Mnt, UTS, User。
  2. 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)都有什么?各自的区别是什么?

主要有三种机制,灵活度递增:

  1. nodeSelector
    • 形式:简单的键值对 (key: value)。
    • 逻辑:必须匹配所有标签(AND 关系)。
    • 缺点:功能单一,无法表达复杂逻辑(如 OR, NOT)。
  2. Node Affinity (节点亲和性)
    • 形式:在 affinity 字段中定义,支持表达式。
    • 类型
      • requiredDuringSchedulingIgnoredDuringExecution:硬约束,必须满足,否则不调度。
      • preferredDuringSchedulingIgnoredDuringExecution:软约束,尽量满足,打分制。
    • 优势:支持 In, NotIn, Exists, Gt, Lt 等操作符,可组合逻辑。
  3. 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 中。表示“我能忍受这个污点”。
  • 配合流程
    1. 管理员给 Master 节点打上污点:kubectl taint nodes master node-role.kubernetes.io/master:NoSchedule
    2. 普通 Pod 没有容忍度 -> 调度失败
    3. 系统组件 Pod(如 CNI, kube-proxy)在 Spec 中配置了 toleration 匹配该 key/effect -> 允许调度到 Master

39. Service 的 4 种类型?

  1. ClusterIP(默认):仅在集群内部暴露一个虚拟 IP。用于内部微服务互访。
  2. NodePort:在 ClusterIP 基础上,在每个节点的指定端口(30000-32767)暴露服务。外部可通过 NodeIP:NodePort 访问。
  3. LoadBalancer:在 NodePort 基础上,请求云厂商创建一个外部负载均衡器(ELB/SLB),将流量转发到 NodePort。用于公有云环境对外暴露。
  4. ExternalName:不涉及代理。将服务映射到 DNS 名称(如 my.db.example.com)。Pod 访问该 Service 时,DNS 解析直接返回外部域名。用于访问集群外部的数据库或服务。

40. Service 的两种代理模式(iptables/IPVS)?

kube-proxy 实现:

  1. iptables
    • 原理:利用 Linux Netfilter 框架,为每个 Service 生成大量的 NAT 规则链。
    • 优点:稳定,几乎所有 Linux 内核默认支持。
    • 缺点:规则是线性的。当 Service 和 Endpoint 数量巨大时(成千上万),规则链变长,流量匹配延迟增加,性能下降明显。更新规则需全量刷新,可能有短暂中断。
  2. IPVS
    • 原理:利用 Linux 内核的 IP Virtual Server 模块,在内核态维护哈希表。
    • 优点:高性能。查找复杂度为 O(1),适合大规模集群。支持更多负载均衡算法(轮询、最小连接、源地址哈希等)。
    • 要求:节点内核需加载 ip_vs 模块。K8s v1.11+ 成熟支持。
    • 现状:大规模生产环境推荐使用 IPVS 模式。

41. K8s 提供了哪几种对外暴露访问方式?

从简单到复杂,主要有以下几种:

  1. NodePort:最简单,直接利用节点 IP+ 高位端口。适合测试或无 LB 环境。
  2. LoadBalancer Service:利用云厂商 LB。适合公有云,成本较高,每个 Service 对应一个 LB IP。
  3. Ingress(最常用):
    • 七层负载均衡(HTTP/HTTPS)。
    • 只需一个 LB IP(入口),通过域名和路径路由到集群内不同的 Service。
    • 支持 SSL 终止、重写规则等。需部署 Ingress Controller (Nginx, Traefik, ALB Ingress)。
  4. Gateway API:Ingress 的继任者,更通用、更强大的标准,支持 TCP/UDP/gRPC 等多种协议和更细粒度的路由控制(逐渐普及中)。
  5. 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)反映了其在生命周期中的位置:

  1. Pending:API Server 已创建对象,但 Pod 尚未调度到节点,或者正在下载镜像。
    • 生命周期阶段:调度前或初始化中。
  2. Running:Pod 已绑定节点,所有容器已创建,至少有一个容器正在运行、即将启动或重启中。
    • 生命周期阶段:正常运行中。
  3. Succeeded:所有容器都成功终止(退出码 0),且不会重启。
    • 生命周期阶段:任务完成(常见于 Job)。
  4. Failed:所有容器都已终止,且至少有一个容器是非正常退出(退出码非 0)。
    • 生命周期阶段:任务失败。
  5. Unknown:由于节点通信故障,无法获取 Pod 状态。
    • 生命周期阶段:状态丢失。
  • 常见中间/异常状态(Status 字段显示)
    • ContainerCreating:正在拉取镜像或挂载卷。
    • ErrImagePull / ImagePullBackOff:镜像拉取失败。
    • CrashLoopBackOff:容器反复崩溃重启,K8s 在等待冷却期。
    • OOMKilled:容器因内存超限被内核杀死。
    • Terminating:Pod 正在被删除,等待优雅终止。

45. Node 节点不能工作的处理流程?

当发现节点异常(如 NotReady 或无响应)时:

  1. 查看状态kubectl get nodes 确认状态(NotReady, Unknown)。
  2. 检查 Podkubectl get pods -n kube-system -o wide | grep <node-name> 查看该节点上的系统组件(CNI, kube-proxy)是否正常运行。
  3. 登录节点:SSH 登录到故障节点。
  4. 检查系统资源top, free -m, df -h 查看 CPU、内存、磁盘是否满载(磁盘满会导致 kubelet 停止工作)。
  5. 检查关键服务
    • systemctl status kubelet:查看 kubelet 是否存活,journalctl -u kubelet -f 查看日志报错(如证书过期、配置错误、CNI 插件报错)。
    • systemctl status dockercontainerd:检查容器运行时。
  6. 检查网络:Ping Master 节点 API Server IP,检查防火墙规则,检查 CNI 插件配置。
  7. 检查证书/etc/kubernetes/pki/ 下的证书是否过期。
  8. 尝试重启systemctl restart kubelet
  9. 极端情况:如果节点彻底失联且无法恢复,可能需要 kubectl drain 驱逐业务,然后 kubectl delete node 移除节点,重新初始化加入。

46. K8s 常见健康检查的探针(Probe)有几种?

主要有三种,作用于容器级别:

  1. Liveness Probe(存活探针)
    • 作用:判断容器是否“死锁”或“假死”。
    • 失败动作重启容器(Restart)。
    • 场景:程序死循环、线程池耗尽但进程未退出。
  2. Readiness Probe(就绪探针)
    • 作用:判断容器是否“准备好接收流量”。
    • 失败动作:从 Service 的 Endpoints 中移除 IP(切断流量),不重启
    • 场景:应用启动加载大文件、依赖的 DB 尚未连通。
  3. Startup Probe(启动探针) (K8s 1.16+ Beta, 1.18+ Stable):
    • 作用:专门用于处理启动缓慢的应用。在它成功之前,Liveness 和 Readiness 都不会执行。
    • 失败动作:无(直到成功或达到失败阈值导致 Pod 重启)。
    • 场景:遗留应用启动需要几分钟,避免 Liveness 探针过早杀掉正在启动的容器。

47. K8s 中网络通信类型有几种?

K8s 网络模型要求满足以下四种通信场景:

  1. Pod 与 Pod 之间(同一节点或不同节点):直接通过 IP 通信,无需 NAT。
  2. Pod 与 Service 之间:通过 Service VIP 和 kube-proxy 规则进行负载均衡通信。
  3. 外部用户与 Service 之间:通过 NodePort, LoadBalancer 或 Ingress 访问集群内部服务。
  4. 节点与 Pod 之间:节点上的组件(如 kubelet, prometheus)访问本地或其他节点的 Pod。

48. K8s 中网络插件(CNI)有哪些?各自特点是什么?

CNI (Container Network Interface) 是标准接口,常见插件:

  1. Flannel
    • 特点:简单、轻量、易部署。Overlay 网络(VXLAN 模式)。
    • 缺点:功能单一,不支持 NetworkPolicy(网络策略),性能一般(VXLAN 有封装损耗)。
    • 场景:小型集群、测试环境、对网络策略无要求的场景。
  2. Calico
    • 特点:高性能(支持 BGP 路由模式,无封装损耗),功能强大(支持严格的 NetworkPolicy),生态成熟。
    • 缺点:BGP 模式对底层网络有一定要求(需支持 BGP 或 IPIP 穿透)。
    • 场景:生产环境首选,特别是需要网络隔离和大规模集群。
  3. Cilium
    • 特点:基于 eBPF 技术,性能极高,可观测性强(Hubble),支持七层网络策略(HTTP/gRPC)。
    • 场景:对性能、安全、可观测性有极高要求的现代化集群。
  4. Weave Net
    • 特点:自动加密(sleeve 模式),部署极其简单。
    • 场景:对安全性有基础要求且不想复杂配置的场景。
  5. Cloud Provider CNI (如 AWS VPC CNI, Aliyun Terway):
    • 特点:直接将 Pod 分配到云厂商的 VPC 子网中,Pod 拥有真实云内网 IP。
    • 场景:公有云托管集群,追求原生网络性能和兼容性。

49. Pod 网络连接超时的几种情况?

  1. CNI 插件故障:节点上的 CNI 组件未运行或配置错误,导致 Pod 网卡未正确分配 IP 或路由不通。
  2. NetworkPolicy 拦截:配置了默认拒绝(Deny All)的策略,且未放行特定流量。
  3. 目标 Pod 未就绪:目标 Pod 的 Readiness Probe 失败,流量未被转发(如果是通过 Service 访问)。
  4. 防火墙/安全组:云厂商的安全组或节点内部的 iptables/firewalld 阻断了端口。
  5. IP 冲突或路由缺失:跨节点通信时,底层物理网络路由不可达,或 Overlay 隧道建立失败。
  6. DNS 解析超时:如果是通过域名访问,CoreDNS 故障或配置错误导致解析慢或失败。
  7. 应用自身问题:目标应用处理请求过慢、死锁或监听地址错误(如只监听了 localhost)。

50. 访问 Pod 的 IP:端口 或 Service 的 IP 显示超时的处理思路?

排查步骤:

  1. 确认目标状态kubectl get pod/svc 确认 Pod 是 Running,Service 有 Endpoints。
    • 关键点:如果 Service 的 Endpoints 为空,说明没有后端 Pod,流量无处转发。
  2. 同节点测试:登录到 Pod 所在的节点,使用 curl <Pod_IP>:<Port> 测试。
    • 如果通:说明 Pod 正常,问题在跨节点网络或 Service 规则。
    • 如果不通:说明 Pod 应用未启动、监听端口错误或节点本地防火墙/CNI 问题。
  3. 检查 NetworkPolicykubectl get networkpolicy 查看是否有策略限制了源或目的。
  4. 检查 kube-proxy:查看 kube-proxy 日志,确认 iptables/IPVS 规则是否生成。在节点执行 iptables-save | grep <Service_IP> 查看规则是否存在。
  5. 抓包分析:在源 Pod 或节点上使用 tcpdump 抓包,看 SYN 包是否发出,是否有 RST 或 DROP。
  6. DNS 检查:如果是域名访问超时,先试 IP。如果 IP 通域名不通,排查 CoreDNS。
  7. MTU 问题:跨节点大包不通可能是 MTU 设置不一致(Overlay 网络需预留头部空间)。

51. Pod 的生命周期阶段?

从创建到销毁的标准流程:

  1. Pending:创建申请提交,等待调度。
  2. ContainerCreating:调度完成,正在拉取镜像、挂载存储、配置网络。
  3. Running
    • Init Containers 执行(如果有)。
    • Main Containers 启动。
    • Probes 开始工作(Startup -> Readiness -> Liveness)。
  4. Succeeded / Failed:任务型 Pod 的最终状态。
  5. Terminating
    • 收到删除指令。
    • 发送 SIGTERM 信号给容器进程(优雅退出)。
    • 等待 terminationGracePeriodSeconds(默认 30s)。
    • 若未退出,发送 SIGKILL 强制杀死。
    • 清理资源(网络、存储挂载)。
  6. Deleted:从 Etcd 和 API 中移除。

52. Pod 处于 Running,但应用不正常的几种情况?

Running 仅代表容器进程在运行,不代表业务正常:

  1. 应用内部报错:代码逻辑错误、配置文件错误、依赖服务连不上(需看 kubectl logs)。
  2. 死锁/假死:进程在跑,但无法处理请求(需靠 Liveness Probe 发现并重启)。
  3. 未通过就绪检查:应用启动慢或依赖未好,流量被切断(需看 Readiness Probe 状态,kubectl describe pod)。
  4. 资源限制:CPU 被节流(Throttling)导致响应极慢,或内存接近 Limit 导致频繁 GC。
  5. 端口监听错误:进程启动了,但监听在错误的 IP(如 127.0.0.1 而不是 0.0.0.0)或错误端口。
  6. 持久化存储满:磁盘写满导致应用无法写入日志或数据而卡住。
  7. 时钟不同步:节点时间偏差导致 TLS 握手失败或逻辑判断错误。

53. 当遇到 CoreDNS 经常重启和报错,这种故障如何排查?

CoreDNS 是集群 DNS 核心,不稳定会影响全网。
排查思路:

  1. 查看日志kubectl logs -n kube-system -l k8s-app=kube-dns
    • 常见错误:plugin/loop: Loop in Hints(通常是因为节点 hosts 文件配置不当或上游 DNS 配置环路)。
    • OOMKilled:内存不足,需调整 limits.memory
  2. 检查配置 (ConfigMap)kubectl edit cm coredns -n kube-system
    • 检查 forward 插件指向的上游 DNS 是否可达。
    • 检查是否有语法错误。
  3. 检查网络插件兼容性:某些 CNI 插件(如早期版本的 Calico/Flannel)与 CoreDNS 的 IP 分配或网络策略冲突。
  4. 检查节点 DNS 配置:CoreDNS 依赖宿主机的 /etc/resolv.conf 进行上游转发,如果宿主机 DNS 配置错误,CoreDNS 也会失效。
  5. 资源竞争:节点负载过高导致 CoreDNS 被误杀或调度不均,建议设置亲和性让 CoreDNS 分散在不同节点。
  6. 版本问题:K8s 版本升级后,CoreDNS 配置格式可能变化(如 proxy 改为 forward)。

54. K8s 集群节点状态为 NotReady 的都有哪些情况?

NotReady 意味着 Kubelet 无法向 API Server 上报“我准备好了”的状态。
常见原因:

  1. Kubelet 服务挂掉systemctl status kubelet 显示 inactive 或 failed。
  2. 容器运行时故障:Docker/Containerd 未运行或无响应,Kubelet 无法检查容器状态。
  3. CNI 插件未就绪:节点上的 CNI 配置缺失或 Pod 网络未打通,Kubelet 会认为节点未准备好(NetworkPluginNotReady)。
  4. 资源耗尽
    • 磁盘压力 (DiskPressure):日志或镜像占满磁盘,Kubelet 进入保护模式。
    • 内存压力 (MemoryPressure)。
    • PID 耗尽 (PIDPressure)。
  5. 证书过期:Kubelet 连接 API Server 的客户端证书过期,导致认证失败,心跳中断。
  6. 时间不同步:节点时间与集群其他节点偏差过大,导致 TLS 握手失败。
  7. 网络中断:节点与 Master 节点之间的网络不通,心跳包丢失。
  8. Swap 未关闭:K8s 默认要求关闭 Swap,如果开启且 Kubelet 配置未允许,可能导致启动失败或状态异常。

5. 调度和资源管理 (Scheduling & Resources)

55. K8s 的几种调度方式?

Kubernetes 的调度不仅仅是“自动”,它提供了多种策略来控制 Pod 落在哪个节点上:

  1. 自动调度 (Default Scheduler)
    • kube-scheduler 根据节点的剩余资源(CPU/Mem)、亲和性、污点等默认策略,自动选择最优节点。
  2. 指定节点调度 (nodeName)
    • 在 Pod Spec 中直接指定 nodeName: <node-name>
    • 特点:跳过调度器,强制绑定。如果该节点资源不足或不存在,Pod 会一直 Pending。
  3. 节点选择器 (nodeSelector)
    • 基于简单的键值对标签匹配 (key: value)。节点必须拥有该标签才能被调度。
  4. 节点亲和性 (Node Affinity)
    • 硬策略 (required...):必须满足条件,否则不调度。支持复杂的逻辑运算(In, NotIn, Exists 等)。
    • 软策略 (preferred...):尽量满足,打分制,不满足也能调度。
  5. 污点与容忍 (Taints and Tolerations)
    • 排斥机制。节点设置污点(Taint),Pod 设置容忍度(Toleration)。只有容忍了污点的 Pod 才能调度到该节点。常用于专用节点(如 GPU 节点)或 Master 节点隔离。
  6. Pod 亲和性与反亲和性 (Pod Affinity/Anti-Affinity)
    • 根据其他 Pod的位置来调度。
    • 亲和:让 Pod 尽量靠近某些 Pod(如同一服务的不同组件)。
    • 反亲和:让 Pod 尽量远离某些 Pod(如将同一应用的副本分散到不同节点/可用区,实现高可用)。
  7. 拓扑分布约束 (Topology Spread Constraints)
    • 更精细的控制,确保 Pod 在指定的拓扑域(如可用区、主机名、区域)中均匀分布,避免倾斜。

56. K8s 中一个 Node 节点突然断电,恢复后上面的 Pod 无法启动怎么办?

这种情况通常是因为节点状态异常或资源冲突。
排查与解决步骤:

  1. 检查节点状态
    • kubectl get nodes。如果节点仍为 NotReady,先修复节点(参考第 54 题:检查 kubelet、CNI、证书、资源等)。
  2. 检查 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:可能是原节点资源未释放,或者调度器认为原节点不可用但还没触发驱逐逻辑。
  3. 检查驱逐逻辑
    • K8s 有 pod-eviction-timeout(默认 5 分钟)。如果节点失联超过此时间,控制器管理器会将 Pod 标记为终止并重新调度。如果刚恢复,可能还在等待期内。
  4. 资源冲突
    • 如果节点恢复后,原来的 Pod 试图启动但失败,检查是否因为挂载的卷(Volume)具有 ReadWriteOnce (RWO) 属性,且未被正确卸载(例如云盘还挂载在旧的网络命名空间或认为仍被占用)。可能需要手动介入解除挂载或重启 kubelet。
  5. 最终手段
    • 如果节点数据损坏严重,最稳妥的方式是:kubectl drain <node-name> --ignore-daemonsets --delete-emptydir-data (如果节点可达) 或直接 kubectl delete node <node-name>,然后重置该节点并重新加入集群,让 Pod 调度到其他节点。

57. Pod 超过节点资源限制的故障情况有哪些?

这里指 Pod 请求/限制超过了节点能提供的能力,或运行时超出了 Limit。

  1. 调度失败 (Pending)
    • 原因:Pod 的 requests (请求值) 大于任何可用节点的剩余资源。
    • 现象:Pod 一直处于 Pending 状态,事件显示 FailedScheduling: Insufficient cpu/memory
  2. OOMKilled (内存超限)
    • 原因:容器进程使用的内存超过了 limits.memory
    • 现象:Pod 状态变为 Running 但容器反复重启,kubectl get pod 显示 OOMKilled,退出码 137。
  3. CPU 节流 (Throttling)
    • 原因:容器使用的 CPU 超过了 limits.cpu
    • 现象:Pod 不会重启,但应用响应变慢、卡顿。可以通过监控看到 cpu_cfs_throttled_seconds_total 指标升高。
  4. Evicted (被驱逐)
    • 原因:节点整体资源不足(如磁盘满、内存压力),Kubelet 主动驱逐优先级较低(QoS 为 BestEffort 或 Burstable)的 Pod。
    • 现象:Pod 状态变为 Failed,理由为 Evicted
  5. 创建失败 (CreateContainerConfigError)
    • 原因:极少见,但如果配置的 Limit 小于 Request,或者数值格式错误,会导致无法创建。

58. Pod 的自动扩容和缩容的方法有哪些?(HPA/VPA)

  1. HPA (Horizontal Pod Autoscaler,水平自动伸缩)
    • 原理:增加或减少 Pod 的副本数量
    • 指标:基于 CPU 使用率、内存使用率,或通过 Metrics Server/Prometheus Adapter 获取自定义指标(如 QPS、消息队列长度)。
    • 适用:无状态应用(Deployment),最常用的扩缩容方式。
    • 命令kubectl autoscale deployment <name> --cpu-percent=50 --min=1 --max=10
  2. VPA (Vertical Pod Autoscaler,垂直自动伸缩)
    • 原理:调整 单个 Pod 的资源请求 (requests) 和限制 (limits)(即加大/减小 CPU/内存配额)。
    • 代价:调整资源通常需要重启 Pod 才能生效(因为容器启动时已确定 cgroup 限制)。
    • 适用:有状态应用或无法简单通过增加副本来扩展的应用。注意:HPA 和 VPA 通常不建议同时用于同一个资源的同一个维度(如都控制 CPU),以免冲突。
  3. Cluster Autoscaler (CA,集群自动伸缩)
    • 原理:当 Pod 因资源不足无法调度(Pending)时,自动增加节点;当节点利用率低时,自动减少节点
    • 依赖:需要云厂商支持或底层基础设施支持动态添加机器。
    • 关系:通常配合 HPA 使用。HPA 增加 Pod -> 资源不足 -> CA 增加 Node。

59. K8s 中 Service 访问异常的常见问题有哪些?如何处理?

  1. Endpoints 为空
    • 原因:Service 的 selector 标签与 Pod 的 labels 不匹配。
    • 处理kubectl get endpoints <svc-name> 查看是否为空。修正 Deployment 或 Service 的标签。
  2. 目标 Pod 未就绪
    • 原因:Pod 虽然 Running,但 Readiness Probe 失败,导致 IP 被从 Endpoints 移除。
    • 处理kubectl describe pod 查看探针失败原因,修复应用启动逻辑或调整探针参数。
  3. 网络插件 (CNI) 问题
    • 原因:跨节点通信失败,iptables/IPVS 规则未生成。
    • 处理:检查 CNI 插件 Pod 状态,重启 kube-proxy,检查节点间网络连通性。
  4. 端口映射错误
    • 原因:Service 的 targetPort 与容器实际监听端口不一致。
    • 处理:核对 YAML 配置。
  5. NetworkPolicy 拦截
    • 原因:存在默认拒绝的 NetworkPolicy。
    • 处理kubectl get networkpolicy,检查入站/出站规则,添加允许规则。
  6. DNS 解析失败
    • 原因:CoreDNS 故障。
    • 处理:尝试直接用 IP 访问。如果 IP 通域名不通,排查 CoreDNS(参考第 53 题)。

60. K8s 中 Pod 删除失败,有哪些情况?和如何解决?

Pod 卡在 Terminating 状态无法删除:

  1. 节点失联 (Node Unreachable)
    • 原因:Pod 所在的节点宕机或网络中断,API Server 发送删除指令后,Kubelet 无法接收并执行,也无法上报状态。
    • 解决:强制删除。kubectl delete pod <pod-name> --grace-period=0 --force。这会直接从 Etcd 移除记录,但需注意如果是有状态应用,可能需要人工清理残留资源。
  2. Finalizers (终结器) 阻塞
    • 原因:Pod 或其他关联资源(如 PVC)上有 finalizers 字段,控制器逻辑未完成清理工作(例如外部存储卷正在卸载中,或自定义控制器卡死)。
    • 解决
      • 先排查关联控制器日志。
      • 若确认安全,可手动编辑资源移除 finalizer:kubectl edit pod <pod-name>,删除 metadata.finalizers 列表中的内容,保存后 K8s 会立即完成删除。
  3. 存储卷挂载无法卸载
    • 原因:底层存储(如 NFS、云盘)繁忙或驱动 bug,导致 Volume 无法 Detach。
    • 解决:检查 CSI 驱动日志,必要时在节点上手动 umount,或重启该节点上的 kubelet。
  4. API Server 负载过高
    • 原因:集群并发量大,删除请求处理延迟。
    • 解决:等待或扩容 API Server。

61. Pause 容器的概念和作用?

Pause 容器(也称为 Infra Container 或 Sandbox Container)是 K8s Pod 设计的核心基石。

  • 概念:每个 Pod 在启动业务容器之前,都会先启动一个极小的镜像(k8s.gcr.io/pauseregistry.k8s.io/pause),这个容器就是 Pause 容器。
  • 核心作用
    1. 持有命名空间 (Hold Namespaces)
      • Pause 容器负责创建并持有 Pod 共享的 Network Namespace(IP 地址、端口范围)和 IPC Namespace
      • 业务容器加入(Join)Pause 容器的网络命名空间,从而共享 IP 和 localhost 通信能力。
    2. 作为 PID 1 (Init Process)
      • 在 Linux 中,PID 1 负责回收僵尸进程。Pause 容器作为一个极简的 init 进程运行,负责回收 Pod 内业务容器产生的僵尸进程,防止资源泄漏。
    3. 生命周期管理
      • 只要 Pause 容器活着,Pod 的网络环境就存在。
      • 如果业务容器崩溃重启,Pause 容器不受影响,IP 地址保持不变,保证服务连续性。
      • 只有当 Pause 容器退出时,整个 Pod 才会销毁。
  • 为什么需要它?:如果没有 Pause 容器,当主业务容器重启时,其网络命名空间可能会重建,导致 IP 变化,破坏 K8s “Pod IP 固定”的承诺。

6. 网络和通信 (Networking)

62. 同一个节点多个 Pod 之间通信示意图及原理?

原理:
在同一个节点(Node)上,所有 Pod 都连接到同一个虚拟网桥(通常是 cni0docker0,取决于 CNI 插件)。

  1. 网络命名空间隔离但连通:每个 Pod 有自己的 Network Namespace,拥有独立的 IP。
  2. 网桥转发:CNI 插件会在宿主机创建一个虚拟网桥,并将每个 Pod 的虚拟网卡(veth pair 的一端)插入到这个网桥中。
  3. 二层通信:当 Pod A 访问 Pod B 的 IP 时,数据包从 Pod A 发出 -> 经过 veth pair -> 到达宿主机网桥 -> 网桥根据 MAC 地址表直接转发给 Pod B 的 veth pair -> 进入 Pod B。
  4. 无需 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 为例:

  1. 路由查找:Pod A (Node 1) 发送数据包给 Pod B (Node 2)。Node 1 的路由表知道 Pod B 的网段属于 Node 2 的 IP。
  2. 封装 (Encapsulation)
    • 数据包到达 Node 1 的网桥。
    • flanneld 守护进程(或内核 VXLAN 模块)拦截数据包。
    • 将原始数据包(源 IP: Pod A, 目的 IP: Pod B)作为载荷,封装在一个新的 UDP 包中。
    • 新包头:源 IP = Node 1 IP, 目的 IP = Node 2 IP, 目的端口 = 8472 (VXLAN 默认)。
  3. 物理传输:封装后的包通过物理网络发送到 Node 2。
  4. 解封装 (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

  1. DNS 解析
    • 应用 A 想要访问应用 B 的 Service,只需使用 Service 的名称,例如 http://my-service
    • Pod 内的 /etc/resolv.conf 配置了搜索域为当前 Namespace。
    • DNS 查询请求发送给 CoreDNS,CoreDNS 解析 my-service 为对应的 ClusterIP
  2. 流量转发
    • 应用 A 向 ClusterIP 发起请求。
    • 节点上的 kube-proxy 监听到该 ClusterIP 的流量,根据 iptables 或 IPVS 规则,将流量负载均衡转发到后端某个具体的 Pod IP。
  3. 简称调用:直接使用 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) 格式。

  1. DNS 格式
    • 格式:<ServiceName>.<NamespaceName>.svc.cluster.local
    • 通常简写为:<ServiceName>.<NamespaceName> (因为 svc.cluster.local 是默认搜索后缀)。
  2. 流程
    • 应用 A (NS: dev) 访问 应用 B (NS: prod)。
    • 调用地址:http://db-service.prod
    • CoreDNS 解析 db-service.prod.svc.cluster.local 得到 prod 命名空间下 db-service 的 ClusterIP。
    • 后续流量转发逻辑同单命名空间(通过 kube-proxy 转发)。
  3. 注意: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 记录)。

工作原理:

  1. 定义

    apiVersion: v1
    kind: Service
    metadata:
      name: my-db
      namespace: default
    spec:
      type: ExternalName
      externalName: db.example.com  # 外部真实域名
    
  2. 调用过程

    • 当 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 发起连接。
  3. 关键特点

    • 无代理:流量不经过 kube-proxy,也不经过 Service 的虚拟 IP。它是直连外部服务的。
    • 依赖 DNS:完全依赖集群内部的 DNS 解析能力。
    • 用途
      • 将集群外的数据库、消息队列抽象为集群内的 Service 名称,使应用代码无需修改(代码里写 my-db,实际连的是外部 AWS RDS 或自建 MySQL)。
      • 实现服务迁移的透明化(先指向旧 IP,后期修改 Service 指向新 IP,应用无感知)。
    • 局限性:不支持端口映射(externalName 本身不带端口,依赖 DNS 解析后的默认端口或应用指定端口),不支持 Session Affinity,不支持选择器。

深入理解总结:
它本质上是一个 DNS 别名(CNAME),而不是一个真正的负载均衡器或代理。它解决了“如何让集群内应用通过统一的 Service 名称访问集群外资源”的问题,实现了内外网服务寻址的统一接口。

7. 日志和配置 (Logging & Config)

67. Docker 镜像的优化方法有哪些?

优化目标:减小体积加快构建速度提高安全性

  1. 选择合适的基础镜像
    • 使用 AlpineDistroless 镜像(体积极小,仅包含运行所需库,无 shell,安全性高)。
    • 避免使用 ubuntucentos 等全量发行版,除非必须。
  2. 多阶段构建 (Multi-stage Builds)
    • 在第一个阶段编译代码(需要 GCC, Maven 等重型工具)。
    • 在第二个阶段只复制编译好的二进制文件/产物到干净的基础镜像中。
    • 效果:最终镜像不包含编译工具和源代码,体积可减少 90% 以上。
  3. 优化 Dockerfile 指令顺序
    • 变化频率低的指令(如安装系统依赖、复制 package.json)放在前面。
    • 变化频率高的指令(如复制源代码 COPY . .)放在最后。
    • 原理:充分利用 Docker 的层缓存 (Layer Cache),加速构建。
  4. 合并 RUN 指令
    • 将多个 RUN 命令合并为一个,用 && 连接,并清理缓存(如 apt-get clean, rm -rf /var/cache/apk/*)。
    • 效果:减少镜像层数(Layer),减小体积。
  5. 使用 .dockerignore
    • 排除不需要上传到 Docker 守护进程的文件(如 .git, node_modules, logs, *.md)。
    • 效果:加快 docker build 上下文传输速度,避免敏感信息泄露。
  6. 移除无用文件
    • 删除文档、man pages、临时文件。
    • 对于 Python/Node 应用,安装依赖时使用 --no-cache-dirproduction 模式。

68. K8s 中针对标准化输出方式(stdout/stderr)的日志,如何进行收集?

这是 K8s 推荐的日志处理方式(Cloud-Native 方式)。

  • 原理:容器进程将日志打印到标准输出(stdout)和标准错误(stderr)。Docker/Containerd 捕获这些流,并将其写入节点上的 JSON 文件(通常位于 /var/log/pods/<pod_uid>/<container_name>/<run_id>.log)。
  • 收集方案
    1. DaemonSet 模式(主流)
      • 在每个节点部署一个日志采集 Agent(如 Filebeat, Fluentd, Fluent Bit, Logstash)。
      • Agent 以 DaemonSet 运行,挂载宿主机的 /var/log/pods 目录。
      • Agent 实时监控日志文件变化,解析 JSON,添加 Pod 元数据(Namespace, Pod Name, Labels),然后发送到中央存储(如 Elasticsearch, Kafka, S3)。
    2. Sidecar 模式(不推荐用于纯 stdout 日志,资源开销大):
      • 在每个 Pod 中伴生一个日志容器,共享空目录卷,主容器将日志重定向到文件,Sidecar 收集发送。
    3. 直接推送
      • 应用 SDK 直接将日志推送到日志后端(侵入性强,不推荐)。

69. K8s 中针对容器内部的日志文件,如何进行收集?

很多传统应用会将日志写入容器内的文件(如 /var/log/app/access.log),而非 stdout。

  • 挑战:容器重启后,内部文件会丢失(如果是 emptyDir 或未挂载持久卷)。
  • 收集方案
    1. Sidecar 模式(经典方案)
      • 在 Pod 中定义一个专门的日志 Sidecar 容器。
      • 主容器和 Sidecar 共享一个 emptyDirhostPath 卷。
      • 主容器将日志写入该卷中的文件。
      • Sidecar 容器运行日志采集 agent(如 filebeat),监控该卷中的文件并发送到后端。
      • 缺点:每个 Pod 多跑一个容器,资源消耗大,管理复杂。
    2. DaemonSet + 宿主机路径映射(推荐方案)
      • 主容器将日志文件挂载到宿主机的特定目录(通过 hostPath 或特定的卷插件)。
      • 节点上的 DaemonSet 日志 Agent 监控宿主机上的这些特定目录。
      • 注意:K8s 默认不推荐随意使用 hostPath,需规划好目录结构(如 /var/log/myapp/<namespace>/<pod>)。
    3. Log-Pilot / Filebeat 自动发现
      • 利用采集工具的自动发现机制,识别容器内的日志路径配置,直接从容器文件系统读取(需挂载 /var/lib/docker/run/containerd 等,较复杂且依赖运行时)。
      • 更常见的做法是:修改应用配置,将日志路径指向一个挂载出来的 Volume,让外部 Agent 能访问到。

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),现已逐渐演进为更通用的方案,但其核心逻辑依然适用。

  • 收集机制
    1. DaemonSet 部署:Log-Pilot 以 DaemonSet 形式运行在每个节点。
    2. 监听 Docker/Containerd 事件:Log-Pilot 监听容器启动/停止事件。
    3. 自动挂载日志目录:它会自动挂载宿主机的 /var/log/pods (或 Docker 的 json-log 路径)。
    4. 标签过滤与解析
      • 通过读取容器的 Labels 或 Annotations(例如 aliyun.logs.stdout=stdout)。
      • 识别出哪些容器是输出到 stdout 的。
    5. 采集与发送
      • 直接读取运行时生成的 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 如何收集容器内的日志?

  • 收集机制
    1. 文件路径发现:Log-Pilot 支持通过环境变量或 Annotation 指定容器内部的日志文件路径。
    2. 挂载点映射
      • Log-Pilot 容器启动时,通常会挂载宿主机的整个文件系统根目录(或特定目录,如 / 挂载到 /host),或者利用 Docker 的驱动信息找到容器层的可读写层。
      • 它能够“穿透”到容器内部的文件系统视图中去读取文件。
    3. 配置方式
      • 通过 Annotation 指定:aliyun.logs.<name>=<path>
      • 例如:aliyun.logs.access=/var/log/nginx/access.log
    4. 工作流程
      • 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 节点)等。

类型:

  1. Node Affinity:基于节点标签的亲和/反亲和。
  2. 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):

  1. Available(可用)
    • PV 已创建并存在于集群中,但尚未被任何 PersistentVolumeClaim (PVC) 绑定。
    • 此时 PV 处于空闲状态,等待匹配。
  2. Bound(已绑定)
    • PV 已成功与某个 PVC 绑定。
    • 此时 PV 专属于该 PVC,其他 PVC 无法再使用此 PV。
  3. Released(已释放)
    • 关联的 PVC 已被用户删除。
    • PV 对象本身仍存在,但资源已被释放。
    • 注意:此时数据仍保留在底层存储中,PV 不会 立即变为 Available,因为需要等待回收策略(Reclaim Policy)执行完毕(如删除数据或保留数据)。
  4. Failed(失败)
    • PV 的自动回收过程失败(例如:云厂商 API 调用失败、存储后端故障、权限不足等)。
    • 需要管理员手动介入干预(修复存储问题或手动删除 PV)。
  5. Recycled / Terminating(回收中/终止中)
    • 注:Recycled 策略在较新版本 K8s 中已废弃,但在旧版本中存在。
    • 当 PVC 删除后,根据 persistentVolumeReclaimPolicy 的不同(Retain, Delete, Recycle),PV 会经历清理数据或删除底层存储资源的过程,最终回到 Available 或被彻底删除。

75. K8s 中 Etcd 的特点?

Etcd 是 Kubernetes 的核心数据库,存储集群的所有状态数据。其核心特点包括:

  1. 强一致性 (Strong Consistency)
    • 基于 Raft 共识算法,保证集群中所有节点的数据在任何时刻都是一致的。读取操作默认也是线性的(Linearizable),确保读到最新数据。
  2. 高可用性 (High Availability)
    • 采用集群部署(通常奇数个节点,如 3, 5, 7),允许部分节点故障而不影响服务。只要超过半数节点存活,集群即可正常工作。
  3. 键值存储 (Key-Value Store)
    • 数据结构简单,基于路径的层级键值对(类似文件系统目录结构),非常适合存储配置信息和状态元数据。
  4. Watch 机制 (监听/通知)
    • 支持客户端对特定 Key 或目录进行监听。当数据发生变化时,Etcd 会主动推送通知给客户端。这是 K8s Controller 模式(控制循环)的基础。
  5. 轻量级与高性能
    • 用 Go 语言编写,编译为单一二进制文件,部署简单。针对读写优化,但在高并发写场景下性能会有瓶颈(K8s 主要是读多写少,适合 Etcd)。
  6. 安全性
    • 支持 TLS 加密通信和基于角色的访问控制 (RBAC)。
  7. TTL (Time To Live)
    • 支持键的过期时间,常用于实现分布式锁或临时注册信息(K8s 中 Node 的心跳检测依赖此机制)。

76. 简述 Etcd 适应的场景?

Etcd 的设计目标决定了它适用的场景:

  1. 服务发现与服务注册
    • 利用其 Key-Value 结构和 Watch 机制,服务启动时注册 IP,客户端监听变化获取最新服务列表(K8s 的核心功能)。
  2. 配置管理与共享
    • 存储应用的配置信息,支持动态更新配置并实时通知应用生效(如 K8s 的 ConfigMap 底层存储)。
  3. 分布式锁与选举
    • 利用 TTL 和原子操作(Compare-And-Swap),实现分布式环境下的互斥锁和 Leader 选举。
  4. 集群状态存储
    • 存储整个集群的“真实状态”(Source of Truth),如 Pod 定义、Node 状态、Secret 等(K8s 的主要用途)。
  5. 不适用场景
    • 海量数据存储:Etcd 不适合存储大量非结构化数据或大文件(建议 Value 大小控制在 1MB 以内,总数据量建议在 GB 级别,不宜过大)。
    • 高频写入:由于 Raft 协议需要多数派确认,写性能受限,不适合高吞吐的日志存储或消息队列场景。

77. Etcd 集群节点之间是怎么同步数据的?

Etcd 集群通过 Raft 协议 进行数据同步,核心流程如下:

  1. 角色划分
    • Leader (领导者):集群中唯一能处理写请求的节点。所有写操作必须先发给 Leader。
    • Follower (跟随者):被动接收 Leader 的日志复制,处理读请求(取决于一致性级别)。
    • Candidate (候选人):当 Leader 挂掉或超时,Follower 转变为 Candidate 发起选举。
  2. 写同步流程
    • 接收请求:Client 发送写请求给 Leader。
    • 追加日志:Leader 将操作作为一条日志条目(Log Entry)追加到自己的本地日志中。
    • 复制日志:Leader 并行地将该日志条目发送给所有 Follower。
    • 多数派确认:Follower 收到日志后写入本地,并回复 ACK。当 Leader 收到超过半数 (Quorum) 节点的 ACK 后,认为该日志已提交(Committed)。
    • 应用状态:Leader 将日志应用到状态机(更新内存中的数据树),并通知 Follower 应用该日志。
    • 返回结果:Leader 向 Client 返回成功。
  3. 心跳机制
    • Leader 定期向 Follower 发送心跳包(空日志),维持领导地位并防止 Follower 发起选举。
  4. 快照 (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),向其他节点发送 RequestVote RPC。
  • 投票:其他节点如果在该任期内还没投过票,且 Candidate 的日志比自己新(或至少一样新),就投赞成票。
  • 当选:Candidate 获得多数派选票后,成为 Leader,并开始发送心跳。其他 Candidate 退回到 Follower。
  • 分裂投票:如果多个节点同时超时成为 Candidate,导致票数分散,无人当选。它们会等待新的随机超时时间后再次尝试,概率上总会有一方先超时从而赢得选举。

B. 日志复制 (Log Replication)

  • 唯一入口:只有 Leader 能接收写请求。
  • 流程
    1. Leader 接收命令,追加到本地日志。
    2. 并行发送给所有 Follower。
    3. 一旦多数派节点成功写入日志,Leader 提交(Commit)该条目。
    4. 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 制定的标准接口规范,用于配置容器网络。
  • 核心机制
    1. 插件化:K8s 本身不实现网络,而是调用 CNI 插件(如 Calico, Flannel, Cilium, Weave)。
    2. 调用时机:当 Kubelet 创建 Pod 时,会调用 CNI 插件为 Pod 分配 IP 地址并配置网络接口(veth pair)。
    3. 输入输出:Kubelet 将包含容器 ID、网络命名空间路径等信息的 JSON 配置文件传给 CNI 插件,插件执行网络配置后返回结果(主要是 IP 地址)。
    4. IPAM:CNI 通常配合 IPAM (IP Address Management) 插件来管理 IP 池的分配。
  • 目标:实现“每个 Pod 一个 IP”,且所有 Pod 无需 NAT 即可互相通信。

81. 简述 Kubernetes 如何实现集群管理?

K8s 采用 控制平面 (Control Plane)工作节点 (Worker Nodes) 分离的架构,基于 声明式 API控制循环 (Control Loop) 进行管理:

  1. API Server:集群的统一入口,所有组件通过 REST API 交互。
  2. Etcd:存储集群所有状态数据(Source of Truth)。
  3. Controller Manager:运行各种控制器(如 Deployment Controller, Node Controller),不断对比 期望状态(用户定义的 YAML)和 实际状态(Etcd 中的数据),驱动集群向期望状态收敛。
  4. Scheduler:负责将未调度的 Pod 分配到合适的节点。
  5. Kubelet:运行在每个节点上,监听 API Server,负责启动/停止容器,汇报节点状态。
  6. 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) 进行二层转发。
  • 流程
    1. CNI 插件在节点上创建一个网桥(如 cni0)。
    2. 每个 Pod 通过 veth pair 连接到该网桥。
    3. Pod A 发送数据包 -> veth -> 网桥 -> 网桥根据 MAC 地址表直接转发给 Pod B 的 veth -> Pod B。
    4. 特点:不走 iptables NAT,延迟极低,类似同一交换机下的通信。

84. 不同节点上的 Pod 通信原理?

  • 原理:依赖 CNI 插件实现的 Overlay 网络 (如 VXLAN, IPIP) 或 路由模式 (如 BGP)。
  • 流程 (以 VXLAN 为例)
    1. Pod A (Node 1) 发送包给 Pod B (Node 2)。
    2. Node 1 的 CNI 组件拦截包,将其封装在 UDP 包中(外层 IP 为 Node 1 和 Node 2 的 IP)。
    3. 物理网络传输到 Node 2。
    4. Node 2 解封装,还原原始包,通过本地网桥交给 Pod B。
  • 特点:对应用透明,应用看到的始终是 Pod IP,底层由 CNI 处理跨机路由。

85. 简述 Kubernetes Scheduler 使用哪两种算法将 Pod 调度到 Node?

调度过程分为两个阶段:

  1. 预选 (Predicates / Filtering)
    • 作用:过滤掉不满足条件的节点。
    • 策略:资源充足性(CPU/Mem)、端口冲突、节点亲和性/污点容忍、卷绑定等。
    • 结果:得到一个合格节点列表。
  2. 优选 (Priorities / Scoring)
    • 作用:对合格节点进行打分,选择得分最高的。
    • 策略:资源均衡度(避免倾斜)、节点亲和性权重、Pod 反亲和性(分散部署)、拓扑分布约束等。
    • 结果:选出最优节点进行绑定 (Bind)。

86. 简述 Kubernetes 如何保证集群的安全性?

  1. 认证 (Authentication):确认用户身份(x509 证书、Bearer Token、ServiceAccount)。
  2. 授权 (Authorization):确认用户权限(RBAC - 基于角色的访问控制,ABAC, Webhook)。
  3. 准入控制 (Admission Control):请求落地前的最后检查(如限制特权容器、强制镜像签名、资源配额 LimitRange/ResourceQuota)。
  4. 网络安全:NetworkPolicy 限制 Pod 间流量,TLS 加密组件间通信。
  5. 秘密管理:Secret 对象加密存储敏感信息(建议开启 Etcd 静态加密)。
  6. 镜像安全:扫描漏洞,使用可信仓库,禁止 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 的常见调度方式?

  1. 自动调度:默认调度器根据资源和服务策略自动选择。
  2. 指定节点 (nodeName):强制指定具体节点名。
  3. 节点选择器 (nodeSelector):基于标签简单匹配。
  4. 节点亲和性 (Node Affinity):基于标签的复杂逻辑匹配(硬/软)。
  5. 污点与容忍 (Taints & Tolerations):节点排斥,Pod 需容忍才能调度。
  6. Pod 亲和/反亲和:根据其他 Pod 的位置调度。
  7. 拓扑分布约束:跨域均匀分布。

91. 简述一下在 K8s 中删除 Pod 的流程?

  1. 接收请求:用户执行 kubectl delete,API Server 接收请求。
  2. 更新状态:API Server 将 Pod 标记为 Terminating,记录 deletionTimestamp
  3. 移除端点:Endpoint Controller 检测到状态变化,将该 Pod IP 从 Service 的 Endpoints 列表中移除(切断流量)。
  4. PreStop 钩子:如果定义了 preStop 生命周期钩子,Kubelet 执行它(用于优雅关闭)。
  5. 发送 SIGTERM:Kubelet 向容器主进程发送 SIGTERM 信号,应用开始清理工作。
  6. 等待宽限期:等待 terminationGracePeriodSeconds(默认 30s)。
  7. 强制杀死:若超时仍未退出,发送 SIGKILL 强制终止。
  8. 清理资源:Kubelet 清理容器、网络、挂载卷等资源。
  9. 最终删除: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 集群内的应用如何访问外部的服务?

  1. ExternalName Service:将 Service 映射为外部域名(CNAME),应用访问 Service 域名,DNS 解析到外部 IP。
  2. 直接 IP/域名访问:应用代码直接配置外部服务的 IP 或公网域名(需节点能通外网)。
  3. Egress Gateway:通过 Istio 等网格组件或专用网关统一出口,进行流量控制和审计。
  4. 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)
    1. Endpoint Controller 发现新 Pod,将其 IP 添加到对应的 Endpoint 列表中。
    2. Kube-Proxy 监听到 Endpoint 变更,在所有节点的 iptables/IPVS 中添加一条转发规则,指向新 Pod IP。
    3. Service 本身定义不变,但后端容量增加。
  • Pod 删除
    1. Endpoint Controller 发现 Pod 终止,将其 IP 从 Endpoint 列表中移除。
    2. Kube-Proxy 监听到变更,删除对应的转发规则,流量不再发往该 Pod。
    3. 若 Pod 正在终止,Service 会先停止向其分发新流量(优雅下线)。

99. Deployment 怎么扩容或缩容?

  1. 命令方式
    • kubectl scale deployment <name> --replicas=5
  2. 修改 YAML
    • 编辑 spec.replicas 字段,apply 生效。
  3. 自动扩缩容 (HPA)
    • 配置 HorizontalPodAutoscaler,根据 CPU/内存或自定义指标自动调整 replicas 数量。
  • 原理:Deployment 控制器检测到 replicas 数变化,创建或删除对应的 ReplicaSet,进而创建或终止 Pod。

100. K8s 数据持久化的方式有哪些?

  1. EmptyDir:临时存储,随 Pod 销毁而消失(用于缓存、临时交换空间)。
  2. HostPath:挂载宿主机文件系统,风险高,仅限单节点测试或特权系统组件。
  3. NFS / GlusterFS / CephFS:网络文件系统,支持多节点读写,适合共享存储。
  4. 云厂商块存储 (Cloud Volumes)
    • AWS EBS, GCP PD, Azure Disk, 阿里云云盘等。
    • 通常通过 CSI (Container Storage Interface) 驱动动态供给 PV。
    • 特性:高性能,通常支持 ReadWriteOnce (RWO)。
  5. 对象存储 (S3/OSS):通过挂载工具(如 s3fs)或应用 SDK 访问,适合非结构化数据。
  6. StatefulSet + PVC:有状态应用的标准持久化方案,保证 Pod 重启后挂载相同的 PV。

10. 高级主题 (Advanced Topics)

101. 什么是 Kubernetes?它的主要目标是什么?

  • 定义:Kubernetes (K8s) 是一个开源的容器编排引擎,用于自动化部署、扩展和管理容器化应用程序。它由 Google 设计并捐赠给 CNCF。
  • 主要目标
    1. 自动化部署与回滚:自动发布应用,若失败则自动回滚。
    2. 服务发现与负载均衡:无需修改应用代码,自动分配 IP 和 DNS。
    3. 存储编排:自动挂载本地或云存储。
    4. 自动扩缩容:根据负载自动调整 Pod 数量或节点数量。
    5. 自愈能力:自动重启失败的容器,替换不可用的节点。
    6. 密钥与配置管理:安全地管理敏感信息和配置文件。

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 的副本数量。

  1. 手动扩展
    • 命令:kubectl scale deployment <name> --replicas=5
    • 修改 YAML 中的 spec.replicas 字段并 apply。
  2. 自动扩展 (HPA)
    • 创建 HorizontalPodAutoscaler 对象,基于 CPU、内存或自定义指标自动调整副本数。
    • 命令:kubectl autoscale deployment <name> --cpu-percent=50 --min=2 --max=10

107. 如何在 Kubernetes 中进行滚动更新 (Rolling Update)?

滚动更新允许在不中断服务的情况下更新应用。

  • 方法
    1. 修改 Deployment 的 YAML 文件(如更改镜像版本 image: nginx:1.21)。
    2. 执行 kubectl apply -f deployment.yaml
    3. 或者使用命令:kubectl set image deployment/<name> <container>=<new-image>
  • 过程: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 副本数量。
  • 工作流程
    1. Metrics Server 收集指标。
    2. HPA 定期查询指标。
    3. 如果指标高于阈值,增加 Pod;低于阈值,减少 Pod。
  • 限制:仅适用于可以通过增加副本来提升性能的应用(无状态应用)。

110. 如何进行存储卷 (Volume) 的使用?

  1. 定义 Volume:在 Pod 的 spec.volumes 中定义存储来源(如 emptyDir, hostPath, persistentVolumeClaim, configMap 等)。
  2. 挂载 Volume:在容器的 spec.containers.volumeMounts 中指定挂载点 (mountPath) 和对应的 volume 名称。
  3. 持久化流程 (推荐)
    • 创建 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

  1. 数据采集
    • Metrics Server:提供基础资源指标(CPU/Mem),供 HPA 和 kubectl top 使用。
    • Prometheus:通过 Service Discovery 自动发现 K8s 组件(Node, Pod, Service)和中间件,拉取指标数据。
    • Exporters:节点导出器 (Node Exporter)、Kube-State-Metrics (监控 K8s 对象状态)。
  2. 可视化:Grafana 连接 Prometheus 数据源,展示仪表盘。
  3. 日志监控:ELK (Elasticsearch, Logstash, Kibana) 或 EFK (Fluentd/Fluent Bit) 栈。
  4. 告警:Alertmanager 配置规则,发送通知到邮件/Slack/钉钉。

114. 如何进行跨集群部署和管理?

  • 联邦集群 (KubeFed):CNCF 项目,允许在一个控制平面管理多个 K8s 集群,实现配置同步和故障转移(目前成熟度一般)。
  • GitOps (推荐):使用 ArgoCDFlux
    • 将多个集群的配置存储在 Git 仓库。
    • ArgoCD 在每个集群中运行,监听 Git 变化并自动同步应用到对应集群。
  • 多集群管理平台:如 Rancher, OpenShift ACM, Google Anthos,提供统一的 UI 和策略管理。
  • 服务网格 (Istio):通过 Istio Multi-Cluster 实现跨集群的服务发现和流量治理。

115. 什么是 Kubernetes 的生命周期钩子 (Lifecycle Hooks)?

允许容器在特定生命周期节点执行命令。

  1. postStart:容器创建后立即执行。若失败,容器会被杀死。注意:不能保证在容器 ENTRYPOINT 之前运行。
  2. preStop:容器被终止前执行(收到 SIGTERM 之前)。常用于优雅下线(如刷新缓冲区、通知注册中心下线)。
  • 执行方式:执行 Shell 命令 (exec) 或 HTTP 请求 (httpGet)。

116. 什么是 Pod 的探针 (Probe)?(Liveness, Readiness, Startup)

探针用于检测容器状态,Kubelet 据此采取行动。

  1. Liveness Probe (存活探针)
    • 作用:检测容器是否死锁或无法恢复。
    • 失败动作重启容器
    • 场景:应用死循环、线程池耗尽。
  2. Readiness Probe (就绪探针)
    • 作用:检测容器是否准备好接收流量。
    • 失败动作:从 Service 的 Endpoints 中移除 IP(切断流量),但不重启。
    • 场景:应用正在加载大文件、依赖服务未连通。
  3. Startup Probe (启动探针)
    • 作用:用于启动缓慢的容器。在它成功之前,Liveness 和 Readiness 都不会生效。
    • 场景:遗留应用启动需要几分钟,避免被 Liveness 误杀。

117. 什么是 Kubernetes 的安全性措施?

  1. 认证 (AuthN):x509 证书、ServiceAccount Token、OIDC。
  2. 授权 (AuthZ):RBAC (Role-Based Access Control) 是最常用的授权模式。
  3. 准入控制 (Admission Control):Mutating/Validating Webhook,强制安全策略(如禁止特权容器、强制镜像签名)。
  4. 网络策略 (NetworkPolicy):限制 Pod 间的进出流量(白名单机制)。
  5. Pod 安全标准 (PSS):替代旧的 PSP,限制 Pod 的安全上下文(如禁止 root 用户、禁止挂载宿主机目录)。
  6. 秘密管理:Secrets 加密存储,集成外部密钥管理系统。
  7. 镜像扫描:集成 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=.lastTimestampkubectl 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) 旨在消除单点故障。

  1. 控制平面 (Control Plane) HA
    • 多 Master 节点:部署 3 个或更多奇数个 API Server / Controller Manager / Scheduler。
    • Etcd 集群:部署奇数个节点(3, 5, 7),跨可用区分布,利用 Raft 协议保证数据一致性。
    • 负载均衡:在 Master 节点前架设负载均衡器 (LB),指向所有 API Server。
  2. 工作节点 (Worker Nodes) HA
    • 多节点部署,配合 Pod 反亲和性,确保关键应用分散在不同节点/可用区。
    • 使用集群自动伸缩组 (Auto Scaling Group) 自动替换故障节点。
  3. 网络与存储 HA
    • CNI 插件高可用配置。
    • 存储后端采用多副本机制(如 Ceph, 云厂商多副本云盘)。

123. 什么是 K8s 的配置管理工具?

除了原生的 ConfigMap/Secret,还有第三方工具:

  1. Helm:最流行的包管理工具,基于模板。
  2. Kustomize:K8s 原生集成 (kubectl kustomize),基于补丁 (Patch) 和叠加 (Overlay) 机制,无需模板语法,更适合纯 YAML 管理。
  3. Ansible/Terraform:基础设施即代码工具,用于集群搭建和初始配置。
  4. ArgoCD/Flux:GitOps 工具,将 Git 仓库作为配置源,自动同步集群状态。
  5. External Secrets Operator:将外部密钥系统(AWS Secrets Manager, Vault)同步为 K8s Secret。

124. 什么是 K8s 的网络模型?

K8s 网络模型遵循以下核心原则(CNI 规范):

  1. Pod IP 唯一性:每个 Pod 拥有一个唯一的 IP 地址。
  2. 无 NAT 通信:所有 Pod 可以在无需 NAT 的情况下相互通信(无论是否在同一节点)。
  3. 节点与 Pod 互通:节点上的 Agent(如 Kubelet)可以与该节点或其他节点上的 Pod 通信。
  • 实现:通过 CNI 插件(Calico, Flannel, Cilium 等)构建 Overlay 网络或 BGP 路由网络来实现上述模型。

125. Kubernetes 的升级策略有哪些?

主要指集群版本升级和应用升级。

  1. 应用升级 (Deployment)
    • 滚动更新 (RollingUpdate):默认策略,逐步替换,零停机。
    • 重建 (Recreate):先杀光旧 Pod,再建新 Pod,会有短暂停机。
    • 蓝绿部署 (Blue/Green):部署全新版本环境,切换 Service 流量,旧环境保留以备回滚。
    • 金丝雀发布 (Canary):先将少量流量导入新版本,验证无误后全量切换(常结合 Istio 或 Ingress 控制器实现)。
  2. 集群升级 (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 用于测试:

  1. 生成 YAMLkubectl run my-pod --image=nginx --restart=Never --dry-run=client -o yaml > pod.yaml
  2. 编辑 YAML:确保 kind: Pod,配置镜像、端口等。
  3. 应用kubectl apply -f pod.yaml
  4. 直接命令kubectl run my-pod --image=nginx --restart=Never (交互式创建)。
    注意:直接创建的 Pod 不会被自动重启或扩缩容,适合调试。

128. 如何将应用程序部署到 Kubernetes?

标准流程是通过控制器(如 Deployment):

  1. 编写 manifests:创建 deployment.yaml (定义副本、镜像、资源) 和 service.yaml (定义暴露方式)。
  2. 应用配置kubectl apply -f deployment.yaml -f service.yaml
  3. 验证kubectl get pods 查看状态,kubectl logs 查看日志。
  4. 包管理 (可选):使用 Helm Chart (helm install my-app ./chart)。
  5. CI/CD 集成:流水线自动执行 kubectl applyhelm 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 内置了强大的服务发现机制:

  1. 环境变量:当 Pod 启动时,K8s 会自动将当前 Namespace 内所有 Service 的信息注入为环境变量(如 MY_SERVICE_SERVICE_HOST, MY_SERVICE_SERVICE_PORT)。
  2. DNS (推荐)
    • 集群内运行 CoreDNS (或 kube-dns)。
    • 每个 Service 都有 DNS 记录:<service-name>.<namespace>.svc.cluster.local
    • 同 Namespace 下可直接通过 <service-name> 访问。
    • 应用只需配置域名,无需硬编码 IP。

131. 怎样进行容器间通信?

  1. 同一 Pod 内
    • 通过 localhost + 端口通信。
    • 共享网络命名空间,IP 相同。
    • 可通过共享 Volume 交换文件。
  2. 同一节点不同 Pod
    • 通过 Pod IP 直接通信(CNI 插件保证二层互通)。
  3. 不同节点 Pod
    • 通过 Pod IP 直接通信(CNI 插件通过 Overlay 网络或路由实现跨节点互通)。
    • 或通过 Service (ClusterIP) 进行负载均衡访问。
  4. 外部访问
    • 通过 Service (NodePort/LoadBalancer) 或 Ingress。

132. 如何进行安全访问控制 (RBAC)?

RBAC 通过四个核心对象实现:

  1. Role / ClusterRole:定义权限规则(能做什么,如 get, list, create 哪些资源)。
    • Role:限定在特定 Namespace。
    • ClusterRole:集群范围或所有 Namespace。
  2. RoleBinding / ClusterRoleBinding:将角色绑定给用户/组/ServiceAccount。
    • 定义谁(Subject)拥有什么权限(RoleRef)。
  3. User/Group/ServiceAccount:身份主体。
  4. 配置示例
    # 创建 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),实现业务零停机:

  1. 配置策略:在 Deployment 中设置 strategy.type: RollingUpdate
    • maxSurge:更新过程中允许超出期望副本数的最大数量。
    • maxUnavailable:更新过程中允许不可用的最大数量。
  2. 执行更新:修改镜像版本 (kubectl set image ...apply)。
  3. 配合探针:必须配置 readinessProbe,确保新 Pod 完全启动并准备好接收流量后,才销毁旧 Pod。
  4. 应用层要求:应用需支持优雅停机(监听 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 不适合长期海量存储,通常配合 ThanosCortex 将数据卸载到对象存储 (S3/GCS)。

137. 如何设置警报规则并配置 Alertmanager?

  1. 定义规则 (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"
    
  2. 加载规则:在 prometheus.yml 中引用 rule_files
  3. 配置 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 查询,查看原始数据表格和简单图表。
    • 缺点:功能简陋,不适合生产大屏展示。
  • Grafana
    • 行业标准可视化平台。
    • 功能:连接 Prometheus 数据源,创建丰富的仪表盘(Dashboard),支持多种图表、变量插值、模板化、告警面板。
    • 生态:拥有大量社区预制的 K8s/Prometheus 模板。

141. 什么是 Prometheus 的推模式 (Push) 和拉模式 (Pull) 抓取?

  • 拉模式 (Pull - 默认)
    • Prometheus Server 主动去 Target 的 /metrics 接口抓取数据。
    • 优点:控制端掌握节奏,易于监控 Target 是否存活,防火墙配置简单(只需 Target 对 Server 开放)。
    • 适用:大多数长期运行的服务。
  • 推模式 (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:

  1. 多副本独立运行:部署两套完全相同的 Prometheus 实例,抓取相同的目标。
    • 查询时通过 Grafana 配置 PromQL Federation 或使用 Thanos Query / Cortex 进行合并查询。
    • 只要有一套存活,数据就不丢失(数据会有重复,查询层去重)。
  2. 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) 详解?

  • 核心逻辑:基于角色的权限控制,解耦了“用户”和“权限”。
  • 四大资源
    1. Role:Namespaced 级别的权限集合(定义动词 verbs + 资源 resources + API 组 apiGroups)。
    2. ClusterRole:Cluster 级别的权限集合(可访问所有 Namespace 或集群级资源如 Node, PV)。
    3. RoleBinding:将 Role 授予特定 Namespace 内的 Subject (User/Group/SA)。
    4. ClusterRoleBinding:将 ClusterRole 授予集群范围的 Subject。
  • 聚合 ClusterRole:可以通过 aggregationRule 自动聚合带有特定 Label 的其他 ClusterRole 的权限,方便插件扩展。
  • 默认行为:默认拒绝所有未明确允许的请求。

146. K8s 中如何安全地传递敏感信息 (如密码、密钥等)?

  1. 使用 Secret 对象
    • 创建:kubectl create secret generic my-secret --from-literal=password=123
    • 使用方式:
      • 环境变量valueFrom.secretKeyRef
      • 挂载卷:以文件形式挂载到容器内(推荐,避免环境变量泄露给子进程或日志)。
  2. 加密存储 (Encryption at Rest)
    • 配置 API Server 的 EncryptionConfiguration,使 Etcd 中存储的 Secret 数据经过加密(使用 AES-CBC 或 aescbc 提供者),即使 Etcd 文件被盗也无法解密。
  3. 外部密钥管理 (最佳实践)
    • 使用 External Secrets OperatorSealed Secrets
    • 将密钥存储在专业的密钥管理系统(AWS Secrets Manager, HashiCorp Vault, Azure Key Vault)中,同步到 K8s。
    • 避免将明文 Secret YAML 提交到 Git 仓库。

147. Kubernetes 中如何管理容器的安全性?可以列举几点?

  1. Pod Security Standards (PSS):启用 PSS (Baseline, Restricted),禁止特权容器、宿主机网络/PID 命名空间、Root 用户运行。
  2. 非 Root 运行:在 securityContext 中设置 runAsNonRoot: truerunAsUser
  3. 只读文件系统:设置 readOnlyRootFilesystem: true,防止恶意篡改二进制文件。
  4. 能力丢弃 (Drop Capabilities):默认丢弃所有 Linux Capabilities (drop: ["ALL"]),仅添加必要的(如 NET_BIND_SERVICE)。
  5. 镜像扫描:在 CI/CD 流水线中集成 Trivy/Clair,阻止有高危漏洞的镜像上线。
  6. 网络策略 (NetworkPolicy):默认拒绝所有流量,仅放行必要的 Pod 间通信。
  7. ServiceAccount 最小权限:不为 Pod 绑定默认的 default SA(尤其不要绑定 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:集中式日志平台,支持全文检索、聚合分析和可视化。

149. 如何使用 Kubernetes 进行多环境部署(如开发、测试、生产)?

  1. Namespace 隔离 (轻量级)
    • 创建 dev, test, prod Namespace。
    • 配合 KustomizeHelm Values 区分配置(如 replica 数、资源限制、镜像 tag)。
    • 优点:简单,资源共享。缺点:隔离性较弱(噪声邻居问题)。
  2. 独立集群 (重量级/推荐用于 Prod)
    • 为 Dev/Test/Prod 建立完全独立的 K8s 集群。
    • 通过 CI/CD 流水线将应用部署到不同集群。
    • 优点:故障隔离彻底,安全性高,可定制不同版本的 K8s。
  3. GitOps 管理
    • 使用 ArgoCD,在 Git 仓库中维护不同目录(overlays/dev, overlays/prod),分别同步到对应的 Namespace 或集群。

150. 如何在 Kubernetes 中实现应用程序的配置管理?

  1. ConfigMap:存储非敏感配置(配置文件、环境变量)。
    • 挂载为文件:适用于传统应用读取配置文件。
    • 注入环境变量:适用于云原生应用。
  2. Secret:存储敏感配置。
  3. 外部配置中心
    • 应用启动时从 Apollo, Nacos, Consul 拉取配置。
    • 配合 Sidecar 或 Init Container 同步配置到本地文件。
  4. Helm/Kustomize:在部署阶段通过模板渲染生成具体的 ConfigMap/Secret,实现“一次构建,多处部署”。
  5. 动态更新
    • 挂载 ConfigMap 为文件时,应用需支持热重载或配合 Sidecar (如 Reloader) 重启 Pod。
    • 环境变量方式通常需要重启 Pod 才能生效。

151. Kubernetes 与 CI/CD (如 Jenkins, GitLab CI) 如何集成?

  1. Kubectl 方式
    • CI 环境中安装 kubectl,配置 kubeconfig。
    • 脚本执行 kubectl apply -f ...kubectl set image ...
    • 缺点:命令式,难以回滚,状态管理弱。
  2. Helm 方式
    • CI 执行 helm upgrade --install
    • 优点:版本管理,回滚方便,参数化配置。
  3. GitOps 方式 (现代最佳实践)
    • CI 只负责构建镜像、推送镜像、更新 Git 仓库中的 Manifest (镜像 tag)。
    • ArgoCD/Flux (运行在 K8s 内) 监听 Git 变化,自动同步集群状态。
    • 优点:声明式,审计性强,集群权限无需暴露给 CI。
  4. 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)。
      • 支持灾难恢复、集群迁移、定时备份。
  • 配置即代码:最根本的备份是 Git 仓库中的 Manifest/Helm Chart。

153. Kubernetes 中如何管理和优化资源 (如 CPU、内存)?

  1. 合理设置 Request/Limit
    • 基于实际压测数据设置,避免过大浪费或过小导致 OOM/节流。
    • 利用 QoS 等级 (Guaranteed/Burstable) 保障关键业务。
  2. 垂直自动伸缩 (VPA)
    • 分析历史用量,自动推荐或调整 Request/Limit 值(注意:修改 Limit 通常需要重启 Pod)。
  3. 水平自动伸缩 (HPA)
    • 根据负载动态增减副本,提高资源利用率。
  4. 集群自动伸缩 (CA)
    • 当节点资源不足时自动增加节点,空闲时缩容节点。
  5. 资源配额 (ResourceQuota)
    • 限制 Namespace 总资源使用,防止单一团队耗尽集群资源。
  6. 调度优化
    • 使用亲和性/反亲和性、拓扑分布约束,平衡节点负载,避免热点。

154. Kubernetes 中如何管理和更新容器的安全补丁?

  1. 基础镜像更新
    • 定期重建基础镜像(OS 层补丁),触发应用镜像重新构建。
  2. 自动化扫描与修复
    • 集成 Trivy/Grype 在 CI 中扫描。
    • 使用 RenovateDependabot 自动检测基础镜像漏洞并提 PR 更新 Dockerfile。
  3. 滚动更新策略
    • 发布新镜像版本,利用 Deployment 滚动更新替换旧 Pod。
  4. 运行时防护
    • 使用 Falco 等工具监控异常行为。
    • 对于无法立即重启的关键应用,考虑热补丁技术(较少见,通常还是重启)。
  5. K8s 组件升级
    • 定期升级 Kubelet, Kube-Proxy 及控制平面组件以修复 CVE。

155. Kubernetes 中如何实现故障转移和自动恢复?

  1. Pod 级别自愈
    • Restart Policy:容器崩溃自动重启。
    • Liveness Probe:检测到死锁/无响应,自动重启 Pod。
    • Controller (Deployment/StatefulSet):Pod 意外删除或节点故障导致 Pod 丢失时,控制器会自动在新节点创建新 Pod。
  2. 节点级别故障转移
    • Node Controller:检测到 Node 失联 (NotReady) 超过阈值,将该节点上的 Pod 标记为终止,并在其他健康节点重新调度。
    • Pod Disruption Budget (PDB):确保在自愿干扰(如节点维护)期间,始终有最小数量的 Pod 可用。
  3. 多可用区 (Multi-AZ) 部署
    • 配置 Topology Spread ConstraintsPod Anti-Affinity,强制 Pod 分散在不同的可用区 (Zone)。
    • 当某个 AZ 整体故障时,其他 AZ 的 Pod 继续服务,配合 LoadBalancer 流量切换。
  4. 控制平面 HA
    • 多 Master + Etcd 集群,单点故障不影响集群管理功能。