
简介《容器集群k8s从入门到精通》是一份面向Kubernetes初学者与云原生运维人员的PDF电子书系统梳理了应用部署从传统物理机、虚拟化到容器化的演进脉络解释了容器编排需求产生的原因并引出Kubernetes自我修复、弹性伸缩、服务发现、负载均衡等核心功能。内容覆盖集群控制节点与工作节点的组件职责包括ApiServer、Scheduler、ControllerManager、Etcd、Kubelet和KubeProxy并结合Nginx部署实例完整走通请求→调度→创建Pod→对外访问的流程。资源为单个PDF文件大小4.22MB目录按章节展开第一章介绍Kubernetes概念、组件与工作原理第二章详细规划一主两从集群的IP、主机配置并逐步安装docker、kubeadm、kubelet覆盖集群环境搭建全过程适合边学边练。目前已有657人学习下载可作为k8s入门扫盲、面试复习或本地搭建集群的速查手册。 这两年容器集群的坑我踩了不少现在回头看k8s之所以让那么多人头大不是因为概念多而是因为很多人上手姿势不对。我第一次在公司搭k8s集群的时候照着网上的教程刷了一整天最后kubectl get nodes还是只有 NotReady那种挫败感我到现在都记得。后来把整套东西重新学了一遍才发现大部分问题都出在没搞懂 k8s 的设计意图就直接上命令结果装完了也不知道怎么排查。这篇文章就当是一份从入门到精通的 k8s 学习笔记适合正在学容器集群、准备上手 k8s 或者面试前突击的朋友。我把学习路径、部署流程、经典应用、常见坑和面试要点都串在一起重点讲清楚哪些地方必须理解哪些地方可以直接背命令以及我自己踩过的坑怎么绕开。说白了就是让你少走弯路。1. 先搞清楚k8s 到底解决了什么问题1.1 从单机容器到集群调度的必然选择先说一个最基础的问题一台机器上用 Docker 跑几个容器跟用 k8s 管理几十台机器上的几百个容器完全是两个世界。单机 Docker 时代你手动docker run一个 nginx端口映射好数据卷挂好跑起来就完事了。但等你到了几十个容器、几十台机器的规模麻烦就来了容器挂了你得手动拉起来流量大了你得手动扩容新版本上线你得手动一台台更新容器间的地址变了你还要手动改配置。这些碎片化的工作堆在一起占用了大量运维时间而且人肉操作总免不了出错。那能不能把这些事情自动化答案就是 k8s。k8s 本身不直接跑容器它是一个容器编排平台扮演的是调度器的角色。你告诉它我要跑 3 个 nginx每个占用 2 核 CPU、1G 内存对外提供 80 端口访问剩下的事情——在哪台机器上跑、容器挂了怎么拉起、流量怎么分配、滚动更新怎么做——全部由 k8s 自动完成。我在实际项目中体会最深的是k8s 其实是一种声明式思维的转变。你描述的是最终想要的状态而不是一步一步怎么做。比如你想要 5 个副本k8s 就会想尽办法让集群里始终有 5 个副本某个节点死了它会把上面的 Pod 重新调度到别的节点。这种思维一旦建立很多架构上的问题会豁然开朗。1.2 学习 k8s 之前需要具备的基础这里我说句实在话很多人零基础直接学 k8s学得很痛苦不是因为 k8s 本身有多难而是前面缺的东西太多了。以我带过的初级工程师的经验来看最好先具备这几个基础第一Linux 基本操作。k8s 的节点基本都是 Linux 服务器你至少要会用 systemctl 管理服务、会用journalctl看日志、会配置网络相关的参数。不要求你精通内核但常见的排障操作得顺手。第二Docker 的使用经验。k8s 的 Pod 里跑的还是容器镜像、容器、数据卷这些概念是通用的。如果你连docker run和docker build都没摸过建议先去玩两周 Docker 再回来。注意k8s 不是替代 Docker 的它俩是不同层面的东西后面我会专门讲这个区别。第三基本的网络知识。k8s 里的 Service、Pod 网络、Ingress 这些概念本质都是在做网络通信。IP、端口、DNS、负载均衡这些基础概念不清楚的话排查网络问题的时候会非常痛苦。至于 YAML 语法这个不用特意学写几天配置文件自然就熟了。关键是理解 YAML 描述的资源模型而不是记住语法。2. 核心概念拆解别被术语劝退2.1 控制面与工作节点k8s 的大脑和手脚k8s 集群从物理结构上分两部分控制面和工作节点。控制面是大脑负责做决策和记录状态。它里面跑着几个关键组件kube-apiserver是整个系统的入口所有请求都要经过它etcd保存集群的全部状态数据相当于数据库kube-controller-manager是各种控制器的集合负责维护集群状态比如 Pod 挂了要拉起kube-scheduler负责决定新 Pod 应该放到哪个节点上。这四个组件协作构成了 k8s 的控制逻辑。工作节点是手脚真正跑应用的地方。每个节点上都有kubelet它负责和 apiserver 通信管理本机的 Pod 生命周期kube-proxy负责实现 Service 的流量转发还有容器运行时现在一般是containerd负责真正拉镜像、启停容器。这里我提醒一句生产环境最好有 3 个控制面节点做高可用但学习和测试阶段单控制面完全够用。很多人一开始就想去搭复杂的多控制面集群结果被各种证书和选举问题劝退其实没必要先把单节点的逻辑跑通再说。2.2 Pod、Deployment、Service 三件套这三个概念是 k8s 里最基础、也最重要的资源我用自己的话解释一下。Pod 是 k8s 的最小调度单元。一个 Pod 里可以有一个或多个容器这些容器共享网络和存储。一般来说一个 Pod 里跑一个主容器同 Pod 的辅助容器主要负责日志收集、流量代理这类旁路功能。一个 Pod 的 IP 是随机的、会变化的所以你不能直接用 Pod IP 来对外提供服务。Deployment 负责管理无状态应用的副本。你定义一个副本数是 3k8s 就会保证始终有 3 个 Pod 在跑。更新镜像时它会做滚动更新先起新 Pod等新的就绪了再杀掉旧的整个过程服务不中断。降级的时候也很优雅把副本数改成 0Pod 就被清掉但不影响 Deployment 本身——这也是声明式的优势。Service 是稳定的访问入口。它有一个固定的虚拟 IPClusterIP不管你后面对应的 Pod IP 怎么变通过 Service 访问都是一样的地址。它做负载均衡把流量分发到一组 Pod 上。打个比方Pod 像是饭店的后厨师傅随时可能换人但 Service 就是这个饭店固定的招牌地址客人只管来店里会给客人安排好。这三个概念是层层递进的关系Deployment 管理 Pod 的副本和生命周期Service 给这些 Pod 提供稳定的访问方式。实际写完第一个 YAML 你就会发现k8s 的资源对象之间并不是孤立的而是一张互相引用的网。3. 动手搭建集群从单节点到生产级3.1 准备工作和组件选型我建议用kubeadm来搭集群它是官方提供的初始化工具也是目前最主流的方案。使用 kubeadm你不需要手动去生成各种证书、配置各组件参数它能自动化完成大部分工作。部署之前有几件事必须提前确认好一是操作系统。Ubuntu 22.04 或者 CentOS 7.9 都可以但注意内核版本不要太老否则一些网络和存储功能可能有问题。我习惯用 Ubuntu因为它的 containerd 安装包更新更及时。二是容器运行时。k8s 从 1.24 版本之后默认就不再支持 Docker 作为运行时了现在主流是containerd。很多人不知道这个变化还在按照老教程去配置 docker shim结果 kubeadm init 直接报错。这里明确一下containerd 才是现在的第一选择。三是网络规划。k8s 的 Pod 网络默认使用 10.244.0.0/16 或者 10.244.0.0/16 这样的网段你初始化的时候要指定这个参数后续网络插件也要跟它保持一致。不同网络插件支持的网段可能有差异比如 flannel 默认就是 10.244.0.0/16calico 可以用 10.244.0.0/16 也可以自定义。为了避免后续踩坑我统一用 10.244.0.0/16。3.2 初始化与安装完整流程我以 Ubuntu containerd kubeadm 为例把一套可执行的流程放出来你照着敲基本能一次过。第一步系统基础配置# 关闭 swapkubelet 默认不允许节点使用 swap sudo swapoff -a sudo sed -i / swap / s/^/#/ /etc/fstab # 加载内核模块 sudo tee /etc/modules-load.d/containerd.conf EOF overlay br_netfilter EOF sudo modprobe overlay sudo modprobe br_netfilter # 配置网络转发参数 sudo tee /etc/sysctl.d/k8s.conf EOF net.bridge.bridge-nf-call-iptables 1 net.ipv4.ip_forward 1 net.bridge.bridge-nf-call-ip6tables 1 EOF sudo sysctl --system第二步安装 containerd 和 kubeadm# 安装 containerd sudo apt-get update sudo apt-get install -y containerd # 配置 containerd 使用 systemd cgroup 驱动 sudo mkdir -p /etc/containerd containerd config default | sudo tee /etc/containerd/config.toml /dev/null # 编辑 config.toml修改 SystemdCgroup true # 添加 k8s 软件源并安装 sudo apt-get update sudo apt-get install -y apt-transport-https ca-certificates curl gpg sudo curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg echo deb [signed-by/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ / | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt-get update sudo apt-get install -y kubelet kubeadm kubectl sudo apt-mark hold kubelet kubeadm kubectl第三步初始化控制面节点sudo kubeadm init --pod-network-cidr10.244.0.0/16初始化成功后按照输出提示执行以下命令配置 kubectlmkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config第四步安装网络插件这里用 flannelkubectl apply -f https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml等一会儿看到kubectl get pods -n kube-flannel里的 Pod 都 Running 了再执行kubectl get nodes节点的状态就变成 Ready 了。如果是单节点测试还要去掉 master 节点的污点否则普通 Pod 不会调度到 master 上kubectl taint nodes --all node-role.kubernetes.io/control-plane-这里我再多提一句如果是在隔离内网离线部署不能直接访问外网拉取镜像和安装包就需要提前把依赖的镜像打成 tar 包导入再用私有仓库或者导入到 containerd 里。离线部署的坑更多但思路是一样的先把环境依赖准备好再跑初始化。如果是生产环境建议把配置管理工具和镜像仓库提前规划好否则后续维护会很头疼。4. 从 Docker 容器思维平滑过渡到 k8s 思维4.1 k8s 和 Docker 到底有什么区别这个问题是面试高频题也是很多新人的困惑点。我的理解很简单Docker 是容器引擎解决的是单个容器怎么跑的问题k8s 是容器编排平台解决的是一堆容器怎么协作、怎么管理的问题。拿交通运输来做类比Docker 好比是制造单辆卡车的工厂你造出一辆卡车可以装货跑路。但车多了之后谁走哪条路、车坏了怎么替换、货物的负载怎么均衡卡车工厂就管不了了。k8s 就是一个物流调度中心统一调度和管理所有的卡车保证货能按时送到。具体到工程实践上Docker Composer 和 k8s 的区别更值得我们关注。Docker Compose 适合单机上的多容器编排你写一个 compose 文件docker compose up -d就全部启动了。但它做不到跨节点的调度也没有故障自愈能力更谈不上滚动发布。k8s 的 Deployment、Service、Ingress 这些资源对象本质上都是为跨节点、大规模、高可用的应用场景设计的。所以这个问题的答案应该是它不是替代关系而是不同抽象层次的东西。Docker 帮助我们打包和交付应用k8s 帮助我们在大规模环境下运行和管理这些交付物。4.2 Docker Compose 升级到 k8s 的迁移思路实际工作中很多团队是从 Docker Compose 起步的后来规模大了想把服务迁移到 k8s。这里我分享一下实测过的迁移思路能帮你减少很多弯路。第一步梳理服务依赖关系。你先用docker compose config输出完整的配置看哪些服务需要持久化存储哪些服务之间要有网络依赖端口怎么暴露。这些信息都要转化到 k8s 的资源配置里。第二步按服务类型拆分资源对象。无状态应用用 Deployment Service有状态应用MySQL、Redis 这类用 StatefulSet Headless Service需要对外暴露的服务用 Ingress 来管理。注意Compose 文件里的 service 和 k8s 的 Service 不是一个概念千万别搞混Compose 的 service 是一个完整应用单元k8s 的 Service 只是一个稳定的网络访问入口。第三步处理配置和密钥。Compose 里的 environment 环境变量在 k8s 里要转换到 ConfigMap 和 Secret。把配置从镜像里剥离出来这是 k8s 的一个设计哲学——镜像不动配置可变同一个镜像可以跑在不同的环境里。第四步数据持久化。这是迁移里最容易出问题的地方。Compose 里你挂一个本机目录就行但 k8s 里你得考虑数据应该放在哪块存储上。单机测试可以用 hostPath多节点生产环境就要考虑 NFS 或者云厂商的块存储了。我在实际迁移中还发现原生的 k8s YAML 虽然写起来麻烦但改起来比 Compose 灵活得多。Compose 文件里各种服务之间的依赖关系是隐含在配置里的而 k8s 的资源对象边界清晰、职责明确一眼就能看出谁依赖谁。迁移完成后你会发现应用在 k8s 上的可观测性、可扩展性、可维护性都会好很多。5. 经典练习在 k8s 集群中部署一套 LNMP5.1 架构设计和资源配置LNMP 是指 Linux Nginx MySQL PHP这是一个经典组合非常适合拿来练习 k8s 编排。我们这里重点看 Nginx、MySQL、PHP 三个组件怎么在 k8s 里拆分编排。先说 MySQL它属于有状态应用数据必须持久化所以要用 StatefulSet 而不是 Deployment。每个 MySQL 副本可以有自己的持久化存储Pod 重建后数据不会丢。对外的服务访问用 Headless Service这样每个 Pod 都有稳定的网络标识方便做主从复制。再说 Nginx 和 PHP。Nginx 负责接收 HTTP 请求静态文件直接返回动态请求转发给 PHP-FPM。这两个组件要共享一个代码目录。在 k8s 里最简单的做法是把 PHP-FPM 和 Nginx 放在同一个 Pod 里共享一个 emptyDir 卷或者用一个独立的共享存储卷比如 NFS。考虑到可扩展性用共享存储更稳妥这样 Nginx 的副本数和 PHP-FPM 的副本数可以独立扩缩容。整个架构拆下来大概是这样的结构一个状态工作负载 MySQL配 1 个 PVC暴露内部端口 3306一个无状态工作负载 PHP-FPM配好环境变量连接 MySQL一个无状态工作负载 Nginx共享代码卷反向代理到 PHP-FPM一个 Ingress 对外暴露 80 端口5.2 核心步骤与关键 YAML 示例我直接给一份简化但能跑通的 YAML你需要根据自己的镜像名和存储类调整一下。MySQL 部分apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mysql-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 5Gi --- apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql spec: serviceName: mysql replicas: 1 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:8.0 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: password ports: - containerPort: 3306 volumeMounts: - name: mysql-data mountPath: /var/lib/mysql volumeClaimTemplates: - metadata: name: mysql-data spec: accessModes: [ ReadWriteOnce ] resources: requests: storage: 5Gi --- apiVersion: v1 kind: Service metadata: name: mysql spec: clusterIP: None selector: app: mysql ports: - port: 3306 targetPort: 3306PHP-FPM 和 Nginx 的配置文件较多我这里就不展开贴全部代码了但核心思路要掌握PHP 容器里要装好 pdo_mysql 扩展启动命令指定监听 9000 端口Nginx 容器里写一个 default.conf把location ~ \.php$的请求转发到php-fpm:9000。两个容器在同一个 Pod 里共享同一个 emptyDir 或共享卷这样就实现了一个 Pod 内的 Nginx PHP-FPM 协作。这里有一个非常容易踩的坑很多人在 Windows 的 WSL 或者 Mac 本机上能跑通 LNMP但一到 k8s 里就发现 Nginx 连不上 PHP-FPM。最常见的原因是没搞清楚容器的网络命名空间问题。同一个 Pod 里的不同容器共享网络命名空间可以用 localhost 直接访问但不同 Pod 之间必须通过 Service DNS 来访问。Nginx 配置里的fastcgi_pass如果写的是127.0.0.1:9000那必须保证 PHP-FPM 和 Nginx 在同一个 Pod 里才有效。部署完成后用kubectl get pods检查所有 Pod 都是 Running再用kubectl exec进去验证 MySQL 连接和 PHP 解析基本就大功告成了。这套 LNMP 练完你对 Deployment、StatefulSet、Service、PVC、ConfigMap、Secret 这些核心资源的理解就都串起来了。6. 常见问题排查与面试自测6.1 五大典型故障排查实录我把自己这几年遇到的问题做了个梳理下面这几个问题占了我在生产环境排障时遇到的七八成如果你也能掌握这套排查思路日常的 k8s 运维基本就够用了。第一个Pod 一直 Pending。这表示调度器没有找到合适的节点来运行这个 Pod。最常见的原因是两个一是节点资源不够CPU 或内存不足二是节点上有污点但你定义的 Pod 没有对应的容忍。排查方法很简单kubectl describe pod pod-name看最后面的 Events 信息原因会直接写出来。如果看到0/1 nodes are available要么扩容节点要么删除污点要么调低资源请求。第二个Pod 一直 CrashLoopBackOff。说明容器启动后立刻崩了被 kubelet 反复拉起然后不断循环。这种情况下马上看日志kubectl logs pod-name --previous可以看上一次退出前的日志。常见原因有镜像里的启动命令写错、环境变量缺失、健康检查探针配置太严格。我遇到最多的是 Liveness 探针配置的问题把探针的初始等待时间设得太短容器还没起来就被杀掉重来了。第三个CoreDNS 一直 Pending。这个十有八九是网络插件没装好或者网络插件的网段和 kubeadm init 时指定的 Pod 网段不一致。这个问题的根因一般是网络插件下载失败或 CIDR 冲突。解决方法是重新 apply 网络插件但要注意kubectl apply -f之前先把之前安装过的残留资源清理干净否则会有很多冲突。另外 coredns 的镜像在部分网络环境下拉取会比较慢耐心等一下就好。第四个服务间访问不通。这通常是 Service 的 selector 和 Pod 的 label 没对上。我排查的时候习惯先看 Service 的 Endpoints 是否正常kubectl get endpoints service-name如果显示none说明 Service 没有关联到任何 Pod。这种情况要么是 Pod 的标签和 Service 的 selector 不匹配要么是 Pod 的targetPort和容器实际监听的端口不一样。第五个k8s 里的日志看不到。很多人习惯 Windows 下直接看文件但在 k8s 排查问题第一反应是kubectl logs而不是进容器找文件。日志路径、日志轮转、log 采集工具的选择又是另一个大话题但基本排查套路就是先看 Pod 日志再看容器日志文件最后看宿主机日志。这三层的定位路径搞清楚能解决大部分问题。6.2 面试题精选与自查清单如果你正在准备面试我建议把这些问题当作自查清单过一遍能答上来基本就说明你具备了基础的 k8s 知识框架k8s 和 Docker 的区别是什么你是怎么理解容器编排的Pod 是什么为什么 k8s 的最小调度单位是 Pod 而不是容器Deployment 和 StatefulSet 分别适用什么场景Service 有哪几种类型ClusterIP、NodePort、LoadBalancer 之间的区别kube-proxy 的三种模式 iptables、ipvs、userspace 有什么区别简述一个 Pod 从创建到 Running 的完整流程涉及哪些组件k8s 中如何进行滚动更新和回滚如果 etcd 挂了k8s 集群会出现什么状况你在实际项目中如何做资源配额管理和限制LimitRange 和 ResourceQuota 的区别存储方面PV、PVC、StorageClass 三者的关系是什么这些问题看起来多其实核心还是对 k8s 整体架构和核心资源模型的理解。我面试的时候不太喜欢问特别偏的题目能把架构逻辑讲清楚、把上面常见的坑讲明白就已经很能证明实战能力了。7. 最后说点我的实际体会k8s 这套技术栈跟以前大部分中间件不一样它不是一个单纯的工具而是一整套分布式系统的设计哲学。如果只是背命令可能过几天就忘了但如果你理解了它为什么这样设计——比如为什么要有声明式 API、为什么要引入控制循环、为什么网络要分这么多层——再遇到新问题你就能举一反三了。我的建议是学的时候不要贪多先搭起一个单节点集群把 Pod、Deployment、Service 这三个核心概念玩熟再把 LNMP 这类经典架构在集群里跑一遍最后去研究网络、存储、权限这些进阶主题。每一步都亲自动手操作遇到问题自己去查、去试、去解决这个过程比任何教程都值钱。最后再分享一个小技巧遇到问题的时候养成用kubectl describe而不是猜测的习惯。它输出的 Events 部分会把调度、拉取镜像、健康检查等各个阶段的信息记录下来绝大多数问题都能从这里面找到线索。很多人排障效率低不是不懂 k8s而是连最基础的信息收集都没做全。先把 describe 看熟后面你会少踩很多坑这也是我从入门到精通这段路上最大的一个心得。本文还有配套的精品资源点击获取