K8s 场景面试题(二)
涵盖 Kubernetes 核心概念、网络排查、CI/CD、日志收集、GPU 运维等 24 道面试题的详细解答,适用于 K8s 运维/云原生工程师面试准备。
本文整理了 K8s 运维工程师面试中常见的 24 道问题,涵盖核心概念、网络、存储、CI/CD、可观测性、GPU 运维等多个维度,并给出详细的回答思路和示例。
1、K8s 的 Service 和 Ingress 的区别
| 维度 | Service | Ingress |
|---|---|---|
| 工作层级 | L4(传输层,TCP/UDP) | L7(应用层,HTTP/HTTPS) |
| 作用 | 集群内服务发现和负载均衡 | 外部流量路由到集群内服务,基于域名/路径 |
| 访问方式 | ClusterIP/NodePort/LoadBalancer | 需要 Ingress Controller(如 Nginx、Traefik) |
| 典型场景 | 微服务间通信、暴露单个服务 | 多服务共享一个入口、SSL 终止、路径路由 |
| 配置示例 | type: LoadBalancer + selector | rules.host + paths.backend |
一句话总结:Service 解决"服务间怎么找到彼此",Ingress 解决"外部用户怎么访问集群内的多个服务"。
2、Secret 存储在 K8s 哪里
etcd - K8s 所有数据(包括 Secret)都持久化存储在 etcd 中。
安全机制:
- 静态加密:etcd 中的 Secret 数据默认是 base64 编码(注意不是加密),生产环境应启用 etcd 加密 providers(如
aescbc或kms) - 运行时:kubelet 会将 Secret 挂载到 Pod 的文件系统或作为环境变量
- 内存中:kube-apiserver 缓存 Secret,kubelet 在节点上缓存(
/var/lib/kubelet/pods/)
查看方式:
etcdctl get /registry/secrets/default/my-secret3、ConfigMap 怎么应用到 Pod 中,如果有二进制的文件
三种使用方式:
- 环境变量注入
envFrom:
- configMapRef:
name: my-config- Volume 挂载(最常用,支持热更新)
volumes:
- name: config
configMap:
name: my-config- 命令行参数
args: ["--config=$(CONFIG_KEY)"]二进制文件处理: ConfigMap 不适合存二进制文件(会被 UTF-8 编码损坏),应该使用:
- Secret:
type: Opaque,以 base64 存储二进制数据 - Volume 挂载 binaryData:ConfigMap 支持
binaryData字段(1.10+) - 更推荐:使用 Init Container 下载二进制文件,或挂载 PV/对象存储
4、K8s 遇到过什么问题
准备 2-3 个真实案例,建议覆盖不同层面:
案例 1:资源相关
- Pod OOMKilled,但 limits 设置合理 → 发现是内存泄漏 + metrics-server 未正确配置导致 HPA 未生效
案例 2:网络相关
- 跨 Node Pod 无法通信 → CNI 插件(Calico)IP 池耗尽,或 iptables 规则被 Docker 覆盖
案例 3:存储相关
- PV 挂载失败 → CSI 驱动版本不兼容,或 fstype 不匹配
回答结构:现象 → 排查过程 → 根本原因 → 解决方案 → 预防措施
5、K8s 网络问题一般怎么排查
完整排查流程图:
┌─────────────────────────────────────────────────────────────────┐
│ 第一层:Pod 自身状态 │
│ kubectl get pod <pod> -o wide │
│ kubectl describe pod <pod> # 看 Events 是否有网络相关错误 │
└─────────────────────────┬───────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 第二层:容器网络命名空间 │
│ kubectl exec -it <pod> -- sh │
│ 检查:IP 地址、路由表、DNS 配置、网卡状态 │
│ cat /etc/resolv.conf # 看 nameserver 是否是 coredns │
└─────────────────────────┬───────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 第三层:同节点 Pod 通信 │
│ 进入 Pod A,ping Pod B 的 IP(同节点) │
│ 如果不通 → CNI 插件没正确创建 veth pair 或网桥配置错误 │
└─────────────────────────┬───────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 第四层:跨节点 Pod 通信 │
│ 检查: │
│ 1. CNI 插件状态(Calico/Flannel/Cilium) │
│ kubectl get pods -n kube-system | grep calico │
│ 2. 节点路由表:ip route │
│ 3. Overlay 网络封装是否正常(VXLAN/IPIP) │
│ 4. 安全组/防火墙是否放行 Pod CIDR │
└─────────────────────────┬───────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 第五层:Service 访问 │
│ 检查: │
│ 1. Service Endpoints 是否有 Pod IP │
│ kubectl get endpoints <svc> │
│ 2. kube-proxy 模式(iptables/IPVS) │
│ kubectl logs -n kube-system kube-proxy-<xxx> │
│ 3. iptables 规则是否创建 │
│ iptables -t nat -L KUBE-SERVICES │
└─────────────────────────┬───────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────┐
│ 第六层:外部访问 │
│ 检查: │
│ 1. NodePort:节点安全组是否放行端口 │
│ 2. LoadBalancer:云厂商 LB 是否绑定正确 │
│ 3. Ingress:Controller 是否运行、规则是否匹配 │
│ kubectl get ingress │
│ kubectl logs -n ingress-nginx <controller-pod> │
└─────────────────────────────────────────────────────────────────┘常用诊断命令:
# 1. 网络连通性测试
kubectl run test --image=nicolaka/netshoot --restart=Never --rm -it -- /bin/bash
nslookup kubernetes.default # 测试 DNS
tcpdump -i any -n port 53 # 抓包看 DNS 请求
# 2. CNI 插件诊断(Calico 示例)
calicoctl node status
calicoctl get ippool -o wide
calicoctl ipam show
# 3. 查看 Service 后端
iptables -t nat -L KUBE-SEP-XXXXX # 看具体的 Service Endpoint 规则
ipvsadm -Ln # 如果使用 IPVS 模式
# 4. 检查网络策略是否阻挡
kubectl get networkpolicy6、有个服务启动需要 5 分钟,服务要高可用需要哪些架构和组件
问题核心:启动慢 + 高可用
架构设计:
-
Pod 层面
startupProbe:设置较长的启动探针(> 5 分钟),避免被误杀preStophook:优雅停机,保证连接排空terminationGracePeriodSeconds:延长终止时间
-
副本层面
- HPA:基于 CPU/自定义指标自动扩缩容
- PDB:PodDisruptionBudget,保证最小可用副本数
- 多副本预热:提前启动新 Pod,避免冷启动延迟
-
流量层面
- Readiness Probe:就绪后才接收流量
- 滚动更新策略:
maxSurge: 1, maxUnavailable: 0 - 连接池 + 重试机制:客户端配置重试和熔断
-
架构层面
- 蓝绿部署:准备一套完整的热备环境
- 预热 Job:定时预热缓存、连接池
- 分级启动:核心功能先启动,非核心异步加载
7、蓝绿部署和滚动更新在切换过程中用哪个
根据场景选择:
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 常规迭代 | 滚动更新 | 资源占用少,自动化程度高 |
| 重大版本/数据库变更 | 蓝绿部署 | 可快速回滚,零停机 |
| 需要验证生产流量 | 金丝雀发布 | 小流量验证,逐步切换 |
| 启动慢的服务 | 蓝绿部署 | 避免滚动更新中同时存在多个慢启动 Pod |
蓝绿切换的关键:通过修改 Service 的 Selector 或 Ingress 权重实现流量切换,保留旧版本便于回滚。
8、探针实现方式有几种
三种探针:
| 探针类型 | 用途 | 失败行为 |
|---|---|---|
| Liveness Probe | 检测容器是否存活 | 重启容器 |
| Readiness Probe | 检测容器是否就绪接收流量 | 从 Service Endpoints 移除 |
| Startup Probe | 检测应用是否启动完成(慢启动服务) | 杀死容器,受 failureThreshold × periodSeconds 控制 |
探测方式:
- HTTP GET:
httpGet,返回 200-399 为成功 - TCP Socket:
tcpSocket,端口可连接为成功 - Exec:执行命令,退出码 0 为成功
- GRPC(1.24+):
grpc,适用于 GRPC 服务
9、CI/CD 解释一下
CI(持续集成):
- 代码提交后自动构建、测试
- 工具:Jenkins、GitLab CI、GitHub Actions、Argo Workflows
- 产出:镜像、制品包、测试报告
CD(持续交付/部署):
- 持续交付:自动构建并准备好部署,但需手动触发发布
- 持续部署:全自动发布到生产环境
K8s 场景下的 CI/CD 流程:
git push → 代码扫描 → 单元测试 → 构建镜像 → 推送镜像仓库
→ 更新镜像 Tag → 部署到测试环境 → 集成测试 → 审批 → 部署到生产GitOps 模式(推荐):
- 使用 ArgoCD/Flux 监听 Git 仓库
- 代码和配置分离,配置变更即部署
10、代码扫描过程对发现问题有什么帮助
代码扫描的价值:
-
安全漏洞发现
- 依赖组件 CVE(如 Log4j、Fastjson)
- 硬编码密钥、密码
- SQL 注入、XSS 漏洞
-
代码质量
- 代码异味、复杂度
- 重复代码
- 不符合规范
-
合规性
- 敏感信息泄露(API Key、Token)
- 开源协议合规
工具链:
- SAST:SonarQube、CodeQL、Semgrep
- SCA:Snyk、Trivy(容器镜像扫描)
- 秘密扫描:GitLeaks、TruffleHog
11、在 Jenkins 中不同环境中构建参数不同,怎么实现
方案一:Jenkinsfile + 参数化构建(推荐)
// Jenkinsfile
pipeline {
agent any
parameters {
choice(
name: 'DEPLOY_ENV',
choices: ['dev', 'staging', 'prod'],
description: '选择部署环境'
)
string(
name: 'VERSION',
defaultValue: 'latest',
description: '镜像版本标签'
)
booleanParam(
name: 'SKIP_TESTS',
defaultValue: false,
description: '是否跳过测试'
)
}
environment {
// 根据环境加载不同配置
CONFIG = loadEnvConfig(params.DEPLOY_ENV)
}
stages {
stage('加载环境配置') {
steps {
script {
def envConfig = [
dev: [
namespace: 'app-dev',
replicas: 1,
resources: [cpu: '100m', memory: '256Mi'],
configMap: 'app-config-dev',
ingressHost: 'dev.app.example.com'
],
staging: [
namespace: 'app-staging',
replicas: 2,
resources: [cpu: '500m', memory: '512Mi'],
configMap: 'app-config-staging',
ingressHost: 'staging.app.example.com'
],
prod: [
namespace: 'app-prod',
replicas: 3,
resources: [cpu: '1000m', memory: '1Gi'],
configMap: 'app-config-prod',
ingressHost: 'app.example.com'
]
]
env.ENV_CONFIG = envConfig[params.DEPLOY_ENV]
echo "当前环境: ${params.DEPLOY_ENV}"
echo "命名空间: ${env.ENV_CONFIG.namespace}"
}
}
}
stage('构建镜像') {
steps {
sh """
docker build -t myapp:${params.VERSION} .
docker push myapp:${params.VERSION}
"""
}
}
stage('部署到 K8s') {
steps {
script {
// 使用 envsubst 替换模板中的变量
sh """
export NAMESPACE=${env.ENV_CONFIG.namespace}
export REPLICAS=${env.ENV_CONFIG.replicas}
export CPU_LIMIT=${env.ENV_CONFIG.resources.cpu}
export MEMORY_LIMIT=${env.ENV_CONFIG.resources.memory}
export CONFIG_MAP=${env.ENV_CONFIG.configMap}
export INGRESS_HOST=${env.ENV_CONFIG.ingressHost}
export IMAGE_TAG=${params.VERSION}
envsubst < k8s/deployment-template.yaml > k8s/deployment.yaml
kubectl apply -f k8s/deployment.yaml -n ${env.ENV_CONFIG.namespace}
"""
}
}
}
}
}方案二:使用 ConfigMap 存储环境配置(GitOps 风格)
# k8s/config/dev-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: jenkins-pipeline-config
namespace: jenkins
data:
dev.properties: |
namespace=app-dev
replicas=1
cpu_limit=100m
memory_limit=256Mi
ingress_host=dev.app.example.com
staging.properties: |
namespace=app-staging
replicas=2
cpu_limit=500m
memory_limit=512Mi
ingress_host=staging.app.example.com
prod.properties: |
namespace=app-prod
replicas=3
cpu_limit=1000m
memory_limit=1Gi
ingress_host=app.example.com方案三:使用 Jenkins Credentials 管理敏感参数
// 不同环境使用不同的 Credential
stage('部署') {
steps {
script {
def credentialId = "kubeconfig-${params.DEPLOY_ENV}"
withCredentials([file(credentialsId: credentialId, variable: 'KUBECONFIG')]) {
sh """
kubectl --kubeconfig=$KUBECONFIG apply -f k8s/
"""
}
// 数据库密码等敏感信息
def dbCredential = "db-password-${params.DEPLOY_ENV}"
withCredentials([string(credentialsId: dbCredential, variable: 'DB_PASSWORD')]) {
sh """
kubectl create secret generic db-secret \
--from-literal=password=$DB_PASSWORD \
--dry-run=client -o yaml | kubectl apply -f -
"""
}
}
}
}方案四:多分支流水线(每个环境一个分支)
pipeline {
agent any
environment {
DEPLOY_ENV = getEnvFromBranch(env.BRANCH_NAME)
}
stages {
stage('部署') {
when {
anyOf {
branch 'main'
branch 'develop'
branch 'release'
}
}
steps {
sh "echo 部署到 ${env.DEPLOY_ENV}"
}
}
}
}
def getEnvFromBranch(branch) {
switch(branch) {
case 'main': return 'prod'
case 'release': return 'staging'
case 'develop': return 'dev'
default: return 'dev'
}
}12、收集后端日志和前端日志怎么收集
整体架构图:
┌─────────────────────────────────────────────────────────────────────────────┐
│ 数据采集层 │
├─────────────────────────────┬───────────────────────────────────────────────┤
│ 后端日志 │ 前端日志 │
├─────────────────────────────┼───────────────────────────────────────────────┤
│ ┌─────────────────────┐ │ ┌──────────────────────────────────────┐ │
│ │ Pod stdout/stderr │ │ │ 浏览器/APP │ │
│ │ (容器标准输出) │ │ └──────────────┬─────────────────────┘ │
│ └──────────┬──────────┘ │ │ │
│ │ │ ┌──────────────▼──────────────┐ │
│ ┌──────────▼──────────┐ │ │ SDK 日志采集 │ │
│ │ DaemonSet 采集 │ │ │ - 错误捕获 (onerror) │ │
│ │ (Fluentd/Filebeat) │ │ │ - 性能数据 (Performance API)│ │
│ └──────────┬──────────┘ │ │ - 用户行为埋点 │ │
│ │ │ └──────────────┬──────────────┘ │
│ ┌──────────▼──────────┐ │ │ │
│ │ 日志文件挂载 │ │ ┌──────────────▼──────────────┐ │
│ │ (EmptyDir/HostPath)│ │ │ 日志上报网关 │ │
│ └──────────┬──────────┘ │ │ (Nginx/OpenResty) │ │
│ │ │ └──────────────┬──────────────┘ │
│ ┌──────────▼──────────┐ │ │ │
│ │ Sidecar 模式 │ │ ┌──────────────▼──────────────┐ │
│ │ (业务+采集容器) │ │ │ 消息队列 (Kafka) │ │
│ └──────────┬──────────┘ │ └──────────────┬──────────────┘ │
└─────────────┼──────────────┴──────────────────┼──────────────────────────┘
│ │
┌─────────────▼─────────────────────────────────▼────────────────────────────┐
│ 数据处理层 │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 日志处理引擎 (Flink/Logstash) │ │
│ │ - 结构化解析(JSON/正则) │ │
│ │ - 字段提取(trace_id、user_id、timestamp) │ │
│ │ - 数据清洗(脱敏、过滤) │ │
│ │ - 日志分级(ERROR/WARN/INFO) │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────┬──────────────────────────────────────────────┘
│
┌─────────────────────────────▼──────────────────────────────────────────────┐
│ 数据存储层 │
├─────────────────────────────┬───────────────────────────────────────────────┤
│ 实时检索 (ES/ClickHouse) │ 长期归档 (S3/OSS/Ceph) │
│ ├─ 热数据 (7天) │ ├─ 压缩存储 │
│ ├─ 温数据 (30天) │ ├─ 低成本 │
│ └─ 索引生命周期管理 │ └─ 按需恢复 │
└─────────────────────────────┴───────────────────────────────────────────────┘后端日志收集配置(Filebeat DaemonSet):
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: filebeat
namespace: logging
spec:
selector:
matchLabels:
app: filebeat
template:
metadata:
labels:
app: filebeat
spec:
containers:
- name: filebeat
image: docker.elastic.co/beats/filebeat:8.11.0
volumeMounts:
- name: varlog
mountPath: /var/log
- name: varlibdockercontainers
mountPath: /var/lib/docker/containers
readOnly: true
- name: filebeat-config
mountPath: /etc/filebeat
volumes:
- name: varlog
hostPath:
path: /var/log
- name: varlibdockercontainers
hostPath:
path: /var/lib/docker/containers
- name: filebeat-config
configMap:
name: filebeat-config
---
apiVersion: v1
kind: ConfigMap
metadata:
name: filebeat-config
namespace: logging
data:
filebeat.yml: |
filebeat.inputs:
- type: container
paths:
- /var/lib/docker/containers/*/*.log
processors:
- add_kubernetes_metadata:
host: ${NODE_NAME}
matchers:
- logs_path:
logs_path: "/var/lib/docker/containers/"
output.kafka:
hosts: ["kafka-1:9092", "kafka-2:9092"]
topic: "k8s-logs"
partition.round_robin:
reachable_only: true前端日志 SDK 示例:
// frontend-logger.js
class FrontendLogger {
constructor(config) {
this.endpoint = config.endpoint;
this.appName = config.appName;
this.env = config.env;
this.sampleRate = config.sampleRate || 1.0;
this.initErrorCapture();
this.initPerformanceCapture();
}
initErrorCapture() {
// JS 运行时错误
window.onerror = (msg, url, line, col, error) => {
this.send({
type: 'error',
subtype: 'js_error',
message: msg,
filename: url,
lineno: line,
colno: col,
stack: error?.stack,
userAgent: navigator.userAgent,
url: window.location.href,
timestamp: new Date().toISOString()
});
};
// Promise 未处理错误
window.addEventListener('unhandledrejection', (event) => {
this.send({
type: 'error',
subtype: 'unhandled_promise',
message: event.reason?.message || String(event.reason),
stack: event.reason?.stack,
url: window.location.href,
timestamp: new Date().toISOString()
});
});
// 资源加载错误
window.addEventListener('error', (event) => {
if (event.target !== window) {
this.send({
type: 'error',
subtype: 'resource_error',
target: event.target.tagName,
src: event.target.src || event.target.href,
outerHTML: event.target.outerHTML.slice(0, 200)
});
}
}, true);
}
send(data) {
const payload = {
...data,
app: this.appName,
env: this.env,
userId: this.getUserId(),
sessionId: this.getSessionId()
};
// 使用 sendBeacon 确保页面关闭也能发送
if (navigator.sendBeacon) {
navigator.sendBeacon(this.endpoint, JSON.stringify(payload));
} else {
fetch(this.endpoint, {
method: 'POST',
body: JSON.stringify(payload),
keepalive: true
}).catch(() => {});
}
}
}13、前端 JS 崩溃日志
收集内容:
- Error message + stack trace
- SourceMap 还原原始代码位置
- 用户环境(浏览器、版本、OS)
- 页面 URL、操作路径
- 性能指标(FID、LCP、CLS)
崩溃类型分类:
| 崩溃类型 | 触发场景 | 捕获方式 |
|---|---|---|
| JavaScript Error | 语法错误、运行时异常 | window.onerror |
| Unhandled Promise | async/await 未 catch | unhandledrejection |
| Resource Error | 图片/JS/CSS 加载失败 | error 事件捕获 |
| Console Error | console.error 调用 | 重写 console 方法 |
| 框架级 Error | React/Vue 渲染错误 | Error Boundary |
完整 SDK 示例:
// crash-reporter.js
class CrashReporter {
constructor(config) {
this.config = {
endpoint: config.endpoint,
appKey: config.appKey,
version: config.version,
maxBreadcrumbs: 20,
...config
};
this.breadcrumbs = [];
this.install();
}
install() {
// 1. JS 全局错误
window.onerror = (message, source, lineno, colno, error) => {
this.captureException(error || new Error(message), {
type: 'javascript',
source, lineno, colno
});
};
// 2. Promise 未处理错误
window.addEventListener('unhandledrejection', (event) => {
this.captureException(event.reason, {
type: 'unhandledrejection'
});
event.preventDefault();
});
// 3. 资源加载错误
window.addEventListener('error', (event) => {
if (event.target !== window) {
this.captureMessage('Resource failed to load', {
type: 'resource',
target: event.target.tagName.toLowerCase(),
src: event.target.src || event.target.href
});
}
}, true);
// 4. 页面卸载前批量上报
window.addEventListener('beforeunload', () => this.flush());
}
captureException(error, extra = {}) {
const event = {
event_id: this.generateId(),
timestamp: new Date().toISOString(),
level: 'error',
message: error.message,
stacktrace: this.parseStack(error.stack),
url: window.location.href,
user_agent: navigator.userAgent,
...extra
};
this.send(event);
}
parseStack(stack = '') {
return stack.split('\n').slice(1).map(line => {
const match = line.match(/at\s+(.*?)\s+\((.*?):(\d+):(\d+)\)/);
if (match) {
return {
function: match[1],
filename: match[2],
lineno: parseInt(match[3]),
colno: parseInt(match[4])
};
}
return null;
}).filter(Boolean);
}
send(event) {
if (navigator.sendBeacon) {
navigator.sendBeacon(this.config.endpoint, JSON.stringify(event));
} else {
fetch(this.config.endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(event),
keepalive: true
}).catch(() => {});
}
}
}工具:Sentry、阿里云 ARMS、腾讯云前端监控
14、关于日志收集怎么搭建
完整架构:
┌─────────────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐
│ Application │───→│ Agent │───→│ Kafka │───→│ Flink │
│ Logs │ │(Filebeat)│ │ (Buffer) │ │(Process)│
└─────────────┘ └──────────┘ └──────────┘ └────┬────┘
│
┌─────────────────────────┼─────────┐
↓ ↓ ↓
┌──────┐ ┌────────┐ ┌─────────┐
│ ES │ │S3/OSS │ │ClickHouse│
│(查询) │ │(归档) │ │ (分析) │
└──────┘ └────────┘ └─────────┘关键组件:
- 采集层:Filebeat、Fluent Bit、Promtail
- 缓冲层:Kafka(削峰填谷)
- 处理层:Logstash、Vector、Flink(日志结构化)
- 存储层:Elasticsearch(检索)、S3(冷存)、ClickHouse(分析)
- 展示层:Kibana、Grafana
15、日志收集延迟
延迟来源:
- 采集端:Filebeat
harvester_buffer_size、close_inactive - 传输层:网络带宽、Kafka 分区不足
- 处理层:Logstash filter 复杂、线程数不足
- 存储层:ES 写入压力、索引分片过多
优化方案:
- 使用内存队列,批量发送(
bulk_max_size) - Kafka 分区数 = Consumer 实例数
- 调整 Filebeat
flush_interval和max_retries - 按时间分索引(避免单个索引过大)
16、日志快照链接
需求理解:生成一个临时链接,允许特定时间段/条件下的日志查看
实现方案:
- Kibana:"Share" 功能生成短链接(含查询条件、时间范围)
- 自建:后端生成 JWT Token,嵌入查询参数,有效期控制
- S3 预签名 URL:将日志导出到对象存储,生成临时下载链接
17、日志数据量增长多少
回答思路:
- 日增量:XX GB/TB
- 增长率:月均增长 XX%(业务扩张、日志级别调整)
- 存储策略:热数据 7 天(SSD)、温数据 30 天(SAS)、冷数据 1 年(S3)
- 成本优化:日志采样、日志分级、压缩存储、ILM(Index Lifecycle Management)
数据示例:
"我们集群日产生日志约 500GB,通过设置 log_level=warn 在生产环境,以及按服务重要性采样,控制了 30% 的增长。使用 ES ILM 策略自动迁移旧索引到冷节点。"
18、日志收集推动研发配合
推动策略:
-
标准化
- 制定日志规范(JSON 格式、必填字段:time/level/trace_id/service)
- 提供日志 SDK(自动注入 trace_id、标准化格式)
-
工具化
- 提供日志查询平台(自助排查,减少运维介入)
- 接入告警(Error 日志自动触发钉钉/企微通知)
-
可视化
- 业务大盘(错误率、P99 延迟)
- 监控值班制度,让研发感知价值
-
流程化
- 日志规范纳入代码 Review Checklist
- 新服务上线必须通过日志验收
19、GPU 服务器运维
与普通服务器的区别:
| 维度 | 普通服务器 | GPU 服务器 |
|---|---|---|
| 硬件 | CPU 为主 | NVIDIA GPU + CPU |
| 驱动 | 内核即可 | NVIDIA Driver + CUDA Toolkit |
| 调度 | 原生支持 | 需要 GPU Device Plugin |
| 隔离 | 命名空间/Cgroup | MIG/vGPU/Time-slicing |
| 监控 | CPU/内存/磁盘 | GPU 利用率、显存、温度、ECC |
| 故障 | 系统崩溃 | Xid 错误、显存泄漏、NVLink 故障 |
K8s GPU 环境搭建:
# 1. 节点安装 NVIDIA 驱动
sudo apt install -y nvidia-driver-535
sudo reboot
# 2. 安装 nvidia-container-toolkit
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | \
sudo tee /etc/apt/sources.list.d/nvidia-docker.list
sudo apt update
sudo apt install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
# 3. 部署 NVIDIA Device Plugin
kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/v0.14.0/nvidia-device-plugin.yml
# 4. 验证
kubectl get nodes -o json | jq '.items[].status.capacity | with_entries(select(.key | contains("nvidia")))'GPU 工作负载示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: gpu-inference
spec:
replicas: 2
selector:
matchLabels:
app: gpu-inference
template:
metadata:
labels:
app: gpu-inference
spec:
nodeSelector:
accelerator: nvidia-tesla-a100
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
containers:
- name: inference
image: my-gpu-app:v1
resources:
limits:
nvidia.com/gpu: 1
memory: "16Gi"
cpu: "8"
env:
- name: NVIDIA_VISIBLE_DEVICES
value: "all"
- name: CUDA_CACHE_DISABLE
value: "1"关键监控指标:
| 指标 | 说明 | 告警阈值 |
|---|---|---|
DCGM_FI_DEV_GPU_UTIL | GPU 利用率 | > 95% 持续 10min |
DCGM_FI_DEV_FB_USED | 显存使用 | > 90% |
DCGM_FI_DEV_GPU_TEMP | GPU 温度 | > 85°C |
DCGM_FI_DEV_ECC_SBE_VOL_TOTAL | 单比特 ECC 错误 | > 0(关注) |
DCGM_FI_DEV_ECC_DBE_VOL_TOTAL | 双比特 ECC 错误 | > 0(立即处理) |
DCGM_FI_DEV_XID_ERRORS | Xid 错误码 | > 0 |
常见问题排查:
# GPU 未被识别
nvidia-smi
kubectl logs -n kube-system nvidia-device-plugin-daemonset-xxxx
# 显存泄漏(Pod 删除后显存未释放)
nvidia-smi # 查看 PID
ps -ef | grep <pid>
kill -9 <pid>
# Xid 错误诊断
nvidia-smi -q | grep -i xid20、GPU 运维经验
常见问题:
-
显存泄漏
- 现象:Pod 删除但显存未释放(僵尸进程)
- 解决:设置 Pod 强制终止时间、使用 MPS(Multi-Process Service)
-
驱动问题
- 现象:CUDA 版本不匹配导致程序崩溃
- 解决:使用 GPU Operator 统一管理驱动
-
共享 GPU
- 方案:vGPU(NVIDIA vGPU)、MIG(A100/H100)、Time-slicing
-
调度优化
- 使用 GPU 亲和性调度、Binpack/Spread 策略
- Volcano/Kube-batch 批调度
21、在工作中有什么主动用心发现问题提升效率的事情
准备 1-2 个真实案例:
案例 1:自动化脚本
- 发现每次发版手动改镜像麻烦 → 写了一个 Jenkins Shared Library,自动提取 Git Commit 前 6 位作为镜像 Tag,节省每次 10 分钟
案例 2:监控完善
- 发现磁盘满告警滞后 → 增加磁盘使用率预测告警(基于增长率),提前 3 天预警
案例 3:知识库
- 重复排查相同问题 → 建立运维 Wiki + 故障 Runbook,平均故障处理时间从 30min 降到 5min
回答要点:问题发现 → 主动思考 → 方案设计 → 实施过程 → 效果量化
22、对未来运维的发展
趋势分析:
-
平台工程(Platform Engineering)
- 运维从"背锅"转向"赋能",构建内部开发者平台(IDP)
- 自服务、GitOps、基础设施即代码
-
AIOps
- 智能告警收敛、根因分析、容量预测
- 大模型辅助故障诊断
-
云原生深化
- Serverless、Service Mesh、eBPF 可观测性
- FinOps(云成本优化)
-
安全左移
- DevSecOps,安全融入 CI/CD 每个环节
-
稳定性工程(SRE)
- SLI/SLO/Error Budget 文化
- 混沌工程验证系统韧性
个人发展:
- 深入一门(K8s/网络/存储)+ 了解全局
- 编程能力(Go/Python)必备
- 软技能:跨团队沟通、项目管理
23、部署模型怎么部署
大模型部署场景:
-
推理服务化
- vLLM:高吞吐 LLM 推理服务
- Triton Inference Server:NVIDIA 多框架支持
- Text Generation Inference (TGI):HuggingFace 出品
-
K8s 部署
- 使用 KServe / Seldon Core 模型服务框架
- GPU 节点亲和性、HPA 基于队列长度扩缩容
- 模型存储:PVC / S3(使用 init container 下载)
-
优化手段
- 模型量化(INT8/INT4)
- 连续批处理(Continuous Batching)
- PageAttention(vLLM)
- 模型并行(Tensor Parallelism)
示例架构:
用户请求 → Ingress → KServe Predictor → vLLM Pod (GPU)
↓
HPA (基于 GPU 利用率/延迟)24、我还有什么想问公司的
技术向:
- 目前 K8s 集群规模多大?多集群管理用什么方案(联邦/集群联邦)?
- 可观测性体系建设情况?是否自研还是使用云厂商方案?
- 有没有做 GitOps?使用 ArgoCD 还是 Flux?
- 是否有 FinOps 实践?云成本优化有哪些举措?
团队向:
- 运维团队的定位和边界?是否有 SRE 团队?
- 值班制度怎么安排?是否有自动化手段减少人工值班?
- 技术债情况?是否有专门的时间做技术优化?
发展向:
- 对这个岗位的期望?短期和长期目标?
- 团队的技术成长路径?是否有培训或会议预算?
总结
这 24 道面试题覆盖了 K8s 运维工程师需要掌握的核心知识领域:
- 基础概念(1-3题):Service/Ingress、Secret、ConfigMap
- 故障排查(4-5题):问题定位方法论、网络排查流程
- 高可用设计(6-8题):架构设计、部署策略、探针机制
- DevOps 实践(9-11题):CI/CD、代码扫描、Jenkins 参数化
- 可观测性(12-18题):日志收集、前端监控、延迟优化
- 专项运维(19-20题):GPU 服务器、AI 基础设施
- 软技能(21-24题):主动性、行业洞察、面试反问
建议结合自身项目经验来回答,尤其是第 4、21 题要有真实的案例支撑。技术问题可以配合画图或写伪代码来展示思路。