Kubernetes 集群实战部署指南:从零搭建生产级K8s环境

📋 目录


第一章:准备工作

1.1 环境规划

节点配置(4节点示例):

节点名称 角色 配置 内网IP 说明
k8s-master control-plane 2核4G 192.168.1.10 控制平面节点
k8s-node1 worker 2核8G 192.168.1.11 工作节点
k8s-node2 worker 2核8G 192.168.1.12 工作节点
k8s-node3 worker 2核4G 192.168.1.13 Ingress入口节点

网络规划

复制代码
Pod网络(Calico):  10.244.0.0/16
Service网络:        10.96.0.0/12
API Server端口:     6443
NodePort范围:       30000-32767

集群架构图
存储层
网络层
工作节点
控制平面节点 (192.168.1.10)
管理
管理
管理
挂载
挂载
挂载
NodePort/Ingress
k8s-master

2核4G
API Server :6443
etcd
kube-scheduler
kube-controller-manager
k8s-node1

192.168.1.11

2核8G
k8s-node2

192.168.1.12

2核8G
k8s-node3

192.168.1.13

2核4G

Ingress入口
Calico VXLAN

10.244.0.0/16
Service网络

10.96.0.0/12
NFS动态存储

192.168.1.10:/data/nfs
外部流量

1.2 系统要求

硬件要求

  • Master节点:≥2核CPU,≥2GB内存,≥20GB磁盘
  • Worker节点:≥2核CPU,≥4GB内存,≥40GB磁盘
  • 所有节点需要内网互通

软件要求

  • 操作系统:CentOS Stream 9 / Ubuntu 20.04+ / Debian 11+
  • 内核版本:≥4.19(建议5.x)
  • 容器运行时:containerd 1.6+
  • 网络插件:Calico 3.27

云服务器配置

  • ✅ 安全组开放端口:6443(API Server)、10250(kubelet)、2379-2380(etcd)、4789(VXLAN)
  • ✅ 关闭云防火墙或配置白名单
  • ⚠️ 重要:云环境不支持IPIP协议,必须使用VXLAN模式

1.3 关键决策

决策1:网络插件选择

插件 模式 云环境支持 性能 推荐场景
Calico IPIP 封装 ❌ 不支持 物理机/私有云
Calico VXLAN 封装 ✅ 支持 云服务器(推荐)
Flannel VXLAN 封装 ✅ 支持 小规模集群

为什么云环境必须用VXLAN?

  • 云厂商安全组不支持IPIP协议(协议号4)
  • VXLAN使用UDP 4789端口,可以通过安全组规则放行
  • 实测:阿里云/腾讯云/华为云均不支持IPIP

决策2:镜像源选择

由于网络原因,国内环境需要配置镜像加速:

bash 复制代码
# Kubernetes镜像源
registry.aliyuncs.com/google_containers

# containerd镜像加速
https://mirror.ccs.tencentyun.com
https://dockerproxy.com

决策3:存储方案

方案 优点 缺点 适用场景
NFS 简单易用,支持ReadWriteMany 性能一般 开发/测试环境
Ceph RBD 高性能,高可用 部署复杂 生产环境
云盘CSI 原生支持,稳定 成本高 云上生产环境

本文选择NFS动态存储,适合快速搭建测试环境。


第二章:系统初始化

⚠️ 以下操作需要在所有节点执行(除非特别说明)

2.1 主机名与hosts配置

设置主机名(每个节点执行不同命令):

bash 复制代码
# Master节点
hostnamectl set-hostname k8s-master

# Worker节点1
hostnamectl set-hostname k8s-node1

# Worker节点2
hostnamectl set-hostname k8s-node2

# Worker节点3
hostnamectl set-hostname k8s-node3

配置hosts文件(所有节点):

bash 复制代码
cat >> /etc/hosts << EOF
192.168.1.10 k8s-master
192.168.1.11 k8s-node1
192.168.1.12 k8s-node2
192.168.1.13 k8s-node3
EOF

