面试 | 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 面试基本稳了。

相关推荐
Volunteer Technology2 小时前
RabbitMQ面试场景题归纳
分布式·面试·rabbitmq
食指Shaye2 小时前
docker的学习日记
学习·docker·eureka
ErizJ2 小时前
面试 | Go八股
面试·golang
℘团子এ2 小时前
什么是Docker
前端·docker·容器
Rsun045512 小时前
Docker部署项目
运维·docker·容器
janthinasnail2 小时前
使用Docker安装OpenClaw
docker·容器·openclaw
XPii2 小时前
FPGA工程师面试资料【1】
fpga开发·面试·职场和发展
研究点啥好呢2 小时前
百度 人工智能工程师面试题精选
人工智能·pytorch·神经网络·百度·ai·面试·文心一言
小夏卷编程11 小时前
Ubuntu 20.04.4 宝塔 docker showdoc v3.2 更新到v3.7.3
运维·docker·容器