运维常见面试题_07_配置管理与监控(Ansible · Prometheus · Alertmanager)· 容器编排(Kubernetes)

Q120. 如何配置 Ansible 的清单(inventory)和 SSH 免密登录?

1. 是什么 :Ansible 的清单(Inventory) 是一份定义「被管理主机」及其分组、变量、连接参数的清单文件(默认 /etc/ansible/hosts,也常用自定义路径);SSH 免密登录 是通过公私钥认证让控制端无需输入密码即可登录被管主机,是 Ansible 高效批量操作的前提。

2. 为什么用它 :Ansible 是无 Agent 架构(通过 SSH 直连),必须先知道管哪些主机、怎么连过去,清单承担「主机清单 + 分组 + 变量」三重职责;SSH 免密避免每次执行要输密码,尤其批量执行上百台时是必需的体验和效率保障。

3. 怎么用它

① 配置 Inventory(支持多种写法)

ini 复制代码
# /etc/ansible/hosts ------ 每行一个主机,用 [] 定义组
[webservers]
192.168.1.11 ansible_user=root
192.168.1.12
web.example.com

[db]
192.168.1.21 ansible_port=2222   # 可指定端口

[all:vars]          # 组通用变量
ansible_python_interpreter=/usr/bin/python3
yaml 复制代码
# 也支持 YAML 格式 inventory:groups/hosts/vars
all:
  hosts:
    mail.example.com:
  children:
    webservers:
      hosts:
        192.168.1.11:
        192.168.1.12:
      vars:
        http_port: 8080
  • 指定清单运行:ansible -i myhosts -m ping webservers;不指定默认 /etc/ansible/hosts

② 配置 SSH 免密(控制端生成密钥 → 拷贝到被管端)

bash 复制代码
# 1) 生成密钥对(若还没有)
ssh-keygen -t rsa -b 4096        # 一路回车,生成 ~/.ssh/id_rsa(私钥) 和 id_rsa.pub(公钥)

# 2) 将公钥拷贝到目标主机(会提示输入密码一次)
ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.1.11

# 3) 验证免密
ssh root@192.168.1.11   # 无需密码即成功
  • 原理:控制端持有私钥 ,被管端 ~/.ssh/authorized_keys公钥;登录时服务端用公钥验签,验证通过即放行。
  • 多主机批量可用循环 ssh-copy-id,或用 sshpass -p '密码' 做首次注入(注意安全)。
  • 测试连通:ansible -i hosts all -m ping,返回 pong 即成功。

4. 使用场景:初始化一批新服务器、批量执行命令前准备连接;面试关键:答出「Inventory 三要素(主机/组/变量)」+「ssh-keygen 生成、ssh-copy-id 分发、authorized_keys 存公钥/控制端存私钥」这条完整链路,并说明 Ansible 无 Agent、靠 SSH 的特点。


Q121. 编写一个 playbook 来安装 Nginx 并启动服务。

1. 是什么 :Ansible Playbook 是使用 YAML 编写的「一揽子任务清单」,按顺序在目标主机上执行安装、配置、启动等操作;本题要求把「装 Nginx + 启动」落地为一个可重复执行的 playbook(通常还含配置、设置开机自启)。

2. 为什么用它 :Playbook 把一次次手动命令固化为幂等、可重复、可版本化 的自动化步骤------同一台机器跑多次结果一致、不会反复安装,这正是自动化运维的核心价值,也是 Ansible 比手工 apt install 强的原因。

3. 怎么用它(以 CentOS/RHEL 的 yum 为例,Ubuntu 换成 apt):

yaml 复制代码
---
- name: 安装并启动 Nginx
  hosts: webservers            # 作用于 inventory 里的 webservers 组
  become: yes                  # 提权执行(root)
  tasks:
    - name: 安装 nginx
      ansible.builtin.yum:
        name: nginx
        state: present

    - name: 复制(生成)自定义配置
      ansible.builtin.template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      notify: 重启 nginx          # 配置变更后触发 handler

    - name: 启动并设置开机自启
      ansible.builtin.systemd:
        name: nginx
        state: started
        enabled: yes

  handlers:
    - name: 重启 nginx
      ansible.builtin.systemd:
        name: nginx
        state: restarted
  • 运行:ansible-playbook -i hosts install_nginx.yml
  • 关键点:模块 ansible.builtin.yum(装包)、template(按模板生成配置)、systemd(管理服务,state: started + enabled: yes 表示启动且开机自启);handlers 在任务"变更"时才触发。
  • 校验:ansible-playbook -i hosts install_nginx.yml --syntax-check;跑完后 curl http://目标IP 验证。

4. 使用场景 :批量初始化 Web 服务器、环境标准化、配合 CI/CD 发布。面试关键:能画出 playbook 骨架------hostsbecometasks(装包/配置/启服务)、handlers 触发重启;并点出 systemd 模块同时完成启动与开机自启、notify/handlers 只在配置变更时重启这一最佳实践。


Q122. 如何调试 Ansible 的 playbook?如何提高 Ansible 的执行效率?

1. 是什么调试 指在 Playbook 报错或结果不符合预期时定位问题的手段;提效指通过并发、免密码、关闭事实收集等手段缩短批量执行时间,二者是把 Ansible 从「能跑」推向「好用、可维护、大规模可用」的能力。

2. 为什么用它:Playbook 错在哪一步、变量为何没生效、主机为何不通都需要有章法地定位,否则排查靠猜;而管理几十上百台主机时,串行执行或反复收集 Facts 会非常慢,提效手段直接影响运维人效与响应速度。

3. 怎么用它

① 调试手段

bash 复制代码
# 语法检查(不执行)
ansible-playbook -i hosts play.yml --syntax-check

# 只列出将执行哪些任务,不真正执行(dry-run 预演)
ansible-playbook -i hosts play.yml --check

# 逐步查看每台主机/任务结果,含省略输出
ansible-playbook -i hosts play.yml -v / -vv / -vvv / -vvvv

# 指定只跑某个 play/host / 某个 task
ansible-playbook -i hosts play.yml --limit webservers
ansible-playbook -i hosts play.yml --start-at-task="安装 nginx"

# 任务内打印变量定位
- debug:
    msg: "用户变量是 {{ user }}"
  • 常见调试点:模块参数拼错、变量未定义({``{ }} 引号)、become 权限不足、模板路径错误。

② 提效手段

yaml 复制代码
# 1) 关闭不必要的 Facts 收集(Gathering Facts 最耗时)
- name: 提效版
  hosts: all
  gather_facts: no
bash 复制代码
# 2) 并发控制:fork 并行执行(默认 5)
ansible -i hosts all -f 30 -m ping
ansible-playbook -i hosts play.yml --forks 30

# 3) 开启 SSH pipelining:减少 SSH 连接次数(需在 ansible.cfg 配置)
# [ssh_connection]  pipelining = True

# 4) 用 SSH 长连接 ControlMaster 复用连接
# [ssh_connection]  ssh_args = -o ControlMaster=auto -o ControlPersist=60s

# 5) 缓存 Facts 到内存/文件,跨 play 复用,避免每次重查
# [defaults]  gathering = smart  ; fact_caching = jsonfile ; fact_caching_connection = /tmp/facts_cache
  • 取舍:gather_facts: no 会丢掉节点信息,需按需再开;并发数要结合控制端性能与网络合理设置。