验证

bash 复制代码
# 测试主机名解析
ping -c 2 k8s-master
ping -c 2 k8s-node1

# 检查主机名
hostname

2.2 关闭防火墙和SELinux

关闭防火墙

bash 复制代码
# 停止并禁用firewalld
systemctl stop firewalld
systemctl disable firewalld

# 验证状态
systemctl status firewalld

关闭SELinux

bash 复制代码
# 临时关闭
setenforce 0

# 永久关闭
sed -i 's/^SELINUX=enforcing$/SELINUX=disabled/' /etc/selinux/config

# 验证
getenforce  # 应显示 Permissive 或 Disabled

关闭swap

bash 复制代码
# 临时关闭
swapoff -a

# 永久关闭(注释swap行)
sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab

# 验证
free -h  # swap行应为0

2.3 内核参数优化

加载必需的内核模块

bash 复制代码
cat > /etc/modules-load.d/k8s.conf << EOF
overlay
br_netfilter
EOF

# 立即加载
modprobe overlay
modprobe br_netfilter

# 验证
lsmod | grep -E "overlay|br_netfilter"

配置内核参数

bash 复制代码
cat > /etc/sysctl.d/k8s.conf << EOF
# 启用IP转发
net.ipv4.ip_forward = 1

# 桥接流量经过iptables
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1

# 禁用IPv6(可选)
net.ipv6.conf.all.disable_ipv6 = 0
net.ipv6.conf.default.disable_ipv6 = 0

# 优化网络性能
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 30
net.core.somaxconn = 32768
EOF

# 应用配置
sysctl --system

# 验证关键参数
sysctl net.ipv4.ip_forward
sysctl net.bridge.bridge-nf-call-iptables

2.4 时间同步配置

安装并启动chronyd

bash 复制代码
# 安装时间同步工具
yum install -y chrony

# 启动服务
systemctl start chronyd
systemctl enable chronyd

# 验证时间同步状态
chronyc sources -v
timedatectl status

配置时区

bash 复制代码
# 设置为中国时区
timedatectl set-timezone Asia/Shanghai

# 验证
date

验证所有节点时间一致

bash 复制代码
# 在所有节点执行
date "+%Y-%m-%d %H:%M:%S"

# 时间差应小于1秒

✅ 第一阶段完成检查清单

  • 所有节点主机名已设置且可互相解析
  • 防火墙、SELinux、swap已关闭
  • 内核模块已加载(overlay、br_netfilter)
  • 内核参数已生效(ip_forward=1)
  • 时间同步正常,所有节点时间一致

第三章:安装容器运行时

Kubernetes从1.24版本开始移除了对Docker的内置支持,推荐使用containerd作为容器运行时。

3.1 安装containerd

配置YUM源(使用阿里云镜像):

bash 复制代码
# 安装依赖
yum install -y yum-utils device-mapper-persistent-data lvm2

# 添加Docker CE仓库(包含containerd)
yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# 查看可用版本
yum list containerd.io --showduplicates | sort -r

安装containerd

bash 复制代码
# 安装指定版本(推荐1.6.x)
yum install -y containerd.io-1.6.32

# 启动服务
systemctl start containerd
systemctl enable containerd

# 验证安装
containerd --version
systemctl status containerd

3.2 配置containerd

生成默认配置文件

bash 复制代码
# 创建配置目录
mkdir -p /etc/containerd

# 生成默认配置
containerd config default > /etc/containerd/config.toml

修改配置文件(关键配置):

bash 复制代码
# 1. 启用SystemdCgroup
sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml

# 2. 配置镜像加速(使用腾讯云镜像)
sed -i '/\[plugins."io.containerd.grpc.v1.cri".registry.mirrors\]/a\        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]\n          endpoint = ["https://mirror.ccs.tencentyun.com", "https://dockerproxy.com"]' /etc/containerd/config.toml

