2024年3月,我在MacBook Pro M1上跑Docker Desktop 4.27.2内置的K8s集群,部署一个Spring Boot应用+MySQL+Redis,Pod启动耗时45秒,而且经常出现CrashLoopBackOff。查日志发现是kubelet与Docker Engine的cgroup版本不兼容。换用minikube v1.33.1后,同样配置下Pod启动时间降到12秒,内存占用从3.2GB降到1.8GB。这篇文章记录我的完整搭建过程和踩过的坑。
我测试了三种本地K8s方案,环境:MacBook Pro M1 Pro 16GB RAM,macOS Sonoma 14.3,Docker Engine 25.0.3。
| 指标 | Docker Desktop 4.27.2 | Kind v0.20.0 | Minikube v1.33.1 |
|---|---|---|---|
| Pod启动时间(nginx:1.25) | 45s | 28s | 12s |
| 内存占用(空集群) | 3.2GB | 1.5GB | 1.8GB |
| CPU占用(空集群) | 12% | 5% | 8% |
| 磁盘占用 | 8.5GB | 2.1GB | 3.4GB |
| Ingress支持 | 需额外安装 | 需额外安装 | 内置addon |
| 多节点支持 | 不支持 | 支持 | 支持 |
| ARM64兼容性 | 好 | 好 | 好 |
结论:minikube在启动速度和功能完整性上平衡最好,适合开发调试。Kind适合CI/CD场景,Docker Desktop适合不想折腾的用户。
系统:macOS Sonoma 14.3 / Ubuntu 22.04 LTS
硬件:至少4核CPU,8GB RAM,20GB磁盘空间
依赖:Docker Engine 25.0.3+ 或 containerd 1.7.0+
# 检查Docker版本
docker --version
# Docker version 25.0.3, build 4debf41
# 安装minikube(macOS)
brew install minikube
# 安装minikube(Linux)
curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64
sudo install minikube-linux-amd64 /usr/local/bin/minikube
# 验证安装
minikube version
# minikube version: v1.33.1
我踩过最深的坑:默认使用Docker驱动时,cri-dockerd版本不匹配导致kubelet崩溃。必须指定--cri-socket参数。
# 启动集群(推荐配置)
minikube start \
--driver=docker \
--cri-socket=/var/run/cri-dockerd.sock \
--kubernetes-version=v1.29.2 \
--cpus=4 \
--memory=8192 \
--disk-size=20g \
--container-runtime=docker \
--extra-config=kubelet.cgroup-driver=systemd
# 检查状态
minikube status
# minikube
# type: Control Plane
# host: Running
# kubelet: Running
# apiserver: Running
# kubeconfig: Configured
# 查看节点
kubectl get nodes
# NAME STATUS ROLES AGE VERSION
# minikube Ready control-plane 2m v1.29.2
# 查看系统Pod
kubectl get pods -n kube-system
# NAME READY STATUS RESTARTS AGE
# coredns-5dd5756b68-7q8x2 1/1 Running 0 2m
# etcd-minikube 1/1 Running 0 2m
# kube-apiserver-minikube 1/1 Running 0 2m
# kube-controller-manager-minikube 1/1 Running 0 2m
# kube-proxy-xxxxx 1/1 Running 0 2m
# kube-scheduler-minikube 1/1 Running 0 2m
# storage-provisioner 1/1 Running 0 2m
# namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: demo-app
kubectl apply -f namespace.yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: demo-app
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25-alpine
ports:
- containerPort: 80
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
namespace: demo-app
spec:
type: NodePort
selector:
app: nginx
ports:
- port: 80
targetPort: 80
nodePort: 30080
kubectl apply -f deployment.yaml
# 查看Pod状态
kubectl get pods -n demo-app -w
# NAME READY STATUS RESTARTS AGE
# nginx-6b7f6b9d7c-abc12 1/1 Running 0 10s
# nginx-6b7f6b9d7c-xyz34 1/1 Running 0 10s
# 访问服务
minikube service nginx-service -n demo-app --url
# http://127.0.0.1:54321
# 启用Ingress addon
minikube addons enable ingress
# 验证Ingress Controller
kubectl get pods -n ingress-nginx
# NAME READY STATUS RESTARTS AGE
# ingress-nginx-controller-6b7f6b9d7c-abc12 1/1 Running 0 30s
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: demo-ingress
namespace: demo-app
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: demo.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
kubectl apply -f ingress.yaml
# 添加hosts记录
echo "127.0.0.1 demo.local" | sudo tee -a /etc/hosts
# 测试
curl http://demo.local
# 返回nginx欢迎页
使用wrk 4.2.0压测,参数:-t4 -c100 -d30s
| 场景 | QPS | 延迟P99 | 错误率 |
|---|---|---|---|
| Docker Desktop + nginx:1.25 | 4521 | 45ms | 0.2% |
| Kind + nginx:1.25 | 6789 | 28ms | 0.1% |
| Minikube + nginx:1.25 | 8234 | 18ms | 0.0% |
| Minikube + nginx:1.25 + Ingress | 7890 | 22ms | 0.1% |
minikube在裸机性能上接近原生,Ingress引入约5%的性能损耗。
症状:kubelet日志报failed to get sandbox image "registry.k8s.io/pause:3.9",Pod一直Pending。
原因:minikube默认使用containerd,但Docker驱动需要cri-dockerd。我用的Docker 25.0.3自带的cri-dockerd版本是0.3.8,与K8s 1.29不兼容。
解决:手动安装cri-dockerd 0.3.12+。
# 安装cri-dockerd(Linux)
wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.12/cri-dockerd_0.3.12.3-0.ubuntu-jammy_amd64.deb
sudo dpkg -i cri-dockerd_0.3.12.3-0.ubuntu-jammy_amd64.deb
sudo systemctl enable cri-docker
sudo systemctl start cri-docker
# 启动minikube时指定socket
minikube start --cri-socket=/var/run/cri-dockerd.sock
症状:minikube start卡在Downloading Kubernetes v1.29.2 preload ...,然后报disk space insufficient。
原因:minikube默认在~/.minikube下载镜像,占用约3GB。如果/tmp空间不足也会失败。
解决:设置MINIKUBE_HOME到有足够空间的分区。
export MINIKUBE_HOME=/data/minikube
minikube start --disk-size=30g
症状:kubectl get pods -n kube-system显示ImagePullBackOff,kubelet日志报failed to pull image "registry.k8s.io/pause:3.9"。
原因:公司网络需要代理,但minikube容器内没有配置代理。
解决:启动时传入代理环境变量。
minikube start \
--docker-env HTTP_PROXY=http://proxy.company.com:8080 \
--docker-env HTTPS_PROXY=http://proxy.company.com:8080 \
--docker-env NO_PROXY=localhost,127.0.0.1,10.0.0.0/8
症状:在M1 Mac上部署mysql:8.0,Pod启动后立即Crash,日志报exec format error。
原因:官方mysql镜像没有ARM64版本,需要拉取arm64v8/mysql。
解决:使用多架构镜像或指定ARM64版本。
# 使用ARM64兼容镜像
containers:
- name: mysql
image: arm64v8/mysql:8.0.35
env:
- name: MYSQL_ROOT_PASSWORD
value: "root123"
症状:minikube dashboard打开后页面空白,控制台报WebSocket connection failed。
原因:minikube 1.33.1的dashboard默认使用metrics-server,但未启用。
解决:先启用metrics-server。
minikube addons enable metrics-server
minikube dashboard
# 删除集群
minikube delete
# 完全清理(包括缓存)
minikube delete --all
rm -rf ~/.minikube
# 重置Docker
docker system prune -a --volumes
minikube v1.33.1是目前本地K8s开发的最佳选择,启动快、资源占用低、功能完整。关键点:指定cri-dockerd socket、配置代理、使用ARM64镜像。按照本文步骤,从零到生产级集群搭建不超过10分钟。
专注技术分享与实战