4. 使用场景 :Playbook 上线前校验、生产大批量变更、几百台主机批量软件/配置同步。面试关键:调试答「--check 预演 → -vvv 看详细 → --syntax-checkdebug 打变量 + --limit 缩范围」;提效答「gather_facts 关闭 + fork 并发 + pipelining + ControlMaster 复连 + Facts 缓存」这五板斧。


Q123. Metrics(指标)、Sample(样本)、Time Series(时间序列)是什么?

1. 是什么 :这三个是 Prometheus 数据模型的三层基本单位------Metrics(指标) 是描述被观测对象某一特性的命名项(如 node_cpu_seconds_total);Sample(样本) 是指标在某一时刻的一个具体测量值(时间戳 + 数值 的二元组);Time Series(时间序列) 是同一指标在同一组标签(labels)下随时间产生的一串样本的序列。

2. 为什么用它:抓一套监控不能只记"当前值",必须能追溯变化趋势、按标签区分不同实例;理解这三个层级才能看懂 PromQL 查询逻辑(按"指标名+标签"选取时间序列、再对序列里的样本做运算),是玩转 Prometheus 的地基。

3. 怎么用它

  • 指标(Metric) = 指标名 + 描述;命名规范通常用"库_对象_单位",如 node_memory_MemAvailable_bytes(字节)。

  • 样本(Sample) :存储为 (timestamp, value)。Prometheus HTTP API 返回里体现为 [时间戳, 数值, [标签]]

  • 时间序列(Time Series) :由 指标名 + 标签集唯一标识,例如:

    复制代码
    http_requests_total{method="GET", instance="10.0.0.1:9100"}
    http_requests_total{method="POST", instance="10.0.0.1:9100"}

    上面两个不同标签组合就是两条不同的时间序列;序列里每个时间点就是一个样本。

  • 本质:Series = Identifier(指标名+labels)+ 一组样本,PromQL 查询就是按"名字+标签"选 Series,再对 Series 内样本做聚合/速率计算。

4. 使用场景 :设计 exporter 暴露指标、编写 PromQL、理解 rate() 为什么需要"序列内多个样本"。面试关键:用一个例子串起来------「指标名{标签}= 定位到时间序列 ,序列上每个时间点有一个样本 (ts+value)」;强调标签不同 → 序列不同,这是很多人答不清的关键点。


Q124. 四种指标类型(Counter, Gauge, Histogram, Summary)的区别和用途。

1. 是什么 :Prometheus 的指标在数据采集端分为四种类型 ------Counter(计数器) 只增不减、Gauge(仪表盘) 可增可减、Histogram(直方图) 记录观测值的分布桶、Summary(摘要) 在客户端直接计算分位数------它们适用不同的业务观测需求。

2. 为什么用它:不同被观测量性质不同------请求总量只会增长、当前在线人数会上下波动、请求耗时需要看分布和 P99;类型错了会导致监控语义错误(如对只增计数器做差值),选对类型才能正确表达业务并支撑 PromQL 的计算方式。

3. 怎么用它(对比):

类型 特点 典型例子 PromQL 用法
Counter 只增不减,重启会归零 请求总数、总字节数、node_cpu_seconds_total rate() / increase() 算速率/增量
Gauge 可增可减,可设任意值 当前温度、内存使用量、在线连接数 直接取值/avg/maxdelta() 看变化
Histogram 记录落入各桶(bucket) 的累计计数 请求耗时、响应体大小 histogram_quantile(0.99, ...) 算 P99 分位数
Summary 客户端预计算分位数并暴露 请求耗时(场景要求客户端算) 直接用暴露的 _quantile;无 histogram_quantile
  • Histogram vs Summary 取舍 :Histogram 在服务端 算分位数,可跨实例聚合、标签可选但精确度受桶影响;Summary 在客户端 算,分位值精确但不能跨实例聚合 。默认生产多选 Histogram
  • 命名约定:Counter 加 _total 后缀(如 _requests_total),Histogram 有 _bucket/_sum/_count 三组指标。

4. 使用场景 :设计监控指标、写告警规则(如"QPS 突增"用 counter 的 rate,"内存超 90%"用 gauge,接口 P99 用 histogram)。面试关键:三句话区分------Counter 只会涨、Gauge 会升降、Histogram/Summary 看耗时分布;Histogram 服务端算分位、可聚合,Summary 客户端算、不可聚合,两者核心差异这三点必答。


Q125. PromQL 的基本语法,如何做聚合、筛选、计算?

1. 是什么PromQL(Prometheus Query Language) 是 Prometheus 的查询语言,用「指标名 + 标签匹配 」选取时间序列,再对序列做筛选、聚合、数学/函数计算 ,最终得到仪表盘或告警用的数值。分瞬时查询 (Instant,看当前)和区间查询(Range,看一段时间)。

2. 为什么用它:监控值本身意义有限,往往要"算"才有价值------每秒速率、P99 延迟、CPU 使用率、最高/最低等都有现成语法;掌握 PromQL 才能写出正确的监控面板和告警规则,是监控使用的核心技能。

3. 怎么用它

① 筛选(标签匹配)

promql 复制代码
node_cpu_seconds_total                       # 全部同名序列
node_cpu_seconds_total{cpu="0"}              # 精确匹配(=)
node_cpu_seconds_total{mode!="idle"}         # 不等于(!=)
node_cpu_seconds_total{mode=~"user|system"}  # 正则匹配(=~)
node_memory_*}                                # 名字通配(支持 glob)

② 计算(函数与算术)

promql 复制代码
# 每秒速率:区间查询必需 rate()
rate(node_cpu_seconds_total{mode="idle"}[5m])
# 增量:一段时间内的增长量
increase(http_requests_total[1h])
# CPU 使用率(用空闲率倒推):
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# 瞬时值运算:内存使用率
(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100

③ 聚合(聚合函数 + by/without)

promql 复制代码
sum(rate(http_requests_total[5m]))                       # 求和(总 QPS)
sum(rate(http_requests_total[5m])) by (method)           # 按标签分组聚合
avg / max / min / count / topk(10, expr)                 # 均值/最大/最小/计数/前N
histogram_quantile(0.99, sum(rate(x_bucket[5m])) by (le)) # 算 P99 分位数
  • 常用聚合函数:sumavgminmaxcounttopk/bottomkcount_values;用 by(标签) 分组、without() 排除分组。
  • 常用函数:rate(Counter 速率,必配区间)、increaseirate(高灵敏度速率)、delta(Gauge 变化)、absroundclamp_max

4. 使用场景 :Grafana 面板公式、Prometheus 告警规则(expr 里写 PromQL)、日常排障查询峰值/异常。面试关键:先分清瞬时区间 查询(rate/increase 必须用区间 [5m]);再答 "筛选用标签 {},计算用函数+算术,聚合用 sum ... by(标签) 分组"三段式,能现场写一个 CPU 使用率/请求速率表达式即可加分。


Q126. 如何配置 Alertmanager 实现告警的分组、抑制、静默和路由(到钉钉/微信)?

1. 是什么Alertmanager 是 Prometheus 生态中负责处理告警 的组件------接收 Prometheus 推送的告警,通过路由(route)、分组(group)、抑制(inhibit)、静默(silence) 四条机制整理后,再通过接收器(Webhook/钉钉/企业微信等)发送出去,避免告警风暴、减少重复打扰。

2. 为什么用它 :直接让 Prometheus 推所有告警会"告警轰炸",同一个故障往往触发几十条告警淹没真正的问题;Alertmanager 的四种机制把海量告警收敛成"一条有代表性的通知 + 去重去抑制",实际运维中几乎必不可少的降噪层。

3. 怎么用它alertmanager.yml):

