面试 | Docker K8S

文章目录

  • [Docker & Kubernetes 面试完全指南(Go 校招向)](#Docker & Kubernetes 面试完全指南(Go 校招向))
    • [Part 1:Docker](#Part 1:Docker)
    • [一、Docker 是什么](#一、Docker 是什么)
      • [容器 vs 虚拟机](#容器 vs 虚拟机)
    • 二、核心概念
    • [三、Dockerfile 最佳实践](#三、Dockerfile 最佳实践)
      • 基础写法
      • [Dockerfile 优化要点](#Dockerfile 优化要点)
    • [四、ENTRYPOINT vs CMD(面试必考)](#四、ENTRYPOINT vs CMD(面试必考))
    • [五、容器核心技术原理(Namespace + Cgroups)](#五、容器核心技术原理(Namespace + Cgroups))
      • [Namespace(命名空间)------ 隔离](#Namespace(命名空间)—— 隔离)
      • [Cgroups(控制组)------ 限制资源](#Cgroups(控制组)—— 限制资源)
    • [六、Docker 网络模式](#六、Docker 网络模式)
    • 七、数据卷(Volume)
    • 八、常用命令速查
    • [Part 2:Kubernetes(K8s)](#Part 2:Kubernetes(K8s))
    • [八、K8s 是什么,解决什么问题](#八、K8s 是什么,解决什么问题)
    • 九、核心架构
    • 十、核心对象详解
      • [Pod ------ 最小调度单元](#Pod —— 最小调度单元)
      • [Deployment ------ 无状态应用管理](#Deployment —— 无状态应用管理)
      • [Service ------ 服务发现与负载均衡](#Service —— 服务发现与负载均衡)
      • [Ingress ------ 七层路由](#Ingress —— 七层路由)
      • [ConfigMap & Secret ------ 配置管理](#ConfigMap & Secret —— 配置管理)
      • [PV & PVC ------ 持久化存储](#PV & PVC —— 持久化存储)
    • [十一、Pod 生命周期与健康检查](#十一、Pod 生命周期与健康检查)
    • 十二、调度机制
    • 十三、自动扩缩容(HPA)
    • [十四、StatefulSet ------ 有状态应用](#十四、StatefulSet —— 有状态应用)
    • [十五、DaemonSet ------ 每节点一个 Pod](#十五、DaemonSet —— 每节点一个 Pod)
    • [十六、Job & CronJob ------ 一次性与定时任务](#十六、Job & CronJob —— 一次性与定时任务)
      • [Job ------ 运行到完成](#Job —— 运行到完成)
      • [CronJob ------ 定时任务](#CronJob —— 定时任务)
    • [十七、RBAC ------ 权限控制(面试加分)](#十七、RBAC —— 权限控制(面试加分))
    • 十八、命名空间(Namespace)与资源隔离
    • [十九、常用 kubectl 命令](#十九、常用 kubectl 命令)
    • [二十、Go 应用容器化最佳实践](#二十、Go 应用容器化最佳实践)
    • 二十一、面试高频问题速答
    • 二十二、一张图记住核心

Docker & Kubernetes 面试完全指南(Go 校招向)


Part 1:Docker


一、Docker 是什么

Docker 是一个容器化平台 ,将应用及其依赖打包成标准化的容器,实现"一次构建,到处运行"。

容器 vs 虚拟机

复制代码
虚拟机:
┌──────────────────────────────────┐
│  App A  │  App B  │  App C       │
│  依赖A  │  依赖B  │  依赖C       │
│  Guest OS│ Guest OS│ Guest OS    │  ← 每个VM有完整操作系统
│         Hypervisor               │
│           Host OS                │
│           硬件                   │
└──────────────────────────────────┘

容器:
┌──────────────────────────────────┐
│  App A  │  App B  │  App C       │
│  依赖A  │  依赖B  │  依赖C       │
│         Docker Engine            │  ← 共享宿主机OS内核
│           Host OS                │
│           硬件                   │
└──────────────────────────────────┘
对比项 虚拟机 容器
启动时间 分钟级 秒级(毫秒级)
磁盘占用 GB 级 MB 级
隔离性 强(完整OS) 弱(共享内核)
性能损耗 高(硬件虚拟化) 低(进程级)
资源利用率

面试答法 :容器本质是宿主机上的一个进程,通过 Linux 的 Namespace(隔离视图)和 Cgroups(限制资源)实现了进程间的隔离和资源管控,并不是真正的虚拟化。


二、核心概念

三大核心对象

复制代码
镜像(Image)  ─── 构建 ──→  容器(Container)
     ↑                              │
     │                              │ 运行时
  Dockerfile                        ↓
                              Registry(仓库)
                           Docker Hub / 私有仓库
  • 镜像(Image) :只读的模板,包含应用代码、运行时、依赖、配置。类比:Java 的 .class 文件
  • 容器(Container):镜像的运行实例,有独立的文件系统、网络、进程空间。类比:Java 的运行进程
  • 仓库(Registry):存储和分发镜像的服务,如 Docker Hub、阿里云 ACR

分层存储与联合文件系统(面试高频)

Docker 镜像采用分层结构,每条 Dockerfile 指令产生一个只读层:

复制代码
Dockerfile:
  FROM ubuntu:20.04        → Layer 1: ubuntu 基础层(只读)
  RUN apt install go       → Layer 2: 安装 Go(只读)
  COPY . /app              → Layer 3: 复制代码(只读)
  RUN go build             → Layer 4: 编译产物(只读)

运行容器时:
  Layer 4(只读)
  Layer 3(只读)
  Layer 2(只读)
  Layer 1(只读)
  Container Layer          ← 可写层(容器停止后默认丢失)

联合文件系统(OverlayFS):将多个只读层叠加,加上一个可写层,呈现为统一的文件系统视图。

核心优势

  • 多个容器共享相同的基础层,节省磁盘空间
  • 拉取镜像时,已有的层不重复下载,加速部署
  • 修改只读层中的文件时,采用 Copy-on-Write:先复制到可写层再修改,原只读层不变

三、Dockerfile 最佳实践

基础写法

dockerfile 复制代码
# 多阶段构建(面试加分项)
# 阶段一:编译
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download                    # 单独拷贝依赖,利用缓存
COPY . .
RUN CGO_ENABLED=0 go build -o server . # 静态编译

# 阶段二:运行
FROM alpine:3.18                       # 最小化运行镜像
RUN apk add --no-cache ca-certificates # 只装必要工具
WORKDIR /app
COPY --from=builder /app/server .      # 只拷贝编译产物
EXPOSE 8080
CMD ["./server"]

多阶段构建的好处 :编译镜像包含 Go SDK(600MB),运行镜像只需二进制文件(15MB),镜像体积缩小 40 倍

Dockerfile 优化要点

dockerfile 复制代码
# ❌ 坏写法:每次代码改动都要重新下载依赖
COPY . .
RUN go mod download

# ✅ 好写法:依赖单独一层,代码改动不影响依赖层缓存
COPY go.mod go.sum ./
RUN go mod download   ← 这层被缓存,只要 go.mod 不变就不重新执行
COPY . .

原则变化少的层放前面,变化多的层放后面,充分利用构建缓存。

其他要点:

  • .dockerignore 排除无用文件(.gitnode_modules、本地配置)
  • 合并 RUN 命令减少层数:RUN apt update && apt install -y xx && rm -rf /var/lib/apt/lists/*
  • 非必要不用 root 用户运行(安全)

四、ENTRYPOINT vs CMD(面试必考)

两者都用于指定容器启动时执行的命令,但行为不同:

对比项 CMD ENTRYPOINT
作用 提供默认命令(可被覆盖) 定义容器的入口点(通常不覆盖)
docker run 追加参数 替换整个 CMD 追加到 ENTRYPOINT 之后
配合使用 作为 ENTRYPOINT 的默认参数 固定执行的主程序
dockerfile 复制代码
# 只有 CMD:docker run myimage ls 会替换掉 CMD,执行 ls
FROM ubuntu
CMD ["echo", "hello"]

# 只有 ENTRYPOINT:docker run myimage --help 会变成 /server --help
FROM alpine
ENTRYPOINT ["/server"]

# 最佳实践:ENTRYPOINT 定主程序,CMD 提供默认参数
FROM alpine
ENTRYPOINT ["/server"]
CMD ["--port=8080"]
# docker run myimage              → /server --port=8080
# docker run myimage --port=9090  → /server --port=9090(CMD 被覆盖)

两种格式

dockerfile 复制代码
# Shell 格式:由 /bin/sh -c 执行,PID 不是 1,收不到 SIGTERM → 无法优雅退出
CMD echo hello
ENTRYPOINT /server

# Exec 格式(推荐):直接执行,PID=1,能收到 SIGTERM → 优雅退出
CMD ["echo", "hello"]
ENTRYPOINT ["/server"]

面试答法 :ENTRYPOINT 定义容器主程序,docker run 追加的参数会传给它;CMD 是默认参数,可以被 docker run 后面的命令完全替换。生产中用 Exec 格式的 ENTRYPOINT,确保进程 PID=1 能正确接收 SIGTERM,实现优雅退出。


五、容器核心技术原理(Namespace + Cgroups)

Namespace(命名空间)------ 隔离

Linux Namespace 让每个容器看到独立的系统视图

Namespace 隔离内容
PID 进程 ID,容器内 PID=1
NET 网络接口、路由表、端口
MNT 文件系统挂载点
UTS 主机名和域名
IPC 进程间通信
USER 用户和用户组 ID

Cgroups(控制组)------ 限制资源

Cgroups 限制容器能使用的资源上限

bash 复制代码
docker run -m 512m --cpus=2 nginx
# 限制该容器:最多 512MB 内存,最多使用 2 个 CPU 核

面试答法:Docker 容器本质是用 Namespace 隔离进程视图(让容器以为自己独占系统),用 Cgroups 限制资源使用量(防止单个容器耗尽宿主机资源),用 OverlayFS 提供分层文件系统。三者结合构成"轻量级虚拟化"。


六、Docker 网络模式

模式 说明 使用场景
bridge(默认) 容器接入虚拟网桥,通过 NAT 访问外网 单机多容器通信
host 容器直接使用宿主机网络,无隔离 高性能,需要直接绑定宿主机端口
none 无网络,完全隔离 纯计算任务
overlay 跨宿主机的容器网络(Docker Swarm) 多机容器通信
bash 复制代码
# bridge 模式下容器间通信
docker network create mynet
docker run --network mynet --name serviceA app-a
docker run --network mynet --name serviceB app-b
# serviceB 可以直接用 serviceA 作为域名访问容器A

七、数据卷(Volume)

容器的可写层在容器停止后数据丢失,Volume 解决持久化问题:

bash 复制代码
# 命名卷(推荐):Docker 管理存储位置
docker run -v mysql_data:/var/lib/mysql mysql

# 绑定挂载:直接挂载宿主机目录(开发常用)
docker run -v /host/path:/container/path nginx

# 只读挂载(防止容器修改配置文件)
docker run -v /config:/config:ro nginx

八、常用命令速查

bash 复制代码
# 镜像操作
docker build -t myapp:v1 .              # 构建镜像
docker images                           # 列出本地镜像
docker pull nginx:alpine                # 拉取镜像
docker push registry/myapp:v1          # 推送镜像
docker rmi myapp:v1                     # 删除镜像

# 容器操作
docker run -d -p 8080:80 --name web nginx   # 后台运行,端口映射
docker ps                               # 查看运行中的容器
docker ps -a                            # 查看所有容器
docker logs -f web                      # 实时查看日志
docker exec -it web /bin/sh             # 进入容器
docker stop web && docker rm web        # 停止并删除

# 资源清理
docker system prune -a                  # 清除所有未使用资源


Part 2:Kubernetes(K8s)


八、K8s 是什么,解决什么问题

Kubernetes 是 Google 开源的容器编排平台,解决大规模容器集群的管理问题。

没有 K8s 时的痛点

复制代码
容器多了 → 手动部署太繁琐
容器挂了 → 需要人工重启
流量多了 → 手动扩容太慢
发版本了 → 停服更新,有停机时间

K8s 解决

  • 自动调度:决定容器跑在哪台机器上
  • 自愈:容器崩溃自动重启,节点故障自动迁移
  • 水平扩缩容:一条命令扩容,或根据 CPU 自动扩缩
  • 滚动更新:零停机发布新版本,失败自动回滚
  • 服务发现:内置 DNS,服务间通过名称互相访问

九、核心架构

复制代码
                    ┌──────────────── Master Node ────────────────┐
                    │                                              │
kubectl ───────────▶│  API Server   ← 所有操作的唯一入口           │
                    │      │                                       │
                    │  etcd(持久化存储所有集群状态)               │
                    │      │                                       │
                    │  Scheduler    ← 决定 Pod 调度到哪个 Node     │
                    │      │                                       │
                    │  Controller Manager ← 维持期望状态           │
                    └──────────────────────────────────────────────┘
                              │
              ┌───────────────┼───────────────┐
              ▼               ▼               ▼
         Worker Node 1   Worker Node 2   Worker Node 3
         ┌──────────┐    ┌──────────┐    ┌──────────┐
         │ kubelet  │    │ kubelet  │    │ kubelet  │  ← 管理本节点Pod
         │ kube-proxy    │ kube-proxy    │ kube-proxy  ← 维护网络规则
         │  Pod     │    │  Pod     │    │  Pod     │
         │  Pod     │    │  Pod     │    │          │
         └──────────┘    └──────────┘    └──────────┘

核心组件说明

组件 职责
API Server 集群的统一入口,所有操作(kubectl/内部组件)都通过它;RESTful API + 认证授权
etcd 分布式 KV 存储,保存集群全部状态(节点、Pod、配置等),是集群的"数据库"
Scheduler 监听未调度的 Pod,根据资源、亲和性等策略,将 Pod 分配到合适的 Node
Controller Manager 运行各种控制器(Deployment/ReplicaSet/Node 等),持续对比期望状态和实际状态并修正
kubelet 每个 Node 上的代理,负责启动/停止容器,向 API Server 上报节点和 Pod 状态
kube-proxy 每个 Node 上维护 iptables/IPVS 规则,实现 Service 的负载均衡和转发

十、核心对象详解

Pod ------ 最小调度单元

Pod 是 K8s 中最小的部署单元,可以包含一个或多个容器。

yaml 复制代码
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: app
    image: myapp:v1
    ports:
    - containerPort: 8080
    resources:
      requests:             # 调度时保证的资源
        cpu: "100m"         # 0.1 个 CPU 核
        memory: "128Mi"
      limits:               # 最大可用资源(超出被限制/OOM Kill)
        cpu: "500m"
        memory: "512Mi"
  - name: sidecar           # 同一 Pod 的 sidecar 容器
    image: log-collector:v1

同一 Pod 内的容器

  • 共享 Network Namespace(相同 IP,通过 localhost 互访)
  • 共享 存储卷(可挂载同一 Volume)
  • 共享 生命周期(一起创建、一起销毁)

面试答法:Pod 是对"紧密协作的容器组"的抽象,一个 Pod 内的容器共享网络和存储,适合主应用 + sidecar(日志采集、代理)的部署模式。K8s 永远不直接操作容器,只操作 Pod。


Deployment ------ 无状态应用管理

yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 3               # 期望 3 个 Pod 副本
  selector:
    matchLabels:
      app: myapp
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1           # 更新时最多多出 1 个 Pod
      maxUnavailable: 0     # 更新时不允许有不可用的 Pod(零停机)
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: myapp
        image: myapp:v2

层级关系

复制代码
Deployment(期望状态管理)
    └── ReplicaSet(副本数量保障)
            └── Pod × 3(实际运行的容器)

滚动更新过程

复制代码
初始: [Pod-v1] [Pod-v1] [Pod-v1]

第1步: 创建新Pod  → [Pod-v1] [Pod-v1] [Pod-v1] [Pod-v2]
第2步: 旧Pod就绪  → [Pod-v1] [Pod-v1] [Pod-v2]
第3步: 继续替换  → [Pod-v1] [Pod-v2] [Pod-v2]
第4步: 完成      → [Pod-v2] [Pod-v2] [Pod-v2]
bash 复制代码
kubectl rollout undo deployment/myapp          # 回滚到上一版本
kubectl rollout undo deployment/myapp --to-revision=2  # 回滚到指定版本
kubectl rollout history deployment/myapp       # 查看历史版本

Service ------ 服务发现与负载均衡

Pod 的 IP 是不固定的(重启后变化),Service 提供稳定的访问入口。

yaml 复制代码
apiVersion: v1
kind: Service
metadata:
  name: myapp-svc
spec:
  selector:
    app: myapp           # 选中带此 Label 的 Pod
  ports:
  - port: 80             # Service 端口
    targetPort: 8080     # Pod 端口
  type: ClusterIP        # 服务类型

四种 Service 类型

类型 访问范围 说明
ClusterIP(默认) 集群内部 分配虚拟 IP,仅集群内可访问
NodePort 集群外部 在每个 Node 上开放固定端口(30000-32767)
LoadBalancer 集群外部 云厂商提供外部负载均衡器(AWS ELB 等)
ExternalName 集群内访问外部 将 Service 映射到外部域名

Service 的实现原理(kube-proxy)

复制代码
请求 → Service VIP(虚拟IP)
    → kube-proxy 维护的 iptables/IPVS 规则
    → 随机选择一个健康的 Pod IP 转发

Ingress ------ 七层路由

Service 是四层(TCP/UDP)负载均衡,Ingress 提供七层(HTTP/HTTPS)路由:

yaml 复制代码
apiVersion: networking.k8s.io/v1
kind: Ingress
spec:
  rules:
  - host: api.example.com
    http:
      paths:
      - path: /user
        backend:
          service:
            name: user-svc
            port: 80
      - path: /order
        backend:
          service:
            name: order-svc
            port: 80

常用 Ingress Controller:Nginx Ingress、Traefik、Istio Gateway


ConfigMap & Secret ------ 配置管理

yaml 复制代码
# ConfigMap:非敏感配置
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
data:
  APP_ENV: "production"
  LOG_LEVEL: "info"
  config.yaml: |
    server:
      port: 8080

---
# Secret:敏感信息(base64 编码存储)
apiVersion: v1
kind: Secret
type: Opaque
data:
  DB_PASSWORD: cGFzc3dvcmQxMjM=   # base64("password123")
  JWT_SECRET: c2VjcmV0a2V5        # base64("secretkey")

在 Pod 中使用

yaml 复制代码
spec:
  containers:
  - name: app
    envFrom:
    - configMapRef:
        name: app-config          # 全部 ConfigMap key 注入为环境变量
    - secretRef:
        name: app-secret
    volumeMounts:
    - name: config-vol
      mountPath: /etc/config      # 挂载为文件
  volumes:
  - name: config-vol
    configMap:
      name: app-config

注意 :Secret 只是 base64 编码,不是加密。生产环境应配合 Vault 或云厂商 KMS 加密存储。


PV & PVC ------ 持久化存储

复制代码
PV(Persistent Volume)   ← 管理员预先创建,描述实际存储(NFS/云盘等)
PVC(Persistent Volume Claim) ← 开发者按需申请存储资源
yaml 复制代码
# 开发者只需关心 PVC(我需要多少存储)
apiVersion: v1
kind: PersistentVolumeClaim
spec:
  accessModes:
  - ReadWriteOnce          # 单节点读写
  resources:
    requests:
      storage: 10Gi        # 申请 10GB
  storageClassName: ssd    # 存储类型

# Pod 中挂载 PVC
volumes:
- name: data
  persistentVolumeClaim:
    claimName: my-pvc

十一、Pod 生命周期与健康检查

Pod 状态流转

复制代码
Pending(调度中)→ Running(运行中)→ Succeeded(正常退出)
                                    → Failed(异常退出)
                 → Unknown(节点失联)

Pending 时间过长的原因

  • 资源不足(CPU/Memory requests 无法满足)
  • 节点选择器/亲和性规则无法匹配
  • 镜像拉取失败(ImagePullBackOff)

三种健康检查

yaml 复制代码
containers:
- name: app
  livenessProbe:          # 存活探针:失败则重启容器
    httpGet:
      path: /healthz
      port: 8080
    initialDelaySeconds: 30   # 启动后等 30s 再开始探测
    periodSeconds: 10          # 每 10s 探测一次
    failureThreshold: 3        # 连续失败 3 次才重启

  readinessProbe:         # 就绪探针:失败则从 Service 摘流
    httpGet:
      path: /ready
      port: 8080
    initialDelaySeconds: 5

  startupProbe:           # 启动探针:专为慢启动应用,期间不执行其他探针
    httpGet:
      path: /healthz
      port: 8080
    failureThreshold: 30
    periodSeconds: 10     # 最多等 5 分钟启动
探针 失败后果 用途
livenessProbe 重启容器 检测容器是否陷入死锁/僵死
readinessProbe 从 Service 摘除(不接收流量) 检测容器是否准备好接收流量
startupProbe 重启容器 给慢启动应用更长的初始化时间

面试答法:三种探针解决不同问题。liveness 保证容器"活着",readiness 保证容器"能处理请求",startup 避免慢启动应用被 liveness 误杀。生产中三者配合使用:startup 确保启动完成,readiness 控制流量接入,liveness 长期保活。


十二、调度机制

Pod 调度流程

复制代码
1. kubectl apply → API Server 写入 etcd(Pod 状态=Pending,nodeName 为空)
2. Scheduler watch 到未调度的 Pod
3. 过滤(Filtering):排除不满足条件的 Node(资源不足、污点不匹配等)
4. 打分(Scoring):对剩余 Node 打分(资源均衡、亲和性等)
5. 选出得分最高的 Node,更新 Pod 的 nodeName
6. 对应 Node 上的 kubelet watch 到分配给自己的 Pod,启动容器

常用调度策略

yaml 复制代码
spec:
  # 节点选择器(硬性要求)
  nodeSelector:
    disk: ssd

  # 节点亲和性(软硬均支持)
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:   # 硬性
        nodeSelectorTerms:
        - matchExpressions:
          - key: zone
            operator: In
            values: ["zone-a", "zone-b"]

    # Pod 反亲和性(避免同一应用的 Pod 集中在一个节点)
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:  # 软性
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchLabels:
              app: myapp
          topologyKey: kubernetes.io/hostname

  # 污点容忍(允许调度到有污点的节点)
  tolerations:
  - key: "gpu"
    operator: "Exists"
    effect: "NoSchedule"

十三、自动扩缩容(HPA)

yaml 复制代码
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
spec:
  scaleTargetRef:
    kind: Deployment
    name: myapp
  minReplicas: 2
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 70    # CPU 使用率超 70% 时扩容

HPA 工作原理

复制代码
Metrics Server 采集各 Pod 的 CPU/Memory 使用率
    ↓
HPA Controller 计算:期望副本数 = ceil(当前副本数 × 当前指标/目标指标)
    ↓
当 CPU=140%,目标70%,当前2副本:期望 = ceil(2 × 140/70) = 4
    ↓
更新 Deployment 的 replicas=4,触发扩容

十四、StatefulSet ------ 有状态应用

Deployment 管理无状态应用(Pod 可以随意替换),StatefulSet 用于有状态应用(如 MySQL、Kafka、ZooKeeper):

特性 Deployment StatefulSet
Pod 名称 随机(app-7d4f9-xxx) 有序固定(app-0, app-1, app-2)
启动顺序 并行启动 按序启动(0→1→2)
存储 共享或临时 每个 Pod 独立的 PVC
网络标识 不固定 固定 DNS(app-0.svc)
删除顺序 随机 逆序删除(2→1→0)

十五、DaemonSet ------ 每节点一个 Pod

DaemonSet 确保集群中每个(或指定的)Node 上都运行一个 Pod 副本,常用于:

  • 日志采集:每个 Node 上运行 Fluentd/Filebeat,收集该节点的日志
  • 监控 Agent:每个 Node 上运行 Prometheus Node Exporter,采集节点指标
  • 网络插件:如 Calico、Flannel,需要在每个 Node 上运行
  • 存储插件:如 Ceph 客户端
yaml 复制代码
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: log-collector
spec:
  selector:
    matchLabels:
      app: log-collector
  template:
    metadata:
      labels:
        app: log-collector
    spec:
      containers:
      - name: fluentd
        image: fluentd:v1.14
        volumeMounts:
        - name: varlog
          mountPath: /var/log        # 读取宿主机日志
      volumes:
      - name: varlog
        hostPath:
          path: /var/log

与 Deployment 的区别

  • Deployment:指定副本数量(如 3 个),由调度器决定分布在哪些 Node
  • DaemonSet:不指定副本数,每个符合条件的 Node 自动运行一个

新 Node 加入集群时,DaemonSet Controller 自动在其上创建 Pod;Node 删除时,对应 Pod 也被清理。


十六、Job & CronJob ------ 一次性与定时任务

Job ------ 运行到完成

Job 保证一个或多个 Pod 成功完成,适合数据库迁移、批量处理等一次性任务

yaml 复制代码
apiVersion: batch/v1
kind: Job
metadata:
  name: db-migration
spec:
  completions: 1        # 需要成功完成的 Pod 数
  parallelism: 1        # 并行运行的 Pod 数
  backoffLimit: 3       # 失败后最多重试 3 次
  template:
    spec:
      restartPolicy: Never   # Job Pod 必须设置为 Never 或 OnFailure
      containers:
      - name: migration
        image: myapp:v2
        command: ["./migrate", "--up"]

CronJob ------ 定时任务

yaml 复制代码
apiVersion: batch/v1
kind: CronJob
metadata:
  name: report-generator
spec:
  schedule: "0 2 * * *"     # Cron 表达式:每天凌晨 2 点
  concurrencyPolicy: Forbid  # 上一次未完成时,不创建新 Job(防重叠)
  successfulJobsHistoryLimit: 3   # 保留最近 3 个成功 Job 的记录
  failedJobsHistoryLimit: 1
  jobTemplate:
    spec:
      template:
        spec:
          restartPolicy: OnFailure
          containers:
          - name: reporter
            image: report-tool:v1
            command: ["./generate-report"]

concurrencyPolicy 三种策略

  • Allow(默认):允许并发运行多个 Job
  • Forbid:上一次未完成则跳过
  • Replace:用新 Job 替换运行中的旧 Job

十七、RBAC ------ 权限控制(面试加分)

K8s 默认开启 RBAC(Role-Based Access Control),控制 能对哪些资源 执行哪些操作

核心概念

复制代码
Subject(主体)          Role(角色)             Resource(资源)
ServiceAccount    ──绑定──▶ Role/ClusterRole ──定义──▶ pods/deployments/...
User                                                     verbs: get/list/create/delete
Group
  • Role:命名空间级别的权限定义
  • ClusterRole:集群级别的权限定义(跨 Namespace)
  • RoleBinding:将 Role 绑定到 Subject(在某个 Namespace 生效)
  • ClusterRoleBinding:将 ClusterRole 绑定到 Subject(全集群生效)

实际案例

yaml 复制代码
# 1. 创建 ServiceAccount(应用的身份)
apiVersion: v1
kind: ServiceAccount
metadata:
  name: go-service-sa
  namespace: production

---
# 2. 创建 Role(定义权限:只能读取 ConfigMap 和 Secret)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: config-reader
  namespace: production
rules:
- apiGroups: [""]
  resources: ["configmaps", "secrets"]
  verbs: ["get", "list"]     # 只读,不能创建/删除

---
# 3. 绑定:把 Role 赋给 ServiceAccount
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: go-service-config-reader
  namespace: production
subjects:
- kind: ServiceAccount
  name: go-service-sa
roleRef:
  kind: Role
  name: config-reader
  apiGroup: rbac.authorization.k8s.io

---
# 4. Pod 使用这个 ServiceAccount
spec:
  serviceAccountName: go-service-sa
  containers:
  - name: go-service
    ...

常见 verbs

操作 verbs
查看列表 list
查看详情 get
监听变化 watch
创建 create
更新 update, patch
删除 delete
全部 *

面试答法:K8s RBAC 通过 Role/ClusterRole 定义权限(能对哪些资源做哪些操作),通过 RoleBinding/ClusterRoleBinding 将权限绑定给 ServiceAccount(应用身份)或 User(人)。微服务中每个服务用独立的 ServiceAccount,遵循最小权限原则,只授予必要的权限,避免容器逃逸后横向攻击。


十八、命名空间(Namespace)与资源隔离

bash 复制代码
# 不同团队/环境用不同 Namespace 隔离
kubectl create namespace dev
kubectl create namespace prod

# 给 Namespace 设置资源配额
apiVersion: v1
kind: ResourceQuota
metadata:
  namespace: dev
spec:
  hard:
    pods: "20"
    requests.cpu: "4"
    requests.memory: 8Gi
    limits.cpu: "8"
    limits.memory: 16Gi

十九、常用 kubectl 命令

bash 复制代码
# 查看资源
kubectl get pods -n default                    # 查看 Pod
kubectl get pods -o wide                       # 显示 Node 信息
kubectl describe pod myapp-xxx                 # 查看 Pod 详情(排查问题首选)
kubectl logs myapp-xxx -c app -f               # 查看容器日志(-c 指定容器)
kubectl top pod                                # 查看 Pod 资源使用

# 操作资源
kubectl apply -f deploy.yaml                   # 应用配置(创建/更新)
kubectl delete -f deploy.yaml                  # 删除资源
kubectl scale deployment myapp --replicas=5    # 手动扩缩容
kubectl set image deployment/myapp app=myapp:v3 # 更新镜像

# 调试
kubectl exec -it myapp-xxx -- /bin/sh          # 进入容器
kubectl port-forward pod/myapp-xxx 8080:8080   # 本地端口转发
kubectl get events --sort-by=.lastTimestamp    # 查看集群事件

# 滚动更新
kubectl rollout status deployment/myapp        # 查看更新状态
kubectl rollout pause deployment/myapp         # 暂停更新(灰度)
kubectl rollout resume deployment/myapp        # 恢复更新
kubectl rollout undo deployment/myapp          # 回滚

二十、Go 应用容器化最佳实践

dockerfile 复制代码
# 生产级 Go 应用 Dockerfile
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o server .
#   -w -s:去掉调试信息,进一步缩小体积

FROM scratch                    # 极致精简,比 alpine 更小
COPY --from=builder /app/server /server
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
EXPOSE 8080
ENTRYPOINT ["/server"]

K8s 部署 Go 应用的完整配置

yaml 复制代码
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: go-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: go-service
  template:
    spec:
      containers:
      - name: go-service
        image: registry/go-service:v1
        ports:
        - containerPort: 8080
        env:
        - name: APP_ENV
          valueFrom:
            configMapKeyRef:
              name: app-config
              key: APP_ENV
        - name: DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: app-secret
              key: DB_PASSWORD
        resources:
          requests:
            cpu: "100m"
            memory: "128Mi"
          limits:
            cpu: "500m"
            memory: "512Mi"
        livenessProbe:
          httpGet:
            path: /healthz
            port: 8080
          initialDelaySeconds: 10
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /ready
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
        lifecycle:
          preStop:
            exec:
              command: ["/bin/sh", "-c", "sleep 5"]  # 优雅退出:等待流量切走

二十一、面试高频问题速答

Q:Docker 容器和虚拟机的区别?

虚拟机通过 Hypervisor 模拟硬件,每个 VM 有完整 OS,启动慢、占用资源多。容器共享宿主机内核,用 Namespace 隔离进程视图,用 Cgroups 限制资源,本质是宿主机上的进程,启动秒级、资源开销小。

Q:Docker 镜像为什么分层?有什么好处?

镜像分层基于 OverlayFS,每条 Dockerfile 指令产生一个只读层。好处:① 多镜像共享相同基础层,节省存储;② 构建时利用缓存,只重建变化的层;③ 拉取镜像时已有的层不重复下载,加速部署。

Q:K8s 中 Pod、Deployment、Service 的关系?

Pod 是最小运行单元,但直接管理 Pod 不可靠(挂了不会自动重建)。Deployment 通过 ReplicaSet 维持 Pod 副本数量,实现滚动更新和回滚。Service 为一组 Pod 提供稳定的访问入口,解决 Pod IP 变化的问题,并提供负载均衡。

Q:K8s 如何实现零停机发布?

Deployment 的滚动更新:先创建新版本 Pod,健康检查通过后将其加入 Service,再逐步替换旧版本 Pod。配合 maxUnavailable=0(不允许不可用 Pod),确保始终有足够的 Pod 处理流量。readinessProbe 确保新 Pod 真正就绪后才接收流量。

Q:liveness 和 readiness 探针有什么区别?

liveness 探针失败会重启容器,用于检测容器是否进入无法自愈的状态(如死锁)。readiness 探针失败不重启,只是把 Pod 从 Service 的 Endpoints 中摘除,停止接收新请求,用于检测容器是否准备好处理流量(如初始化中、依赖不可用)。

Q:K8s 中如何管理配置和敏感信息?

非敏感配置用 ConfigMap,敏感信息用 Secret(base64 编码)。两者都可以以环境变量或文件形式注入 Pod。注意 Secret 的 base64 不是加密,生产环境需配合外部密钥管理系统(如 Vault)。

Q:K8s 的 Service 是如何实现负载均衡的?

kube-proxy 监听 Service 和 Endpoints 变化,在每个 Node 上维护 iptables(或 IPVS)规则。请求到达 Service VIP 后,由内核的 iptables/IPVS 规则随机/轮询转发到健康的 Pod IP。IPVS 模式性能更好,支持更多负载均衡算法。

Q:Pod 一直处于 Pending 状态怎么排查?

执行 kubectl describe pod <name> 查看 Events 部分。常见原因:① 资源不足(Insufficient cpu/memory);② 节点选择器/亲和性不匹配;③ 污点未容忍(Taint);④ PVC 未绑定存储。

Q:K8s 如何实现服务发现?

K8s 内置 CoreDNS,为每个 Service 自动注册 DNS 记录:<service-name>.<namespace>.svc.cluster.local。Pod 通过 Service 名称直接访问,CoreDNS 解析到 Service 的 ClusterIP,再由 kube-proxy 转发到具体 Pod。

Q:Deployment 和 StatefulSet 的区别?

Deployment 管理无状态应用,Pod 可随意替换,名称随机,存储可共享。StatefulSet 管理有状态应用,Pod 名称有序固定(app-0/1/2),每个 Pod 有独立 PVC,有序启动和删除,Pod 重建后网络标识不变。适用于 MySQL、Kafka 等需要稳定标识和独立存储的应用。

Q:ENTRYPOINT 和 CMD 有什么区别?

CMD 提供默认命令,docker run 时传入参数会完全替换 CMD。ENTRYPOINT 定义容器主程序,docker run 传入的参数会追加到 ENTRYPOINT 后。最佳实践:用 ENTRYPOINT 固定主程序,CMD 提供可覆盖的默认参数。同时必须使用 Exec 格式(["cmd"])而非 Shell 格式,确保进程 PID=1 能正确收到 SIGTERM 实现优雅退出。

Q:DaemonSet 和 Deployment 有什么区别?什么场景用 DaemonSet?

Deployment 指定副本数,由调度器决定 Pod 分布;DaemonSet 不指定副本数,在每个符合条件的 Node 上运行一个 Pod。用于需要在每台机器上运行的基础设施组件:日志采集(Fluentd)、监控 Agent(Node Exporter)、网络插件(Calico)等。Node 加入集群时自动部署,Node 移除时自动清理。

Q:Job 和 Deployment 的区别?CronJob 怎么用?

Deployment 管理持续运行的服务(不退出);Job 管理运行完即退出的一次性任务,保证 Pod 成功完成指定次数,失败会重试。CronJob 按 Cron 表达式定期创建 Job,适合报表生成、数据清理等定时任务。注意 Job 的 Pod 必须设置 restartPolicy: NeverOnFailure,CronJob 需要设置 concurrencyPolicy 控制并发行为。

Q:什么是 K8s RBAC?在生产中怎么用?

RBAC 是基于角色的访问控制。通过 Role/ClusterRole 定义权限(对哪些资源做哪些操作),通过 RoleBinding/ClusterRoleBinding 将权限绑定给 ServiceAccount(应用身份)或用户。生产实践:每个微服务使用独立的 ServiceAccount,只授予运行所需的最小权限(比如只读 ConfigMap/Secret),遵循最小权限原则,防止容器被攻破后横向扩散。

Q:如何给一个 K8s 集群中的 Go 服务做优雅退出?

① 监听 SIGTERM 信号,停止接收新请求,等待现有请求处理完成;② 在 Pod spec 中配置 preStop hook 加 sleep(等待 Service 摘流完成,因为 K8s 摘流和发 SIGTERM 是并行的);③ 设置合理的 terminationGracePeriodSeconds(默认30s)。


二十二、一张图记住核心

复制代码
Docker 核心:
┌─────────────────────────────────────────────────────────────┐
│  Namespace(隔离视图)+ Cgroups(限制资源)= 轻量级容器       │
│  OverlayFS 分层存储 = 共享基础层,节省空间,加速构建          │
│  多阶段构建 = 编译环境不进最终镜像,体积最小化               │
└─────────────────────────────────────────────────────────────┘

K8s 核心:
┌─────────────────────────────────────────────────────────────┐
│  Pod(最小单元)← Deployment(无状态)/ StatefulSet(有状态) │
│  DaemonSet(每节点一个)/ Job(一次性)/ CronJob(定时)      │
│  Service(稳定访问)← ClusterIP / NodePort / LoadBalancer    │
│  ConfigMap / Secret(配置与密钥分离)                        │
│  liveness + readiness(健康检查 + 流量控制)                 │
│  HPA(自动扩缩容)+ 滚动更新(零停机发布)                   │
│  RBAC(ServiceAccount + Role + RoleBinding = 最小权限)      │
└─────────────────────────────────────────────────────────────┘

排查问题三板斧:
  kubectl describe pod <name>   → 看 Events(调度/启动失败原因)
  kubectl logs <name> -f        → 看应用日志(运行时错误)
  kubectl get events            → 看集群事件(全局异常)

总结:Docker 面试核心是"容器 vs 虚拟机"、"镜像分层原理"、"ENTRYPOINT vs CMD";K8s 面试核心是"核心对象的职责与关系"(Pod/Deployment/StatefulSet/DaemonSet/Job/Service/Ingress)、"零停机发布流程"、"健康检查三种探针"、"RBAC 权限控制"。把这些讲清楚,Docker + K8s 面试基本稳了。

相关推荐
Benszen4 小时前
Docker容器化技术全解析
运维·docker·容器
豆沙糕6 小时前
Python异步编程从入门到实战:结合RAG流式回答全解析
开发语言·python·面试
前端摸鱼匠6 小时前
【AI大模型春招面试题13】残差连接(Residual Connection)与层归一化(Layer Norm)在Transformer中的作用?
人工智能·深度学习·语言模型·面试·transformer·求职招聘
馨谙6 小时前
OpenEBS + PV/PVC 解析:命令、文件、作用、后续用法
云原生·容器·kubernetes
再ZzZ7 小时前
Docker快速部署Kafka(内网通用版本)
docker·容器·kafka
亚马逊云开发者7 小时前
告别手动部署:在 Amazon EKS 上用 CodePipeline + Argo CD 搭建 GitOps CI/CD
elasticsearch·ci/cd·kubernetes
Stack Overflow?Tan908 小时前
linux ubuntu22.04安装ROS2humble完整版的流程
linux·docker·ros2
→长歌9 小时前
2026Java面试30题精解
java·python·面试
笨笨没好名字9 小时前
结构工程/机械工程/工业设计/硬件工程师面试题目(题源大疆:12+28)
人工智能·面试·职场和发展
LSL666_10 小时前
JVM面试题——垃圾收集器
java·jvm·面试·垃圾收集器