运维常见面试题_07_配置管理与监控(Ansible · Prometheus · Alertmanager)· 容器编排(Kubernetes)
Q120. 如何配置 Ansible 的清单(inventory)和 SSH 免密登录?
1. 是什么:Ansible 的清单(Inventory) 是一份定义「被管理主机」及其分组、变量、连接参数的清单文件(默认 /etc/ansible/hosts,也常用自定义路径);SSH 免密登录 是通过公私钥认证让控制端无需输入密码即可登录被管主机,是 Ansible 高效批量操作的前提。
2. 为什么用它:Ansible 是无 Agent 架构(通过 SSH 直连),必须先知道管哪些主机、怎么连过去,清单承担「主机清单 + 分组 + 变量」三重职责;SSH 免密避免每次执行要输密码,尤其批量执行上百台时是必需的体验和效率保障。
3. 怎么用它:
① 配置 Inventory(支持多种写法):
# /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 格式 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 免密(控制端生成密钥 → 拷贝到被管端):
# 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):
---
- 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 骨架——hosts、become、tasks(装包/配置/启服务)、handlers 触发重启;并点出 systemd 模块同时完成启动与开机自启、notify/handlers 只在配置变更时重启这一最佳实践。
Q122. 如何调试 Ansible 的 playbook?如何提高 Ansible 的执行效率?
1. 是什么:调试指在 Playbook 报错或结果不符合预期时定位问题的手段;提效指通过并发、免密码、关闭事实收集等手段缩短批量执行时间,二者是把 Ansible 从「能跑」推向「好用、可维护、大规模可用」的能力。
2. 为什么用它:Playbook 错在哪一步、变量为何没生效、主机为何不通都需要有章法地定位,否则排查靠猜;而管理几十上百台主机时,串行执行或反复收集 Facts 会非常慢,提效手段直接影响运维人效与响应速度。
3. 怎么用它:
① 调试手段:
# 语法检查(不执行)
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权限不足、模板路径错误。
② 提效手段:
# 1) 关闭不必要的 Facts 收集(Gathering Facts 最耗时)
- name: 提效版
hosts: all
gather_facts: no
# 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-check→ debug 打变量 + --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/max;delta() 看变化 |
| 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. 怎么用它:
① 筛选(标签匹配):
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)
② 计算(函数与算术):
# 每秒速率:区间查询必需 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):
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 分位数
- 常用聚合函数:
sum、avg、min、max、count、topk/bottomk、count_values;用by(标签)分组、without()排除分组。 - 常用函数:
rate(Counter 速率,必配区间)、increase、irate(高灵敏度速率)、delta(Gauge 变化)、abs、round、clamp_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):
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):
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,真正创建运行容器的引擎 |
- 数据流一句话:
kubectl→apiserver(校验+写入 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。 - 使用示例:
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 高可用 |
# 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 挂载 | 同左(三种方式皆可) |
# 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 引用示例:
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 |
# 查看 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 再拉镜像启动。
# 查看调度器调度失败的 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}'):Waiting、Running、Terminated。 - 生命周期钩子/探针:
postStart(容器启动后执行)、preStop(容器终止前执行)。- 三种探针:
startupProbe(启动)、livenessProbe(存活)、readinessProbe(就绪)。
- 重启策略
restartPolicy(Pod 级字段):Always(默认):无论退出码如何,总是重启。OnFailure:仅当容器以非 0 退出才重启(适合 job)。Never:不重启(适合一次性 job)。
- 注意:DaemonSet/Deployment 等控制的 Pod 通常
Always;Job/CronJob 用OnFailure/Never。
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 种重启策略;重点强调 CrashLoopBackOff 是 restartPolicy: 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 一体):
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。
# 应用 / 查看 / 删除
kubectl apply -f deploy.yaml
kubectl get deployment,service,pod -o wide
kubectl delete -f deploy.yaml
4. 使用场景:任何 Web/后端服务的标准部署;面试关键:背出 Deployment 的五大结构(replicas、selector.matchLabels、template.metadata.labels、containers、image/ports)和 Service 的三大要素(type、selector、ports),并强调"selector 标签匹配"这一最容易出错的点。
Q137. 如何实现应用的滚动更新和回滚?
1. 是什么:滚动更新(Rolling Update) 是 Deployment 默认的升级策略——分批、渐进地用新版本 Pod 替换旧版本 Pod,过程中服务不中断;回滚(Rollback) 是把集群状态恢复到上一个(或某个历史)版本。二者都由 Deployment 的 strategy、revisionHistoryLimit 控制。
2. 为什么用它:直接删掉所有旧 Pod 再上新会瞬间"全断";滚动更新保证更新期间始终有可用副本、零/低停机;一旦新版本出问题,快速回滚到旧版能最大限度降低线上事故影响——这是生产发布的标配能力。
3. 怎么用它(配置 + 命令):
配置策略:
spec:
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1 # 更新中最多可"不可用"的副本数(0~100%)
maxSurge: 1 # 更新中最多可"超出期望副本数"的额外新副本
revisionHistoryLimit: 10 # 保留多少个历史版本供回滚
触发滚动更新:
kubectl set image deployment/my-app my-app=my-app:v2 # 改镜像触发
# 或 edit / apply 修改 YAML
查看进度:
kubectl rollout status deployment/my-app # 查看 rollout 进度
kubectl rollout history deployment/my-app # 查看历史版本
回滚:
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. 怎么用它:
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 和配额。
# 查看节点/命名空间资源
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. 怎么用它(三种探测方式 + 区别):
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 重建数据仍在。常用类型有 emptyDir、hostPath、PersistentVolume(PV)+PersistentVolumeClaim(PVC)、ConfigMap/Secret 挂载等。
2. 为什么用它:数据库、日志、配置文件等数据不能随容器销毁而丢失;有状态应用(DB、Redis、MQ)必须有持久存储。Volume 把"数据"与"容器生命周期"解耦,是 StatefulSet/有状态服务的基础。
3. 怎么用它(常用卷类型):
① emptyDir(临时,Pod 内共享):
spec:
containers:
- name: app
volumeMounts:
- { name: cache, mountPath: /data }
volumes:
- name: cache
emptyDir: {} # Pod 删除即清空,仅用于容器间共享临时数据
② hostPath(宿主机目录):
volumes:
- name: log
hostPath: { path: /var/log/myapp } # 挂到宿主机(有安全隐患,慎用)
③ PV + PVC(推荐,真正持久化 + 动态供给):
# 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-0、db-1各自绑定一块卷)。
# 查看存储资源
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/内存数据。
# 安装 metrics-server(如未装)
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# 验证指标可用
kubectl top pod
创建 HPA:
# 基于 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)。
# 容器必须配 requests.cpu,HPA 才有分母
resources:
requests: { cpu: "250m", memory: "256Mi" }
limits: { cpu: "500m", memory: "512Mi" }
查看 HPA 状态:
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),再配合 ResourceQuota、LimitRange、RBAC、NetworkPolicy 实现资源与权限的隔离。
2. 为什么用它:一个集群往往多个部门/租户共用,若不隔离会造成资源互相抢占、配置互相污染、权限失控、误删串扰。Namespace 从"资源/对象归属 + 配额 + 权限 + 网络"多个维度做边界,是最经济(不用起多套集群)的多租户方案。
3. 怎么用它:
① 创建 Namespace:
kubectl create namespace dev
kubectl create namespace prod
# 或 YAML
# apiVersion: v1
# kind: Namespace
# metadata: { name: prod }
② 在指定命名空间操作:
kubectl get pods -n dev
kubectl apply -f app.yaml -n prod
③ 资源配额 ResourceQuota(限制命名空间总资源):
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 设置默认/范围):
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 权限绑定:
# 创建给租户的用户/ServiceAccount,并只授予其 namespace 读写权限
kubectl create rolebinding dev-user --clusterrole=edit --user=alice -n dev
⑥ NetworkPolicy(网络层隔离,需 CNI 支持):控制不同 Namespace / Pod 之间的流量放行。
查看与切换默认命名空间:
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. 怎么用它:
① 查看日志
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 交互
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/连通
③ 更完整的调试手段
- describe:
kubectl 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 排查链路。
Q144. 如何管理集群的节点?
1. 是什么:节点管理指对集群中的 Node 进行查看、标记、调度控制、添加/删除、维护等操作,常用 kubectl 命令管理节点的 标签、污点/容忍、cordon/drain、状态与 kubelet 配置。
2. 为什么用它:节点是承载 Pod 的物理/虚机,日常运维需要"让某节点不接新 Pod、维护时排空已有 Pod、给特定节点打标用于调度、下线不再用的节点"。掌握节点管理是集群容量规划、故障隔离、版本升级的基础。
3. 怎么用它:
查看节点:
kubectl get nodes # 列出所有节点(状态/角色/版本)
kubectl get nodes -o wide # 显示节点 IP、容器运行时等
kubectl describe node k8s-node01 # 查看节点详情(资源、污点、标签、事件)
kubectl top node # 查看节点资源占用
标记与调度控制:
# 给节点打标签(配合 nodeSelector / nodeAffinity 调度)
kubectl label node k8s-node01 disktype=ssd
kubectl label node k8s-node01 disktype- # 删除标签(加 -)
# 污点/容忍:阻止普通 Pod 调度到某节点
kubectl taint node k8s-master01 key=value:NoSchedule # 添加污点
kubectl taint node k8s-master01 key=value:NoSchedule- # 删除污点(末尾 -)
# cordon:标记节点"不可调度"(新 Pod 不再来,已在跑的保持)
kubectl cordon k8s-node01
# drain:排空节点(先 cordon,并驱逐其上 Pod,常用于升级/下线)
kubectl drain k8s-node01 --ignore-daemonsets --delete-emptydir-data
# uncordon:恢复可调度
kubectl uncordon k8s-node01
添加/删除节点:
# 添加:给新节点安装 kubelet/kubeadm/kubectl,再用 kubeadm join 加入
kubeadm join ... --cri-socket unix:///var/run/cri-dockerd.sock
# 下线:先 drain 排空,再删除该 Node 对象
kubectl delete node k8s-node02
4. 使用场景:节点升级/维护(cordon+drain)、下线故障节点、按标签做专用节点调度、节点角色隔离(Master 加 NoSchedule 污点)。面试关键:区分 cordon 与 drain——cordon 只"不再接收新 Pod",drain 会"排空已运行 Pod",两者常用于维护/升级前的顺序操作;并会打标签/污点来精细控制调度。
Q145. 如何备份和恢复 etcd 集群?
1. 是什么:etcd 是 Kubernetes 的集群状态数据库,存所有对象、配置、证书等。备份/恢复都用 snapshot(快照)命令:备份 snapshot save 把 etcd 状态导出为快照文件,恢复 snapshot restore 把快照还原到 etcd 数据目录。
⚠️ 版本差异(重要):在 etcd 3.5+ / 3.6 中,
snapshot相关的子命令已从etcdctl迁移到独立工具etcdutl(官方已提示etcdctl snapshot ...废弃)。因此分两版:
- 新版(3.5+/3.6,建议):用
etcdutl snapshot save/restore/status。- 旧版(3.4 及之前,兼容):用
etcdctl snapshot save/restore/status。
注意:endpoint health、get/put等在线操作仍用etcdctl;只有 snapshot 这类"离线操作数据文件"的命令用etcdutl。
2. 为什么用它:etcd 丢失=集群元数据丢失,集群基本不可用。定期备份 etcd 是**灾难恢复(DR)**的最后防线,能应对节点故障、误删对象、etcd 数据损坏等场景——没有备份就是"裸奔"。
3. 怎么用它(下面给出新版 etcdutl 与 旧版 etcdctl 两个版本)。
① 确认 etcd 信息(Master 上,kubeadm 部署的在 /etc/kubernetes/manifests/etcd.yaml):
# 在线检查 etcd 健康 —— 无论新旧版都用 etcdctl
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
endpoint health
③ 备份(snapshot save):
etcdutl(新版,etcd 3.5+/3.6):
ETCDCTL_API=3 etcdutl --endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
snapshot save /backup/etcd-$(date +%Y%m%d).db
# 查看快照(etcdutl)
ETCDCTL_API=3 etcdutl snapshot status /backup/etcd-$(date +%Y%m%d).db
etcdctl(旧版 / 兼容,etcd 3.4 及之前):把 etcdutl 换成 etcdctl 即可。
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
snapshot save /backup/etcd-$(date +%Y%m%d).db
# 查看快照(etcdctl)
ETCDCTL_API=3 etcdctl snapshot status /backup/etcd-$(date +%Y%m%d).db
④ 恢复(snapshot restore):
etcdutl(新版,etcd 3.5+/3.6):
# 停掉 etcd(对 kubeadm 部署可先停止 kubelet,或直接清理静态 Pod)
# 恢复到新的数据目录(不建议直接覆盖原目录)
ETCDCTL_API=3 etcdutl snapshot restore /backup/etcd-20260828.db \
--data-dir=/var/lib/etcd-restore \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
etcdctl(旧版 / 兼容,etcd 3.4 及之前):同样把 etcdutl 换成 etcdctl。
ETCDCTL_API=3 etcdctl snapshot restore /backup/etcd-20260828.db \
--data-dir=/var/lib/etcd-restore \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key
- 恢复后,把 etcd 的
data-dir指向/var/lib/etcd-restore,重启 etcd。 - 生产常配合定时备份(cron 或 Velero),并异地/对象存储保存快照。
💡 新版本命令提示:在较新二进制中,
etcdctl snapshot ...会直接打印Deprecated: Use "etcdutl snapshot ..." instead的提示,请以etcdutl为准。
⑤ 工具化方案:用 Velero(备份整个集群,含 etcd 与 PV 数据)做更高层的备份恢复。
4. 使用场景:灾备演练、etcd 数据损坏/误删、集群迁移、升级前快照。面试关键:背出 snapshot save(备份)与 snapshot restore(恢复)+ 那四个证书参数(--cacert/--cert/--key/--endpoints);并答出"新版用 etcdutl、旧版用 etcdctl(3.5+ 已把 snapshot 命令迁移到 etcdutl)“这个版本差异,以及"恢复要换 data-dir、生产要定时 + 异地保存”。同时强调 etcd 备份是集群灾难恢复的兜底。
Q146. Pod 一直处于 Pending 状态,如何排查?
1. 是什么:Pending 表示 Pod 已被 API 接受,但还没被调度到节点上运行(或调度后在等镜像/等待中)。它是调度失败的典型表现,通常由”没有合适的节点可以放”导致。
2. 为什么用它:Pod 卡在 Pending 会一直不工作,服务不就绪。Pendinning 常见根因集中在资源不足、节点选择/亲和不满足、污点不匹配、镜像拉取问题、端口冲突等,按序排查能快速定位是"哪个约束拦住了调度"。
3. 怎么用它(排查流程):
# 1) 看 Pod 状态与事件(最重要)
kubectl get pod <pod-name> -o wide # 确认 Pending + 所在命名空间/节点
kubectl describe pod <pod-name> # 看 Events 里的失败原因(关键!)
常见原因与对策:
| 原因 | 现象/事件 | 解决 |
|---|---|---|
| 资源不足 | 0/1 nodes are available: Insufficient cpu | 扩容节点 / 减小 requests / 清空闲 Pod |
| 节点选择不匹配 | 0/1 nodes available: node(s) didn't match node selector | 修正 nodeSelector/nodeAffinity / 给节点打正确标签 |
| 污点不匹配 | 0/1 nodes available: node(s) didn't tolerate ... | 给 Pod 加对应 toleration / 去掉节点污点 |
| 端口冲突 | PodFitsHostPorts 相关事件 | 避免 hostPort 冲突 / 换端口 |
| 镜像拉取 | image pull back off / ErrImagePull | 检查镜像名/仓库/认证 |
# 2) 看节点是否有足够资源(Pendinning 常因资源不够)
kubectl get nodes # 查看各节点分配/容量
kubectl describe node <node> | grep -A5 Allocatable # 看可分配资源
# 3) 看是否整体无节点可调度 / 节点状态
kubectl get nodes -o wide
kubectl cluster-info
4. 使用场景:新部署 Pod 一直 Pending;排障重点看 describe 的 Events。面试关键:第一反应 kubectl describe pod 看事件;再按"资源不够、节点/亲和不匹配、污点不容忍、端口冲突、镜像拉取失败"五类原因逐一排查;并知道 0/3 nodes are available 就是"没有任何节点满足调度要求"。
Q147. Pod 一直处于 ContainerCreating 状态,如何排查?
1. 是什么:ContainerCreating 表示 Pod 已调度到节点并建立了 Pod 层,但容器还没创建成功,卡在拉镜像、挂卷、启动容器或网络(CNI)配置等阶段。
2. 为什么用它:ContainerCreating 比 Pending 更进一步(节点已确定),说明问题出在节点上的容器运行时层。常见根因:镜像拉取慢/失败、CNI 网络插件问题、存储卷挂载失败、权限/端口配置错误,逐层排查能定位到 kubelet/containerd 侧。
3. 怎么用它(排查流程):
# 1) 看 Pod 事件(同样先 describe)
kubectl describe pod <pod-name> # Events 里看 ContainerCreating 的具体报错
# 2) 看节点上容器运行时与 kubelet 日志
journalctl -u kubelet -f # 节点上跟踪 kubelet 日志
journalctl -u containerd -f # 若是 containerd
journalctl -u cri-docker -f # 若是 cri-docker
# 3) 看镜像拉取状态
kubectl get pods -o jsonpath='{.status.containerStatuses}' <pod-name>
常见原因:
| 原因 | 解决 |
|---|---|
| 镜像拉取慢/失败 | 检查网络/镜像加速器 / 提前去节点 docker pull 预拉 |
| CNI 网络插件未就绪 | 检查 Calico/flannel 是否 Running、crictl/kubelet 网络配置 |
| 挂载卷失败 | 检查 PV/PVC 是否 Bound、StorageClass、mount 权限 |
| sandbox/pause 镜像问题 | 检查该节点是否已导入 pause 镜像、版本是否一致 |
| 容器运行时权限/参数 | 检查 kubelet 的 --cri-socket、cgroup 驱动是否一致 |
| cgroup 驱动不一致 | 确保 docker/containerd 用 systemd 且与 kubelet 一致 |
# 在节点上直接用 crictl 查看容器运行时状态
crictl ps -a
crictl images
# 查看节点网络插件 Pod 是否正常
kubectl get pod -n kube-system
4. 使用场景:Pod 调度成功但容器起不来;重点查镜像与 CNI 网络。面试关键:先 describe 看事件,再去节点看 kubelet/containerd 日志;按"镜像拉取、CNI 网络、卷挂载、pause 镜像、cgroup/CRI 配置"五类排查;并强调"容器运行时(cri-docker/containerd)的 socket 与 cgroup 驱动必须和 kubelet 对齐"。
Q148. Pod 不断重启,如何查看日志和排查原因?
1. 是什么:Pod 不断重启(典型状态为 CrashLoopBackOff)表示容器启动后又崩溃,被 kubelet 反复重启,形成一个"崩溃-重启-再崩溃"的死循环。
2. 为什么用它:CrashLoopBackOff 是最常见的 Pod 故障,通常源于应用启动报错、启动命令/配置错误、OOMKilled、liveness 探针失败等"容器内本身的错误"。关键是拿到崩溃那次的日志(而非重启后空白的新日志)才能定位。
3. 怎么用它(排查流程):
# 1) 看容器重启次数与状态
kubectl get pod <pod-name> # RESTARTS 列看重启次数
kubectl describe pod <pod-name> # 看 Last State / Reason(如 OOMKilled、Error)
# 2) 看"崩溃前"的日志(关键!重启后的当前日志可能为空)
kubectl logs <pod-name> --previous # 查看上次崩溃的日志
kubectl logs <pod-name> -c <container> --previous # 多容器指定容器
kubectl logs <pod-name> --tail=50 # 看最近 50 行
kubectl logs <pod-name> --timestamps # 带时间戳便于定位时序
常见崩溃原因:
| 原因 | 表现 | 排查/解决 |
|---|---|---|
| 启动命令/入口错误 | CMD/ENTRYPOINT 不对、缺少依赖 | 看 kubectl logs --previous 的报错 |
| 配置/环境变量缺失 | 连接不到 DB、读不到配置 | 检查 ConfigMap/Secret、env |
| OOMKilled | Status 为 OOMKilled | 提高内存 limits / 优化应用内存 |
| liveness 探针失败 | Liveness probe failed | 调大 initialDelay/failureThreshold / 修探针路径 |
| 端口/权限 | 端口被占用、无权限 | 检查端口、容器用户/权限 |
| 资源不足 | 启动即被调度问题 | 检查 requests/节点资源 |
# 应用启动后立即崩溃,可以利用 debug 临时容器进入排查
kubectl debug -it <pod-name> --image=busybox -- sh
4. 使用场景:任何 CrashLoopBackOff 的定位;核心工具是 --previous。面试关键:强调 kubectl logs --previous 看崩溃前日志;再按"启动报错、配置缺失、OOMKilled、探针失败"排查;点出 describe 的 Last Reason(如 OOMKilled)能快速定性,比只看重启次数更准。
Q149. 如何实现 Kubernetes 的权限控制?
1. 是什么:Kubernetes 权限控制基于 RBAC(基于角色的访问控制),核心三要素:Subject(主体:User/Group/ServiceAccount)→ Role/ClusterRole(角色:权限集合)→ RoleBinding/ClusterRoleBinding(绑定:把角色授予主体)。管理员用 RBAC 精确控制"谁能对哪些资源做什么操作"。
2. 为什么用它:K8s 默认所有操作都是白名单,需要明确授权。若不做权限隔离,任何能访问 apiserver 的人都拥有集群管理权,极其危险。RBAC 让不同团队、用户、ServiceAccount 各司其职、最小权限,是集群安全的基础。
3. 怎么用它(RBAC 四件套):
# 1) 创建 ServiceAccount(给 Pod/CI 用的身份)
kubectl create serviceaccount ci-robot
# 2) 创建角色(Namespace 内生效用 Role;集群级用 ClusterRole)
kubectl create role pod-reader --verb=get,list,watch --resource=pods
# 3) 创建集群角色(集群范围,可管理 node/namespaces 等)
kubectl create clusterrole cluster-admin --verb=* --resource=*
RBAC 四要素的关系:
- Subject:谁能操作(用户、组、ServiceAccount)。
- Role / ClusterRole:能做什么(一组
verb + resource规则)。 - RoleBinding / ClusterRoleBinding:把角色授予主体(
roleRef+subjects)。 - 区别:
Role/RoleBinding授权某个命名空间;ClusterRole/ClusterRoleBinding授权整个集群(所有命名空间)。
# 示例:把"pod-reader"角色绑定给 ci-robot 这个 SA(在 dev 命名空间)
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ci-read-pods
namespace: dev
subjects:
- kind: ServiceAccount
name: ci-robot
namespace: dev
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
常用校验命令:
kubectl auth can-i list pods --as=ci-robot -n dev # 模拟某用户是否有权限
kubectl get role,rolebinding,clusterrole,clusterrolebinding -A # 查看授权
其他权限机制(补充):
- ServiceAccount + 挂载 token:Pod 内应用用 SA 访问 API。
- NetworkPolicy:网络层访问控制(不让 Pod 任意互访)。
- 准入控制器(Admission Control):如 ResourceQuota、PodSecurityPolicy(已被 Pod Security 替代)。
- kubectl config / kubeconfig:用
--user指定不同用户身份。
4. 使用场景:给不同团队/CI 账号最小权限、限制某个用户只能读 Pod、隔离多租户。面试关键:背出 RBAC 四件套"Subject + Role/ClusterRole + RoleBinding/ClusterRoleBinding + API 规则(verb/resource)";说明 Role 限命名空间、ClusterRole 限整个集群;并知道 kubectl auth can-i 验证权限。
Q150. Kubernetes 的资源服务质量(QoS)有哪几类?如何保证关键服务的资源?
1. 是什么:QoS(Quality of Service,服务质量) 是 K8s 根据容器是否声明了资源 requests/limits,把 Pod 划分为三档:Guaranteed(有保证)→ Burstable(有波动)→ BestEffort(尽力而为),档次越高,在资源紧张时越不容易被驱逐。
2. 为什么用它:当节点内存不足触发**驱逐(eviction)**时,K8s 会优先杀掉低优先级(低 QoS)的 Pod,以保护关键业务。合理设置 QoS 能让核心服务(如数据库、网关)在资源紧张时存活,而让临时/批处理 Pod 先被清理,是"资源保障 + 合理腾挪"的关键。
3. 怎么用它(三档判定规则):
| QoS 等级 | 判定条件 | 特点 | 淘汰优先级 |
|---|---|---|---|
| Guaranteed | 每个容器都设置了 limits 且等于 requests(CPU/内存均有) | 最稳定,最不容易被驱逐 | 最低 |
| Burstable | 容器设置了 requests 或 limits(但非全部 = 最高档) | 大多应用属于这一档 | 中间 |
| BestEffort | 容器未设置任何 requests/limits | 资源无保证,最容易被驱逐 | 最高(最先被杀) |
# ① Guaranteed:requests == limits(最稳,保护关键服务)
resources:
requests: { cpu: "1", memory: "2Gi" }
limits: { cpu: "1", memory: "2Gi" }
# ② Burstable:设置了 requests 但 limits 更大(通常应用)
resources:
requests: { cpu: "250m", memory: "256Mi" }
limits: { cpu: "500m", memory: "512Mi" }
# ③ BestEffort:什么都不写(临时/批处理 Pod)
# 不写 resources
保证关键服务的资源(进一步手段):
- 高 QoS(Guaranteed):给关键服务设
requests == limits。 - PriorityClass(优先级类):结合 QoS,用高优先级 + 低 QoS 会被驱逐时先保高优先级;驱逐顺序 = 先低 QoS,再低 PriorityClass。
- LimitRange / ResourceQuota:命名空间层面默认给 Pod 定 requests/limits,避免误建 BestEffort。
- 节点预留与 Pod 优先级:给节点
system-reserved、kube-reserved预留系统资源。 - 亲和/反亲和 + 污点:把关键服务调度到资源充足的专属节点。
4. 使用场景:保护关键无状态/有状态服务、合理规划临时 Pod 的淘汰顺序。面试关键:背出三档"Guaranteed(requests=limits,最稳)→ Burstable(有 requests/limits 但不等,最常见)→ BestEffort(无 requests/limits,最先被驱逐)“;并说"用 Guaranteed + PriorityClass + LimitRange 保护关键服务”。
Q151. 如何优化 Kubernetes 的调度?
1. 是什么:调度优化指通过合理配置资源、污染/容忍、亲和/反亲和、PriorityClass、节点选择、调度器配置等,让 Pod 被调度到"更合适"的节点,实现资源均衡、热节点分散、关键服务保障、性能提升。
2. 为什么用它:默认调度器只按"资源够不够"做基础判断,可能导致热点节点、资源浪费、关键服务与高负载混跑等问题。优化调度能提升集群利用率、稳定性与性能,减少 Pending 和资源争抢。
3. 怎么用它(常用优化手段):
# ① 资源 requests 合理设置:让调度器有足够依据,避免把多个 Pod 塞到同一节点
resources:
requests: { cpu: "250m", memory: "256Mi" }
# ② 节点亲和(nodeAffinity):把 Pod 调度到特定节点(如 GPU/SSD 专用节点)
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- { key: disktype, operator: In, values: ["ssd"] }
# ③ 污点 + 容忍:默认 Master 有 NoSchedule 污点(普通 Pod 不去);也可用污点隔离专用节点
# 给关键工作节点加污点,仅允许带容忍的关键服务上去
# ④ Pod 亲和/反亲和:让 Pod 聚合同一节点(性能)或分散到不同节点(高可用/容灾)
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels: { app: db }
topologyKey: kubernetes.io/hostname # 让 db 副本分散到不同节点
# ⑤ PriorityClass:高优先级 Pod 优先生成,低优先级(批处理)可被抢占
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata: { name: high }
value: 1000000
globalDefault: false
# ⑥ 资源均衡(BalancedResourceAllocation)等优选策略,在 kube-scheduler 配置中调整
# ⑦ 自定义调度器 / 多调度器(default-scheduler 之外再起一个,Pod 用 schedulerName 指定)
# 查看调度情况
kubectl describe pod <pod> | grep -i node
kubectl get happenings | grep -i "successfully assigned"
4. 使用场景:让关键服务分散到不同节点避免单点、让 GPU 任务到 GPU 节点、避免热点节点、保护核心业务不被抢占。面试关键:按"资源设置 + 亲和/反亲和 + 污点容忍 + 优先级 + 多调度器"分层讲;重点说清"反亲和(podAntiAffinity)用拓扑键把副本分散到不同节点实现高可用";并强调合理 requests 是调度质量的前提。
Q152. 如何限制用户和命名空间的资源配额?
1. 是什么:通过 ResourceQuota(资源配额) 限制某个命名空间内可创建的资源总量(CPU/内存/PVC/对象数量等),用 LimitRange(范围限制) 给命名空间内每个 Pod/容器设定默认与最大/最小的资源值。二者配合,在多租户场景下防止某个团队/用户"滥用"集群资源。
2. 为什么用它:不加限制时,某个团队可能创建大量 Pod/请求过量资源,耗尽整个集群资源、影响其他租户。配额和范围限制把"资源上限"和"单对象默认值"固定下来,实现多租户的资源公平与隔离,防止"一个 namespace 吃垮集群"。
3. 怎么用它:
① ResourceQuota(限总量):
apiVersion: v1
kind: ResourceQuota
metadata:
name: dev-quota
namespace: dev
spec:
hard:
requests.cpu: "20" # 命名空间内所有 Pod CPU requests 总和上限
requests.memory: "40Gi"
limits.cpu: "40"
limits.memory: "80Gi"
count/pods: "100" # Pod 总数上限
count/deployments.apps: "20"
persistentvolumeclaims: "10" # PVC 数量上限
② LimitRange(设单对象默认/范围):
apiVersion: v1
kind: LimitRange
metadata:
name: dev-lr
namespace: dev
spec:
limits:
- type: Container # 对每个容器生效
default: { cpu: "500m", memory: "512Mi" } # 未写时的默认 limits
defaultRequest: { cpu: "250m", memory: "256Mi" } # 未写时的默认 requests
max: { cpu: "4", memory: "8Gi" } # 上限
min: { cpu: "50m", memory: "64Mi" } # 下限
- type: PersistentVolumeClaim
max: { storage: "20Gi" }
③ 资源配额与限额的应用顺序:
# 创建配额与范围限制到命名空间
kubectl apply -f dev-quota.yaml
kubectl apply -f dev-lr.yaml
# 查看
kubectl get resourcequota,limitrange -n dev
# 验证:当请求超过配额时会报错(如 "exceeded quota")
kubectl apply -f big-deploy.yaml -n dev # 会因超配额被拒
④ 结合 RBAC 与 namespace 隔离:给不同租户的 ServiceAccount/Role 仅授权自己 namespace 的权限 + 对该 namespace 建 ResourceQuota,实现"权限 + 资源"双重隔离。
4. 使用场景:多团队/多租户共用集群、限制某项目资源规模、防止失控的批量部署。面试关键:区分 ResourceQuota(管"命名空间总量")与 LimitRange(管"单个容器默认/范围");说清"配额从总量卡上限、范围限制从单对象兜底默认值",二者配套使用实现多租户资源隔离。
Q153. 解释 Sidecar 模式及其应用场景。
1. 是什么:Sidecar(边车)模式是在 K8s 中让主容器旁边运行一个辅助容器(sidecar),二者同属一个 Pod,共享网络命名空间(localhost 互通)与存储卷,但职责分离——主容器做核心业务,sidecar 做辅助功能(日志采集、代理、监控、配置同步等)。
2. 为什么用它:把"跨业务的横切关注点"(日志、链路、代理、熔断、监控)抽成独立容器,而不需要修改主应用代码,从而做到业务容器"纯净"、辅助能力可独立扩展/升级/复用,也便于统一管理和实现服务网格(Service Mesh)。
3. 怎么用它(同 Pod 多容器):
apiVersion: v1
kind: Pod
metadata:
name: app-with-sidecar
spec:
containers:
- name: app # 主业务容器
image: myapp:v1
ports: [ { containerPort: 8080 } ]
- name: log-sidecar # 边车容器
image: fluentd # 收集日志
volumeMounts:
- { name: log, mountPath: /var/log/myapp }
- name: proxy # 也可再放一个代理/边车
image: envoy
volumes:
- name: log
emptyDir: {}
核心要点:
- 同 Pod 共享网络:sidecar 与主容器通过
localhost互访(共享 Pod 网络命名空间),且端口不能冲突。 - 共享存储:sidecar 通过 volume 与主容器共享数据(如日志目录)。
- 生命周期与 Pod 一致:sidecar 随 Pod 创建/销毁,一起调度到同一节点。
- 服务网格典型应用:Istio/Linkerd 把 Envoy 作为 sidecar 自动注入,做流量治理、mTLS、可观测性。
典型应用场景:
| 场景 | sidecar 作用 |
|---|---|
| 日志采集 | fluentd/filebeat 读取主容器的日志并转发到 ELK |
| 服务网格 | Envoy sidecar 做代理、熔断、mTLS 加密 |
| 监控/指标 | 采集应用指标(prometheus-exporter) |
| 配置同步 | 从配置中心拉取并热更新配置 |
| SSH/调试/代理 | 提供调试 shell、入站/出站代理 |
| 数据库/缓存代理 | 本地代理连接池、读写分离 |
4. 使用场景:微服务统一接入日志/监控/服务网格、给旧应用无侵入加能力。面试关键:一句话"Sidecar 是与主容器同 Pod 共享网络和存储的辅助容器,把日志/代理/监控等横切功能独立出来’**;强调"共享 localhost 网络 + 共享卷",并举例 Istio 的 Envoy 注入是典型场景。
Q154. 如何保障 Kubernetes 集群的安全?
1. 是什么:Kubernetes 安全是多维度纵深防御,覆盖:访问控制(RBAC/认证/授权)→ 镜像安全 → 运行时安全 → 网络隔离(NetworkPolicy)→ 秘钥管理 → 审计与监控等层面。从"谁能进集群、哪些镜像能跑、Pod 间能否互访、敏感信息是否泄露"几个关键点加固。
2. 为什么用它:K8s 集群是核心基础设施,一旦被攻破影响整个应用。默认配置通常不够安全(如宽松 RBAC、无网络策略、弱口令、常见默认配置),必须按安全基线加固,防横向渗透、防滥用、防数据泄露。
3. 怎么用它(各层安全措施):
① 访问控制(认证 + 授权):
- 用 RBAC 最小权限授权(避免给宽泛的
cluster-admin)。 - 严格管理 ServiceAccount、证书、kubeconfig 的颁发与轮换。
- 用 Admission Controller / OIDC 等对接企业身份认证。
② 镜像与供应链安全:
- 使用私有可信仓库(Harbor),启用镜像签名/扫描(Trivy、Docker image scan)。
- 用 ImagePolicyWebhook / Admission 只允许可信镜像运行。
- 不拉公共不可信镜像;加
imagePullSecrets与alwaysPullImages(强制校验)。
③ 运行时安全:
- Pod 应以非 root(runAsNonRoot)、只读根文件系统(readOnlyRootFilesystem)、**drop 特权(capabilities)**运行。
- 使用 Pod Security Admission(PSA,替代 PodSecurityPolicy):
privileged/baseline/restricted三档限制。 - 安全上下文(securityContext):限制资源、禁用特权容器、限制 syscall。
securityContext:
runAsNonRoot: true
runAsUser: 1000
allowPrivilegeEscalation: false
capabilities: { drop: ["ALL"] }
readOnlyRootFilesystem: true
④ 网络隔离(NetworkPolicy):默认 Pod 可任意互访,用 NetworkPolicy 控制"谁能访问谁"(默认拒绝 + 白名单放行),减少横向渗透面。
⑤ 秘钥管理:用 Secret + 加密(etcd 加密、KMS、外部 secret 如 vault/sealed-secrets),避免明文存储。
⑥ 审计与监控:
- 开启 API 审计日志(audit log) 记录敏感操作。
- Kube-bench(按 CIS 基线检查集群安全)。
- Falco / 运行时安全 检测异常行为。
- 监控集群异常(apiserver 异常访问、异常 Pod)。
4. 使用场景:生产集群安全加固、等保要求、安全检查。面试关键:分层列出"访问控制(RBAC)→ 镜像供应链 → 运行时非 root → 网络隔离 → 秘钥加密 → 审计监控";重点讲 NetworkPolicy 默认拒绝、Pod Security Admission 限制特权、rbac 最小权限,这几个是 K8s 安全的抓手。
Q155. 如何实现跨集群的应用部署和故障转移?
1. 是什么:跨集群部署与故障转移指在多个 Kubernetes 集群(如主备集群、多可用区/多云集群)上部署同一应用,并在集群故障时自动切换到存活集群,实现更高的可用性(多集群容灾)与地区级容灾。常用手段:GitOps 多集群配置分发、kubeconfig 多集群切换、DNS/负载均衡引流、Velero/跨集群资源同步等。
2. 为什么用它:单集群存在单点故障(集群级宕机、region 故障、etcd 损坏)。跨集群部署 + 故障转移能在集群级别故障时保障业务不中断,是**生产高可用/容灾(DC 双活、跨地域容灾)**的进阶要求。
3. 怎么用它(常见方案):
① 多集群配置分发(GitOps / 多集群管理):
- 用 Argo CD / Flux / KubeVela / Rancher 把同一套 yaml 部署到多个集群(通过多集群上下文),实现配置统一、声明式发布。
- 用 Helm 管理多环境/多集群的模板。
② 多集群切换(kubeconfig / kubectl ctx):
kubectl config get-contexts # 查看所有集群上下文
kubectl config use-context prod-a # 切换集群
kubectl get pods --context prod-b # 指定集群
# 用 kubectl 别名/脚本管理多集群;或用 kubectx 工具快速切换
③ 故障转移(流量/入口切换):
- DNS 切换:把应用域名解析切换到存活集群的负载均衡入口(如云 LB / Ingress / External-DNS)。
- 全局负载均衡(GSLB):智能 DNS / 云 CDN 做地域性、健康检查驱动的流量引导。
- 多云/多集群 LB(如 Ingress 多播、服务网格多集群、
service.clusterIP跨集群)做流量灾备。
④ 数据层跨集群同步:
- 数据库主从/异地(如 MySQL 主备、跨 region 复制)。
- 存储与卷:用 Velero / Kasten 跨集群备份恢复;对象存储多region复制。
⑤ 自动故障转移(主动切换为主):
# 用 GitOps 工具(如 Argo CD)配合集群健康检查,实现"主集群故障 → 切到备集群"的自动化
# 或:监控集群健康(Prometheus/uptime),触发切换脚本/更新 DNS 记录
⑥ 更多理念:
- 服务网格多集群(Istio multicluster) 实现跨集群服务发现与流量灰度。
- KubeFed / Karmada:多集群管理平台,统一管理多个集群的部署与策略(Karmada 较主流)。
4. 使用场景:同城双活 / 跨区域容灾 / 多云备份、集群级别故障演练。面试关键:按"配置分发(GitOps/Argo CD + Hel)→ 多集群切换(kubeconfig/context)→ 流量切换(DNS/GSLB/LB)→ 数据同步(DB 主备 + Velero 备份)→ 自动故障转移(健康检查驱动切换)"讲;并提到 Karmada / Argo CD / GSLB 是跨集群与故障转移的常用工具。
更多推荐
所有评论(0)