一、为什么需要Kubernetes?------从痛苦到解放
1.1 没有K8s的日子
假如你是一家电商公司的运维。最开始只有一个"用户服务",用Docker跑在一台服务器上,很舒服。
后来加了"订单服务""支付服务""库存服务""推荐服务"......每个服务为了高可用,至少要跑3个副本。
然后噩梦开始了:
-
服务器宕机:某台物理机突然挂了,上面跑的十几个容器全部消失,需要人工去其他机器上重新启动。
-
流量突增:双11来了,订单服务需要从3个副本扩容到30个,你得一台一台机器去拉镜像、启动容器,再配置负载均衡。
-
版本更新:新上线一个功能,需要滚动更新(先启动新版本,等稳定后再停旧版本),手动操作极易出错,且回滚麻烦。
-
服务发现:每个容器重启后IP会变,A服务怎么知道B服务的地址?用固定的宿主机端口?端口冲突怎么办?
-
资源利用不均:有的机器CPU跑满,有的机器空闲,但又不能自动把容器搬过去。
这些问题Docker本身解决不了------Docker是"单机容器引擎",它只管"在一台机器上把容器跑起来"。
而Kubernetes(K8s) 就是来统一解决以上所有问题的:它把多台服务器变成一个统一的"资源池",你只需要告诉它"我要跑什么、跑几个",剩下的调度、伸缩、修复、服务发现全部自动完成。
1.2 K8s能做什么?
-
自动部署与回滚:支持滚动更新,可以一键回滚到上一版本。
-
弹性伸缩:根据CPU使用率或自定义指标,自动增加或减少Pod数量。
-
服务发现与负载均衡:每个服务有一个固定的虚拟IP和DNS名,自动把流量分发到后端Pod。
-
自我修复:如果某个Pod挂了,Controller会马上拉起一个新的;节点宕机后,会在其他健康节点上重建Pod。
-
存储编排:自动挂载持久化存储(本地、NFS、云盘等),Pod漂移时存储也跟着迁移。
-
配置管理:通过ConfigMap和Secret管理配置和密码,无需重新打包镜像。
二、Kubernetes核心概念------用最简单的话说清楚
| 概念 | 一句话解释 | 现实类比 |
|---|---|---|
| Pod | K8s里最小的部署单元,一个Pod里可以有一个或多个容器(通常一个Pod一个容器)。 | 一个"豆荚"里可以有一颗或多颗豆子。 |
| Deployment | 管理一组相同的Pod,负责滚动更新、扩缩容、回滚。 | 生产线的班长,决定开几条流水线,怎么换新设备。 |
| Service | 为一组Pod提供固定的访问入口(VIP和DNS),做负载均衡。 | 餐厅的"叫号台",客人不知道后厨哪个厨师在做菜,统一找叫号台就行。 |
| Namespace | 将集群内部资源"隔离"成多个虚拟集群,用于区分环境(dev/test/prod)或团队。 | 办公楼的楼层,研发部在5楼,财务部在6楼,互不干扰。 |
| Ingress | 七层(HTTP/HTTPS)路由,通过域名和路径把外部流量转发到不同的Service。 | 商场总服务台,根据你想去的店铺名(域名)引导你去相应楼层。 |
| ConfigMap | 存储配置信息(非敏感),可以挂载到Pod中变成环境变量或文件。 | 工地上的"图纸",工人按图纸施工。 |
| Secret | 存储敏感信息(密码、token),类似ConfigMap但会做base64编码。 | 保险柜,只有授权人能打开。 |
| Volume | 存储卷,Pod内挂载的磁盘,可以是临时、宿主机目录、网络存储等。 | U盘,拔下来插到另一台电脑还能用(如果支持)。 |
| Node | 工作节点,可以是物理机或虚拟机,负责运行Pod。 | 工厂里的工人,干活的。 |
| Master | 控制平面,包含API Server、Scheduler等组件,管理所有Node。 | 工厂厂长、调度员、监控室。 |
2.1 为什么要有Pod?
很多人第一次学K8s会疑惑:为什么不直接管理容器,还要弄个Pod?
因为有些容器需要紧密协作:比如一个容器写日志,另一个容器收集日志;或者一个容器做代理,另一个容器是实际服务。如果把它们放在同一个Pod里,它们可以共享同一个IP和存储卷,通过localhost通信,非常高效。
2.2 Deployment vs StatefulSet vs DaemonSet
| 类型 | 适用场景 | 特点 |
|---|---|---|
| Deployment | 无状态应用(Web前端、API) | Pod名随机,顺序无关,可随意替换 |
| StatefulSet | 有状态应用(数据库、消息队列) | Pod有固定名称(如mysql-0, mysql-1),顺序启停,每个Pod可挂载独立存储 |
| DaemonSet | 每个节点都要运行的守护进程(监控agent、日志收集、网络插件) | 新节点加入自动部署一个Pod |
三、Kubernetes集群架构详解(看懂这张图就懂了一半)
text
+---------------------------------------------------------------+
| Master Node |
| +-------------------+ +------------------+ +-------------+ |
| | API Server | | Scheduler | | Controller | |
| | (集群入口,认证) | | (调度Pod到Node) | | Manager | |
| +-------------------+ +------------------+ | (维持期望状态)| |
| +-------------+ |
| +-------------------------------------------------------------+ |
| | etcd (集群状态存储) | |
| +-------------------------------------------------------------+ |
+---------------------------------------------------------------+
|
| (API调用)
↓
+---------------------------------------------------------------+
| Worker Node 1 |
| +------------------+ +------------------+ +--------------+ |
| | kubelet | | kube-proxy | | Container | |
| | (管理Pod生命周期) | | (网络规则/负载均衡)| | Runtime | |
| +------------------+ +------------------+ | (如Docker) | |
| +--------------+ |
| +---------------------------------------------------------+ |
| | Pod A | Pod B | Pod C ... | |
| +---------------------------------------------------------+ |
+---------------------------------------------------------------+
+
同样结构的 Worker Node 2, 3...
3.1 各个组件是干什么的?(理解即可,不用背)
Master组件:
-
API Server :一切操作的入口,无论是
kubectl命令还是内部组件,都通过它通信。它负责认证、授权、准入控制。 -
Scheduler:当你要创建一个Pod时,Scheduler会看哪个Node资源够用(CPU、内存、亲和性等),然后把Pod"绑定"到那个Node上。
-
Controller Manager:里面有很多控制器(Deployment Controller、Node Controller等)。它们不断检查"当前状态"是否等于"你期望的状态",如果不相等就采取行动(比如重启挂了的Pod)。
-
etcd :分布式键值存储,保存集群的所有配置和状态(有哪些Node、Pod、Service等)。高可用必备,一般部署3个或5个奇数节点。
Node组件:
-
kubelet:每个Node上的"管家",接收API Server的指令,负责创建、停止、监控Pod;上报Node和Pod状态。
-
kube-proxy:维护节点上的网络规则(iptables/IPVS),实现Service的虚拟IP和负载均衡。
-
容器运行时:真正跑容器的引擎,如Docker、containerd、CRI-O。Kubelet通过CRI接口与它交互。
四、环境准备(所有节点执行)
实验环境
| 主机名 | IP 地址 | 操作系统 | 配置 |
|---|---|---|---|
| k8s-master | 192.168.10.101 | CentOS 7.9 / Rocky Linux 8 | 2核4G |
| k8s-node1 | 192.168.10.102 | CentOS 7.9 / Rocky Linux 8 | 2核2G |
| k8s-node2 | 192.168.10.103 | CentOS 7.9 / Rocky Linux 8 | 2核2G |
所有操作使用
root用户,或使用sudo。确保节点之间网络互通,可访问互联网。
4.1 基础配置(三台都做)
bash
# 1. 关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
# 2. 关闭 SELinux
setenforce 0
sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
# 3. 关闭 swap(K8s 强制要求)
swapoff -a
sed -i '/swap/s/^/#/' /etc/fstab
# 4. 修改主机名(分别执行)
# Master:
hostnamectl set-hostname k8s-master
# Node1:
hostnamectl set-hostname k8s-node1
# Node2:
hostnamectl set-hostname k8s-node2
# 5. 配置 hosts(所有节点)
cat >> /etc/hosts <<EOF
192.168.10.101 k8s-master
192.168.10.102 k8s-node1
192.168.10.103 k8s-node2
EOF
# 6. 加载内核模块
cat > /etc/modules-load.d/k8s.conf <<EOF
overlay
br_netfilter
EOF
modprobe overlay
modprobe br_netfilter
# 7. 优化内核参数
cat > /etc/sysctl.d/k8s.conf <<EOF
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sysctl --system
# 8. 时间同步
yum install -y chrony
systemctl enable --now chronyd
chronyc sources
五、安装容器运行时(containerd),前面有搭建docker的步骤根据自己的情况选择
containerd和docker对比:
-
开发阶段 (你现在做的事) :依然用Docker 。你用
docker build命令打包出来的镜像,是整个行业标准(OCI标准)。 -
生产阶段 (K8s做的事) :实际运行时并不再是Docker 。K8s会拉取你刚才用Docker打包好的镜像,然后调用轻量的
containerd来运行这个镜像。 -
一句话总结 :Docker在生产环境中从 "车轮" (运行容器)的角色,变成了 "图纸" (构建镜像标准)的角色。
containerd则从幕后走向前台,成为那只看似没动、实则日夜狂奔的"车轮"。
K8s 1.24 之后移除了 dockershim,官方推荐使用 containerd,它支持 OCI 镜像(包括 Docker 镜像),且性能更好。我们安装 containerd。
bash
# 添加 containerd 的 yum 源(阿里云)
yum install -y yum-utils
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 安装 containerd
yum install -y containerd.io
# 生成默认配置文件
mkdir -p /etc/containerd
containerd config default > /etc/containerd/config.toml
# 修改配置文件:将 SystemdCgroup 改为 true,并使用国内镜像加速
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sed -i 's|registry.k8s.io|registry.aliyuncs.com/google_containers|g' /etc/containerd/config.toml
# 配置镜像加速(可选,添加 docker.io 镜像)
cat >> /etc/containerd/config.toml <<EOF
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
endpoint = ["https://docker.m.daocloud.io", "https://docker.unsee.tech"]
EOF
# 启动 containerd
systemctl daemon-reload
systemctl enable --now containerd
# 验证
crictl version
注意:containerd 完全兼容 Docker 镜像,你可以继续用
docker build构建镜像,然后用ctr或crictl管理。
六、安装 kubeadm、kubelet、kubectl
bash
# 添加 K8s 阿里云源
cat > /etc/yum.repos.d/kubernetes.repo <<EOF
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=0
EOF
# 安装指定版本(使用 v1.28.2,当前主流)
yum install -y kubelet-1.28.2 kubeadm-1.28.2 kubectl-1.28.2 --nogpgcheck
# 设置 kubelet 开机自启(暂时不会启动成功,需要初始化集群后才正常)
systemctl enable kubelet
七、初始化控制平面节点(Master)
7.1 预拉取镜像
bash
kubeadm config images pull --image-repository registry.aliyuncs.com/google_containers
7.2 创建初始化配置文件(推荐)
为了更清晰控制参数,我们使用配置文件方式:
bash
cat > kubeadm-init.yaml <<EOF
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
advertiseAddress: 192.168.10.101 # 改为你的 Master IP
bindPort: 6443
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.28.2
imageRepository: registry.aliyuncs.com/google_containers
controlPlaneEndpoint: "192.168.10.101:6443"
networking:
podSubnet: 10.244.0.0/16 # 必须与网络插件一致
serviceSubnet: 10.96.0.0/12
dns:
type: CoreDNS
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
EOF
7.3 执行初始化
bash
kubeadm init --config=kubeadm-init.yaml --upload-certs
初始化成功后,最后几行会输出类似这样的 join 命令(务必保存):
bash
kubeadm join 192.168.10.101:6443 --token xxxxx --discovery-token-ca-cert-hash sha256:xxxxx
7.4 配置 kubectl(让当前用户能操作集群)
bash
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config
# 验证
kubectl get nodes
# 输出 master 状态为 NotReady(网络插件未安装)
八、安装网络插件(Calico)
网络插件是实现 Pod 跨节点通信的关键。这里使用 Calico,性能好且支持网络策略。
bash
# 安装 Tigera Operator(Calico 官方推荐方式)
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.27/manifests/tigera-operator.yaml
# 下载 custom-resources.yaml 并修改 Pod CIDR
wget https://raw.githubusercontent.com/projectcalico/calico/v3.27/manifests/custom-resources.yaml
sed -i 's|192.168.0.0/16|10.244.0.0/16|g' custom-resources.yaml
# 应用配置
kubectl create -f custom-resources.yaml
# 等待所有 Pod 运行(约 2 分钟)
watch kubectl get pods -n calico-system
所有 Pod 都为 Running 后,查看节点状态:
bash
kubectl get nodes
# 应该变为 Ready
九、工作节点加入集群
在 k8s-node1 和 k8s-node2 上执行前面保存的 kubeadm join 命令:
bash
kubeadm join 192.168.10.101:6443 --token xxxxx --discovery-token-ca-cert-hash sha256:xxxxx
如果 token 过期,在 Master 上重新生成:
bash
kubeadm token create --print-join-command
加入后回到 Master 验证:
bash
kubectl get nodes
# 应该看到三个节点都是 Ready 状态
至此,K8s 集群搭建完成!🎉
十、验证集群健康
bash
# 查看所有 Namespace 下的 Pod
kubectl get pods --all-namespaces
# 查看集群信息
kubectl cluster-info
# 查看组件状态
kubectl get componentstatuses
如果 CoreDNS 等 Pod 处于 Running 状态,说明集群正常。
十一、部署 Kubernetes Dashboard
Dashboard 是官方提供的 Web UI,方便管理集群。
11.1 安装 Dashboard
bash
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml
11.2 创建管理员用户
创建 dashboard-admin.yaml:
yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: admin-user
namespace: kubernetes-dashboard
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: admin-user
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: admin-user
namespace: kubernetes-dashboard
应用:
bash
kubectl apply -f dashboard-admin.yaml
11.3 获取登录 Token
bash
kubectl -n kubernetes-dashboard create token admin-user
复制输出的一长串 token。
11.4 暴露 Dashboard 服务(NodePort)
默认 Dashboard 的服务类型是 ClusterIP,仅集群内部访问。我们改为 NodePort 以便外部访问。
bash
kubectl patch svc kubernetes-dashboard -n kubernetes-dashboard -p '{"spec":{"type":"NodePort"}}'
查看 NodePort 端口:
bash
kubectl get svc -n kubernetes-dashboard
输出示例:
text
NAME TYPE CLUSTER-IP PORT(S) AGE
kubernetes-dashboard NodePort 10.109.89.23 443:30088/TCP 2m
11.5 访问 Dashboard
浏览器访问:https://任意节点IP:30088(注意是 https)
-
浏览器会提示"不安全",点击"高级" -> "继续前往"
-
选择 "Token" 登录方式
-
粘贴上面获取的 token,即可进入 Dashboard 管理界面。
你可以在这里查看所有 Namespace、Pod、Deployment、Service 等资源,甚至可以直接编辑 YAML。
十二、部署测试应用(Nginx)
创建一个 Deployment 和 Service 来验证集群功能。
创建 nginx-test.yaml:
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: NodePort
selector:
app: nginx
ports:
- port: 80
targetPort: 80
nodePort: 30080 # 可选,范围 30000-32767
部署:
bash
kubectl apply -f nginx-test.yaml
# 查看 Pod 分布
kubectl get pods -o wide
# 查看 Service 端口
kubectl get svc nginx-service
测试访问:http://任意节点IP:30080,应看到 Nginx 欢迎页面。
十三、必知必会的知识点补充
13.1 资源限制(Requests & Limits)
每个 Pod 都应配置资源请求和限制,防止某个 Pod 耗尽节点资源。
yaml
resources:
requests:
memory: "128Mi"
cpu: "200m"
limits:
memory: "256Mi"
cpu: "500m"
-
requests:调度时保证的最小资源。 -
limits:容器运行时允许使用的最大资源。
13.2 滚动更新与回滚
bash
# 更新镜像
kubectl set image deployment/nginx-deployment nginx=nginx:1.20 --record
# 查看更新历史
kubectl rollout history deployment/nginx-deployment
# 回滚到上一个版本
kubectl rollout undo deployment/nginx-deployment
13.3 使用 ConfigMap 管理配置
bash
# 创建 ConfigMap
kubectl create configmap app-config --from-literal=APP_ENV=prod
# 在 Pod 中引用(作为环境变量)
...
env:
- name: APP_ENV
valueFrom:
configMapKeyRef:
name: app-config
key: APP_ENV
13.4 持久化存储(PV/PVC)
生产环境建议使用 PV 和 PVC 对接 NFS、Ceph 或云存储。示例(hostPath 仅用于测试):
yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
---
# 在 Pod 中挂载
volumes:
- name: data
persistentVolumeClaim:
claimName: my-pvc
13.5 污点与容忍
Master 节点默认有一个污点:node-role.kubernetes.io/control-plane:NoSchedule,因此普通 Pod 不会调度到 Master 上。查看污点:
bash
kubectl describe node k8s-master | grep Taint
给节点添加污点:
bash
kubectl taint nodes node1 key=value:NoSchedule
Pod 添加容忍才能被调度到有污点的节点:
yaml
tolerations:
- key: "key"
operator: "Equal"
value: "value"
effect: "NoSchedule"
13.6 节点亲和性
yaml
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
13.7 常用排错命令
bash
# 查看 Pod 详细事件
kubectl describe pod <pod-name>
# 查看 Pod 日志
kubectl logs <pod-name> [-c <container-name>]
# 进入容器
kubectl exec -it <pod-name> -- /bin/bash
# 查看集群事件
kubectl get events --all-namespaces --sort-by='.lastTimestamp'
# 查看节点资源使用(需要先安装 metrics-server)
kubectl top nodes
kubectl top pods
十四、常见问题排查
| 问题 | 可能原因 | 解决方法 |
|---|---|---|
kubectl get nodes 显示 NotReady |
未安装网络插件 | 安装 Calico 或 Flannel |
kubeadm init 拉取镜像失败 |
网络不通或镜像仓库不可达 | 使用阿里云镜像仓库 registry.aliyuncs.com/google_containers |
| 节点加入失败,token 无效 | token 过期 | Master 上 kubeadm token create --print-join-command 重新获取 |
| Pod 一直 Pending | 资源不足或没有合适的节点 | 检查节点资源,增加节点或降低 Pod 资源请求 |
| Service 的 ClusterIP 无法 ping 通 | 正常现象,ClusterIP 是虚拟 IP,只支持 TCP/UDP,不支持 ICMP | 使用 curl 或 telnet 测试端口 |
| Dashboard 登录后无权限 | 使用的 token 权限不足 | 创建 cluster-admin 的 ServiceAccount 并获取 token |
| containerd 拉取镜像慢 | 未配置镜像加速 | 修改 /etc/containerd/config.toml 添加 registry.mirrors,重启 containerd |
十五、总结与后续学习建议
恭喜!您已经完成了:
-
✅ 理解 K8s 的核心价值与架构
-
✅ 亲手搭建了一个 1 Master + 2 Node 的生产级集群(使用 containerd + Calico)
-
✅ 部署了 Dashboard 可视化界面并成功登录
-
✅ 运行了第一个 Nginx 应用并进行访问测试
-
✅ 学习了资源限制、滚动更新、ConfigMap、存储、污点等关键知识点
下一步建议:
-
学习 Helm:用 Helm 打包和部署复杂应用(如 MySQL、Redis)。
-
部署 Ingress Controller:使用 Nginx Ingress 实现域名路由和 HTTPS 自动证书。
-
监控系统:搭建 Prometheus + Grafana 监控集群和应用。
-
日志系统:EFK(Elasticsearch + Fluentd + Kibana)收集日志。
-
CI/CD:集成 GitLab CI 或 Jenkins,实现代码推送自动构建镜像并部署到 K8s。
-
服务网格:了解 Istio,实现流量切分、熔断、灰度发布。
这份文档的所有命令都已经过实际测试,您可以直接复制粘贴到您的实验环境中使用。如果遇到问题,请对照"常见问题排查"部分解决。