# 3. 配置sandbox镜像(使用阿里云镜像)
sed -i 's|registry.k8s.io/pause:3.8|registry.aliyuncs.com/google_containers/pause:3.9|' /etc/containerd/config.toml

重启containerd

bash 复制代码
systemctl restart containerd

# 验证配置
systemctl status containerd
ctr version

3.3 验证安装

测试镜像拉取

bash 复制代码
# 拉取测试镜像
ctr image pull docker.io/library/busybox:latest

# 查看镜像列表
ctr image ls | grep busybox

# 清理测试镜像
ctr image rm docker.io/library/busybox:latest

检查配置

bash 复制代码
# 验证SystemdCgroup配置
grep "SystemdCgroup = true" /etc/containerd/config.toml

# 验证镜像加速配置
grep -A 2 "registry.mirrors" /etc/containerd/config.toml

第四章:部署K8s集群

4.1 安装kubeadm、kubelet、kubectl

配置Kubernetes YUM源

bash 复制代码
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
repo_gpgcheck=0
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF

安装指定版本(所有节点):

bash 复制代码
# 查看可用版本
yum list kubeadm --showduplicates | sort -r

# 安装1.28.2版本
yum install -y kubelet-1.28.2 kubeadm-1.28.2 kubectl-1.28.2

# 启动kubelet(此时会失败,正常现象)
systemctl enable kubelet
systemctl start kubelet

# 验证安装
kubeadm version
kubectl version --client

4.2 初始化Master节点

⚠️ 以下操作仅在Master节点执行

创建初始化配置文件

bash 复制代码
cat > kubeadm-config.yaml << EOF
apiVersion: kubeadm.k8s.io/v1beta3
kind: ClusterConfiguration
kubernetesVersion: v1.28.2
controlPlaneEndpoint: "192.168.1.10:6443"
imageRepository: registry.aliyuncs.com/google_containers
networking:
  podSubnet: "10.244.0.0/16"
  serviceSubnet: "10.96.0.0/12"
---
apiVersion: kubeadm.k8s.io/v1beta3
kind: InitConfiguration
localAPIEndpoint:
  advertiseAddress: "192.168.1.10"
  bindPort: 6443
nodeRegistration:
  criSocket: unix:///var/run/containerd/containerd.sock
  taints:
  - effect: NoSchedule
    key: node-role.kubernetes.io/control-plane
---
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
cgroupDriver: systemd
EOF

执行初始化

bash 复制代码
# 预拉取镜像(可选,加快初始化速度)
kubeadm config images pull --config kubeadm-config.yaml

# 初始化集群
kubeadm init --config kubeadm-config.yaml

# 初始化成功后会输出类似以下内容:
# Your Kubernetes control-plane has initialized successfully!
#
# To start using your cluster, you need to run the following as a regular user:
#   mkdir -p $HOME/.kube
#   sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
#   sudo chown $(id -u):$(id -g) $HOME/.kube/config
#
# Then you can join any number of worker nodes by running the following on each as root:
# kubeadm join 192.168.1.10:6443 --token <token> \
#     --discovery-token-ca-cert-hash sha256:<hash>

⚠️ 重要 :保存输出中的kubeadm join命令,后续Worker节点加入集群时需要使用。

配置kubectl

bash 复制代码
# 配置kubectl访问集群
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/config

# 验证集群状态
kubectl get nodes
kubectl get pods -A

此时Master节点状态为NotReady,因为还未安装网络插件。

4.3 Worker节点加入集群

⚠️ 以下操作在所有Worker节点执行

使用Master节点初始化时输出的kubeadm join命令:

bash 复制代码
# 示例命令(实际token和hash请使用你的输出)
kubeadm join 192.168.1.10:6443 --token abcdef.0123456789abcdef \
    --discovery-token-ca-cert-hash sha256:1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef

如果token过期(24小时后失效):

bash 复制代码
# 在Master节点生成新token
kubeadm token create --print-join-command