yaml 复制代码
route:
  group_by: ['alertname']          # 按告警名分组(同类合并)
  group_wait: 30s                  # 组首告警后等 30s 再发,给后续合并留时间
  group_interval: 5m               # 已有组再触发时的发送间隔
  repeat_interval: 4h              # 未被确认的告警重复提醒间隔
  receiver: 'dingtalk'
  routes:                          # 更细的子路由
    - matchers: [ 'severity="critical"' ]
      receiver: 'wechat'
      continue: false

# 抑制:当某告警存在时,抑制另一些告警
inhibit_rules:
  - source_matchers: ['severity="critical"']
    target_matchers: ['severity="warning"']
    equal: ['alertname', 'instance']   # 同告警名同实例时,critical 抑制 warning

receivers:
  - name: 'dingtalk'
    webhook_configs:
      - url: 'https://oapi.dingtalk.com/robot/send?access_token=xxx'
        send_resolved: true
  - name: 'wechat'
    wechat_configs:
      - api_url: 'https://qyapi.weixin.qq.com/cgi-bin/'
        corp_id: '企业ID'
        agent_id: '应用ID'
        api_secret: '密钥'
        to_party: '部门ID'
  • 四个机制一句话
    • 分组(grouping):相同/相关告警合并成一条通知,减少轰炸;
    • 抑制(inhibition):较高层级(如 Critical)告警存在时,抑制相关低层级(Warning)告警;
    • 静默(silence) :管理员手动屏蔽某类告警一段时间(如维护窗口),用 amtool silence add 或 Web UI;
    • 路由(routing):按 matcher 把不同告警发到不同接收器(钉钉/微信/邮件/值班组)。
  • 关联配置:Prometheus 侧 alertmanager: static_configs: - targets 把告警推到 Alertmanager;接收器里 Webhook 是通用通道,接入钉钉机器人/企业微信机器人通常都用 webhook_configs 或官方邮件/微信配置。

4. 使用场景 :告警风暴降噪、不同严重级别/团队分级告警、大促护维护窗口静默。面试关键:四个机制逐个讲清含义+例子 ------分组按 group_by、抑制 inhibit_rules、静默维护窗口、路由按 matcher 分发到钉钉/微信;并给一个 Webhook→钉钉机器人的最小配置。


Q127. 如何用 Recording Rules 提升查询性能?

1. 是什么Recording Rules(预计算规则) 是 Prometheus 的一种预计算机制 ------把频繁执行、且计算量大的复杂 PromQL ,按固定周期(默认 1m)提前算出结果存成新指标,查询时直接读这个"现成指标",而不是实时去扫原始时间序列

2. 为什么用它 :仪表盘里反复查询同一个昂贵表达式(如跨多实例的 rate()+sum+by),每次都让 Prometheus 临时重算,会拖慢面板渲染、增加 CPU 负担并可能超时;预计算把 "重活"分摊为固定周期做一次,让查询即时返回,是 Grafana 大面板和超大规模采集时的标配优化。

3. 怎么用它rules/recording.yml):

