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 骨架------hosts、become、tasks(装包/配置/启服务)、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-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. 怎么用它:
① 筛选(标签匹配):
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 分位数
- 常用聚合函数:
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):
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,真正创建运行容器的引擎 |
- 数据流一句话:
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。 - 使用示例:
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}') :Waiting、Running、Terminated。 - 生命周期钩子/探针 :
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 种重启策略 ;重点强调 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 一体):
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 的五大结构 (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. 怎么用它(配置 + 命令):
配置策略:
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 重建数据仍在。常用类型有 emptyDir、hostPath、PersistentVolume(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-0、db-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),再配合 ResourceQuota 、LimitRange 、RBAC 、NetworkPolicy 实现资源与权限的隔离。
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/连通
③ 更完整的调试手段
- 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 排查链路。