验证节点加入(在Master节点执行):

bash 复制代码
# 查看节点状态(此时都是NotReady,正常)
kubectl get nodes

# 输出示例:
# NAME         STATUS     ROLES           AGE   VERSION
# k8s-master   NotReady   control-plane   5m    v1.28.2
# k8s-node1    NotReady   <none>          2m    v1.28.2
# k8s-node2    NotReady   <none>          2m    v1.28.2
# k8s-node3    NotReady   <none>          2m    v1.28.2

4.4 部署流程图





开始部署
安装kubeadm/kubelet/kubectl
是Master节点?
创建kubeadm-config.yaml
预拉取镜像
kubeadm init
配置kubectl
保存join命令
等待Master初始化完成
执行kubeadm join
检查节点状态
节点NotReady?
安装Calico网络插件
部署完成


✅ 第二阶段完成检查清单

  • containerd已安装并配置镜像加速
  • kubeadm、kubelet、kubectl已安装(版本1.28.2)
  • Master节点初始化成功
  • kubectl可以访问集群
  • 所有Worker节点已加入集群
  • 所有节点状态为NotReady(等待网络插件)

下一步:第五章将部署Calico网络插件(VXLAN模式)和NFS存储,这是最关键的章节。


第五章:网络与存储配置

5.1 部署Calico网络插件(VXLAN模式)

⚠️ 关键:云环境必须使用VXLAN模式

5.1.1 为什么云环境不能用IPIP?

网络模式对比
VXLAN模式(云环境推荐)
VXLAN封装

UDP 4789
云安全组放行✅
Pod B

10.244.2.20
vxlan.calico接口
物理网卡
目标节点
IPIP模式(物理机可用)
IPIP封装

协议号4
云安全组拦截❌
Pod A

10.244.1.10
tunl0接口
物理网卡
目标节点

核心区别

  • IPIP:使用IP协议号4封装,云厂商安全组不支持
  • VXLAN:使用UDP 4789端口,可以通过安全组规则放行
5.1.2 下载并修改Calico配置
bash 复制代码
# 下载Calico 3.27版本配置文件
curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.27.0/manifests/calico.yaml

# 备份原文件
cp calico.yaml calico.yaml.bak

修改配置文件(3处关键修改):

bash 复制代码
# 1. 修改Pod网络CIDR(与kubeadm-config.yaml保持一致)
sed -i 's|# - name: CALICO_IPV4POOL_CIDR|- name: CALICO_IPV4POOL_CIDR|' calico.yaml
sed -i 's|#   value: "192.168.0.0/16"|  value: "10.244.0.0/16"|' calico.yaml

# 2. 修改网络模式为VXLAN(默认是IPIP)
sed -i 's|# - name: CALICO_IPV4POOL_IPIP|- name: CALICO_IPV4POOL_IPIP|' calico.yaml
sed -i 's|#   value: "Always"|  value: "Never"|' calico.yaml

# 添加VXLAN配置
sed -i '/CALICO_IPV4POOL_IPIP/a\            - name: CALICO_IPV4POOL_VXLAN\n              value: "Always"' calico.yaml

# 3. 配置网卡自动检测(可选,多网卡环境需要)
sed -i '/CALICO_IPV4POOL_VXLAN/a\            - name: IP_AUTODETECTION_METHOD\n              value: "interface=eth0"' calico.yaml

手动验证配置(推荐):

bash 复制代码
# 检查关键配置
grep -A 1 "CALICO_IPV4POOL_CIDR" calico.yaml
grep -A 1 "CALICO_IPV4POOL_IPIP" calico.yaml
grep -A 1 "CALICO_IPV4POOL_VXLAN" calico.yaml

期望输出:

yaml 复制代码
- name: CALICO_IPV4POOL_CIDR
  value: "10.244.0.0/16"
- name: CALICO_IPV4POOL_IPIP
  value: "Never"
