← 返回文章列表

K8s 场景面试题(二)

涵盖 Kubernetes 核心概念、网络排查、CI/CD、日志收集、GPU 运维等 24 道面试题的详细解答,适用于 K8s 运维/云原生工程师面试准备。

28 分钟阅读
字号

本文整理了 K8s 运维工程师面试中常见的 24 道问题,涵盖核心概念、网络、存储、CI/CD、可观测性、GPU 运维等多个维度,并给出详细的回答思路和示例。


1、K8s 的 Service 和 Ingress 的区别

维度ServiceIngress
工作层级L4(传输层,TCP/UDP)L7(应用层,HTTP/HTTPS)
作用集群内服务发现和负载均衡外部流量路由到集群内服务,基于域名/路径
访问方式ClusterIP/NodePort/LoadBalancer需要 Ingress Controller(如 Nginx、Traefik)
典型场景微服务间通信、暴露单个服务多服务共享一个入口、SSL 终止、路径路由
配置示例type: LoadBalancer + selectorrules.host + paths.backend

一句话总结:Service 解决"服务间怎么找到彼此",Ingress 解决"外部用户怎么访问集群内的多个服务"。


2、Secret 存储在 K8s 哪里

etcd - K8s 所有数据(包括 Secret)都持久化存储在 etcd 中。

