
很多人在用 Docker 跑通第一个容器后会产生一个很自然的疑问Docker 已经把应用和环境打包到镜像里一个docker run就能启动服务配套docker-compose也能管理一组容器为什么社区里还要强调 KubernetesK8s这个问题的答案不在于 Docker 不够好而在于 Docker 解决的问题域在单机K8s 解决的问题域在集群。Docker 负责的是“把应用装进标准集装箱”K8s 负责的是“成千上万个集装箱在一个港口集群里怎么卸货、怎么堆放、怎么在吊机故障时自动转移、怎么根据订单量扩减泊位”。如果只管理一两台服务器Docker Compose 确实够用一旦服务数量变多、机器数量变多、发布频率变高单靠 Docker 命令和 Compose 文件就很难回答下面几个问题某台机器挂了容器会自动迁移到其他机器吗流量高峰期需要 5 个副本能不能一条配置完成扩容新版本发布能不能不中断服务地滚动上线这篇文章围绕这条主线展开先分析 Docker 和 K8s 的职责边界再通过一个应用部署演进案例解释 K8s 为什么会出现然后给出快速上手 K8s 的方式、常见故障排查路径以及新人最容易踩的坑。读完你可以对着自己的项目判断当前阶段到底需不需要 K8s。1. 先理清 Docker 干了什么又没干什么1.1 Docker 的价值把应用和运行环境一起打包Docker 的核心贡献是让“环境”变成了可交付的软件产物。过去部署一个 Java 应用需要先装 JDK、配置环境变量、安装依赖库、调整内核参数每一步都可能出错。使用 Docker 后开发者把 JDK、应用包、配置文件全部写进 Dockerfile构建成镜像然后在任何装有 Docker 的机器上启动容器运行环境都是一致的。一个最简单的打包和启动过程如下# 基于 openjdk 镜像构建应用镜像 docker build -t myapp:1.0.0 . # 启动容器将宿主机 8080 端口映射到容器 8080 端口 docker run -d -p 8080:8080 --name myapp myapp:1.0.0镜像由一层层只读文件组成容器则是在镜像之上增加一个可写层。这样做的直接好处是同一个镜像可以启动多个容器容器之间相互隔离资源占用比虚拟机更小启停速度也更快。这正是 Docker 最重要的价值它把一个复杂的应用运行环境压缩成了一个可复制的标准单元。1.2 Docker 的边界它主要管理一台机器上的容器Docker 本身是一个单机工具。它可以管理这台机器上的镜像、容器、网络和数据卷但它的调度范围仅限于当前宿主机。你执行docker run时容器只会运行在这台机器上这台机器宕机Docker 不会自动把容器迁移到别的机器。这意味着 Docker 没有解决集群层面的问题跨节点调度一个容器应该安排到哪台机器运行Docker 不会做全局决策。故障自愈节点宕机、容器异常退出后Docker 不会自动在另一台节点重建。弹性伸缩业务量增加时Docker 不能根据访问量自动增加容器数量。服务发现多个容器分布在多台机器后客户端如何稳定访问某个服务Docker 没有统一的解决方案。你可能会说Docker 有docker restart、docker run --restartalways这种策略但这些都只作用于当前机器的守护进程。若整个节点断电容器并不会被自动迁移到备用节点。这个边界决定了 Docker 适合作为“单机容器运行环境”但还不够作为“集群容器平台”。1.3 Docker Compose 是编排吗是但只到单机层面Docker Compose 解决的问题是“多个容器怎么协同启动”。比如一个 Web 服务依赖 MySQL 和 Redis用 Compose 可以在一个 YAML 文件里定义三个服务一条命令启动整个栈version: 3.8 services: web: image: myapp:1.0.0 ports: - 8080:8080 depends_on: - mysql - redis mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: rootpass redis: image: redis:7-alpine然后执行docker-compose up -d docker-compose psCompose 确实负责了服务定义、网络连接和启动顺序所以很多人把它理解成“编排工具”。但从集群角度看Compose 的编排边界仍然在一台机器内。它可以指定副本数比如docker-compose up -d --scale web3但所有副本还是跑在同一台宿主机上共享同一份 CPU、内存和网络资源。Docker、Docker Compose 和 Kubernetes 的职责大致可以按下表区分工具核心作用调度范围是否支持跨节点是否支持自动伸缩是否支持故障迁移Docker构建镜像、运行容器单机否否否Docker Compose定义和管理多容器应用单机否手动--scale局限于单机否Kubernetes集群容器编排与调度多节点集群是是是理解这个差异后再去看“有了 Docker 为什么还要 K8s”核心答案就很清楚Docker 是底层引擎K8s 是上层调度平台。K8s 本身也依赖 Docker 或 containerd 这类容器运行时来启动容器两者不是替代关系而是层次关系。2. 从单机到集群一个应用部署演进的例子2.1 阶段一直接跑进程假设你有一个最简 Web 服务编译产物是一个二进制文件或一个 war 包。最早的部署方式是在服务器上安装运行时把进程挂到后台nohup ./myapp app.log 21 这种方式很快会遇到问题服务器环境变了应用可能启动失败多个应用依赖同一个运行库的不同版本会发生冲突进程异常退出后没有机制自动拉起代码升级时需要先手动杀掉旧进程再启动新进程发布期间服务会中断。2.2 阶段二用 Docker 跑容器使用 Docker 后环境隔离问题解决了。同一台服务器上可以同时运行不同 JDK 版本的应用因为每个容器都包含自己的运行环境docker build -t myapp:1.0.0 . docker run -d -p 8080:8080 --name myapp myapp:1.0.0这个阶段部署确实轻松了很多。但单机能力瓶颈很快会出现应用访问量大了这台服务器 CPU 和内存吃紧再启动几个容器可能直接 OOM。于是你自然会买第二台服务器在上面也跑一个相同容器前面再用 Nginx 做负载均衡。这时 Docker 仍然只解决“每台机器上怎么跑容器”而“流量怎么分发、节点状态怎么同步、容器要不要重建”都需要自己手工维护。2.3 阶段三用 Docker Compose 管理一组容器服务依赖多个组件时比如前端 Nginx、后端 PHP-FPM、数据库 MySQL人工一个个docker run很容易忘记参数。Compose 通过声明式文件解决问题version: 3.8 services: nginx: image: nginx:1.25-alpine ports: - 80:80 volumes: - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro php: image: php:8.2-fpm mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: rootpassdocker-compose up -d会按依赖关系启动一组容器服务之间通过 Compose 内部网络互相访问。在单机开发环境中这套体验已经非常顺滑。但它解决不了跨机器的问题如果这台机器负载过高Compose 不会把容器调度到另一台机器如果 MySQL 容器出现故障它只能在同一台机器上重启。2.4 阶段四故障、扩容、发布时的灵魂拷问随着业务继续增长你会逐渐面对这些问题一台服务器宕机业务完全中断因为所有容器都在那台机器上。需要怎样让容器在另外的节点自动重建大促前需要把应用从 2 个实例扩容到 10 个实例能不能不重新打包、不手工登录每台机器发新版本时能不能先启动新 Pod等新 Pod 健康后再停止旧 Pod做到零停机发布多个应用部署在多台机器后一个应用怎么找到另一个应用的实例地址容器重建后 IP 变了怎么能让上游服务无感知这些问题已经超出 Docker 和 Compose 的能力边界。K8s 的核心价值就是把这些操作从“人肉运维”变成“声明期望状态 控制器自动对齐”。比如同样的应用在 K8s 里用下面这份清单描述apiVersion: apps/v1 kind: Deployment metadata: name: myapp spec: replicas: 3 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: containers: - name: myapp image: myapp:1.0.0 ports: - containerPort: 8080这份配置表达了“我希望有 3 个副本镜像版本是 1.0.0”具体把 Pod 调度到哪台节点、节点挂了如何重建、如何滚动更新都由控制器完成。你不再盯着某个容器而是维护一份期望状态K8s 负责让现实朝期望状态收敛。这正是 Docker 时代最缺的能力。3. K8s 用哪些抽象解决了集群问题3.1 Pod容器的调度单位K8s 并没有直接调度容器而是引入了一个更高层次的抽象Pod。一个 Pod 可以包含一个或多个容器这些容器共享同一个网络命名空间、同一条 Pod IP也可以共享存储卷。为什么需要 Pod因为有些容器必须“生死与共”。最典型的场景是日志采集边车容器应用容器写日志边车容器读取日志并发送到采集中心两个容器如果被调度到不同机器就失去意义。把一组强关联容器放进同一个 PodK8s 就能保证它们在同一节点上调度、一起启动、一起停止。对初学者来说先记住K8s 中最小操作单元不是容器而是 Pod。kubectl get pods看到的列表才是你日常排查的主要对象。3.2 Deployment声明期望状态Deployment 是 K8s 里最常用的工作负载控制器。它管理一组 Pod 副本并保证实际副本数始终和期望副本数一致。上面示例中的replicas: 3就是期望副本数。当某个 Pod 被误删Deployment 控制器会自动新建一个当节点宕机控制器也会在其他可用节点上补齐副本。Deployment 还内置了滚动更新策略发布新版本时可以逐步替换旧 Pod过程中服务不中断。使用 Deployment 时不要把实例 IP 写死在配置里。Pod 的名字和 IP 是临时资源重启后都会变化。需要通过 Service 提供稳定的访问入口。3.3 Service稳定的访问入口Service 是 K8s 对外暴露服务的抽象。它为一组 Pod 提供一个固定的服务名字和虚拟 IP客户端不需要关心后端 Pod 的 IP 变化。最常用的 Service 类型有三种类型访问方式适用场景ClusterIP集群内部虚拟 IP服务间内部调用NodePort每个节点暴露一个端口外部访问、本地联调LoadBalancer云厂商负载均衡器公有云生产环境Service 通过 selector 标签选择后端 Pod。比如 Deployment 里的 Pod 打了app: myapp标签Service 就可以这样匹配apiVersion: v1 kind: Service metadata: name: myapp-svc spec: selector: app: myapp ports: - port: 80 targetPort: 8080 type: ClusterIP请求进入 Service 的 80 端口后会被转发到后端 Pod 的 8080 端口。如果 Pod 数量从 3 变成 5Service 会自动感知并扩大后端列表。这就是服务发现的答案。3.4 控制器与控制平面的工作方式K8s 集群可以分成控制平面和工作节点两部分。控制平面上运行着几个关键组件kube-apiserver所有操作的入口提供 REST API是集群的“前端”。etcd保存集群所有状态数据是集群的“数据库”。kube-controller-manager运行各类控制器让实际状态向期望状态收敛。kube-scheduler为新创建的 Pod 选择合适的节点。每个工作节点上还有两个核心进程kubelet负责当前节点上的 Pod 生命周期与 API Server 通信。kube-proxy维护网络规则实现 Service 的负载均衡。当你执行kubectl apply -f deployment.yaml时请求首先打到 kube-apiserver状态写入 etcdscheduler 根据资源情况选择一个节点kubelet 收到指令后调用容器运行时比如 containerd启动容器。之后控制器持续监控实际状态一旦发现 Pod 数量少于期望副本数就会补充新的 Pod。3.5 Docker 和 K8s 的关键差异速查维度Docker单机Kubernetes集群调度的最小单位容器Pod跨节点调度不支持支持故障自愈仅单机重启策略控制器自动重建和迁移弹性伸缩手动扩展自动/手动扩缩容发布策略手动停旧起新滚动更新、回滚服务发现需要自己维护Service / Ingress状态保存数据卷挂载在本地PV/PVC结合分布式存储配置管理环境变量/env_fileConfigMap / Secret这张表不是否定 Docker而是说明两者处于不同层次。生产集群中的 K8s 仍然依赖容器运行时来启动容器只是容器运行时通常换成更轻量的 containerd。Docker 更多承担镜像构建、开发调试和单机部署的角色。4. 如果只是想体验 K8s怎么快速跑起来4.1 学习环境minikube 快速启动本地学习 K8s最稳妥的方式不是立刻搭一个多节点集群而是先用 minikube 在一台机器上模拟集群。minikube 可以创建单节点集群适合验证 Pod、Service、Deployment 这些概念。前提是机器上已经安装好 Docker。然后执行# 以 docker 作为驱动启动 minikube minikube start --driverdocker # 查看集群状态 kubectl get nodes如果你的机器安装了 Docker Desktop也可以在 Docker Desktop 设置里直接启用 Kubernetes。这种方式同样适合学习但它是单节点集群资源上限受本机配置影响不建议当作生产环境。启动完成后K8s 的命令行工具是 kubectl。它负责向 API Server 发送请求。检查 kubectl 是否可用kubectl version --client kubectl cluster-info4.2 生产环境kubeadm 或云托管 Kubernetes生产环境搭建 K8s 与学习环境差异很大。可以自己用 kubeadm 从零搭建多节点集群但这需要处理网络插件CNI、证书续期、etcd 备份、控制平面高可用等问题。也可以使用云厂商托管的 Kubernetes 服务把控制平面交给云平台维护自己只需要关注节点池和应用部署。这里区分一下学习环境与生产环境环境重点需要额外关注学习环境快速验证概念资源足够保留快照测试环境模拟业务部署数据隔离、权限控制生产环境稳定和可运维日志、监控、告警、证书、备份、回滚不要在学习阶段直接照搬生产级高可用方案太多组件会淹没对核心概念的理解。先用 minikube 跑通流程再逐步接触多节点。4.3 一个最小部署示例从镜像到 Pod 再到 Service搭建好集群后用 Nginx 镜像跑一个最小示例验证集群能正常拉取镜像、创建 Pod、暴露服务。先创建一个 Deploymentkubectl create deployment nginx-demo --imagenginx查看 Pod 状态kubectl get pods正常情况下几秒后可以看到一个 nginx-demo 的 Pod 处于 Running 状态。如果镜像拉取较慢状态会停留在 ContainerCreating可以使用kubectl describe pod观察事件。接着创建一个 Service把 Pod 暴露成一个稳定的访问入口kubectl expose deployment nginx-demo --port80 --typeNodePort查看 Servicekubectl get svcNodePort 类型的 Service 会分配一个 30000-32767 范围内的端口。在 minikube 环境中直接执行minikube service nginx-demo会自动打开浏览器访问在普通集群中需要访问任意节点的 IP 加 NodePort 端口。验证完成后清理资源kubectl delete service nginx-demo kubectl delete deployment nginx-demo这个例子很小但已经覆盖了 K8s 最核心的三个对象Deployment、Pod、Service。后面再学习 Ingress、ConfigMap、PersistentVolume 时都是在这个基础上扩展。5. K8s 真正香的场景与不适合的场景5.1 适合 K8s 的场景微服务、弹性伸缩、多环境发布K8s 的价值在复杂场景下才会充分体现。微服务架构中服务数量可能有几十个每个服务有独立的部署、扩容、回滚需求。用脚本维护这些服务会非常痛苦而 K8s 允许每个服务对应一个 Deployment通过标签和命名空间组织资源。比如 LNMP 架构Nginx PHP-FPM MySQL从 Docker Compose 迁移到 K8s 后Nginx、PHP-FPM、MySQL 分别是独立的 Deployment/StatefulSet通过 Service 访问配置用 ConfigMap 管理数据用 PVC 管理。弹性伸缩是 K8s 的另一个强项。借助 HPAHorizontal Pod Autoscaler可以根据 CPU 内存指标自动调整副本数kubectl autoscale deployment myapp --cpu-percent70 --min2 --max10这条命令表达的是“当 CPU 使用率超过 70% 时自动在 2 到 10 个副本之间伸缩”。在 Docker 单机环境里这种能力很难做到。滚动发布和快速回滚也很适合 K8s。修改镜像版本后执行kubectl set image deployment/myapp myappmyapp:1.1.0如果新版本有问题可以一键回滚到上一个版本kubectl rollout undo deployment/myapp这在“线上版本有 bug 需要秒级恢复”的场景下非常关键。5.2 不适合 K8s 的场景单机小项目、无运维团队、超低延迟K8s 不是技术军备竞赛有些场景引入它反而增加负担。个人博客、小型后台、工具站点如果一台服务器就能稳定运行用 Docker Compose 或 supervisor 会更高效。K8s 集群最少也要几个节点控制平面需要资源维护也需要额外精力。对没有专职运维的小团队来说自己搭建的 K8s 集群一旦证书过期、etcd 故障、网络插件出问题排查成本可能比业务本身还高。另外K8s 的网络转发链路比普通进程直接对端口监听更长。虽然性能损耗通常可以接受但如果你在做极低延迟的交易系统、量化计算就需要先做压测不要为了“技术先进”而盲目引入。判断是否适合引入 K8s可以问自己几个问题是否已经有多台服务器服务是否需要按流量自动伸缩发布新版本是否能接受停机团队是否有时间学习和维护集群如果以上问题多数是否那继续使用 Docker Compose 更合理。5.3 从 Docker Compose 平滑迁移到 K8s 的思路如果确定要迁移不建议手工翻译所有 Compose 配置。可以遵循下面这个顺序先梳理镜像。Compose 里每个 service 的 image 是否是稳定 tag最好改成不可变版本号例如1.0.0不要用latest。提取环境变量和配置文件。Compose 里的 environment、env_file 可以映射到 K8s 的 ConfigMap 和 Secret。转换工作负载。无状态服务用 Deployment有状态服务用 StatefulSet。迁移持久化。Compose 里的卷挂载要改成 PVC考虑存储类如何配置。处理网络。Compose 内部服务名会被 K8s Service 名称替代端口访问关系要重新梳理。用工具生成初始清单。可以使用 kompose 将 docker-compose.yml 转换为 K8s YAML但生成结果通常需要人工调整不能直接上生产。# 转换示例 kompose convert -f docker-compose.yml转换后的 YAML 只是起点重点是把上面的 ConfigMap、PVC、Service 结构调整到位。6. 常见问题Docker 与 K8s 联调时的排查链路6.1 Docker 镜像下载慢、构建慢怎么处理现象docker pull或docker build时长时间卡住进度条不动。可能原因默认拉取 Docker Hub 镜像的网络不稳定。构建时没有合理利用缓存每一次都重新拉取基础镜像。Docker daemon 没有配置镜像加速器。检查方式# 查看 docker daemon 配置 cat /etc/docker/daemon.json解决方案为 Docker daemon 配置 registry mirror 加速地址。常见云厂商都提供加速地址具体以服务商文档为准。配置后执行sudo systemctl restart docker。避免在构建过程中频繁变更基础镜像层。把apt-get install、pip install等操作放在 Dockerfile 靠前位置利用构建缓存。如果团队内多台机器都要用同一镜像可以搭建本地镜像仓库减少公网拉取。这类问题通常不是 K8s 本身引起的但会直接影响 K8s 拉取镜像。K8s 节点拉取镜像失败时Pod 会停留在 ContainerCreating事件里会显示Failed to pull image。6.2 容器起来了但访问不到从 Docker 网络到 K8s Service 的排查现象容器状态是 Running但通过浏览器或接口访问不到服务。在 Docker 环境先检查宿主机端口映射docker ps curl http://127.0.0.1:8080如果访问失败看容器内进程是否真的监听在 8080 端口docker exec -it container_id ss -ltn在 K8s 环境排查顺序要扩展# 查看 Pod 是否 Running kubectl get pods -o wide # 查看 Pod 内端口是否正常 kubectl logs pod-name kubectl exec -it pod-name -- ss -ltn # 查看 Service 是否选择到 Pod kubectl get endpoints service-name # 看 Service 详情 kubectl describe svc service-name如果kubectl get endpoints为空说明 Service 的 selector 和 Pod 的 labels 不匹配。这是最常见的问题之一。问题现象可能原因检查方式处理建议Service 访问失败selector 不匹配kubectl get endpoints调整 Service selector 与 Pod label 一致Pod Running 但业务不通应用监听端口不是容器端口kubectl exec查看监听端口修改 targetPort外部访问 NodePort 失败防火墙未放行 NodePort在节点上执行 curl 测试放行端口或改用 LoadBalancerPod 一直 ContainerCreating镜像拉取失败或存储卷挂载失败kubectl describe pod查看 Events 定位失败原因6.3 Pod 反复重启、CrashLoopBackOff 怎么查现象kubectl get pods显示 Pod 状态为CrashLoopBackOff表示容器启动后很快退出又被 K8s 反复拉起。排查步骤# 1. 先看容器日志 kubectl logs pod-name # 2. 如果容器之前崩溃过看上一次日志 kubectl logs pod-name --previous # 3. 看 Pod 详细事件和退出码 kubectl describe pod pod-name退出码是重要线索退出码常见含义常见原因0正常退出容器任务执行完或进程主动结束1应用错误配置错误、端口被占用、启动参数问题137被 SIGKILL 杀死内存超上限被 OOMKilled或手动删除 Pod143被 SIGTERM 终止优雅停机阶段收到终止信号如果退出码是 137重点检查 Pod 内存 limits 和节点可用内存kubectl describe pod pod-name | grep -A5 State: kubectl top nodes如果退出码是 1重点看业务日志。很多情况下是容器缺少环境变量或启动脚本里没有前台运行进程导致容器启动后立即退出。6.4 K8s 故障排查常用命令入口可以把下面这些命令整理成一份排查清单遇到问题时按顺序执行# 集群层 kubectl get nodes kubectl describe node node-name kubectl get events --all-namespaces # 工作负载层 kubectl get pods -o wide kubectl describe pod pod-name kubectl logs pod-name --previous kubectl get deployment deployment-name kubectl rollout status deployment/deployment-name # 网络层 kubectl get svc kubectl get endpoints service-name kubectl get ingress # 资源层 kubectl get pvc kubectl get configmap kubectl get secret生产集群里kubelet 的日志通常位于/var/log/messages或/var/log/syslog视具体操作系统而定。容器运行时使用 containerd 时可以执行crictl ps查看容器状态。这些命令能覆盖大多数“容器起不来、访问不到、反复重启”的问题。7. 新手最该避开的几个坑以及面试常问点7.1 三个与 Docker/K8s 强相关的陷阱陷阱一镜像打好了但容器秒退日志却为空。常见原因是没有前台进程。Docker 容器的主进程一旦退出容器就会停止。如果启动脚本执行了后台启动例如nohup java -jar app.jar 脚本立即返回容器随即退出。正确做法是让主进程前台运行Java、Nginx、PHP-FPM 等都有前台运行参数Dockerfile 的 CMD 或 ENTRYPOINT 应直接执行主进程。陷阱二把有状态数据库随便丢进 Deployment。Deployment 控制下的 Pod 是无状态、可替换的Pod 删除后 PVC 如果没有声明数据可能丢失。MySQL、Redis、Elasticsearch 这类有状态组件应该使用 StatefulSet并搭配稳定的存储卷。不要用普通 Deployment 跑生产数据库除非你明确知道数据卷已经持久化且备份策略完善。陷阱三用 latest 标签部署导致版本不可控。image: myapp:latest在并发发布时会让不同节点拉取到不同版本出现“怪癖 bug”。更推荐每个构建产生一个唯一 tag例如myapp:20250101-abc123部署清单里写明具体版本。这样回滚时只需把 Deployment 的镜像 tag 改回旧版本kubectl rollout undo也有明确依据。7.2 K8s 面试题高频角度面试里最常被问的问题基本围绕这几组概念Docker 和 K8s 有什么区别核心答法是Docker 是容器引擎负责镜像和单机容器运行K8s 是容器编排平台负责跨节点调度、服务发现、故障自愈、弹性伸缩。Pod 和容器的关系核心答法是Pod 是调度单位一个 Pod 可以包含多个共享网络和存储的容器容器是 Pod 内部的最小运行实体。Deployment 和 StatefulSet 有什么区别核心答法是Deployment 适合无状态服务副本可随意替换StatefulSet 适合有稳定标识、稳定存储、有顺序启停的服务。Service 怎么实现负载均衡核心答法是Service 通过 selector 选择后端 Podkube-proxy 维护负载转发规则客户端只需访问 Service 地址。Pod 一直 CrashLoopBackOff 怎么排查核心答法是先kubectl logs看日志再kubectl describe pod看退出码和事件用退出码判断是应用错误还是 OOM。这些热点在 CI/CD、云原生、微服务面试中经常出现理解原理比背答案更重要。7.3 一条务实的学习路径如果你现在刚学完 Docker想进入 K8s可以参考这条路径扎实掌握 Docker 镜像构建和容器运行命令。用 Docker Compose 部署一个多服务项目例如 LNMP 或前后端分离项目。安装 minikube启动单节点集群。学习 Deployment、Pod、Service 三个核心对象。用 kubectl 部署一个无状态应用并暴露访问入口。给应用配置 ConfigMap 和 Secret替换原来写在容器里的配置。学习 Volume 和 PVC把容器数据持久化。学习 Ingress统一管理 HTTP 和 HTTPS 入口。自己搭一个多节点 kubeadm 集群理解证书、插件和节点角色。再学习 HPA、Namespace、RBAC、Helm 等生产必备能力。不要一上来就同时学 Helm、Istio、ArgoCD先把“Pod 起来了、Service 通了、数据不丢、版本能回滚”这条链路打通再扩展周边生态。8. 收尾你的项目到底要不要上 K8s回到标题的问题。Docker 和 K8s 不是二选一而是层次递进的关系。Docker 把应用变成标准容器K8s 让这些容器在集群中稳定、自动、可控地运行。如果你的业务规模仍然是一台服务器、几个容器用 Docker Compose 是最省心的选择当出现多节点、频繁发布、弹性伸缩、故障转移等需求时K8s 的价值才会体现。可以做这样一个决策判断判断条件偏向继续用 Docker Compose偏向引入 K8s服务器数量1 到 2 台3 台以上服务数量1 到 5 个10 个以上发布频率每周一次或更低每天多次流量波动稳定有明显高峰低谷运维团队无专职运维有运维或 DevOps 岗位服务状态有状态为主无状态服务为主故障容忍度允许短时停机要求自动恢复这张表不是绝对标准但能帮你快速判断当下重点。对大多数刚接触云原生的开发者来说Docker 是必须扎实掌握的基础K8s 则是在规模增长后自然需要的下一层能力。先把单机容器玩熟再用 minikube 跑通第一个 Deployment比一开始就搭建复杂集群更容易建立正确认知。如果你的业务已经出现“机器挂了业务中断”“扩容要通宵”“发布过程总有停顿”这些问题再回头看这篇文章里的 Deployment、Service 和排查清单你会更清楚下一步该从哪个方向切入。