- name: CALICO_IPV4POOL_VXLAN
  value: "Always"
5.1.3 部署Calico
bash 复制代码
# 应用配置
kubectl apply -f calico.yaml

# 等待Pod启动(约1-2分钟)
kubectl get pods -n kube-system -l k8s-app=calico-node -w

验证部署

bash 复制代码
# 1. 检查Calico Pod状态
kubectl get pods -n kube-system -l k8s-app=calico-node

# 期望输出:所有Pod都是Running
# NAME                READY   STATUS    RESTARTS   AGE
# calico-node-xxxxx   1/1     Running   0          2m
# calico-node-yyyyy   1/1     Running   0          2m
# calico-node-zzzzz   1/1     Running   0          2m

# 2. 检查节点状态(应该变为Ready)
kubectl get nodes

# 期望输出:所有节点都是Ready
# NAME         STATUS   ROLES           AGE   VERSION
# k8s-master   Ready    control-plane   10m   v1.28.2
# k8s-node1    Ready    <none>          7m    v1.28.2
# k8s-node2    Ready    <none>          7m    v1.28.2
# k8s-node3    Ready    <none>          7m    v1.28.2

# 3. 验证VXLAN接口(在任意节点执行)
ip link show vxlan.calico

# 期望输出:
# 5: vxlan.calico: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UNKNOWN mode DEFAULT group default
#     link/ether 66:xx:xx:xx:xx:xx brd ff:ff:ff:ff:ff:ff

# 4. 检查路由表
ip route | grep vxlan.calico
5.1.4 网络连通性测试

创建测试Pod

bash 复制代码
# 创建3个nginx Pod
kubectl create deployment nginx-test --image=nginx:1.25 --replicas=3

# 等待Pod启动
kubectl get pods -o wide

# 期望输出:Pod分布在不同节点
# NAME                          READY   STATUS    RESTARTS   AGE   IP             NODE
# nginx-test-xxxxxx-xxxxx       1/1     Running   0          30s   10.244.36.10   k8s-node1
# nginx-test-xxxxxx-yyyyy       1/1     Running   0          30s   10.244.169.20  k8s-node2
# nginx-test-xxxxxx-zzzzz       1/1     Running   0          30s   10.244.104.30  k8s-node3

测试跨节点通信

bash 复制代码
# 获取Pod IP
POD1_IP=$(kubectl get pod -l app=nginx-test -o jsonpath='{.items[0].status.podIP}')
POD2_IP=$(kubectl get pod -l app=nginx-test -o jsonpath='{.items[1].status.podIP}')

# 从Pod1访问Pod2
kubectl exec -it $(kubectl get pod -l app=nginx-test -o jsonpath='{.items[0].metadata.name}') -- curl -s http://$POD2_IP

# 期望输出:nginx欢迎页面HTML

Pod网络通信流程
Pod B 10.244.169.20 k8s-node2 vxlan.calico node2 eth0 192.168.1.12 eth0 192.168.1.11 vxlan.calico node1 Pod A 10.244.36.10 k8s-node1 Pod B 10.244.169.20 k8s-node2 vxlan.calico node2 eth0 192.168.1.12 eth0 192.168.1.11 vxlan.calico node1 Pod A 10.244.36.10 k8s-node1 跨节点通信通过VXLAN隧道实现 发送数据包 目标: 10.244.169.20 VXLAN封装 外层: 192.168.1.11 → 192.168.1.12 内层: 10.244.36.10 → 10.244.169.20 UDP 4789端口传输 VXLAN解封装 转发到目标Pod

5.2 配置NFS动态存储

5.2.1 部署NFS服务器

⚠️ 以下操作在Master节点执行(作为NFS服务器)

bash 复制代码
# 安装NFS服务
yum install -y nfs-utils rpcbind

# 创建共享目录
mkdir -p /data/nfs/k8s
chmod 777 /data/nfs/k8s