安全机制

  • 静态加密:etcd 中的 Secret 数据默认是 base64 编码(注意不是加密),生产环境应启用 etcd 加密 providers(如 aescbckms
  • 运行时:kubelet 会将 Secret 挂载到 Pod 的文件系统或作为环境变量
  • 内存中:kube-apiserver 缓存 Secret,kubelet 在节点上缓存(/var/lib/kubelet/pods/

查看方式

etcdctl get /registry/secrets/default/my-secret

3、ConfigMap 怎么应用到 Pod 中,如果有二进制的文件

三种使用方式

  1. 环境变量注入
envFrom:
  - configMapRef:
      name: my-config
  1. Volume 挂载(最常用,支持热更新)
volumes:
  - name: config
    configMap:
      name: my-config
  1. 命令行参数
args: ["--config=$(CONFIG_KEY)"]

二进制文件处理: ConfigMap 不适合存二进制文件(会被 UTF-8 编码损坏),应该使用:

  • Secrettype: 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 networkpolicy

6、有个服务启动需要 5 分钟,服务要高可用需要哪些架构和组件

问题核心:启动慢 + 高可用

架构设计

  1. Pod 层面

    • startupProbe:设置较长的启动探针(> 5 分钟),避免被误杀
    • preStop hook:优雅停机,保证连接排空
    • terminationGracePeriodSeconds:延长终止时间
  2. 副本层面

    • HPA:基于 CPU/自定义指标自动扩缩容
    • PDB:PodDisruptionBudget,保证最小可用副本数
    • 多副本预热:提前启动新 Pod,避免冷启动延迟
  3. 流量层面

    • Readiness Probe:就绪后才接收流量
    • 滚动更新策略maxSurge: 1, maxUnavailable: 0
    • 连接池 + 重试机制:客户端配置重试和熔断
  4. 架构层面

    • 蓝绿部署:准备一套完整的热备环境
    • 预热 Job:定时预热缓存、连接池
    • 分级启动:核心功能先启动,非核心异步加载

7、蓝绿部署和滚动更新在切换过程中用哪个

根据场景选择

场景推荐方案原因
常规迭代滚动更新资源占用少,自动化程度高
重大版本/数据库变更蓝绿部署可快速回滚,零停机
需要验证生产流量金丝雀发布小流量验证,逐步切换
启动慢的服务蓝绿部署避免滚动更新中同时存在多个慢启动 Pod

蓝绿切换的关键:通过修改 Service 的 Selector 或 Ingress 权重实现流量切换,保留旧版本便于回滚。


8、探针实现方式有几种

三种探针

探针类型用途失败行为
Liveness Probe检测容器是否存活重启容器
Readiness Probe检测容器是否就绪接收流量从 Service Endpoints 移除
Startup Probe检测应用是否启动完成(慢启动服务)杀死容器,受 failureThreshold × periodSeconds 控制

探测方式

  1. HTTP GEThttpGet,返回 200-399 为成功
  2. TCP SockettcpSocket,端口可连接为成功
  3. Exec:执行命令,退出码 0 为成功
  4. 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、代码扫描过程对发现问题有什么帮助

代码扫描的价值

  1. 安全漏洞发现

    • 依赖组件 CVE(如 Log4j、Fastjson)
    • 硬编码密钥、密码
    • SQL 注入、XSS 漏洞
  2. 代码质量

    • 代码异味、复杂度
    • 重复代码
    • 不符合规范
  3. 合规性

    • 敏感信息泄露(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 Promiseasync/await 未 catchunhandledrejection
Resource Error图片/JS/CSS 加载失败error 事件捕获
Console Errorconsole.error 调用重写 console 方法
框架级 ErrorReact/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、日志收集延迟

延迟来源

  1. 采集端:Filebeat harvester_buffer_sizeclose_inactive
  2. 传输层:网络带宽、Kafka 分区不足
  3. 处理层:Logstash filter 复杂、线程数不足
  4. 存储层:ES 写入压力、索引分片过多

优化方案

  • 使用内存队列,批量发送(bulk_max_size
  • Kafka 分区数 = Consumer 实例数
  • 调整 Filebeat flush_intervalmax_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、日志收集推动研发配合

推动策略

  1. 标准化

    • 制定日志规范(JSON 格式、必填字段:time/level/trace_id/service)
    • 提供日志 SDK(自动注入 trace_id、标准化格式)
  2. 工具化

    • 提供日志查询平台(自助排查,减少运维介入)
    • 接入告警(Error 日志自动触发钉钉/企微通知)
  3. 可视化

    • 业务大盘(错误率、P99 延迟)
    • 监控值班制度,让研发感知价值
  4. 流程化

    • 日志规范纳入代码 Review Checklist
    • 新服务上线必须通过日志验收

19、GPU 服务器运维

与普通服务器的区别

维度普通服务器GPU 服务器
硬件CPU 为主NVIDIA GPU + CPU
驱动内核即可NVIDIA Driver + CUDA Toolkit
调度原生支持需要 GPU Device Plugin
隔离命名空间/CgroupMIG/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_UTILGPU 利用率> 95% 持续 10min
DCGM_FI_DEV_FB_USED显存使用> 90%
DCGM_FI_DEV_GPU_TEMPGPU 温度> 85°C
DCGM_FI_DEV_ECC_SBE_VOL_TOTAL单比特 ECC 错误> 0(关注)
DCGM_FI_DEV_ECC_DBE_VOL_TOTAL双比特 ECC 错误> 0(立即处理)
DCGM_FI_DEV_XID_ERRORSXid 错误码> 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 xid

20、GPU 运维经验

常见问题

  1. 显存泄漏

    • 现象:Pod 删除但显存未释放(僵尸进程)
    • 解决:设置 Pod 强制终止时间、使用 MPS(Multi-Process Service)
  2. 驱动问题

    • 现象:CUDA 版本不匹配导致程序崩溃
    • 解决:使用 GPU Operator 统一管理驱动
  3. 共享 GPU

    • 方案:vGPU(NVIDIA vGPU)、MIG(A100/H100)、Time-slicing
  4. 调度优化

    • 使用 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、对未来运维的发展

趋势分析

  1. 平台工程(Platform Engineering)

    • 运维从"背锅"转向"赋能",构建内部开发者平台(IDP)
    • 自服务、GitOps、基础设施即代码
  2. AIOps

    • 智能告警收敛、根因分析、容量预测
    • 大模型辅助故障诊断
  3. 云原生深化

    • Serverless、Service Mesh、eBPF 可观测性
    • FinOps(云成本优化)
  4. 安全左移

    • DevSecOps,安全融入 CI/CD 每个环节
  5. 稳定性工程(SRE)

    • SLI/SLO/Error Budget 文化
    • 混沌工程验证系统韧性

个人发展

  • 深入一门(K8s/网络/存储)+ 了解全局
  • 编程能力(Go/Python)必备
  • 软技能:跨团队沟通、项目管理

23、部署模型怎么部署

大模型部署场景

  1. 推理服务化

    • vLLM:高吞吐 LLM 推理服务
    • Triton Inference Server:NVIDIA 多框架支持
    • Text Generation Inference (TGI):HuggingFace 出品
  2. K8s 部署

    • 使用 KServe / Seldon Core 模型服务框架
    • GPU 节点亲和性、HPA 基于队列长度扩缩容
    • 模型存储:PVC / S3(使用 init container 下载)
  3. 优化手段

    • 模型量化(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. 基础概念(1-3题):Service/Ingress、Secret、ConfigMap
  2. 故障排查(4-5题):问题定位方法论、网络排查流程
  3. 高可用设计(6-8题):架构设计、部署策略、探针机制
  4. DevOps 实践(9-11题):CI/CD、代码扫描、Jenkins 参数化
  5. 可观测性(12-18题):日志收集、前端监控、延迟优化
  6. 专项运维(19-20题):GPU 服务器、AI 基础设施
  7. 软技能(21-24题):主动性、行业洞察、面试反问

建议结合自身项目经验来回答,尤其是第 4、21 题要有真实的案例支撑。技术问题可以配合画图或写伪代码来展示思路。

分享

// RELATED_POSTS

0%