Docker+k8s八股文
Docker是什么?
Docker是一个容器化平台,可以把应用和依赖一起打包成镜像,并以容器的形式运行。
容器不是虚拟机,它本质上是宿主机上的一个进程,只是通过Linux内核机制做了资源隔离和资源限制。
1 | 普通进程:直接运行在宿主机上 |
Docker主要解决环境一致性问题:
- 开发环境和生产环境一致
- 应用依赖打包在镜像中
- 部署、扩容、回滚更方便
容器和虚拟机的区别
| 对比 | 容器 | 虚拟机 |
|---|---|---|
| 隔离方式 | 操作系统级隔离 | 硬件级虚拟化 |
| 内核 | 共享宿主机内核 | 每个VM有独立内核 |
| 启动速度 | 秒级甚至更快 | 通常更慢 |
| 资源开销 | 小 | 大 |
| 隔离性 | 较弱 | 更强 |
| 典型技术 | Docker、containerd | VMware、KVM |
容器更轻量,因为它不需要模拟完整硬件,也不需要启动一个完整操作系统。
虚拟机隔离性更强,因为每个虚拟机有自己的Guest OS和内核。
Docker底层原理
Docker底层主要依赖三类能力:
- Namespace:做隔离
- Cgroups:做资源限制
- UnionFS:做镜像分层
1 | Namespace -> 看起来像独立机器 |
Namespace
Namespace用于隔离进程看到的系统资源。
常见Namespace:
| Namespace | 作用 |
|---|---|
| PID | 隔离进程号 |
| NET | 隔离网络设备、IP、端口、路由表 |
| MNT | 隔离挂载点 |
| IPC | 隔离进程间通信 |
| UTS | 隔离hostname |
| USER | 隔离用户和用户组 |
例如在容器里执行:
1 | ps aux |
只能看到容器内的进程,这是PID Namespace的效果。
容器内可以有自己的IP、网卡、端口,这是NET Namespace的效果。
容器内看到自己的文件系统挂载点,这是MNT Namespace的效果。
需要注意:Namespace只负责“看不见”,不负责“用多少”。资源限制由Cgroups负责。
Cgroups
Cgroups用于限制和统计进程组的资源使用。
可以限制:
- CPU使用比例
- 内存上限
- 磁盘IO
- 进程数量
- 设备访问权限
例如Docker限制内存:
1 | docker run -m 512m nginx |
容器中的进程如果超过内存限制,可能会被OOM Kill。
面试回答:
1 | Namespace解决容器之间的资源视图隔离, |
UnionFS和镜像分层
Docker镜像是分层的,每一层都是只读层。
容器运行时,会在镜像只读层之上增加一个可写层。
1 | 容器可写层 |
好处:
- 多个镜像可以复用相同层,节省磁盘
- 构建镜像时可以利用缓存
- 容器删除后只删除可写层,不影响镜像层
Dockerfile中的每条RUN / COPY / ADD等指令通常会生成新的镜像层。
Docker镜像和容器
镜像是静态模板,容器是镜像运行起来后的实例。
1 | Image -> docker run -> Container |
镜像可以理解为程序包,容器可以理解为正在运行的进程环境。
常见命令:
1 | docker build -t app:v1 . |
Dockerfile常见优化
使用小镜像
Go项目可以使用
alpine或scratch作为运行镜像,减少体积。多阶段构建
编译环境和运行环境分离。
1
2
3
4
5
6
7
8FROM golang:1.22 AS builder
WORKDIR /app
COPY . .
RUN go build -o server .
FROM alpine
COPY --from=builder /app/server /server
CMD ["/server"]合理利用缓存
先复制依赖文件,再下载依赖,最后复制源代码。
1
2
3COPY go.mod go.sum ./
RUN go mod download
COPY . .不要把敏感信息写进镜像
密码、Token、私钥应该通过环境变量、Secret或配置中心注入。
容器网络基础
Docker默认使用bridge网络。
宿主机会创建一个docker0网桥,容器通过veth pair连接到这个网桥。
1 | 容器eth0 |
veth pair可以理解为一对虚拟网线,一端在容器里,一端在宿主机上。
容器访问外网时,通常通过宿主机做NAT。
端口映射:
1 | docker run -p 8080:80 nginx |
表示宿主机8080端口转发到容器的80端口。
Docker Volume
容器默认可写层会随着容器删除而删除。
如果数据需要持久化,就需要使用Volume或Bind Mount。
1 | docker run -v /host/data:/container/data mysql |
区别:
- Volume由Docker管理,适合持久化数据
- Bind Mount直接挂载宿主机目录,适合开发调试或挂配置文件
Kubernetes是什么?
Kubernetes简称K8s,是容器编排平台,用于管理大规模容器应用。
Docker负责把单个容器跑起来,K8s负责管理一组机器上的大量容器:
- 调度容器到哪个节点
- 副本数量管理
- 服务发现和负载均衡
- 滚动更新和回滚
- 自动重启故障容器
- 配置和密钥管理
- 存储挂载
K8s核心思想是声明式API:
1 | 用户声明期望状态 |
例如声明:
1 | 我希望 nginx 有 3 个副本 |
如果某个Pod挂了,K8s会自动再创建一个Pod,让副本数重新变成3。
K8s整体架构
K8s集群分为控制平面和工作节点。
1 | Control Plane |
apiserver
apiserver是K8s的统一入口。
所有请求都要经过apiserver,例如:
- kubectl请求
- controller请求
- scheduler请求
- kubelet上报状态
apiserver负责认证、鉴权、准入控制、API处理,并把状态保存到etcd。
etcd
etcd是K8s的分布式KV数据库,用于保存集群状态。
例如:
- Pod信息
- Deployment信息
- Service信息
- ConfigMap
- Secret
- Node状态
etcd基于Raft实现一致性,这点可以和自己的Raft项目关联起来。
面试可以说:
1 | K8s本身不直接把状态存在各个组件内,而是通过apiserver统一写入etcd。 |
scheduler
scheduler负责给未调度的Pod选择一个合适Node。
调度大致分两步:
过滤
过滤掉不满足条件的Node,例如资源不足、节点不可调度、亲和性不满足、污点不能容忍等。
打分
对剩下的Node打分,选择分数最高的Node。
例如资源更均衡、镜像已存在、亲和性更匹配等。
1 | Pending Pod |
GPU调度本质上也是调度问题:节点需要上报GPU资源,Pod需要声明GPU资源,scheduler再选择满足条件的节点。
controller-manager
controller-manager中运行很多控制器。
控制器的核心逻辑是控制循环:
1 | 观察实际状态 |
例如Deployment控制器发现期望副本数是3,但实际只有2个Pod,就会创建新的Pod。
kubelet
kubelet运行在每个Node上,负责管理本节点的Pod。
主要职责:
- 从apiserver获取分配到本节点的Pod
- 调用容器运行时创建容器
- 挂载Volume
- 执行健康检查
- 上报Pod和Node状态
kube-proxy
kube-proxy负责Service的网络转发规则。
它会在节点上维护iptables或ipvs规则,把访问Service的流量转发到后端Pod。
Pod
Pod是K8s中最小调度单位。
一个Pod中可以包含一个或多个容器,这些容器共享:
- 网络Namespace
- 存储Volume
- 生命周期
同一个Pod中的容器可以通过localhost互相访问。
1 | Pod |
为什么K8s不直接调度容器,而是调度Pod?
因为有些容器需要紧密协作,例如主容器和Sidecar:
- 日志采集Sidecar
- 代理Sidecar
- 配置热更新Sidecar
它们需要共享网络和存储,因此抽象成Pod。
Deployment
Deployment用于管理无状态应用。
它不直接管理Pod,而是通过ReplicaSet管理Pod副本。
1 | Deployment -> ReplicaSet -> Pod |
Deployment支持:
- 副本数管理
- 滚动更新
- 回滚
- 自愈
例如:
1 | replicas: 3 |
表示期望有3个Pod副本。
如果某个Pod挂了,Deployment控制器会通过ReplicaSet再创建一个。
StatefulSet
StatefulSet用于管理有状态应用。
和Deployment相比,StatefulSet提供:
- 稳定的Pod名称
- 稳定的网络标识
- 稳定的存储
- 有序部署和有序删除
例如:
1 | mysql-0 |
适合数据库、分布式存储、ZooKeeper等有状态服务。
DaemonSet
DaemonSet保证每个节点上都运行一个Pod。
适合节点级组件:
- 日志采集Agent
- 监控Agent
- 网络插件
- GPU监控Agent
这个岗位里的“开发轻量级节点进程,实现GPU状态、显存利用率实时上报”,很可能就会以DaemonSet方式部署。
1 | 每个Node运行一个Agent Pod |
Service
Pod的IP是不稳定的,Pod重建后IP可能变化。
Service用于给一组Pod提供稳定访问入口。
1 | Service -> Pod1 |
Service通过Label Selector选择后端Pod。
常见类型:
- ClusterIP:集群内部访问
- NodePort:通过每个Node的端口暴露服务
- LoadBalancer:云厂商负载均衡
- Headless Service:不分配ClusterIP,常用于StatefulSet
Ingress
Ingress用于管理HTTP/HTTPS入口流量。
Service偏四层负载均衡,Ingress偏七层路由。
例如:
1 | api.example.com/user -> user-service |
Ingress本身只是规则,真正转发流量的是Ingress Controller,例如Nginx Ingress Controller。
ConfigMap 和 Secret
ConfigMap用于保存普通配置。
Secret用于保存敏感配置,例如密码、Token、证书。
它们都可以通过环境变量或文件挂载进Pod。
1 | ConfigMap -> application.yml |
注意:K8s Secret默认只是Base64编码,不等于强加密。生产环境要结合RBAC、etcd加密等机制。
Label 和 Selector
Label是资源对象上的标签。
Selector用于根据标签选择资源。
例如Pod有标签:
1 | app=video |
Service通过Selector选择:
1 | app=video |
这样Service就能找到对应Pod。
K8s中很多资源关联都依赖Label和Selector,例如Deployment管理Pod、Service选择Pod。
K8s创建Pod的完整流程
用户执行:
1 | kubectl apply -f pod.yaml |
大致流程:
1 | kubectl发送请求到apiserver |
面试回答时记住三个核心点:
- apiserver是入口,状态存etcd
- scheduler只负责选节点
- kubelet才负责在节点上真正创建Pod
K8s控制器原理
K8s控制器的核心是Reconcile循环。
1 | 期望状态:Deployment replicas = 3 |
控制器并不是执行一次就结束,而是持续监听资源变化,不断让实际状态接近期望状态。
这也是Operator的基础思想。
Operator是什么?
Operator可以理解为“把运维经验写成代码”的K8s扩展方式。
普通Deployment只能管理通用无状态应用。
但是数据库、分布式存储、GPU资源管理这类系统有复杂运维逻辑,例如:
- 创建集群
- 扩缩容
- 故障恢复
- 配置更新
- 状态检查
Operator通常通过CRD + Controller实现。
CRD
CRD是Custom Resource Definition,自定义资源定义。
它允许用户扩展K8s API,定义自己的资源类型。
例如定义一个GPUNodePolicy或VideoCluster。
1 | apiVersion: example.com/v1 |
定义CRD后,就可以像操作Pod一样操作自定义资源:
1 | kubectl get videocluster |
Controller
Controller负责监听自定义资源变化,并执行对应动作。
1 | 用户创建VideoCluster |
Go开发Operator常用controller-runtime或kubebuilder。
核心方法一般叫Reconcile:
1 | func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { |
面试只要能说清楚:
1 | Operator = CRD + Controller |
K8s调度原理
Pod调度就是给Pod选择Node。
调度过程:
过滤阶段
判断节点是否满足Pod要求,例如:
- CPU / 内存是否足够
- NodeSelector是否匹配
- NodeAffinity是否满足
- Taint是否能被Toleration容忍
- 端口是否冲突
- PVC所在存储是否可用
打分阶段
给可用节点打分,例如:
- 资源利用率更均衡
- 镜像本地已经存在
- 亲和性更匹配
- 拓扑分布更合理
绑定阶段
把Pod绑定到得分最高的Node。
NodeSelector、Affinity、Taint
NodeSelector
最简单的节点选择方式。
给Node打标签:
1 | kubectl label node node1 gpu=true |
Pod中指定:
1 | nodeSelector: |
表示这个Pod只能调度到带gpu=true标签的节点。
Affinity
Affinity是亲和性,比NodeSelector更灵活。
分为:
- Node Affinity:Pod和Node的亲和性
- Pod Affinity:Pod和Pod之间尽量靠近
- Pod Anti-Affinity:Pod和Pod之间尽量分散
例如为了高可用,多个副本最好分散到不同节点,可以用Pod Anti-Affinity。
Taint 和 Toleration
Taint是节点上的污点,表示这个节点不欢迎普通Pod。
Toleration是Pod上的容忍,表示Pod可以容忍某些污点。
例如GPU节点只希望运行GPU任务,可以给GPU节点打污点:
1 | gpu=true:NoSchedule |
普通Pod不能调度上来,只有带对应Toleration的Pod才能调度。
1 | Taint在Node上,驱逐不合适的Pod |
K8s资源限制
Pod可以设置CPU和内存的request/limit。
1 | resources: |
request表示调度时需要预留的资源。
limit表示运行时最多能使用的资源。
调度器主要看request,不是看limit。
区别:
- CPU超过limit会被限流
- 内存超过limit可能被OOM Kill
QoS类型:
- Guaranteed:request和limit都设置且相等,优先级最高
- Burstable:设置了部分request/limit
- BestEffort:没有设置request/limit,最容易被驱逐
K8s探针
K8s常见探针:
- livenessProbe:存活探针,判断容器是否需要重启
- readinessProbe:就绪探针,判断Pod是否可以接收流量
- startupProbe:启动探针,适合启动慢的应用
区别:
1 | liveness失败 -> kubelet重启容器 |
面试常问:为什么有了liveness还需要readiness?
因为应用活着不代表能接流量。例如服务还在加载模型、初始化缓存、连接数据库,此时进程没死,但不能对外提供服务。
K8s网络
K8s要求每个Pod都有独立IP,并且集群内Pod之间可以直接互通。
Pod网络通常由CNI插件实现,例如Flannel、Calico、Cilium。
CNI负责在Pod创建时配置网络:
- 创建veth pair
- 把一端放进Pod网络Namespace
- 分配Pod IP
- 配置路由或隧道
- 配置网络策略
Service网络
Service提供稳定虚拟IP。
访问Service时,kube-proxy会根据规则把流量转发到后端Pod。
实现方式常见有:
- iptables
- ipvs
iptables规则多时性能和可维护性会下降。
ipvs更适合大规模服务转发,性能更稳定。
DNS
K8s集群内部通常使用CoreDNS做服务发现。
可以通过服务名访问Service:
1 | mysql.default.svc.cluster.local |
同一个namespace下可以直接访问:
1 | mysql |
K8s存储
容器本身是易失的,Pod删除后本地数据也可能丢失。
K8s通过Volume体系挂载存储。
常见概念:
- Volume:Pod中声明的挂载卷
- PV:PersistentVolume,集群中的持久化存储资源
- PVC:PersistentVolumeClaim,用户对存储资源的申请
- StorageClass:动态创建PV的模板
- CSI:容器存储接口,第三方存储插件标准
1 | Pod -> PVC -> PV -> 底层存储 |
为什么需要PVC?
因为用户不应该直接关心底层存储细节,只需要声明:
1 | 我要一个10Gi的可读写存储 |
K8s再通过PVC绑定具体PV。
JuiceFS是什么?
JuiceFS是一个云原生分布式文件系统。
它通常把数据和元数据分开:
- 数据:存到对象存储、本地盘或其他后端
- 元数据:存到Redis、TiKV、MySQL等元数据引擎
在K8s中,JuiceFS通常通过CSI插件挂载给Pod使用。
1 | Pod |
高并发IO场景下,可能关注:
- 元数据性能,例如大量小文件创建、删除、stat
- 缓存命中率
- 对象存储带宽和延迟
- FUSE开销
- 客户端并发参数
- 读写模式是大文件顺序IO还是小文件随机IO
面试只需要能说:
1 | JuiceFS这类分布式文件系统的性能瓶颈不一定在数据本身, |
CRI、CNI、CSI
K8s为了不绑定具体实现,定义了多个接口:
| 接口 | 作用 | 常见实现 |
|---|---|---|
| CRI | 容器运行时接口 | containerd、CRI-O |
| CNI | 容器网络接口 | Calico、Flannel、Cilium |
| CSI | 容器存储接口 | JuiceFS CSI、Ceph CSI、云盘CSI |
CRI
kubelet不直接调用Docker,而是通过CRI调用容器运行时。
现代K8s中更常见的是containerd。
1 | kubelet -> CRI -> containerd -> runc -> Linux容器 |
runc是底层OCI运行时,真正负责创建Namespace、Cgroups并启动容器进程。
CNI
CNI负责Pod网络。
当Pod创建时,容器运行时会调用CNI插件给Pod配置网络。
CSI
CSI负责存储插件。
K8s通过CSI支持不同存储系统,而不是把存储逻辑写死在K8s内部。
GPU在K8s中如何使用?
K8s原生资源只有CPU、内存等通用资源。
GPU通常通过Device Plugin机制接入。
NVIDIA GPU常见流程:
1 | 节点安装GPU驱动 |
Pod中声明GPU资源:
1 | resources: |
GPU资源通常只能写在limits中,并且request和limit相等。
Device Plugin
Device Plugin是K8s管理特殊硬件资源的扩展机制。
例如:
- GPU
- FPGA
- 高性能网卡
Device Plugin运行在节点上,负责:
- 发现本机设备
- 向kubelet注册资源类型
- 上报设备健康状态
- 在Pod启动时分配设备
1 | Device Plugin -> kubelet: 我这里有4张GPU |
当Pod请求GPU时,kubelet调用Device Plugin的Allocate接口,获取需要注入容器的设备文件、环境变量、挂载信息等。
GPU监控Agent
岗位里提到“开发轻量级节点进程,实现GPU状态、显存利用率实时精准上报”。
这类Agent通常部署为DaemonSet,每个Node一个。
它要做的事:
采集本机GPU指标
例如:
- GPU利用率
- 显存总量
- 显存已使用
- 温度
- 功耗
- 进程占用
- ECC错误
暴露指标
常见方式是暴露HTTP
/metrics接口,给Prometheus采集。上报节点状态
可以写入自定义服务,也可以通过K8s API更新Node annotation、CRD status等。
做异常检测
例如GPU不可用、显存异常、温度过高、驱动异常。
Go实现思路:
1 | 定时采集GPU状态 |
采集方式:
- 调用
nvidia-smi - 使用NVIDIA Management Library(NVML)
- 读取设备文件或驱动暴露的信息
生产环境更倾向于用NVML,因为调用命令行开销更大,解析文本也更不稳定。
GPU虚拟化和vGPU
普通情况下,一张GPU作为整体分配给一个Pod。
问题是很多任务用不满整张GPU,直接独占会浪费资源。
GPU虚拟化的目标是把一张物理GPU切分给多个容器使用,提高利用率。
大致方向:
时间片共享
多个任务轮流使用GPU计算资源。
显存切分
给不同容器限制可用显存大小。
设备隔离
让容器只能看到分配给自己的GPU资源。
调度增强
scheduler需要知道每个节点上GPU核心、显存等细粒度资源剩余情况。
面试中可以这样理解:
1 | 普通K8s GPU调度是以整卡为单位。 |
HAMi大致是什么?
HAMi是云原生场景下的GPU虚拟化和异构算力管理方案之一。
它的大致目标是:
- 让K8s能够以更细粒度调度GPU
- 支持GPU共享
- 支持显存限制
- 提高GPU利用率
- 支持多种异构设备
不用在一天内深入实现细节,但可以掌握它解决的问题:
1 | K8s原生只能比较粗粒度地调度GPU,通常是一张卡一张卡分配。 |
可能涉及的组件:
- 调度器扩展:决定Pod放到哪张GPU、分多少显存
- Device Plugin:上报虚拟GPU资源
- Webhook:修改Pod配置,注入环境变量、挂载设备
- Runtime Hook:在容器启动时设置GPU可见性和限制
- 节点Agent:采集GPU状态,上报资源使用情况
面试可以诚实说:
1 | 我目前没有做过HAMi源码级开发, |
K8s调度扩展
如果K8s默认调度器不满足业务需求,可以扩展调度能力。
常见方式:
使用Node Label / Affinity / Taint
最简单,适合基础调度约束。
Scheduler Framework插件
在过滤、打分、绑定等阶段插入自定义逻辑。
自定义Scheduler
自己实现一个调度器,监听特定Pod并绑定Node。
Mutating Webhook
Pod创建时自动修改Pod配置,例如注入Sidecar、环境变量、资源声明等。
GPU虚拟化一般不会只靠一个点完成,而是调度器、Device Plugin、Webhook、节点Agent共同配合。
K8s高可用
K8s高可用主要是控制平面和工作负载两层。
控制平面高可用
apiserver可以多副本部署,前面加负载均衡。
etcd通常部署奇数个节点,例如3个或5个,通过Raft保证一致性。
1 | LB |
如果一个apiserver挂了,其他apiserver仍然能处理请求。
如果etcd失去多数派,集群状态无法写入,会影响整个K8s控制面。
应用高可用
应用层依靠:
- Deployment多副本
- readinessProbe摘除异常Pod
- livenessProbe自动重启
- Pod反亲和性分散副本
- HPA自动扩缩容
- PDB保证主动驱逐时保留可用副本
HPA
HPA是Horizontal Pod Autoscaler,水平自动扩缩容。
根据指标自动调整Pod副本数。
常见指标:
- CPU使用率
- 内存使用率
- 自定义业务指标
例如CPU持续升高,HPA会增加副本数。
1 | 流量升高 -> CPU升高 -> HPA增加Pod副本 -> 分摊压力 |
GPU场景也可能基于GPU利用率、显存使用率、队列长度等自定义指标扩缩容。
监控体系
K8s常见监控方案:
- Prometheus:采集和存储指标
- Grafana:展示监控面板
- Alertmanager:告警
- node-exporter:采集节点指标
- kube-state-metrics:采集K8s资源对象状态
- cAdvisor:采集容器指标
Prometheus通常是拉模型:
1 | Exporter暴露 /metrics |
GPU监控通常还会有GPU Exporter,例如基于NVML采集GPU指标。
日志和排障常用命令
K8s常用命令:
1 | kubectl get pod -A |
排查Pod Pending:
- 资源不足
- 节点标签不匹配
- 污点不能容忍
- PVC无法绑定
- 镜像拉取问题
排查CrashLoopBackOff:
- 应用启动后崩溃
- 配置错误
- 依赖服务不可用
- livenessProbe配置不合理
排查ImagePullBackOff:
- 镜像名错误
- tag不存在
- 私有仓库认证失败
- 节点无法访问镜像仓库
排查Service访问不通:
- Service selector是否匹配Pod label
- Pod readiness是否通过
- Endpoints是否存在
- 容器端口和Service targetPort是否正确
- 网络插件是否异常
Linux基础和岗位关联
这个岗位强调Linux极客,至少要能把容器和Linux基础联系起来。
进程
容器本质是进程。
K8s里一个容器异常退出,本质上是容器主进程退出。
如果容器主进程是PID 1,还要注意信号处理和子进程回收问题。
文件系统
容器镜像分层依赖UnionFS。
容器数据持久化依赖Volume。
分布式存储挂载通常和Linux VFS、FUSE、页缓存等有关。
网络
容器网络依赖Network Namespace、veth、bridge、iptables/ipvs。
K8s Service转发也和iptables/ipvs有关。
资源隔离
容器CPU、内存限制依赖Cgroups。
如果要做GPU隔离,也可以类比理解为:GPU不是普通CPU/内存资源,需要额外的设备发现、分配和运行时控制。
结合个人项目怎么回答?
如果面试官问:你没做过K8s Operator/GPU虚拟化,为什么适合?
可以这样回答:
1 | 我目前没有做过GPU虚拟化的生产项目,但我有Go后端、Linux、Docker和分布式基础。 |
一天内优先复习顺序
如果时间很紧,建议按这个顺序看:
Docker底层
Namespace、Cgroups、UnionFS、容器网络。
K8s核心流程
Pod、Deployment、Service、DaemonSet、Pod创建流程。
K8s控制器和Operator
声明式API、控制循环、CRD、Controller、Reconcile。
调度
request/limit、NodeSelector、Affinity、Taint/Toleration、过滤打分绑定。
GPU方向
Device Plugin、GPU资源上报、DaemonSet监控Agent、vGPU/HAMi解决什么问题。
存储方向
PV/PVC/StorageClass/CSI、JuiceFS基本架构、小文件元数据瓶颈。
最后总结
Docker的核心是:
1 | Namespace隔离 + Cgroups限制 + UnionFS镜像分层 |
K8s的核心是:
1 | 声明式API + 控制器循环 + 调度 + kubelet节点执行 |
Operator的核心是:
1 | CRD定义资源 + Controller监听变化 + Reconcile调谐状态 |
GPU云平台的核心问题是:
1 | 资源发现 -> 指标采集 -> 资源上报 -> 调度分配 -> 运行时隔离 -> 监控告警 |
如果面试中遇到不会的细节,不要乱编,可以把问题拆回这几条主线回答。
说些什么吧!