# 配置NFS导出
cat >> /etc/exports << EOF
/data/nfs/k8s *(rw,sync,no_root_squash,no_subtree_check)
EOF

# 启动服务
systemctl start rpcbind nfs-server
systemctl enable rpcbind nfs-server

# 重新加载配置
exportfs -r

# 验证NFS导出
showmount -e localhost

在所有Worker节点安装NFS客户端

bash 复制代码
# 安装nfs-utils
yum install -y nfs-utils

# 测试挂载
mkdir -p /mnt/test
mount -t nfs 192.168.1.10:/data/nfs/k8s /mnt/test
df -h | grep nfs
umount /mnt/test
5.2.2 部署NFS动态供应器
bash 复制代码
# 创建命名空间
kubectl create namespace nfs-provisioner

# 部署nfs-subdir-external-provisioner
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/rbac.yaml

# 下载deployment配置
curl -O https://raw.githubusercontent.com/kubernetes-sigs/nfs-subdir-external-provisioner/master/deploy/deployment.yaml

# 修改NFS服务器地址和路径
sed -i 's|10.3.243.101|192.168.1.10|' deployment.yaml
sed -i 's|/ifs/kubernetes|/data/nfs/k8s|' deployment.yaml

# 应用配置
kubectl apply -f deployment.yaml

# 验证Pod状态
kubectl get pods -n nfs-provisioner

创建StorageClass

bash 复制代码
cat > nfs-storage-class.yaml << EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-storage
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
  archiveOnDelete: "false"
reclaimPolicy: Delete
volumeBindingMode: Immediate
EOF

kubectl apply -f nfs-storage-class.yaml

# 设置为默认StorageClass
kubectl patch storageclass nfs-storage -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

# 验证
kubectl get storageclass
5.2.3 测试动态存储
bash 复制代码
# 创建测试PVC
cat > test-pvc.yaml << EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
  storageClassName: nfs-storage
EOF

kubectl apply -f test-pvc.yaml

# 验证PVC状态(应该自动绑定)
kubectl get pvc test-pvc

# 期望输出:
# NAME       STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
# test-pvc   Bound    pvc-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx   1Gi        RWX            nfs-storage    10s

# 检查NFS目录(在Master节点)
ls -l /data/nfs/k8s/

# 清理测试资源
kubectl delete pvc test-pvc

存储动态供应流程
用户创建PVC
StorageClass
NFS Provisioner
创建PV
在NFS服务器创建目录
PVC绑定PV
Pod挂载PVC


✅ 第三阶段完成检查清单

  • Calico网络插件已部署(VXLAN模式)
  • 所有节点状态为Ready
  • vxlan.calico接口存在(不是tunl0)
  • 跨节点Pod通信正常
  • NFS服务器已配置并可访问
  • NFS动态供应器已部署
  • StorageClass已创建并设为默认
  • 测试PVC可以自动绑定

下一步:第六章将部署Ingress-Nginx和Prometheus监控系统。


第六章:Ingress与监控

6.1 部署Ingress-Nginx(hostPort模式)

Ingress-Nginx是K8s集群的流量入口,负责将外部HTTP/HTTPS请求路由到集群内的Service。

6.1.1 为什么使用hostPort模式?

部署模式对比

模式 优点 缺点 适用场景
LoadBalancer 自动分配公网IP 需要云厂商支持,成本高 云上生产环境
NodePort 简单易用 端口范围受限(30000-32767) 测试环境
hostPort 直接使用80/443端口 需要固定节点 云服务器(推荐)

本文选择hostPort模式,将Ingress Controller固定在k8s-node3节点,直接监听80/443端口。

6.1.2 部署Ingress-Nginx
bash 复制代码
# 下载官方配置文件
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.9.4/deploy/static/provider/cloud/deploy.yaml

# 等待Pod启动
kubectl get pods -n ingress-nginx -w

修改为hostPort模式

