云厂商的 K8s(EKS / GKE / AKS)按月几十美元。自己买几台便宜 VPS
也能跑 K8s——一台 control plane + 2 台 worker,每月几美元。
适合自学 / 个人项目 / 小规模生产。
下面用 kubeadm 起 v1.30 集群。
准备(每台机器都做)
# 关 swap(K8s 要求)
sudo swapoff -a
sudo sed -i '/swap/d' /etc/fstab
# 内核模块
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
sudo modprobe overlay br_netfilter
# sysctl
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
sudo sysctl --system
装 containerd
sudo apt update
sudo apt install -y containerd
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml
# 启 SystemdCgroup(K8s 要求)
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/' /etc/containerd/config.toml
sudo systemctl restart containerd
装 kubeadm / kubelet / kubectl
sudo apt install -y apt-transport-https ca-certificates curl gpg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/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.30/deb/ /' \
| sudo tee /etc/apt/sources.list.d/kubernetes.list
sudo apt update
sudo apt install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
初始化 control plane(只在 master 上)
sudo kubeadm init \
--pod-network-cidr=10.244.0.0/16 \
--apiserver-advertise-address=<MASTER_IP>
完成后会打印一段 kubeadm join ... 命令——保存下来,下面 worker 用。
让普通用户用 kubectl:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubectl get nodes
# 状态会是 NotReady —— 因为没装 CNI
装 CNI(这里用 Flannel)
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
# 等 1-2 分钟
kubectl get pods -A
kubectl get nodes
# Ready 了
其它 CNI 选择:
- Calico:网络策略 + BGP,生产更常用
- Cilium:eBPF,性能 + 观测最好
- Flannel:最简单,仅 overlay 网络
Worker 加入
每台 worker 上:
sudo kubeadm join <MASTER_IP>:6443 \
--token <TOKEN> \
--discovery-token-ca-cert-hash sha256:<HASH>
Master 上:
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# master Ready control-plane 5m v1.30.0
# worker-1 Ready <none> 1m v1.30.0
# worker-2 Ready <none> 1m v1.30.0
部署个 demo
# nginx-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 3
selector:
matchLabels: { app: nginx }
template:
metadata: { labels: { app: nginx } }
spec:
containers:
- name: nginx
image: nginx:alpine
ports: [{ containerPort: 80 }]
---
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
type: NodePort
selector: { app: nginx }
ports:
- port: 80
nodePort: 30080
kubectl apply -f nginx-demo.yaml
kubectl get pods -o wide
curl http://<任意-Node-IP>:30080
Ingress(暴露 80/443 到公网)
NodePort 30000+ 端口不友好,用 Ingress:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/baremetal/deploy.yaml
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service: { name: nginx, port: { number: 80 } }
把 <MASTER_IP> 或 worker IP DNS 指到 app.example.com,
80/443 流量进 ingress-nginx,再分发到 service。
cert-manager 自动 HTTPS
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata: { name: letsencrypt-prod }
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: [email protected]
privateKeySecretRef: { name: letsencrypt-prod }
solvers:
- http01:
ingress: { class: nginx }
Ingress 加 annotation cert-manager.io/cluster-issuer: letsencrypt-prod,
自动签发 + 续期证书。
备份 etcd
# 在 master 上
sudo 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-$(date +%F).db
定时备份这个文件到对象存储是单 master K8s 集群唯一的 DR 手段。
升级
sudo apt-mark unhold kubeadm
sudo apt install -y kubeadm=1.30.5-*
sudo apt-mark hold kubeadm
sudo kubeadm upgrade plan
sudo kubeadm upgrade apply v1.30.5
# 然后升 kubelet / kubectl
踩过的坑
- swap 没关 kubelet 启动失败:v1.22 之前默认要求;v1.22+ 可以保留 swap
但要在 kubelet 配置里显式failSwapOn: false。 - 防火墙:control plane 需要开 6443、10250、2379-2380,CNI 用的端口
各异(Flannel UDP 8472)。最简单:把 master / worker 之间的网络
完全开放(内网或 VPC)。 - Token 24 小时过期:worker 加入时
kubeadm token create --print-join-command
生成新 token。 - 单 master 没冗余:宕机就完蛋。生产多 master + HA load balancer
- 外部 etcd cluster。kubeadm 也支持。
登录后参与评论。