yaml 复制代码
groups:
  - name: recording_cpu
    rules:
      # 每条 SQL 预计算结果存为 job:xxx 新指标
      - record: job:cpu_usage:rate5m
        expr: |
          100 - (avg by (instance)(irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
      - record: job:http_requests:rate5m
        expr: |
          sum(rate(http_requests_total[5m])) by (job, method)
  • 命名约定:<level>:<metric>:<operation>,如 job:cpu_usage:rate5m,方便溯源。
  • 加载方式:在 Prometheus 配置 rule_files: - "rules/*.yml",重载 Prometheus(curl -X POST http://localhost:9090/-/reload 或重启)。
  • Prometheus -> Status -> Rules 查看规则执行状态;规则名以 __ 开头的也可用于告警。
  • 结合 Alerting Rules(告警规则) :告警规则的 expr 有时也引用 recording rule 的指标,进一步减负。

4. 使用场景 :Grafana 大看板、QPS/延迟等高频查询、成百上千实例的聚合查询优化。面试关键:一句话------"把高频、昂贵的表达式按周期预计算成新指标存起来,查询直接读结果 ";并讲清命名规范 job:metric:操作 和 "只在查询确实慢/频繁时才用,别过度预计算淹没磁盘" 这个取舍。


Q128. 简述 Kubernetes 的架构(Master 和 Node 组件及其功能)。

1. 是什么 :Kubernetes(K8s)采用 控制平面(Master/Control Plane)+ 工作节点(Worker Node) 主从架构,控制面负责"决策与调度",工作节点负责"真正运行容器";两类组件分别承担不同的管理职责。

2. 为什么用它 :把"集群大脑"(决策:调度、控制循环、API)与"日常劳动力"(执行:跑 Pod、转发流量)分离,使集群可水平扩展、高可用、故障自愈,这是理解"Pod 为何能在某台节点上跑起来"的关键。

3. 怎么用它(组件与功能):

控制平面(Master)组件

组件 功能
kube-apiserver 集群唯一的 API 入口,所有交互(kubectl/各个组件)都经它,负责认证、授权、校验、状态存储
etcd 分布式键值存储,保存集群全部状态数据("集群的数据库")
kube-scheduler 调度器:决定新 Pod 调度到哪台节点(考虑资源/亲和/污点)
kube-controller-manager 运行各类控制器(Node/Deployment/ReplicaSet...),维持期望状态
cloud-controller-manager(可选) 对接云厂商(LB/存储/节点管理)

工作节点(Node)组件

组件 功能
kubelet 节点上的"小管家",负责拉镜像、起停容器、汇报状态、执行探针
kube-proxy 维护 iptables/IPVS 规则,实现 Service 的负载均衡与转发
容器运行时 containerd / CRI-O / Docker,真正创建运行容器的引擎
  • 数据流一句话:kubectlapiserver(校验+写入 etcd)→ scheduler 选节点 → 该节点 kubelet 拉镜像起容器 → controller-manager 不断检查让实际状态收敛回期望状态。

4. 使用场景 :K8s 集群部署与排障(如 pod 调度异常查 scheduler、"control plane 组件负载"查 apiserver/etcd)。面试关键:控制面答齐 apiserver/etcd/scheduler/controller-manager 四大件,节点答 kubelet + kube-proxy + 运行时 ;并点出 "apiserver 是唯一入口、etcd 存状态" 这两个记忆锚点,能画出主从结构与数据流更佳。


Q129. Pod, Deployment, Service, Ingress 的概念和关系。

1. 是什么 :这是 K8s 里最容易混的四个资源,它们分属不同层级:Pod (最小运行单元)、Deployment (管理无状态工作负载)、Service (Pod 的稳定访问抽象)、Ingress (集群入口的七层路由)。关系一句话:Deployment 管 Pod,Service 暴露 Pod,Ingress 路由到 Service

2. 为什么用它:K8s 里"一个应用能稳定对外访问"是四层协同的结果------没有它们各自的分工,就无法实现"Pod 随便换,但访问入口和路由却一直稳定"这一 K8s 的核心价值,因此这四个概念必须整体理解而非孤立背诵。

3. 怎么用它(逐个 + 关系链):

  • Pod :一个或多个共享网络/存储的容器集合,K8s 的最小调度单位;Pod IP 会随重建变化,不稳定。

  • Deployment声明式管理一组 Pod 副本 ,负责滚动更新、回滚、扩缩容、故障自愈;它创建并管理实现副本的 ReplicaSet

  • Service :为一组 Pod(靠 selector 标签 选中)提供一个稳定访问入口 + 负载均衡;Pod IP 漂移没关系,Service 的 ClusterIP/域名不变。

  • Ingress :在 Service 之上的七层(HTTP/HTTPS)统一入口按域名/路径把外部请求路由到不同 Service,还带 TLS 证书、路径重写能力。

  • 关系链(对外访问流程):

    复制代码
    客户端 --HTTP--> Ingress(按域名/路径路由) --> Service(选中一组的Pod做LB) --> Pod(真正的容器)
    Deployment 负责这些 Pod 的副本数/更新/自愈
  • 没有 Ingress 也能用:小规模可直接用 NodePort/LoadBalancer 类型 Service 暴露,Ingress 是"更灵活的集中入口"选项。

  • 流量走向记忆Ingress -> Service -> (Endpoints -> Pod 的容器端口)

4. 使用场景 :设计一个 Web 服务在 K8s 的对外暴露方案、排障"能进集群但访问不到 Pod"(依次查 Ingress 路由、Service selector、Pod 就绪探针)。面试关键:先逐个定义再给关系链,**背熟"Deployment 管 Pod、Service 暴露 Pod、Ingress 路由 Service"**这句话;能画出 Ingress→Service→Pod 的流量图,并补充 Deployment 在下层负责副本与自愈即为完整。


Q130. ReplicaSet 和 Deployment 的区别。

1. 是什么ReplicaSet(RS) 是保证指定数量 Pod 副本持续运行 的控制器;Deployment更上层的控制器 ,它在内部管理 ReplicaSet,并提供高级、无损的部署能力(滚动更新、回滚、扩缩容、暂停/恢复)。两者不是并列而是"套娃"关系。

2. 为什么用它 :只靠 ReplicaSet 只能保证"有 N 个副本",但版本升级时无法做到平滑 (既要有旧又要逐步上新);Deployment 在其上封装了滚动更新/回滚等编排策略,让"变更版本"变成可控、可回退的过程,这是生产发布必需的能力。

3. 怎么用它(对比):

维度 ReplicaSet Deployment
职责 维持 Pod 副本数量 管理 RS + 提供发布/回滚能力
是否直接操作 Pod 是(selector + template 造副本) 否(通过其下的 RS 间接管理)
更新方式 替换整个 RS 或手动 滚动更新(RollingUpdate) 渐进替换
回滚 无原生回滚 支持 kubectl rollout undo 回滚到历史版本
更新历史 不保留 保存 revision 历史,可查看/回退
典型使用 极少直接使用 日常部署首选
  • 归档与选择:Deployment 每次更新会创建一个新 RS (旧 RS 缩到 0 但保留供回滚),所以 kubectl get rs 常看到多个历史的 RS。
  • 使用示例:
bash 复制代码
kubectl set image deployment/myapp myapp=myapp:v2     # 触发滚动更新
kubectl rollout status deployment/myapp                # 查看更新进度
kubectl rollout undo deployment/myapp                  # 回滚到上一版
  • 还有 HPA(水平自动扩缩)也是基于 Deployment/RS 的副本数来伸缩,进一步体现 RS 是"副本量的底层实现"。

4. 使用场景 :日常发布(Deployment)、需要按版本无损更新/回滚时;面试关键:一句话**"ReplicaSet 保证副本数量、Deployment 管理 ReplicaSet 并提供滚动更新与回滚";强调二者是包含关系(外层套里层)**而非对等,并点出每次更新会新建 RS 保留历史以便回滚。


Q131. Service 的类型(ClusterIP, NodePort, LoadBalancer)及其使用场景。

1. 是什么Service 是 K8s 给一组 Pod 提供的稳定访问抽象,按是否需要对外暴露、暴露到哪一层,分为 ClusterIP、NodePort、LoadBalancer (还有 Headless),不同 type 决定访问入口和暴露范围。

2. 为什么用它 :Pod IP 不稳定、数量会变,Service 用标签 selector 稳定暴露这组 Pod;但对"内部调用"、"单节点端口暴露"、"云负载均衡"三种诉求各不相同,所以要按场景选 type------选错要么暴露过大、要么访问不到。

3. 怎么用它(类型对比):

类型 访问方式 暴露范围 使用场景
ClusterIP(默认) 集群内虚拟 IP + 域名,svc名.命名空间 集群内部 服务间相互调用(如网关调后端服务)
NodePort 每个节点开放一个端口(30000~32767),节点IP:端口 集群外部(但限端口且依赖节点可达) 测试、无 LB 环境对外暴露
LoadBalancer 自动创建云负载均衡器(阿里云 SLB),分配公网 IP 公网 生产对外服务,交给云 LB 高可用
yaml 复制代码
# ClusterIP(默认,内部调用)
apiVersion: v1
kind: Service
metadata:
  name: backend-svc
spec:
  selector:
    app: backend          # 选中 backend 的 Pod
  ports:
    - port: 80
      targetPort: 8080    # 转发到 Pod 的 8080

# NodePort:多一行 type 即可
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 8080
      nodePort: 32080     # 可显式指定,也可自动分配

# LoadBalancer:云厂商自动建 LB + 公网IP(底层仍走 NodePort)
spec:
  type: LoadBalancer
  • 关系:ClusterIP < NodePort < LoadBalancer (NodePort 在 ClusterIP 之上开节点端口,LoadBalancer 又在 NodePort 之上绑云 LB),生产公网入口常在它们之上再套 Ingress 做域名/路径路由。
  • 对应云场景(阿里云/腾讯云/AWS):LoadBalancer 会自动拉起 SLB/CLB/ELB,并可用 Annotations 配置带宽、证书等。

4. 使用场景 :服务间内部通信用 ClusterIP、没有云 LB 的裸机/测试环境用 NodePort、生产公网服务用 LoadBalancer(再加 Ingress)。面试关键:一个递进记忆------"ClusterIP 对内 → NodePort 在每节点开端口对外 → LoadBalancer 在云上建 LB+公网IP",并答出默认 ClusterIP、NodePort 端口范围 30000-32767、LoadBalancer 底层依赖 NodePort 这三点;能补充"公网入口常用 Ingress"更完整。

Q132. ConfigMap 和 Secret 的作用和区别?

1. 是什么ConfigMap 用于存储非敏感的配置数据 (环境变量、配置文件内容);Secret 用于存储敏感信息 (密码、Token、证书、私钥),二者都是把"配置/凭据"从镜像或 Pod 定义中解耦出来的 API 对象,可通过环境变量挂载文件/卷的方式注入到 Pod。

2. 为什么用它:把配置和业务代码/镜像分离,同一镜像可复用不同配置(开发/测试/生产);敏感信息不写死在镜像、不用明文环境变量,而是集中管理并加密存储,避免泄露;两者都能让配置变更无需重新构建镜像。

3. 怎么用它(对比):

对比项 ConfigMap Secret
存储内容 普通配置(明文) 敏感信息(密码/证书)
存储编码 明文 Base64(再可叠加加密如 sops/KMS)
常见用途 环境变量、配置文件 密码、API Key、TLS 证书、镜像仓库凭据
注入方式 env / envFrom / volume 挂载 同左(三种方式皆可)
yaml 复制代码
# ConfigMap:普通配置
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:                          # 用 data 存明文
  MYSQL_HOST: "10.0.0.5"
  LOG_LEVEL: "INFO"
  app.yaml: |                 # 多行文件内容
    server:
      port: 8080
---
# Secret:敏感信息(值需 Base64 编码)
apiVersion: v1
kind: Secret
metadata:
  name: db-secret
type: Opaque
data:                          # 用 data 必须 Base64
  password: MTIzNDU2           # echo -n "123456" | base64
stringData:                    # 或用 stringData 写明文,apply 时自动编码
  username: admin

Pod 引用示例

yaml 复制代码
spec:
  containers:
  - name: app
    envFrom:
    - configMapRef: { name: app-config }
    - secretRef: { name: db-secret }
    env:
    - name: DB_PASSWORD
      valueFrom:
        secretKeyRef: { name: db-secret, key: password }
    volumeMounts:
    - name: cfg
      mountPath: /etc/config
  volumes:
  - name: cfg
    configMap: { name: app-config }     # 也可以改 secret 同名挂载

4. 使用场景 :应用分层配置、数据库密码/钱包私钥管理、TLS 证书注入、镜像拉取凭据(imagePullSecrets)。面试关键:一句话"ConfigMap 存明文配置、Secret 存敏感凭据,Secret 值用 Base64 编码(且生产应再加密)";并说明两者都通过 env 或 volume 注入、都用于把配置与镜像解耦。


Q133. kube-proxy 的 iptables 和 ipvs 模式原理区别?

1. 是什么kube-proxy 是运行在每个节点上的网络代理,负责实现 Service (ClusterIP、NodePort)的负载均衡与规则维护。它有两种主要实现模式:iptables (默认)和 IPVS,核心都是把访问 Service 的流量转发到后端 Pod。

2. 为什么用它:Service 的 ClusterIP 是虚拟 IP,必须由节点上某种机制把访问它的流量"重定向"到实际 Pod 上。iptables 基于内核包过滤实现;IPVS 基于内核 LVS/IPVS 体系、更专业。理解二者区别直接关系到大规模集群的网络性能与规则复杂度。

3. 怎么用它(对比):

对比项 iptables ipvs
转发原理 每新增一条 Service 生成大量 iptables 规则链,逐条匹配 在内核生成 ipvs 服务与后端列表,hash 查找
性能 匹配链多,规模大时延迟高、性能差 O(1) hash 查找,延迟低、吞吐高
支持算法 仅随机 rr/lc/wrr/sh/dh 等多种调度算法
规则数量 Service 多时规则爆炸 规则紧凑(一条 service 对应一份后端表)
是否支持会话保持 支持(source-hash 等)
特性 通用、简单、兼容性好 高级、高效,但对内核 ipvs 支持有要求
K8s 默认 默认(kube-proxy --proxy-mode=iptables) 手动开启 --proxy-mode=ipvs
bash 复制代码
# 查看 kube-proxy 用什么模式
kubectl get pod -n kube-system -l k8s-app=kube-proxy -o wide
# 或用 curl 访问节点上 kube-proxy 的 metrics 查看
# 更直接:hostPath 里 kube-proxy 的启动参数含 --proxy-mode
# 切换 ipvs:编辑 kube-proxy ConfigMap,将 mode 改为 ipvs
kubectl -n kube-system edit configmap kube-proxy
#   mode: "ipvs"     # 原来是 iptables/空
kubectl -n kube-system rollout restart daemonset kube-proxy

4. 使用场景 :大规模集群(万级 Service/Pod)或对延迟敏感时用 ipvs;中小集群用默认 iptables 即可。面试关键:一句话"iptables 用规则链逐条匹配、规模大时慢;ipvs 用内核 hash 查找、O(1) 更快且支持多种调度算法与会话保持,适合大规模集群 ";并知道修改 kube-proxy 的 mode 字段切换。


Q134. kube-scheduler 的调度流程和常用预选/优选策略?

1. 是什么kube-scheduler 是控制平面负责调度新 Pod 到合适节点的组件。它把"待调度 Pod"与"集群候选节点"做匹配,经过**预选(Filter/Predicate)→ 优选(Score/Priority)→ 绑定(Bind)**三个阶段,选出最合适的一个节点。

2. 为什么用它:Pod 不能随便乱放------要考虑资源是否够用、亲和/反亲和、污点/容忍、跨区高可用等约束。scheduler 用一组可插拔的调度框架/策略,确保每个 Pod 被调度到既满足约束、又尽量合理的节点,是集群资源合理利用和稳定的关键。

3. 怎么用它(调度流程三步):

  • ① 预选(Filtering/Predicate) :从所有节点中筛选出"能容纳该 Pod"的节点 (不满足即淘汰)。常用预选:
    • PodFitsResources:节点剩余资源是否满足 requests。
    • PodFitsHostPorts:端口是否冲突。
    • NodeSelector/NodeAffinity:是否满足节点选择/亲和。
    • TaintToleration:是否容忍节点污点。
    • CheckNodeUnschedulable:节点是否可调度。
  • ② 优选(Scoring/Priority) :对候选节点打分 ,分数高者优先。常用优选:
    • LeastRequested:优先调度到已用资源占比低(剩余多)的节点。
    • BalancedResourceAllocation:优先让 CPU/内存均衡。
    • NodeAffinityPriority:满足亲和加分。
    • ImageLocalityPriority:节点已有所需镜像优先。
  • ③ 绑定(Bind) :把 Pod 绑定到得分最高的节点,写回 nodeName,该节点 kubelet 再拉镜像启动。
bash 复制代码
# 查看调度器调度失败的 Pod(Pending 常因无节点可调度)
kubectl describe pod <pod-name> | grep -A5 Events

# 手动查看节点可用资源
kubectl describe node <node-name> | grep -A5 "Allocatable"

# 查看调度器日志(在 Master)
journalctl -u kube-scheduler -f

# 手动指定调度到某节点(简单做法)
# 在 Pod spec 中加 nodeName / nodeSelector

4. 使用场景 :排查 Pod Pending(无合适节点)、做资源均衡、实现亲和/反亲和(如让有状态服务分散到不同节点)。面试关键:背出"预选(过滤)→ 优选(打分)→ 绑定"三步 ;预选讲 2~3 个(资源、亲和、污点容忍)、优选讲 2~3 个(最空闲、均衡、镜像本地优先);并说明 Pending 通常是预选没通过(资源不够/污点不匹配)。


Q135. 描述 Pod 的生命周期和重启策略?

1. 是什么Pod 生命周期 指 Pod 从创建到结束经历的状态集合(Pending、Running、Succeeded、Failed、Unknown),以及容器内的启动钩子、探针、终止钩子 等阶段;重启策略(restartPolicy) 决定容器退出后 kubelet 是否重启它。

2. 为什么用它:理解生命周期才能解释"为什么 Pod 会重启/为什么会 Failed/为什么容器启动前有初始化";重启策略决定了故障容器的行为(一直重启还是停止),直接影响服务的可用性与人为干预时机。

3. 怎么用它(生命周期状态 + 阶段):

  • Pod 状态机(kubectl get pod 的 STATUS 列)
    • Pending:已创建但还没调度到节点(或镜像拉取中)。
    • Running:Pod 已被调度,容器已启动/运行中。
    • Succeeded:所有容器正常退出(不重启)。
    • Failed:所有容器异常退出(某个容器以非 0 退出)。
    • Unknown:节点失联,无法获取 Pod 状态。
  • 容器阶段(kubectl get pod -o jsonpath='{.status.containerStatuses}'WaitingRunningTerminated
  • 生命周期钩子/探针
    • postStart(容器启动后执行)、preStop(容器终止前执行)。
    • 三种探针:startupProbe(启动)、livenessProbe(存活)、readinessProbe(就绪)。
  • 重启策略 restartPolicy (Pod 级字段):
    • Always(默认):无论退出码如何,总是重启。
    • OnFailure:仅当容器以非 0 退出才重启(适合 job)。
    • Never:不重启(适合一次性 job)。
  • 注意 :DaemonSet/Deployment 等控制的 Pod 通常 Always;Job/CronJob 用 OnFailure/Never
yaml 复制代码
spec:
  restartPolicy: Always        # Always / OnFailure / Never
  containers:
  - name: app
    image: nginx
    lifecycle:
      postStart:
        exec: { command: ["/bin/sh","-c","echo start >> /tmp/log"] }
      preStop:
        exec: { command: ["/bin/sh","-c","echo stop >> /tmp/log"] }

4. 使用场景 :排查 CrashLoopBackOff(Always 重启但反复崩溃)、服务发布/下线时的优雅终止(preStop 做清理)、区分 Job 与 Deployment 的重启行为。面试关键:说出 5 个状态 + 3 种重启策略 ;重点强调 CrashLoopBackOffrestartPolicy: Always 下容器反复崩溃的结果,以及 liveness/readiness 探针在生命周期中承担"存活/就绪"判断。


Q136. 如何编写一个 Deployment 和 Service 的 YAML 文件?

1. 是什么 :用 YAML 定义一个 Deployment (管理工作负载、Deployment 副本数、滚动更新)和一个 Service(为这些 Pod 提供稳定访问入口)。这是 K8s 里最常用、必须手写的两个清单文件。

2. 为什么用它 :K8s 是声明式的,用 YAML 描述"期望状态"再 kubectl apply 是标准用法;掌握 Deployment+Service 的写法,才能把应用(尤其 Web 服务)以容器化方式在集群内部署和暴露。

3. 怎么用它(模板示例,Deployment + Service 一体):

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
  labels: { app: my-app }
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:                  # Pod 模板
    metadata:
      labels:
        app: my-app          # 与 selector 匹配
    spec:
      containers:
      - name: my-app
        image: nginx:1.23
        ports:
        - containerPort: 80
        resources:
          requests: { cpu: "100m", memory: "128Mi" }
          limits:   { cpu: "500m", memory: "512Mi" }
---
apiVersion: v1
kind: Service
metadata:
  name: my-app-svc
spec:
  type: ClusterIP             # 可选 ClusterIP / NodePort / LoadBalancer
  selector:
    app: my-app               # 选中与 Deployment 相同的 Pod
  ports:
  - port: 80                  # Service 端口
    targetPort: 80            # 转发到 Pod 的容器端口(可写名字)
    protocol: TCP

关键点

  • selector 一致性 :Service 的 selector 标签必须与 Deployment 的 template.metadata.labels(及 selector.matchLabels匹配,否则 Service 选不到 Pod。
  • 若用 NodePort,可在 ports 里加 nodePort: 32080(30000-32767)。
  • 若想 kubectl expose 自动生成,可用 kubectl expose deployment my-app --port=80 --target-port=80
bash 复制代码
# 应用 / 查看 / 删除
kubectl apply -f deploy.yaml
kubectl get deployment,service,pod -o wide
kubectl delete -f deploy.yaml

4. 使用场景 :任何 Web/后端服务的标准部署;面试关键:背出 Deployment 的五大结构replicasselector.matchLabelstemplate.metadata.labelscontainersimage/ports)和 Service 的三大要素(typeselectorports),并强调"selector 标签匹配"这一最容易出错的点。


Q137. 如何实现应用的滚动更新和回滚?

1. 是什么滚动更新(Rolling Update) 是 Deployment 默认的升级策略------分批、渐进地 用新版本 Pod 替换旧版本 Pod,过程中服务不中断;回滚(Rollback) 是把集群状态恢复到上一个(或某个历史)版本。二者都由 Deployment 的 strategyrevisionHistoryLimit 控制。

2. 为什么用它:直接删掉所有旧 Pod 再上新会瞬间"全断";滚动更新保证更新期间始终有可用副本、零/低停机;一旦新版本出问题,快速回滚到旧版能最大限度降低线上事故影响------这是生产发布的标配能力。

3. 怎么用它(配置 + 命令):

配置策略

yaml 复制代码
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1       # 更新中最多可"不可用"的副本数(0~100%)
      maxSurge: 1             # 更新中最多可"超出期望副本数"的额外新副本
  revisionHistoryLimit: 10    # 保留多少个历史版本供回滚

触发滚动更新

bash 复制代码
kubectl set image deployment/my-app my-app=my-app:v2     # 改镜像触发
# 或 edit / apply 修改 YAML

查看进度

bash 复制代码
kubectl rollout status deployment/my-app                  # 查看 rollout 进度
kubectl rollout history deployment/my-app                 # 查看历史版本

回滚

bash 复制代码
kubectl rollout undo deployment/my-app                    # 回滚到上一个版本
kubectl rollout undo deployment/my-app --to-revision=2    # 回滚到指定版本

常见问题排查

  • 新版本起不来(镜像错/健康检查失败)→ rollout 会卡住,用 kubectl rollout history + kubectl describe pod 定位。
  • 想让"滚动更新"生效,要求 Deployment 带就绪探针(readinessProbe),否则新 Pod 即便就绪也影响切换时机。

4. 使用场景 :线上发布、灰度渐进、故障快速回滚。面试关键:一句话"滚动更新用 maxUnavailable/maxSurge 控制分批替换、过程不断服;回滚用 rollout undo ";并强调"新版起不来时 rollout 会暂停,需先看历史与 Pod 状态再决定回滚"。


Q138. 如何配置 Pod 的资源请求(requests)和限制(limits)?

1. 是什么requests(请求) 是 Pod 容器最少需要 的资源量(调度时就按它预留);limits(限制) 是容器最多可用 的资源量(超出会被限制/终止)。两者都针对 CPU 和内存,通过 resources 字段声明。

2. 为什么用它 :不设 requests 会让调度器把 Pod 塞到资源不足的节点导致运行劣化;不设 limits 会让单个容器"吃爆"节点资源拖垮整台机器(内存尤其危险)。正确配置 requests/limits 是资源合理调度避免 OOM/CPU 争抢的关键。

3. 怎么用它

yaml 复制代码
spec:
  containers:
  - name: app
    image: nginx
    resources:
      requests:                # 调度依据(下限)
        cpu: "250m"            # 250 毫核 = 0.25 CPU
        memory: "256Mi"        # 256 MiB
      limits:                  # 运行上限
        cpu: "1"               # 最多 1 核
        memory: "512Mi"        # 最多 512 MiB

关键点

  • 单位 :CPU 用 m(milli,1 CPU = 1000m);内存用 Mi/Gi/M(Mi 是 MiB,M 是 MB)。
  • limits ≥ requests(通常 requests 设 60%~80% 的 limits 更合理)。
  • 调度与限制关系
    • 调度只依据 requests(预留)。
    • 运行超 limits CPU:被限流(throttle),不终止。
    • 运行超 limits 内存 :容器被 OOMKill(内存超限会被杀掉,这是大坑)。
  • LimitRange / ResourceQuota:可对命名空间统一设置默认 requests/limits 和配额。
bash 复制代码
# 查看节点/命名空间资源
kubectl describe node <node> | grep -A5 "Allocatable"
kubectl get pod -n <ns> -o custom-columns=NAME:.metadata.name,CPU_REQ:.spec.containers[0].resources.requests.cpu,MEM_REQ:.spec.containers[0].resources.requests.memory

4. 使用场景 :生产所有容器都宜配 requests/limits;排查 OOMKilled、节点资源被打满、批量 Pod 争抢 CPU。面试关键:点出"requests 是调度预留、limits 是运行上限" ;强调"CPU 超限只限流、内存超限杀容器",并说清单位与"limits 必须 ≥ requests"。


Q139. 如何配置 livenessProbe 和 readinessProbe?它们有何区别?

1. 是什么 :两者都是 Kubernetes 探针 ,由 kubelet 周期性探测容器。livenessProbe(存活探针) 判断容器是否需要重启readinessProbe(就绪探针) 判断容器是否能接收流量

2. 为什么用它:光靠"容器进程在"不能代表"应用可用"。liveness 解决"卡死/假死但进程还在"的场景(自动重启恢复);readiness 解决"新 Pod 起来但还没准备好"的场景(先不被调度流量,避免 502)。二者让集群具备自愈和优雅上线能力。

3. 怎么用它(三种探测方式 + 区别):

yaml 复制代码
spec:
  containers:
  - name: app
    image: myapp
    livenessProbe:              # 存活:失败则重启容器
      httpGet:
        path: /health
        port: 8080
      initialDelaySeconds: 10   # 启动后等 10s 再探测
      periodSeconds: 10         # 每 10s 探测一次
      timeoutSeconds: 3         # 单次超时 3s
      failureThreshold: 3       # 连续失败 3 次判定失败
    readinessProbe:             # 就绪:失败则从 Service 摘除
      httpGet:
        path: /ready
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 5

三种探测方式

  • httpGet:访问 HTTP 接口,2xx/3xx 视为健康。
  • tcpSocket:能否建立 TCP 连接。
  • exec:执行命令,退出码 0 视为健康。

区别(必答维度)

对比 livenessProbe readinessProbe
判断什么 容器存活(活没活) 容器就绪(能不能接流量)
失败后果 重启容器(Kill 后重建) 从 Service Endpoint 剔除(不转发流量,不重启)
阶段 整个运行期 整阶段(含滚动更新时控制切换)
典型场景 应用死循环/假死自动恢复 应用启动慢、"预热"完成前不接流量

补充 :还有 startupProbe(启动探针),用来保护启动慢的应用,避免它们被 liveness 误杀------启动成功前只运行 startupProbe ,成功后才交还给 liveness/readiness。若配置了 startupProbe,建议把 liveness 的 failureThreshold 设大(如 30),防止启动慢被重启。

4. 使用场景 :所有无状态服务建议配 readiness;关键业务配 liveness。面试关键:三句话 ------"liveness 失败重启容器、readiness 失败摘出流量、startupProbe 保护慢启动";并用"重启 vs 摘流量"来区分 liveness 和 readiness 的核心差异。


Q140. 如何实现 Pod 的数据持久化?

1. 是什么 :Pod 默认的容器文件系统是临时的 ,容器重启/重建后数据丢失;数据持久化 通过 Volume(卷) 把数据存储到 Pod 外的位置,Pod 重建数据仍在。常用类型有 emptyDirhostPathPersistentVolume(PV)+PersistentVolumeClaim(PVC)ConfigMap/Secret 挂载等。

2. 为什么用它:数据库、日志、配置文件等数据不能随容器销毁而丢失;有状态应用(DB、Redis、MQ)必须有持久存储。Volume 把"数据"与"容器生命周期"解耦,是 StatefulSet/有状态服务的基础。

3. 怎么用它(常用卷类型):

① emptyDir(临时,Pod 内共享)

yaml 复制代码
spec:
  containers:
  - name: app
    volumeMounts:
    - { name: cache, mountPath: /data }
  volumes:
  - name: cache
    emptyDir: {}              # Pod 删除即清空,仅用于容器间共享临时数据

② hostPath(宿主机目录)

yaml 复制代码
volumes:
- name: log
  hostPath: { path: /var/log/myapp }   # 挂到宿主机(有安全隐患,慎用)

③ PV + PVC(推荐,真正持久化 + 动态供给)

yaml 复制代码
# PVC:声明需要什么存储
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data-pvc
spec:
  accessModes: [ReadWriteOnce]
  resources: { requests: { storage: 5Gi } }
---
apiVersion: v1
kind: Pod
spec:
  volumes:
  - name: data
    persistentVolumeClaim: { claimName: data-pvc }
  containers:
  - name: app
    volumeMounts:
    - { name: data, mountPath: /var/lib/mysql }

关键概念

  • PV:集群里真正的一块存储(静态 PV 或由 StorageClass 动态供给)。
  • PVC:用户"申请"存储的请求,绑定到 PV。
  • StorageClass :让存储动态供给(云盘/NFS/本地),省去手动建 PV。
  • StatefulSet :配合有状态应用,每个 Pod 有独立稳定 的 PVC(如 db-0db-1 各自绑定一块卷)。
bash 复制代码
# 查看存储资源
kubectl get pv, pvc, storageclass

4. 使用场景 :数据库/中间件(MySQL、Redis、ES)持久化、日志留存、有状态应用(StatefulSet)。面试关键:分层回答 ------临时共享用 emptyDir、单机用 hostPath、生产持久化用 PV/PVC(可加 StorageClass 动态供给) ;并指出"裸 containers 无卷则数据随 Pod 消失,StatefulSet 才能给每个 Pod 绑定独立稳定卷"。


Q141. 如何配置 Horizontal Pod Autoscaler (HPA)?

1. 是什么HPA(Horizontal Pod Autoscaler) 是 K8s 的水平自动扩缩容 控制器------根据资源指标 (如 CPU 使用率、内存,或自定义指标)或外部指标 ,自动增减 Deployment / StatefulSet 的副本数,实现"负载升高自动加 Pod、负载降低自动减 Pod"。

2. 为什么用它:手动扩缩容滞后且费人力;HPA 让副本数随实际负载动态伸缩,既保证高峰不被打垮,又避免低谷资源浪费,是弹性伸缩(尤其与 K8s 云环境结合)的核心能力。

3. 怎么用它(前提 + 配置):

前提 :集群需安装 metrics-server(采集节点与 Pod 指标),否则 HPA 拿不到 CPU/内存数据。

bash 复制代码
# 安装 metrics-server(如未装)
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# 验证指标可用
kubectl top pod

创建 HPA

bash 复制代码
# 基于 CPU 自动伸缩(最常见),targets 语法(新版)
kubectl autoscale deployment my-app --cpu-percent=80 --min=2 --max=10
# 或写 YAML
cat <<EOF | kubectl apply -f -
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: my-app-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-app
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 80   # 目标 CPU 平均使用率 80%
  behavior:                       # 可选:更精细的伸缩行为
    scaleUp:
      stabilizationWindowSeconds: 30
    scaleDown:
      stabilizationWindowSeconds: 300
EOF

源码要求(关键) :HPA 基于 CPU 自动伸缩时,Deployment 的容器必须已配置 resources.requests.cpu(否则 HPA 无法计算"利用率",因为分母是 requests 而不是 limits)。

yaml 复制代码
# 容器必须配 requests.cpu,HPA 才有分母
resources:
  requests: { cpu: "250m", memory: "256Mi" }
  limits:   { cpu: "500m", memory: "512Mi" }

查看 HPA 状态

bash 复制代码
kubectl get hpa
kubectl describe hpa my-app-hpa

4. 使用场景 :Web 服务、API 网关等流量波动大的无状态应用弹性伸缩。面试关键:前提提醒 ------"要在集群装 metrics-server,且容器必须配 requests.cpu (否则 HPA 算不出利用率)";并说清 HPA 只调节副本数(水平),垂直(调资源大小)是 VPA。让 Pod 数随 CPU 负载自动增减。


Q142. 如何使用 Namespace 实现多租户资源隔离?

1. 是什么Namespace(命名空间) 是 K8s 用来逻辑划分集群 的机制,把一个物理集群切成多个虚拟的、相互隔离的"子集群"。多租户场景下,可用 Namespace 分配给不同团队/项目/环境(如 dev、test、prod),再配合 ResourceQuotaLimitRangeRBACNetworkPolicy 实现资源与权限的隔离。

2. 为什么用它:一个集群往往多个部门/租户共用,若不隔离会造成资源互相抢占、配置互相污染、权限失控、误删串扰。Namespace 从"资源/对象归属 + 配额 + 权限 + 网络"多个维度做边界,是最经济(不用起多套集群)的多租户方案。

3. 怎么用它

① 创建 Namespace

bash 复制代码
kubectl create namespace dev
kubectl create namespace prod
# 或 YAML
# apiVersion: v1
# kind: Namespace
# metadata: { name: prod }

② 在指定命名空间操作

bash 复制代码
kubectl get pods -n dev
kubectl apply -f app.yaml -n prod

③ 资源配额 ResourceQuota(限制命名空间总资源)

yaml 复制代码
apiVersion: v1
kind: ResourceQuota
metadata:
  name: dev-quota
  namespace: dev            # 只对 dev 生效
spec:
  hard:
    requests.cpu: "20"      # 该 ns 所有 Pod CPU requests 总和上限
    requests.memory: "40Gi"
    limits.cpu: "40"
    limits.memory: "80Gi"
    pods: "100"             # Pod 总数上限

④ LimitRange(给命名空间内 Pod 设置默认/范围)

yaml 复制代码
apiVersion: v1
kind: LimitRange
metadata: { name: dev-lr, namespace: dev }
spec:
  limits:
  - type: Container
    default: { cpu: "500m", memory: "512Mi" }
    defaultRequest: { cpu: "250m", memory: "256Mi" }
    max: { cpu: "4", memory: "8Gi" }

⑤ RBAC 权限绑定

bash 复制代码
# 创建给租户的用户/ServiceAccount,并只授予其 namespace 读写权限
kubectl create rolebinding dev-user --clusterrole=edit --user=alice -n dev

⑥ NetworkPolicy(网络层隔离,需 CNI 支持):控制不同 Namespace / Pod 之间的流量放行。

查看与切换默认命名空间

bash 复制代码
kubectl get namespace
kubectl config set-context --current --namespace=dev   # 切换默认 ns

4. 使用场景 :多团队/多项目/多环境共用一套集群;面试关键:说出"Namespace 划分隔离 + ResourceQuota 限资源 + LimitRange 设默认 + RBAC 控权限 + NetworkPolicy 控网络 "五板斧,并提"资源名在 ns 内唯一、跨 ns 可同名"。


Q143. 如何查看 Pod 的日志?如何进入 Pod 进行调试?

1. 是什么查看 Pod 日志kubectl logs进入 Pod 交互调试kubectl exec。这是排查 Pod 内部问题(应用报错、启动失败、配置错误)最常用的两个操作。

2. 为什么用它:Pod 内的容器是"黑盒",看不到内部运行;日志能反映应用运行与报错,exec 能像 SSH 一样进容器查看文件、执行命令、测连通,二者是诊断"应用为何异常/为什么起不来/为何访问不通"的利器。

3. 怎么用它

① 查看日志

bash 复制代码
kubectl logs <pod-name>                        # 查看指定 Pod 日志(单容器)
kubectl logs <pod-name> -c <container>         # 多容器时指定容器
kubectl logs <pod-name> --previous             # 查看上次崩溃前的日志(关键!)
kubectl logs <pod-name> -f                     # 持续跟踪(tail -f)
kubectl logs <pod-name> --tail=100             # 只看最近 100 行
kubectl logs -l app=my-app                     # 按标签看一组 Pod
kubectl logs <pod> --timestamps                # 带时间戳

重要 :Pod 崩溃重启后,当前容器日志可能是新的(空白/无错),用 --previous上次崩溃 的日志才能定位原因;CrashLoopBackOff 排查必用。

② 进入 Pod 交互

bash 复制代码
kubectl exec -it <pod-name> -- /bin/sh         # 进入容器(sh,若容器有 bash 则用 /bin/bash)
kubectl exec -it <pod-name> -c <container> -- /bin/sh   # 指定容器
kubectl exec <pod-name> -- env                  # 查看环境变量
kubectl exec <pod-name> -- cat /etc/nginx/nginx.conf    # 执行单条命令查看文件
kubectl exec -it <pod-name> -- nslookup 后端svc         # 容器内测 DNS/连通

③ 更完整的调试手段

  • describekubectl describe pod <pod> 看 Events、环境、挂载、容器状态。
  • debug 临时容器 (无 exec 能力/无 shell 时):kubectl debug -it <pod> --image=busybox ...kubectl debug node/<node> --image=busybox(在节点侧调试)。
  • 看资源占用kubectl top pod
  • 副本/选择器kubectl get pods -o wide 看 Pod 在哪个节点。

4. 使用场景 :任何 Pod 异常(Failure/CrashLoop/访问不通)的排查。面试关键:点出 --previous(看崩溃前日志)是 CrashLoopBackOff 排查的关键 ;并给"logs 看报错 → describe 看事件 → exec 进去看文件/环境/测连通 → 必要时 debug 临时容器"这条完整的 Pod 排查链路。

相关推荐
瀚高PG实验室1 小时前
PostgreSQL 服务器因整数回绕导致分配空间过小HGVE-2026-E008
运维·服务器·数据库·瀚高数据库
程序员无隅1 小时前
远程控制补上了 Agent 的最后一公里:WorkBuddy 的多端协同体验
运维·服务器
智码看视界1 小时前
Day58-K8s部署Spring Boot微服务:ConfigMap+Secret+HPA
spring boot·微服务·云原生·kubernetes·k8s·hpa
相顾若初见1 小时前
Ansible部署k8s
容器·kubernetes·ansible
mwmbfh1 小时前
【CentOS7环境下Redis 6.2.14 源码编译部署说明】
linux·运维·数据库·redis
做一个AK梦1 小时前
DevOps
运维·devops
hzxpaipai1 小时前
杭州网站运维|企业官网上线前技术检查清单:SEO、GEO、安全、服务器与备份
运维·服务器·nginx·安全
优化Henry1 小时前
关于“星链”互联网系统的几点认识
运维·服务器·网络·笔记·学习·信息与通信
沫璃染墨1 小时前
《从零入门Linux系统篇(二十八):文件篇·一——Linux为什么“万物皆文件”:从C语言文件流到系统调用》
linux·运维·服务器·开发语言·c++·文件