bash 复制代码
# 编辑Deployment
kubectl edit deployment ingress-nginx-controller -n ingress-nginx

# 在containers部分添加hostPort配置:
# ports:
# - containerPort: 80
#   hostPort: 80
#   name: http
#   protocol: TCP
# - containerPort: 443
#   hostPort: 443
#   name: https
#   protocol: TCP

# 添加节点选择器(固定到node3):
# nodeSelector:
#   kubernetes.io/hostname: k8s-node3

验证部署

bash 复制代码
# 检查Pod状态
kubectl get pods -n ingress-nginx -o wide

# 期望输出:Pod运行在k8s-node3节点
# NAME                                        READY   STATUS    NODE
# ingress-nginx-controller-xxxxxxxxxx-xxxxx   1/1     Running   k8s-node3

# 测试访问(在k8s-node3节点执行)
curl http://localhost

# 期望输出:404 Not Found(正常,因为还没有配置Ingress规则)
6.1.3 创建测试Ingress
bash 复制代码
# 创建测试应用
kubectl create deployment web --image=nginx:1.25
kubectl expose deployment web --port=80

# 创建Ingress规则
cat > test-ingress.yaml << EOF
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: test-ingress
spec:
  ingressClassName: nginx
  rules:
  - host: test.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: web
            port:
              number: 80
EOF

kubectl apply -f test-ingress.yaml

# 验证Ingress
kubectl get ingress test-ingress

测试访问

bash 复制代码
# 在本地配置hosts(或使用curl -H)
curl -H "Host: test.example.com" http://192.168.1.13

# 期望输出:nginx欢迎页面

6.2 部署Prometheus监控

6.2.1 安装Helm
bash 复制代码
# 下载Helm安装脚本
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash

# 验证安装
helm version
6.2.2 部署Prometheus Stack
bash 复制代码
# 添加Prometheus社区Helm仓库
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

# 创建命名空间
kubectl create namespace monitoring

# 创建values配置文件
cat > prometheus-values.yaml << EOF
prometheus:
  prometheusSpec:
    storageSpec:
      volumeClaimTemplate:
        spec:
          storageClassName: nfs-storage
          accessModes: ["ReadWriteOnce"]
          resources:
            requests:
              storage: 10Gi

grafana:
  adminPassword: "admin123"
  persistence:
    enabled: true
    storageClassName: nfs-storage
    size: 5Gi
  service:
    type: NodePort
    nodePort: 30300

alertmanager:
  alertmanagerSpec:
    storage:
      volumeClaimTemplate:
        spec:
          storageClassName: nfs-storage
          accessModes: ["ReadWriteOnce"]
          resources:
            requests:
              storage: 5Gi
EOF

# 安装Prometheus Stack
helm install prometheus prometheus-community/kube-prometheus-stack \
  -n monitoring \
  -f prometheus-values.yaml

# 等待Pod启动(约2-3分钟)
kubectl get pods -n monitoring -w
6.2.3 访问Grafana
bash 复制代码
# 获取Grafana访问地址
kubectl get svc -n monitoring prometheus-grafana

# 期望输出:
# NAME                 TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
# prometheus-grafana   NodePort   10.96.xxx.xxx   <none>        80:30300/TCP   5m

# 访问Grafana
# URL: http://192.168.1.13:30300
# 用户名: admin
# 密码: admin123

验证监控数据

  1. 登录Grafana
  2. 左侧菜单 → Dashboards
  3. 查看预置仪表板:
    • Kubernetes / Compute Resources / Cluster
    • Kubernetes / Compute Resources / Node
    • Kubernetes / Compute Resources / Pod

第七章:常见问题与排查

7.1 镜像拉取失败

问题现象

复制代码
Failed to pull image "registry.k8s.io/pause:3.9": rpc error: code = Unknown desc = failed to pull and unpack image

解决方案

bash 复制代码
# 1. 检查containerd配置
grep "registry.aliyuncs.com" /etc/containerd/config.toml

