Docker & Kubernetes 面试题
Docker 与 Kubernetes 面试测试你将应用程序容器化并进行大规模编排的能力。这些问题通常用于 DevOps、SRE 和平台工程岗位。它们涵盖基础概念(如图像和容器)和实践技能(如编写 YAML 清单和调试集群)。预计会有概念解释、动手任务和故障排除场景。
Docker & Kubernetes 面试涵盖内容
容器基础
问题涵盖 Docker 架构、镜像、容器、卷和网络。你可能会被要求编写 Dockerfile 并理解多阶段构建。
Kubernetes 架构
关注控制平面组件、节点、Pod、部署、服务和 Ingress。预计会有关于调度器、kubelet 和 API 服务器的问题。
网络与存储
主题包括 Pod 网络、服务类型、网络策略、持久卷和存储类。你应该理解容器如何在集群内部和跨集群通信。
CI/CD 与监控
关于将 Docker 和 Kubernetes 与 CI/CD 管道集成、使用 Helm、使用 Prometheus 监控以及使用 Fluentd 或类似工具进行日志记录的问题。
Docker & Kubernetes 面试题示例
- Docker 镜像和容器有什么区别?好回答应覆盖
- Docker 镜像是只读模板,包含文件系统和配置,用于创建容器。
- 容器是镜像的运行实例,具有可写层和进程隔离。
- 镜像通过 Dockerfile 构建并存储在仓库中,容器从镜像启动。
- 镜像不可变,容器可变(修改可通过提交生成新镜像)。
查看范例答案
Docker 镜像是一个只读的模板,包含运行应用程序所需的文件系统、依赖项、配置等。它可以被看作是应用程序的“快照”。而 Docker 容器则是镜像的运行实例,它在镜像之上添加了一个可写层,并且拥有自己的进程、网络和文件系统空间。镜像是静态的,通常通过 Dockerfile 构建并存储在 registry 中;而容器是动态的,可以被启动、停止、删除等操作。一个镜像可以创建多个容器,每个容器之间相互隔离。常见的误区是将镜像与容器混淆,或者认为容器就是轻量级虚拟机,实际上它们通过共享主机内核来实现轻量级隔离。理解它们的区别对于正确使用 Docker 至关重要。
- 如何调试处于 CrashLoopBackOff 状态的 Pod?好回答应覆盖
- 首先使用 'kubectl describe pod' 检查 Pod 事件和状态。
- 使用 'kubectl logs' 查看容器日志(注意崩溃后可能被重启)。
- 若日志为空,尝试 'kubectl logs --previous' 查看上一实例日志。
- 登录容器交互式调试:'kubectl exec -it <pod> -- sh'(若容器未崩溃)。
- 检查资源限制、配置错误或镜像拉取问题。
查看范例答案
当 Pod 处于 CrashLoopBackOff 状态时,意味着容器反复启动后立即崩溃。首先执行 'kubectl describe pod <pod-name>' 查看事件,通常会有错误信息如 OOMKilled 或 ImagePullBackOff。接着使用 'kubectl logs <pod-name>' 查看最近一次容器的日志。如果 Pod 重启了多次,可以使用 '--previous' 标志查看上一个实例的日志。如果应用程序启动失败,可能需要调整启动命令或环境变量。若容器仍在运行但即将崩溃,可以通过 'kubectl exec -it <pod-name> -- /bin/sh' 进入容器手动检查进程或配置文件。常见原因包括:资源限制(CPU/内存不足)、配置错误(如数据库连接字符串)、镜像拉取失败、或应用程序代码抛出未捕获异常。通过逐步检查事件、日志和容器状态,可以定位根因。
- 编写一个在端口 3000 上运行的 Node.js 应用程序的 Dockerfile。好回答应覆盖
- 使用官方 Node.js 镜像作为基础。
- 设置工作目录,复制 package.json 并安装依赖。
- 复制源代码,暴露端口 3000,定义启动命令。
- 利用 .dockerignore 避免复制 node_modules。
查看范例答案
编写一个在端口 3000 上运行的 Node.js 应用程序的 Dockerfile 需要遵循多阶段构建最佳实践以提高效率。基础镜像选择 node:lts-alpine 以减小体积。首先复制 package.json 和 package-lock.json,然后运行 npm ci 安装依赖(利用 Docker 缓存)。接着复制应用程序代码,使用 EXPOSE 3000 声明端口,最后使用 CMD ["node", "app.js"] 或类似命令启动应用。注意将 node_modules 添加到 .dockerignore 中避免被复制。如果应用使用环境变量,可以通过 ENV 设置默认值。对于生产环境,建议使用非 root 用户运行容器以增强安全性。以下是一个完整示例。
参考代码dockerfile FROM node:lts-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . EXPOSE 3000 USER node CMD ["node", "app.js"] - 解释 Kubernetes 服务如何工作以及如何实现负载均衡。好回答应覆盖
- Service 通过标签选择器匹配 Pod,提供稳定的网络端点。
- kube-proxy 在每个节点上维护 iptables 或 IPVS 规则实现负载均衡。
- 支持 ClusterIP、NodePort、LoadBalancer 等服务类型。
- 默认使用轮询 (Round Robin) 算法分发流量。
- 通过 Endpoint 或 EndpointSlice 跟踪后端 Pod 的 IP 变化。
查看范例答案
Kubernetes 中的 Service 是一种抽象,它为一组 Pod(通过标签选择器定义)提供稳定的网络访问入口。Service 有四种类型:ClusterIP(集群内部虚拟 IP)、NodePort(在每个节点上映射端口)、LoadBalancer(集成云负载均衡器)和 ExternalName。当 Pod 创建或删除时,Service 会自动更新其端点(Endpoint 或 EndpointSlice)。实际负载均衡由每个节点上的 kube-proxy 组件实现,它通过 iptables 或 IPVS 规则将流量分发到后端 Pod。默认情况下,kube-proxy 使用轮询算法,但也可以配置会话亲和性。Service 还支持无头服务(Headless Service),用于返回所有 Pod IP 而非虚拟 IP。需要注意的是,Service 的负载均衡是四层(传输层)的,不解析 HTTP 协议;如果需要七层负载均衡(如基于 URL 路径),需使用 Ingress。
- 创建一个实现零停机更新滚动的 Deployment。好回答应覆盖
- 使用 maxSurge 和 maxUnavailable 控制滚动更新速率。
- 设置 minReadySeconds 确保 Pod 就绪后再继续。
- 使用就绪探针 (readinessProbe) 和存活探针 (livenessProbe) 确保应用健康。
- 定义版本标签(如 image: myapp:1.0 升级到 myapp:2.0)。
- 利用 kubectl rollout status 监控更新进度。
查看范例答案
为了实现零停机更新滚动,Deployment 的 spec 中需要配置滚动更新策略。关键在于设置 .spec.strategy.rollingUpdate.maxSurge 和 .spec.strategy.rollingUpdate.maxUnavailable。maxSurge 指定更新时最多可以超出期望副本数的 Pod 数量(百分比或绝对值),使得新 Pod 启动速度更快。maxUnavailable 指定更新过程中允许不可用的最大 Pod 数量,确保服务始终有足够的副本响应。此外,必须为容器定义 readinessProbe,以便 kubelet 在 Pod 真正就绪后才将其加入 Service 的端点,避免流量路由到尚未准备好的 Pod。可选的 minReadySeconds 可以指定新 Pod 在标记为就绪后的等待时间,确保稳定。升级时只需修改镜像标签并应用新的 Deployment,Kubernetes 会自动按策略替换 Pod。回滚可通过 'kubectl rollout undo' 快速执行。以下是一个完整的 Deployment YAML 示例。
参考代码yaml apiVersion: apps/v1 kind: Deployment metadata: name: myapp-deployment spec: replicas: 3 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: containers: - name: myapp image: myapp:2.0 ports: - containerPort: 8080 readinessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 5 periodSeconds: 10 livenessProbe: httpGet: path: /health port: 8080 initialDelaySeconds: 15 periodSeconds: 20 - 如何在 Kubernetes 中管理密钥?好回答应覆盖
- 使用 Secret 资源存储敏感数据(如密码、令牌)。
- Secret 可以挂载为卷或环境变量注入到 Pod 中。
- 建议对 Secret 进行加密存储(启用 etcd 加密或使用外部密钥管理)。
- 使用 RBAC 限制对 Secret 的访问,避免过多权限。
- 推荐使用外部工具如 Sealed Secrets、Vault 或 External Secrets Operator。
查看范例答案
Kubernetes 中管理密钥主要使用 Secret 资源。Secret 类似于 ConfigMap,但内容经过 base64 编码,并且可以在 etcd 中加密存储(需启用 encryption-at-rest)。Secret 可以以两种方式提供给 Pod:作为环境变量(通过 env.valueFrom.secretKeyRef)或作为卷挂载(通过 volumes.secret 和 volumeMounts)。例如,数据库密码可以存储在 Secret 中,然后注入到 Pod 的环境变量。为了提高安全性,建议使用 RBAC 限制哪些用户或服务账户可以读取 Secret。此外,对于更敏感的场景,可以使用第三方工具如 Sealed Secrets(将 Secret 加密后存储在 Git 中)或 HashiCorp Vault(动态秘密管理)。Kubernetes 的 External Secrets Operator 可以从外部密钥管理器同步 Secret。注意避免在 YAML 中明文编写 Secret 值,应用 kubectl create secret generic 命令从文件或字面值创建。以下是一个 Secret 创建及挂载示例。
参考代码yaml # 创建 Secret 的 YAML(不推荐明文,通常用 kubectl create) apiVersion: v1 kind: Secret metadata: name: db-secret type: Opaque data: username: YWRtaW4= password: cGFzc3dvcmQxMjM= # Pod 中使用 Secret 作为环境变量 apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mycontainer image: myimage env: - name: DB_USER valueFrom: secretKeyRef: name: db-secret key: username - name: DB_PASS valueFrom: secretKeyRef: name: db-secret key: password - 描述 Pod 从创建到删除的生命周期。好回答应覆盖
- Pod 生命周期包括 Pending、Running、Succeeded/Failed 等阶段。
- 创建时经历调度、拉取镜像、容器启动。
- Pod 可以被删除或驱逐(如节点故障)。
- 容器重启策略影响 Pod 结束状态。
查看范例答案
Pod 的生命周期从创建开始。首先,Pod 进入 Pending 状态,表示已被 API 服务器接受但尚未调度完成。调度器找到合适的节点后,Pod 变为 Running,此时容器启动中,但可能尚未就绪。如果容器启动失败或崩溃,根据重启策略(Always、OnFailure、Never),Pod 会重新启动容器,并可能进入 CrashLoopBackOff 或等待重启。当所有容器正常运行且就绪探针通过后,Pod 进入 Running 状态。如果主进程成功退出,Pod 进入 Succeeded 状态;如果因错误退出且重启策略为 Never 或 OnFailure 且已用尽,则进入 Failed 状态。Pod 会被用户删除(结果不确定)或由于节点故障、资源压力被驱逐。删除时,会触发 preStop 钩子(如有),然后发送 SIGTERM 信号,等待终止宽限期后强制 SIGKILL。Pod 的完整状态转换包括:Pending → Running → Succeeded/Failed,也可能经历 ContainerCreating、Terminating 等中间状态。
- 如何使用 HorizontalPodAutoscaler 基于 CPU 使用率扩展部署?好回答应覆盖
- HorizontalPodAutoscaler (HPA) 基于指标自动调整副本数。
- 需要 Deployment/StatefulSet 设置 requests 和 limits(CPU 使用率)。
- 使用 'kubectl autoscale' 命令或编写 HPA YAML。
- HPA 定期查询指标服务器(metrics-server)获取 CPU 平均使用率。
- 计算公式:期望副本数 = 当前副本数 * (当前平均利用率 / 目标利用率)。
查看范例答案
HorizontalPodAutoscaler (HPA) 是 Kubernetes 自动缩放 Pod 副本数的机制。要基于 CPU 使用率扩展部署,首先需要确保集群上运行了 metrics-server 以提供 CPU 指标。然后,在 Deployment 的容器中必须设置 CPU 资源 requests(用于计算利用率)。HPA 通过一个 YAML 文件定义:指定目标资源(如 Deployment)、最小/最大副本数、以及目标 CPU 利用率百分比。HPA 会周期性地查询 metrics-server 获取当前所有 Pod 的 CPU 平均使用率,然后计算目标副本数(公式:期望副本数 = ceil[当前副本数 * (当前平均 CPU 利用率 / 目标 CPU 利用率)])。如果计算结果与当前副本数不同,HPA 会更新 Deployment 的 replicas 字段。需要注意的是,HPA 对 CPU 的缩放是基于 requests 的比率,例如目标 50% 表示希望 Pod 的 CPU 使用量达到其 request 值的一半。对于其他自定义指标,需要自定义指标适配器。以下是一个基于 CPU 的 HPA 示例。
参考代码yaml apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: myapp-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: myapp-deployment minReplicas: 1 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 50
如何准备
- 练习手动编写 Dockerfile 和 Kubernetes YAML 清单,不依赖工具。
- 使用 Minikube 或 kind 设置本地集群,实验真实部署和服务。
- 彻底理解 kubectl 命令行,包括故障排除命令如 kubectl describe、kubectl logs 和 kubectl exec。
- 学习容器网络的核心概念以及 Kubernetes 如何通过 CNI 插件实现网络。
- 研究常见面试场景,如滚动更新、金丝雀部署和 Pod 资源限制。
常见问题
面试中需要同时了解 Docker 和 Kubernetes 吗?
是的,大多数面试都涵盖两者。Docker 通常是先决条件,Kubernetes 问题假设你对容器基础感到舒适。
准备动手问题的最佳方式是什么?
设置本地集群(Minikube/kind)并练习部署应用、从零编写 YAML 和调试问题。
YAML 清单编写技能有多重要?
非常重要。许多面试包括编写或调试部署、服务和 ConfigMap 的 YAML 文件。
我应该更关注 Docker 还是 Kubernetes?
通常 Kubernetes 权重更高,但 Docker 基础(镜像、Dockerfile、Compose)也会被测试。
有哪些特定的工具我应该了解?
了解 kubectl、Helm 以及使用 docker logs 和 exec 的基本调试。熟悉 Prometheus 和 Grafana 是加分项。
练习 Docker & Kubernetes 题目,即时获取 AI 反馈
上传简历,获得个性化模拟面试,并了解需要改进的地方——免费开始。