面试官问我,要是遇到了下面这些场景,该怎么处理:
"生产环境Pod疯狂重启!"
"服务发现异常,大量502!"
"配置更新后服务没响应!"
"日志突然采集不到了..."
让我们通过10个真实场景,来揭开K8s的神秘面纱。
问题1:调度的黑魔法
问题1
场景:
- 生产环境2个节点
- Node1上运行着3个Pod
- Node2完全空闲
- 新建Pod会被调度到哪里?
很多人想当然: "肯定调度到空闲的Node2啊!" 但真实情况是...
解决方案
理解调度原理
# 节点亲和性示例
apiVersion: v1
kind: Pod
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: zone
operator: In
values:
- zone1
实际调度决策:
- 首先评估节点资源充足度
- 然后计算优先级得分: CPU/内存使用率 (占比30%) 节点亲和性 (占比40%) Pod分布均衡度 (占比30%)
- 选择得分最高的节点
最佳实践:
合理使用节点标签
设置Pod亲和性/反亲和性
利用污点和容忍控制调度
配置资源请求和限制
问题2:OOM的命运
问题2
场景:
apiVersion: v1
kind: Pod
spec:
containers:
- name: memory-hog
image: memory-app:v1
resources:
limits:
memory: "256Mi"
当容器OOM时:
- 是容器重启还是Pod重建?
- 重启策略如何影响?
- 如何避免雪崩效应?
解决方案
- 正确配置资源限制
apiVersion: v1
kind: Pod
spec:
containers:
- name: memory-app
resources:
requests:
memory: "128Mi"
limits:
memory: "256Mi"
# 关键:设置恰当的重启策略
restartPolicy: OnFailure
- 实现优雅终止
// 应用程序层面处理SIGTERM信号
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
// 1. 停止接收新请求
server.stopAcceptingNewRequests();
// 2. 等待现有请求处理完成
server.awaitTermination(30, TimeUnit.SECONDS);
// 3. 清理资源
cleanup();
}));
- 监控与告警
# Prometheus告警规则
groups:
- name: memory-alerts
rules:
- alert: ContainerMemoryUsage
expr: container_memory_usage_bytes > threshold
for: 5m
labels:
severity: warning
最佳实践:
设置合理的内存限制
实现优雅终止机制
配置监控和告警
使用内存自动伸缩
问题3:配置热更新之谜
问题3
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
APP_ENV: "prod"
关键疑问:
配置更新是否热生效?
Pod是否需要重建?
如何实现零停机更新?
解决方案
- 使用ConfigMap卷挂载
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: app-config
- 实现配置热加载
@Configuration
public class ConfigReloader {
@Autowired
private ConfigMap configMap;
// 监听配置变更
@EventListener
public void onConfigChange(ConfigChangeEvent event) {
// 1. 验证新配置
validateNewConfig(event.getNewConfig());
// 2. 原子性更新
atomicUpdateConfig(event.getNewConfig());
// 3. 通知相关组件
notifyComponents();
}
}
- 优雅降级机制
public class ConfigManager {
// 保存最后一个正常的配置
private static Config lastGoodConfig;
public void updateConfig(Config newConfig) {
try {
applyNewConfig(newConfig);
lastGoodConfig = newConfig;
} catch (Exception e) {
// 发生错误时回滚
rollbackToLastGoodConfig();
throw e;
}
}
}
最佳实践:
使用卷挂载而非环境变量
实现配置热加载机制
添加配置验证逻辑
准备降级方案
问题4:Pod稳定性
问题4
场景:
- Pod创建成功后
- 无人为干预
- 是否会自动迁移或重启?
解决方案
- Pod配置最佳实践
apiVersion: v1
kind: Pod
spec:
# 1. 设置合适的QoS等级
containers:
- name: app
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "200m"
# 2. 配置优雅终止
terminationGracePeriodSeconds: 30
# 3. 设置Pod反亲和性避免单点
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
topologyKey: kubernetes.io/hostname
- 实现优雅终止
@Component
public class GracefulShutdown {
@PreDestroy
public void shutdown() {
log.info("Received shutdown signal");
// 1. 停止接收新请求
stopNewRequests();
// 2. 等待现有请求完成
awaitRequestsCompletion(30, TimeUnit.SECONDS);
// 3. 关闭资源连接
closeResources();
}
}
最佳实践:
合理设置资源请求和限制
实现优雅终止机制
使用Pod反亲和性
配置存活和就绪探针
问题5:负载均衡的真相
问题5
apiVersion: v1
kind: Service
metadata:
name: web-service
spec:
type: ClusterIP
ports:
- port: 80
核心问题:
- TCP连接如何均衡?
- 会话保持怎么处理?
- 性能开销多大?
解决方案
- Service配置优化
apiVersion: v1
kind: Service
spec:
type: ClusterIP
# 1. 会话亲和性配置
sessionAffinity: ClientIP
sessionAffinityConfig:
clientIP:
timeoutSeconds: 10800
# 2. 配置负载均衡策略
externalTrafficPolicy: Local
# 3. 设置合适的超时时间
ports:
- port: 80
targetPort: 8080
protocol: TCP
- 应用层会话处理
@Configuration
public class SessionConfig {
@Bean
public HttpSessionIdResolver httpSessionIdResolver() {
// 使用header传递会话ID
return HeaderHttpSessionIdResolver
.xAuthToken();
}
@Bean
public RedisSessionRepository sessionRepository() {
// 使用Redis存储会话
return new RedisSessionRepository(
redisTemplate);
}
}
最佳实践:
使用分布式会话存储
配置合适的会话亲和性
监控连接分布情况
设置合理的超时时间
问题6:日志收集的艺术
问题6
场景:
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
volumeMounts:
- name: log-storage
mountPath: /var/log
关键考量:
如何避免日志丢失?
性能影响如何权衡?
存储成本如何控制?
解决方案
- 日志收集架构
# Fluentd配置
apiVersion: v1
kind: ConfigMap
metadata:
name: fluentd-config
data:
fluent.conf: |
@type tail
path /var/log/containers/*.log
pos_file /var/log/fluentd-containers.log.pos
tag kubernetes.*
read_from_head true
@type json
@type elasticsearch
host elasticsearch-logging
port 9200
logstash_format true
- 应用日志最佳实践
@Slf4j
public class LoggingService {
// 1. 使用结构化日志
private static final String LOG_PATTERN =
"{} | {} | {} | {} | {}";
public void logBusinessEvent(String event) {
log.info(LOG_PATTERN,
LocalDateTime.now(),
Thread.currentThread().getName(),
"BUSINESS",
event,
TraceContext.getCurrentSpan());
}
// 2. 实现日志轮转
@PostConstruct
public void configureLogRotation() {
LoggerContext context =
(LoggerContext) LoggerFactory.getILoggerFactory();
RollingFileAppender appender =
new RollingFileAppender<>();
appender.setContext(context);
appender.setFile("/var/log/app.log");
TimeBasedRollingPolicy policy =
new TimeBasedRollingPolicy<>();
policy.setMaxHistory(7); // 保留7天
appender.setRollingPolicy(policy);
}
}
最佳实践:
使用结构化日志格式
实现日志轮转机制
配置集中式日志收集
设置日志保留策略
问题7:健康检查的误区
问题7
apiVersion: v1
kind: Pod
spec:
containers:
- name: web
livenessProbe:
httpGet:
path: /health
port: 8080
常见误解:
- 存活探针等于应用健康?
- 就绪探针可以省略?
- 探针超时无所谓?
解决方案
- 多层次健康检查
apiVersion: v1
kind: Pod
spec:
containers:
- name: web-app
# 1. 存活探针 - 检查进程是否存活
livenessProbe:
httpGet:
path: /health/liveness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# 2. 就绪探针 - 检查是否可以接收流量
readinessProbe:
httpGet:
path: /health/readiness
port: 8080
initialDelaySeconds: 20
periodSeconds: 5
# 3. 启动探针 - 处理长启动时间
startupProbe:
httpGet:
path: /health/startup
port: 8080
failureThreshold: 30
periodSeconds: 10
- 健康检查端点实现
@RestController
@RequestMapping("/health")
public class HealthController {
@Autowired
private DatabaseHealthChecker dbChecker;
@Autowired
private CacheHealthChecker cacheChecker;
// 1. 存活检查 - 只检查基础组件
@GetMapping("/liveness")
public ResponseEntity checkLiveness() {
if (!isBasicComponentsHealthy()) {
return ResponseEntity.status(500).build();
}
return ResponseEntity.ok("OK");
}
// 2. 就绪检查 - 全面检查
@GetMapping("/readiness")
public ResponseEntity checkReadiness() {
HealthCheckResult result = HealthChecker.builder()
.check(dbChecker)
.check(cacheChecker)
.check(this::checkExternalServices)
.build()
.check();
return result.isHealthy()
? ResponseEntity.ok("OK")
: ResponseEntity.status(503).build();
}
// 3. 自定义健康检查逻辑
private boolean checkExternalServices() {
try {
// 检查外部依赖服务
return externalServiceChecker.isHealthy();
} catch (Exception e) {
log.error("Health check failed", e);
return false;
}
}
}
最佳实践:
区分存活和就绪探针
实现细粒度健康检查
设置合理的超时时间
添加监控和告警
问题8:弹性伸缩的智慧
问题8
场景:
apiVersion: apps/v1
kind: Deployment
spec:
replicas: 3
template:
spec:
containers:
- name: web
resources:
requests:
cpu: "100m"
核心问题:
- 如何应对流量突增?
- 扩容时机如何把控?
- 资源限制如何设置
解决方案
- HPA配置最佳实践
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: web-app
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: web-app
minReplicas: 3
maxReplicas: 10
metrics:
# 1. CPU基准
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
# 2. 自定义指标
- type: Pods
pods:
metric:
name: http_requests_per_second
target:
type: AverageValue
averageValue: 1000
# 3. 行为配置
behavior:
scaleUp:
stabilizationWindowSeconds: 60
policies:
- type: Percent
value: 100
periodSeconds: 15
scaleDown:
stabilizationWindowSeconds: 300
- 应用层自适应
@Configuration
public class AdaptiveConfig {
@Bean
public ThreadPoolTaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 1. 核心线程数动态调整
executor.setCorePoolSize(
calculateOptimalThreads());
// 2. 队列大小自适应
executor.setQueueCapacity(
calculateQueueSize());
// 3. 拒绝策略
executor.setRejectedExecutionHandler(
new CallerRunsPolicy());
return executor;
}
private int calculateOptimalThreads() {
int cpuCores = Runtime.getRuntime().availableProcessors();
return Math.max(cpuCores * 2, 8);
}
}
最佳实践:
设置合理的扩缩容阈值
使用多个扩缩容指标
配置稳定窗口期
实现应用层自适应
问题9:容器登录的真相
问题9
当执行:
kubectl exec -it -- bash
你真的理解:
- 是否真的登录了Pod?
- 网络空间的隔离?
- 权限边界在哪里?
解决方案
- 安全访问配置
apiVersion: v1
kind: Pod
spec:
containers:
- name: app
# 1. 安全上下文
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
allowPrivilegeEscalation: false
# 2. 服务账号
serviceAccountName: restricted-sa
- 调试工具集成
# 创建调试容器
kubectl debug -it pod/web-app --image=busybox
# 使用临时容器
kubectl alpha debug pod/web-app -it \
--image=ubuntu \
--target=app
最佳实践:
使用最小权限原则
配置安全上下文
利用临时调试容器
实施审计日志
问题10:故障排查之道
问题10
场景:Pod反复重启
kubectl describe pod
Status: CrashLoopBackOff
解决方案
- 系统故障排查流程
# 1. 查看Pod状态
kubectl get pod web-app -o wide
# 2. 查看详细信息
kubectl describe pod web-app
# 3. 查看容器日志
kubectl logs web-app -c app --previous
# 4. 查看事件
kubectl get events --sort-by='.lastTimestamp'
# 5. 收集诊断信息
kubectl cluster-info dump
- 应用层诊断接口
@RestController
@RequestMapping("/debug")
public class DiagnosticController {
@GetMapping("/thread-dump")
public Map getThreadDump() {
ThreadMXBean threadMXBean =
ManagementFactory.getThreadMXBean();
return ThreadDumper.dump(threadMXBean);
}
@GetMapping("/heap-dump")
public void triggerHeapDump() {
String filename = String.format(
"/tmp/heap_%d.hprof",
System.currentTimeMillis());
HeapDumper.dumpHeap(filename, true);
}
}
最佳实践:
建立故障排查流程
实现诊断接口
保留故障现场
设置监控告警
写在最后
Kubernetes的稳定运行需要:
- 深入理解各组件工作原理
- 建立完善的监控告警体系
- 制定标准的故障排查流程
- 持续优化和改进
记住:
没有完美的系统,只有不断进化的系统!
#Kubernetes #云原生 #容器化 #运维实战