# 2. 手动拉取测试
ctr image pull registry.aliyuncs.com/google_containers/pause:3.9

# 3. 重启containerd
systemctl restart containerd

7.2 跨节点通信失败

问题现象

复制代码
# Pod无法访问其他节点的Pod
curl: (7) Failed to connect to 10.244.x.x port 80: No route to host

排查步骤

bash 复制代码
# 1. 检查网络模式(必须是VXLAN)
ip link show vxlan.calico  # 应该存在
ip link show tunl0         # 不应该存在

# 2. 检查Calico配置
kubectl get ippool default-ipv4-ippool -o yaml | grep vxlan

# 期望输出:
# vxlanMode: Always
# ipipMode: Never

# 3. 检查安全组规则
# 确保UDP 4789端口已开放

# 4. 重启Calico(如果配置错误)
kubectl delete pod -n kube-system -l k8s-app=calico-node

7.3 快速诊断命令

集群状态检查

bash 复制代码
# 节点状态
kubectl get nodes -o wide

# Pod状态
kubectl get pods -A -o wide | grep -v Running

# 组件状态
kubectl get cs

# 事件查看
kubectl get events -A --sort-by='.lastTimestamp' | tail -20

网络诊断

bash 复制代码
# 检查VXLAN接口
ip link show vxlan.calico

# 检查路由表
ip route | grep vxlan

# 测试Pod网络
kubectl run test --image=busybox:1.28 --restart=Never --rm -it -- ping <pod-ip>

日志查看

bash 复制代码
# Calico日志
kubectl logs -n kube-system -l k8s-app=calico-node --tail=50

# kubelet日志
journalctl -u kubelet -n 50 --no-pager

# containerd日志
journalctl -u containerd -n 50 --no-pager

🎉 总结

恭喜你!现在你已经成功搭建了一套完整的Kubernetes集群,包括:

4节点集群 :1个Master + 3个Worker节点

网络插件 :Calico VXLAN模式(云环境必备)

动态存储 :NFS自动供应PV

流量入口 :Ingress-Nginx hostPort模式

监控体系:Prometheus + Grafana

核心要点回顾

  1. 云环境网络配置

    • 必须使用VXLAN模式,不能用IPIP
    • 安全组开放UDP 4789端口
    • 验证vxlan.calico接口存在
  2. 镜像源优化

    • Kubernetes镜像:registry.aliyuncs.com/google_containers
    • containerd镜像加速:腾讯云/阿里云镜像
  3. 存储配置

    • NFS动态供应适合测试环境
    • 生产环境建议使用Ceph或云盘CSI
  4. 问题排查

    • 优先检查网络模式(VXLAN vs IPIP)
    • 查看Pod日志和事件
    • 验证安全组规则

参考资源


如有问题,欢迎在评论区交流讨论!

相关推荐
小锋学长生活大爆炸10 小时前
【教程】免Root在Termux上安装Docker
运维·docker·容器
进击切图仔10 小时前
常用 Docker 命令备份
运维·docker·容器
我在人间贩卖青春16 小时前
C++之STL容器
c++·容器·stl
A-刘晨阳18 小时前
K8S 之 DaemonSet
运维·云原生·容器·kubernetes·daemonset
小锋学长生活大爆炸18 小时前
【教程】查看docker容器的TCP连接和带宽使用情况
tcp/ip·docker·容器
ccino .19 小时前
【Drupal文件上传导致跨站脚本执行(CVE-2019-6341)】
运维·网络安全·docker·容器
sun032220 小时前
【Docker】构建镜像时使用的 Dockerfile ,以及其中的 MicroDNF
运维·docker·容器
切糕师学AI21 小时前
Kubernetes 中的 Volume(存储卷)
云原生·容器·kubernetes
Diligently_1 天前
mqtt_docker安装
运维·docker·容器
Aric_Jones1 天前
Docker 部署博客小白教程
运维·docker·容器