1. 为什么需要自己搭建K8s集群?
在云原生时代,Kubernetes(简称K8s)已经成为容器编排的事实标准。虽然各大云厂商都提供了托管版K8s服务(如EKS、AKS、GKE等),但自己搭建集群仍然有其不可替代的价值:
- 学习与理解:通过手动搭建可以深入理解K8s的各个组件及其交互方式
- 成本控制:对于长期运行的测试环境或小规模生产环境,自建集群通常更经济
- 定制需求:某些特殊场景(如边缘计算、混合云)需要完全掌控集群配置
- 技能验证:作为云原生工程师的必备技能,面试中常被考察
我在第一次搭建K8s集群时,花了整整三天时间解决各种依赖和配置问题。现在回想起来,那些"踩坑"经历反而让我对Kubernetes的理解更加深刻。下面就把这些经验总结成一份详实的教程。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与前置条件
2.1 硬件要求
虽然K8s官方声称可以在单节点上运行,但为了体验完整功能,建议至少准备:
- 3台Linux服务器(可以是物理机或虚拟机):
- 2核CPU/4GB内存/20GB磁盘(控制平面节点)
- 1核CPU/2GB内存/20GB磁盘(工作节点)
- 网络环境:
- 所有节点间网络互通
- 关闭防火墙或开放必要端口(6443、2379-2380等)
- 确保主机名解析正常(建议配置/etc/hosts)
提示:如果只是学习使用,可以在本地通过VirtualBox创建3台CentOS/Ubuntu虚拟机。我常用2C4G的配置,能流畅运行基础集群。
2.2 操作系统配置
在所有节点上执行以下基础配置:
bash复制# 关闭swap(Kubernetes 1.8+要求)
sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
# 关闭SELinux
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
# 配置内核参数
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF
sudo sysctl --system
2.3 容器运行时安装
Kubernetes支持多种容器运行时,我推荐使用containerd:
bash复制# 安装依赖
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# 添加Docker仓库(containerd包含在Docker中)
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
# 安装containerd
sudo yum install -y docker-ce docker-ce-cli containerd.io
# 配置containerd
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
# 修改sandbox镜像为国内源(加速拉取)
sudo sed -i 's|k8s.gcr.io/pause|registry.aliyuncs.com/google_containers/pause|g' /etc/containerd/config.toml
sudo sed -i 's|SystemdCgroup = false|SystemdCgroup = true|g' /etc/containerd/config.toml
# 启动服务
sudo systemctl enable --now containerd
3. 使用kubeadm部署集群
3.1 安装kubeadm/kubelet/kubectl
在所有节点上执行:
bash复制# 添加Kubernetes仓库
cat <<EOF | sudo tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64/
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://mirrors.aliyun.com/kubernetes/yum/doc/yum-key.gpg https://mirrors.aliyun.com/kubernetes/yum/doc/rpm-package-key.gpg
EOF
# 安装三件套(指定版本避免兼容问题)
sudo yum install -y kubelet-1.28.0 kubeadm-1.28.0 kubectl-1.28.0 --disableexcludes=kubernetes
# 设置kubelet开机启动(先不启动,等初始化完成)
sudo systemctl enable kubelet
3.2 初始化控制平面
在主节点(我选择node1作为master)上执行:
bash复制# 初始化集群(使用国内镜像源)
sudo kubeadm init \
--apiserver-advertise-address=192.168.1.100 \
--image-repository registry.aliyuncs.com/google_containers \
--kubernetes-version v1.28.0 \
--service-cidr=10.96.0.0/12 \
--pod-network-cidr=10.244.0.0/16 \
--ignore-preflight-errors=Swap
初始化成功后,你会看到类似输出:
code复制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
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join 192.168.1.100:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
按照提示配置kubectl:
bash复制mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
3.3 安装网络插件
K8s需要网络插件实现Pod间通信,我选择Calico:
bash复制kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml
等待所有Pod变为Running状态:
bash复制watch kubectl get pods -n kube-system
3.4 加入工作节点
在每个工作节点上执行主节点初始化成功后输出的join命令:
bash复制sudo kubeadm join 192.168.1.100:6443 --token abcdef.0123456789abcdef \
--discovery-token-ca-cert-hash sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
加入成功后,在主节点检查节点状态:
bash复制kubectl get nodes
4. 集群验证与基本操作
4.1 验证集群状态
bash复制# 查看组件状态
kubectl get cs
# 查看所有命名空间的Pod
kubectl get pods --all-namespaces
# 查看节点资源使用
kubectl top nodes
4.2 部署测试应用
bash复制# 运行一个Nginx Deployment
kubectl create deployment nginx --image=nginx:alpine
# 暴露为NodePort服务
kubectl expose deployment nginx --port=80 --type=NodePort
# 获取服务访问端口
NODE_PORT=$(kubectl get svc nginx -o jsonpath='{.spec.ports[0].nodePort}')
curl http://<任意节点IP>:$NODE_PORT
4.3 常用故障排查命令
bash复制# 查看Pod详细状态(适合启动失败时使用)
kubectl describe pod <pod-name>
# 查看Pod日志
kubectl logs <pod-name>
# 进入Pod内部排查
kubectl exec -it <pod-name> -- sh
# 检查kubelet日志
journalctl -u kubelet -f
5. 生产环境增强配置
5.1 控制平面高可用
对于生产环境,建议部署多master节点实现高可用:
bash复制# 在第一个master初始化时添加参数
sudo kubeadm init --control-plane-endpoint "LOAD_BALANCER_DNS:LOAD_BALANCER_PORT" --upload-certs
# 其他master节点加入时使用
sudo kubeadm join LOAD_BALANCER_DNS:LOAD_BALANCER_PORT --token ... \
--discovery-token-ca-cert-hash sha256:... \
--control-plane --certificate-key ...
5.2 证书管理
K8s集群证书默认1年有效期,需要定期更新:
bash复制# 检查证书有效期
kubeadm certs check-expiration
# 更新所有证书
kubeadm certs renew all
5.3 持久化存储
配置NFS作为StorageClass:
bash复制# 安装NFS客户端工具
sudo yum install -y nfs-utils
# 创建StorageClass
cat <<EOF | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-storage
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
archiveOnDelete: "false"
EOF
6. 常见问题与解决方案
6.1 kubeadm init卡住
可能原因:
- 镜像拉取失败(特别是gcr.io的镜像)
- 网络插件未正确安装
- 节点资源不足
解决方案:
bash复制# 查看kubelet日志定位具体问题
journalctl -xeu kubelet
# 手动拉取镜像
docker pull registry.aliyuncs.com/google_containers/kube-apiserver:v1.28.0
6.2 Pod一直处于Pending状态
可能原因:
- 资源不足
- 没有满足的节点(如taints/tolerations不匹配)
- PV/PVC问题
排查步骤:
bash复制kubectl describe pod <pod-name> | grep -A 10 Events
kubectl get events --sort-by='.metadata.creationTimestamp'
6.3 网络插件故障
Calico常见问题处理:
bash复制# 检查Calico Pod日志
kubectl logs -n kube-system <calico-pod-name>
# 重新安装Calico
kubectl delete -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml
kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/calico.yaml
7. 集群维护与升级
7.1 版本升级策略
K8s版本支持策略:
- 每个版本大约支持1年
- 最多支持3个次要版本(如1.28.x、1.27.x、1.26.x)
- 升级路径必须逐步进行(如1.26→1.27→1.28)
7.2 升级控制平面
bash复制# 在所有节点上先升级kubeadm
sudo yum install -y kubeadm-1.28.1 --disableexcludes=kubernetes
# 在主节点上执行升级计划
sudo kubeadm upgrade plan
# 应用升级
sudo kubeadm upgrade apply v1.28.1
# 升级kubelet和kubectl
sudo yum install -y kubelet-1.28.1 kubectl-1.28.1 --disableexcludes=kubernetes
sudo systemctl daemon-reload
sudo systemctl restart kubelet
7.3 升级工作节点
bash复制# 先排空节点(将Pod迁移到其他节点)
kubectl drain <node-name> --ignore-daemonsets
# 升级kubeadm、kubelet
sudo yum install -y kubeadm-1.28.1 kubelet-1.28.1 --disableexcludes=kubernetes
sudo kubeadm upgrade node
sudo systemctl daemon-reload
sudo systemctl restart kubelet
# 恢复节点调度
kubectl uncordon <node-name>
8. 安全加固建议
8.1 RBAC配置
创建最小权限ServiceAccount:
yaml复制apiVersion: v1
kind: ServiceAccount
metadata:
name: limited-user
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-reader
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "watch", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: read-pods
subjects:
- kind: ServiceAccount
name: limited-user
roleRef:
kind: Role
name: pod-reader
apiGroup: rbac.authorization.k8s.io
8.2 Pod安全策略
启用PodSecurity准入控制器:
bash复制# 修改kube-apiserver配置
sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
# 添加以下参数:
- --feature-gates=PodSecurity=true
- --admission-control-config-file=/etc/kubernetes/pss-config.yaml
# 创建配置文件
cat <<EOF | sudo tee /etc/kubernetes/pss-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
- name: PodSecurity
configuration:
apiVersion: pod-security.admission.config.k8s.io/v1
kind: PodSecurityConfiguration
defaults:
enforce: "restricted"
enforce-version: "latest"
audit: "restricted"
audit-version: "latest"
warn: "restricted"
warn-version: "latest"
exemptions:
usernames: []
runtimeClasses: []
namespaces: [kube-system]
EOF
8.3 网络策略
限制命名空间间通信:
yaml复制apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
9. 监控与日志方案
9.1 部署Prometheus
使用kube-prometheus-stack:
bash复制helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install kube-prometheus prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--create-namespace \
--set grafana.adminPassword=admin123
9.2 日志收集方案
使用EFK(Elasticsearch+Fluentd+Kibana):
bash复制helm repo add elastic https://helm.elastic.co
helm install elasticsearch elastic/elasticsearch --namespace logging
helm install fluentd elastic/fluentd --namespace logging
helm install kibana elastic/kibana --namespace logging
10. 备份与恢复
10.1 etcd备份
bash复制# 创建快照
ETCDCTL_API=3 etcdctl --endpoints=https://127.0.0.1:2379 \
--cacert=/etc/kubernetes/pki/etcd/ca.crt \
--cert=/etc/kubernetes/pki/etcd/server.crt \
--key=/etc/kubernetes/pki/etcd/server.key \
snapshot save /tmp/etcd-snapshot-$(date +%Y%m%d).db
# 恢复快照
sudo systemctl stop kubelet
sudo etcdctl snapshot restore /tmp/etcd-snapshot.db \
--data-dir /var/lib/etcd-backup
sudo mv /var/lib/etcd /var/lib/etcd-old
sudo mv /var/lib/etcd-backup /var/lib/etcd
sudo systemctl start kubelet
10.2 资源备份
使用velero进行集群资源备份:
bash复制velero install \
--provider aws \
--plugins velero/velero-plugin-for-aws:v1.0.0 \
--bucket my-backup-bucket \
--secret-file ./credentials-velero \
--use-volume-snapshots=false \
--backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://minio.example.com
# 创建全集群备份
velero backup create full-cluster-backup
11. 性能优化技巧
11.1 kubelet配置优化
bash复制# 修改/var/lib/kubelet/config.yaml
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
evictionHard:
memory.available: "500Mi"
nodefs.available: "10%"
nodefs.inodesFree: "5%"
imagefs.available: "15%"
kubeReserved:
cpu: "500m"
memory: "500Mi"
ephemeral-storage: "1Gi"
systemReserved:
cpu: "500m"
memory: "500Mi"
ephemeral-storage: "1Gi"
11.2 调度器优化
使用节点亲和性和Pod反亲和性:
yaml复制apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
topologyKey: kubernetes.io/hostname
containers:
- name: nginx
image: nginx:alpine
12. 扩展集群功能
12.1 安装Dashboard
bash复制kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml
# 创建访问令牌
kubectl create serviceaccount dashboard-admin -n kubernetes-dashboard
kubectl create clusterrolebinding dashboard-admin --clusterrole=cluster-admin --serviceaccount=kubernetes-dashboard:dashboard-admin
kubectl -n kubernetes-dashboard create token dashboard-admin
# 访问Dashboard
kubectl proxy
# 然后访问 http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/
12.2 安装Ingress Controller
使用Nginx Ingress:
bash复制helm upgrade --install ingress-nginx ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--namespace ingress-nginx --create-namespace
13. 多集群管理
13.1 使用kubectx切换上下文
bash复制# 安装kubectx
sudo git clone https://github.com/ahmetb/kubectx /opt/kubectx
sudo ln -s /opt/kubectx/kubectx /usr/local/bin/kubectx
sudo ln -s /opt/kubectx/kubens /usr/local/bin/kubens
# 查看所有集群
kubectl config get-contexts
# 切换集群
kubectx cluster-1
13.2 使用Cluster API管理多集群
安装Cluster API:
bash复制clusterctl init --infrastructure=aws
创建新集群:
bash复制clusterctl generate cluster my-cluster \
--kubernetes-version v1.28.0 \
--control-plane-machine-count=3 \
--worker-machine-count=3 \
> my-cluster.yaml
kubectl apply -f my-cluster.yaml
14. 边缘计算场景
14.1 部署K3s轻量集群
bash复制# 单节点安装
curl -sfL https://get.k3s.io | sh -
# 多节点集群
curl -sfL https://get.k3s.io | K3S_URL=https://<server-ip>:6443 K3S_TOKEN=<token> sh -
14.2 使用KubeEdge
bash复制# 安装CloudCore
kubectl apply -f https://raw.githubusercontent.com/kubeedge/kubeedge/master/build/cloud.yaml
# 安装EdgeCore
curl -L https://github.com/kubeedge/kubeedge/releases/download/v1.12.0/kubeedge-v1.12.0-linux-amd64.tar.gz | tar xz
cd kubeedge-v1.12.0-linux-amd64/
./edgecore --defaultconfig > edgecore.yaml
./edgecore --config edgecore.yaml
15. 持续集成与GitOps
15.1 集成Jenkins
groovy复制pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'docker build -t my-app:${GIT_COMMIT} .'
}
}
stage('Deploy') {
steps {
sh 'kubectl set image deployment/my-app my-app=my-app:${GIT_COMMIT}'
}
}
}
}
15.2 使用Argo CD实现GitOps
bash复制kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# 获取admin密码
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
创建应用:
yaml复制apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/my-org/my-repo.git
targetRevision: HEAD
path: k8s
destination:
server: https://kubernetes.default.svc
namespace: default
syncPolicy:
automated:
selfHeal: true
prune: true
