minikube:从驱动选择到可恢复的本地 Kubernetes 工作台
同一个 minikube,为什么同事访问方式完全不同
Linux 同事把浏览器指向 minikube ip 就能访问 NodePort,Windows 同事使用 Docker driver 却始终超时;有人执行 docker build 后 Pod 立刻启动,有人得到 ImagePullBackOff;还有人把内存从 4 GiB 改成 8 GiB,重启后发现资源并没有按想象变化。
这些现象通常不是 Kubernetes 随机失灵,而是 minikube 的 profile、driver、container runtime 和宿主网络 没有被当成架构的一部分。minikube 可以把节点放进容器、虚拟机,甚至直接放在宿主机上。驱动决定隔离层和访问路径,容器运行时决定镜像存放位置,profile 决定状态、证书与配置归属;只记住 minikube start,等于把最关键的变量都交给自动探测。
minikube 面向本地学习和开发,不是缩小版生产平台。即使创建多个节点,它们通常仍共享一台开发机、一个虚拟化层和一个故障域。下面会把它做成一套可重复、可取证、能彻底清理的项目工作台,而不是长期承载团队业务的共享服务器。
安装前先决定驱动,不让自动探测替团队做架构选择
minikube Getting Started 提供 Windows、macOS、Linux 和多种架构的发布二进制。发布资产带 SHA-256 校验值;包管理器适合个人安装,企业镜像源应保存版本、来源和校验值。minikube 使用 Apache-2.0 许可证,本身无软件订阅价格,但 Docker Desktop 许可、虚拟化资源、镜像下载、CI 时长和维护 addon 都会产生真实成本。
官方起步资源是至少 2 CPU、2 GiB 可用内存和 20 GiB 磁盘。这个数字只能让控制面起步,不是业务容量承诺。运行 Ingress、metrics-server、数据库和多个服务后,要根据实际 requests、镜像层、emptyDir 和日志增长测量资源。
Windows 可以使用 Getting Started 列出的 Winget 包:
winget install Kubernetes.minikube
minikube versionmacOS 使用 Homebrew 时执行:
brew install minikube
minikube versionLinux amd64 直接安装发布二进制时,把版本和校验值一起固定:
curl -fsSLo minikube \
https://github.com/kubernetes/minikube/releases/download/v1.38.1/minikube-linux-amd64
echo '099477eaf248bcb5bcea8ce78a2898e93ac01461c35189da1848c3de82ecd22e minikube' \
| sha256sum -c -
sudo install -m 0755 minikube /usr/local/bin/minikube
minikube version校验成功会输出 minikube: OK;失败时停止安装并从 Release Assets 重新核对平台、版本和摘要。ARM64 应下载对应资产并使用其独立摘要。minikube 可以通过 minikube kubectl -- ... 下载匹配客户端,团队仍应从 Install Tools 固定常用 kubectl,并验证版本偏差。
安装后执行:
minikube version
minikube start --help
minikube config view第一条确认 CLI 发布版;第二条显示这个版本实际支持的参数,避免复制旧博客里的已变更选项;第三条暴露本机持久化默认值。不要在排障报告中直接粘贴整个 profile 目录或 kubeconfig,它们可能包含证书路径、代理和 registry 信息。
Drivers 页面按操作系统列出状态。Docker 在 Linux、macOS、Windows 都是优先驱动之一,适合已经统一 Docker Desktop/Engine 的团队;Linux 的 KVM2、Windows 的 Hyper-V、macOS 的 VFKit 提供 VM 边界,更适合验证挂载、内核或网络差异。Podman driver 在各平台仍标为 experimental,不能只因为开发机装了 Podman 就把它定成团队默认。none driver 直接改宿主系统,权限与清理风险更高,不适合作为普通开发机基线。
下面以 Docker driver、containerd runtime 和名为 tooling-dev 的 profile 为例。显式固定 Kubernetes 版本,可以让本地与 CI 共享 API 基线;minikube v1.38.1 的发布说明包含 Kubernetes v1.35.1 支持,升级前仍应从 minikube Releases 选择目标组合,并按 Kubernetes version skew policy 校验 kubectl。
minikube start \
--profile tooling-dev \
--driver docker \
--container-runtime containerd \
--kubernetes-version v1.35.1 \
--cpus 4 \
--memory 6144mb \
--nodes 2--profile 隔离集群状态和 context;--driver 决定节点位于 Docker 容器中;--container-runtime 决定 kubelet 通过哪个 CRI 管理镜像。多节点 profile 中,--cpus 和 --memory 是每个节点的资源,不是整个 profile 的总预算:这里两个节点最多会向开发机申请约 8 CPU 和 12 GiB 内存,应先按团队开发机基线调整。--disk-size 面向 VM 磁盘,Docker driver 不应把它当作可靠的 profile 容量护栏;Docker Desktop 磁盘上限、节点可写层、PV 和镜像缓存仍要分别观察。--nodes 2 创建多节点实验拓扑,却不会制造两个物理故障域。
启动成功后不要急着部署,先验证运行对象:
minikube -p tooling-dev status
minikube -p tooling-dev profile list
kubectl --context tooling-dev get nodes -o wide
kubectl --context tooling-dev get pods -Astatus 应显示 host、kubelet、apiserver 与 kubeconfig 为 Running/Configured;节点应为 Ready。刚启动时 storage-provisioner 等组件短暂未 Running 可以等待收敛,若持续异常则执行 minikube -p tooling-dev logs --problems,它会优先收集已识别问题,而不是让人盲猜驱动。
资源参数改变的是本地预算,不是生产容量模型
minikube 的 CPU、内存和磁盘值先作用于驱动承载的节点环境;Pod 的 requests/limits 再由 Kubernetes 调度和 cgroup 执行。Docker driver 下还受 Docker Desktop 全局资源上限约束:命令请求 6 GiB,而 Docker Desktop 只允许更少内存时,控制面或 Pod 仍可能 OOM。
先观察节点能分配多少,而不是相信启动参数已经生效:
kubectl --context tooling-dev get nodes \
-o custom-columns=NAME:.metadata.name,CPU:.status.allocatable.cpu,MEMORY:.status.allocatable.memory
minikube -p tooling-dev ssh -- df -hallocatable 是调度器看到的预算,已经扣除一部分系统保留;df -h 看到的是节点文件系统,不等于宿主剩余空间。容器 driver 与 VM driver 的磁盘扩展、挂载和回收行为不同,更换 driver 或关键网络参数时,最可预测的动作通常是删除 profile 后按配置重建,而不是在已有状态上叠加试错。
如果团队希望持久化默认值,可以使用 minikube config set memory 6144 等命令,但这会影响后续未显式传参的 profile,容易让项目间相互污染。项目脚本显式传参数,个人全局 config 只保留无争议设置;每次故障报告都附上 minikube profile list 与启动命令。
在节点运行时里构建镜像
宿主 Docker daemon、minikube 节点的 containerd 和远程 registry 是三个镜像仓库。docker images 能看到镜像,不代表 containerd 能看到。minikube 提供两条稳定路径:minikube image build 直接使用 profile 的容器运行时构建,minikube image load 把宿主镜像或归档导入 profile。
创建 Dockerfile.minikube-lab:
FROM python:3.13-alpine
WORKDIR /srv
RUN printf 'minikube-local-image-ok\n' > index.html
EXPOSE 8080
USER 65532:65532
CMD ["python", "-m", "http.server", "8080", "--bind", "0.0.0.0"]直接在 minikube 里构建;多节点 profile 必须带 --all,否则镜像只进入主控制面节点,Pod 调度到 worker 后会得到 ErrImageNeverPull:
minikube -p tooling-dev image build \
--all \
-f Dockerfile.minikube-lab \
-t local/minikube-lab:dev-001 .
minikube -p tooling-dev image ls | grep minikube-lab-f 指定 Dockerfile,-t 使用不可变的开发 tag,--all 要求在所有节点构建。构建后再次用 image ls 验证;另一条路径是:
docker build -f Dockerfile.minikube-lab -t local/minikube-lab:dev-001 .
minikube -p tooling-dev image load local/minikube-lab:dev-001
minikube -p tooling-dev image ls | grep minikube-labimage load 适合复用宿主构建缓存或导入离线 tar。不要混用 eval $(minikube docker-env) 与 containerd runtime:docker-env 改变当前 shell 的 Docker 目标,容易让后续 docker build、登录和清理都指向意外 daemon。项目脚本优先使用显式的 minikube image build/load。
构建参数、层历史和 CI 日志可能泄露令牌。真实 registry 凭证不要通过 Dockerfile ARG、镜像 tag 或命令行明文传入;使用构建系统的 secret mount 或受控 CI secret,并确保最终层和构建日志不含秘密。
正向部署:从 Pod Ready 一直验证到宿主入口
创建 k8s/minikube/lab.yaml:
apiVersion: v1
kind: Namespace
metadata:
name: tooling-dev
labels:
owner: local-platform
---
apiVersion: v1
kind: ResourceQuota
metadata:
name: namespace-budget
namespace: tooling-dev
spec:
hard:
requests.cpu: "1"
requests.memory: 512Mi
limits.cpu: "2"
limits.memory: 1Gi
pods: "10"
---
apiVersion: v1
kind: LimitRange
metadata:
name: container-defaults
namespace: tooling-dev
spec:
limits:
- type: Container
defaultRequest:
cpu: 50m
memory: 32Mi
default:
cpu: 200m
memory: 128Mi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: minikube-lab
namespace: tooling-dev
spec:
replicas: 2
selector:
matchLabels:
app: minikube-lab
template:
metadata:
labels:
app: minikube-lab
spec:
containers:
- name: app
image: local/minikube-lab:dev-001
imagePullPolicy: Never
ports:
- name: http
containerPort: 8080
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 1
periodSeconds: 2
resources:
requests:
cpu: 50m
memory: 32Mi
limits:
cpu: 200m
memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
name: minikube-lab
namespace: tooling-dev
spec:
type: NodePort
selector:
app: minikube-lab
ports:
- name: http
port: 80
targetPort: httpimagePullPolicy: Never 强制使用已构建或导入的本地镜像,适合证明镜像链路;远端开发集群应改用可访问 registry、不可变 tag/摘要和受控拉取凭证。ResourceQuota 与 LimitRange 让错误请求尽早被拒绝,也让 addon 和应用争抢宿主资源时更容易归因。
执行部署:
kubectl --context tooling-dev apply -f k8s/minikube/lab.yaml
kubectl --context tooling-dev -n tooling-dev rollout status deploy/minikube-lab --timeout=90s
kubectl --context tooling-dev -n tooling-dev get pods -o wide
kubectl --context tooling-dev -n tooling-dev get endpointslice \
-l kubernetes.io/service-name=minikube-lab
minikube -p tooling-dev service minikube-lab -n tooling-dev --urlrollout 应成功,EndpointSlice 应包含 Ready 地址。最后一条会返回宿主可访问 URL;Docker driver 在 Windows、macOS 或 WSL 中通常需要保持命令进程运行,因为它建立了临时 tunnel。Linux Docker driver 可能直接返回 NodePort 地址。另一个终端对 URL 执行 curl,应得到 minikube-local-image-ok。
需要只验证 Kubernetes Service 而绕过 driver 网络时,使用:
kubectl --context tooling-dev -n tooling-dev port-forward svc/minikube-lab 18080:80如果 port-forward 成功而 minikube service 失败,应用与 Service 链路大概率正常,问题应转向 driver、宿主路由、VPN、防火墙或 SSH tunnel。
反向部署:区分“没有镜像”和“拉不到镜像”
先把 Deployment 指向不存在的本地 tag:
kubectl --context tooling-dev -n tooling-dev set image \
deploy/minikube-lab app=local/minikube-lab:missing
kubectl --context tooling-dev -n tooling-dev rollout status deploy/minikube-lab --timeout=20s
kubectl --context tooling-dev -n tooling-dev get pods
kubectl --context tooling-dev -n tooling-dev describe pod -l app=minikube-lab新 Pod 应进入 ErrImageNeverPull,事件明确说明节点没有镜像且策略禁止拉取。这与 ImagePullBackOff 不同:后者表示 kubelet 实际尝试访问 registry,但在名称、DNS、TLS、认证、限流或网络处失败。
重新导入正确镜像并恢复 tag:
minikube -p tooling-dev image load local/minikube-lab:dev-001
kubectl --context tooling-dev -n tooling-dev set image \
deploy/minikube-lab app=local/minikube-lab:dev-001
kubectl --context tooling-dev -n tooling-dev rollout status deploy/minikube-lab --timeout=90s如果仍失败,检查 Pod 被调度到哪个节点,再确认多节点 profile 中该节点是否拥有镜像。不要用 imagePullPolicy: Always 作为“修复”,它只是把故障从本地镜像缺失改成 registry 依赖。
反向部署:从配额拒绝追到调度拒绝
创建一个请求 100 CPU 的 Pod:
apiVersion: v1
kind: Pod
metadata:
name: impossible-cpu
namespace: tooling-dev
spec:
containers:
- name: app
image: local/minikube-lab:dev-001
imagePullPolicy: Never
resources:
requests:
cpu: "100"
memory: 16Mi
limits:
cpu: "100"
memory: 32Mi保存为 k8s/minikube/impossible-cpu.yaml 并执行:
kubectl --context tooling-dev apply -f k8s/minikube/impossible-cpu.yaml
kubectl --context tooling-dev -n tooling-dev get events --sort-by=.lastTimestamp当前 namespace 的 quota 会先返回 exceeded quota,对象不会创建。这说明 API admission 已经保护了团队预算。若在单独实验 namespace 中移除 quota,同一个 Pod 会创建但保持 Pending,describe pod 出现 FailedScheduling 和 Insufficient cpu。前者通过修改工作负载或配额治理,后者通过降低 requests、释放节点容量或调整本地集群预算解决。
实验结束后执行精确清理:
kubectl --context tooling-dev -n tooling-dev delete pod impossible-cpu --ignore-not-foundIngress、LoadBalancer 与 registry addon
minikube addon 是开发便利组件,不是生产扩展的安装依据。先查看当前二进制实际提供的 addon 和镜像:
minikube -p tooling-dev addons list
minikube -p tooling-dev addons images ingress
minikube -p tooling-dev addons enable ingress
kubectl --context tooling-dev -n ingress-nginx get podsDocker driver 下的 ingress 与 ingress-dns addon 当前只支持 Linux。Windows 或 macOS 开发机要么改用受支持的 VM driver,要么由项目显式安装并固定 Ingress Controller;不能把 Linux 上 addons enable ingress 成功当成全平台结论。下面的规则验证依赖 controller 已经 Ready,不满足这项条件时先停在 addon/driver 层排查。
等待 ingress controller Ready 后,创建 k8s/minikube/ingress.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minikube-lab
namespace: tooling-dev
spec:
ingressClassName: nginx
rules:
- host: minikube-lab.test
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: minikube-lab
port:
number: 80kubectl --context tooling-dev apply -f k8s/minikube/ingress.yaml
kubectl --context tooling-dev -n tooling-dev describe ingress minikube-lab
kubectl --context tooling-dev -n ingress-nginx port-forward \
svc/ingress-nginx-controller 18081:80另一个终端执行:
curl -H 'Host: minikube-lab.test' http://127.0.0.1:18081/预期返回 minikube-local-image-ok。用 port-forward 验证 controller 和规则,可避开各 driver 的宿主路由差异;要测试真实本地域名和入口,再根据 Accessing apps 选择 minikube service、minikube tunnel 或 ingress-dns。minikube tunnel 会修改宿主路由,低端口还可能请求管理员权限,必须保持进程和清理责任明确。若进程异常退出,在确认目标 profile 后执行 minikube -p tooling-dev tunnel --cleanup,并检查 ~/.minikube/tunnels.json 不再保留该 tunnel;LoadBalancer 的 External IP 长期 pending 时,先确认 tunnel 是否运行。
频繁构建多服务时,可以启用 registry addon:
minikube -p tooling-dev addons enable registry
kubectl --context tooling-dev -n kube-system get svc registryregistry 暴露方式随 driver 和操作系统变化,不能把某个平台的 localhost:5000 命令复制给全团队。先按 Registries 核对当前 driver 路径;需要私有仓库认证时,优先使用 namespace 级 imagePullSecrets。registry-creds addon 会把云或 Docker registry 凭证带进 profile,启用前要明确凭证来源、权限、过期和删除动作,不能使用生产管理员凭证做本地联调。
企业内网和离线环境还要准备 minikube 二进制、驱动依赖、Kubernetes 预加载文件、base image、addon 镜像和业务镜像。minikube start --download-only 可提前填充缓存,但最终离线包仍应带来源和摘要;Offline usage 解释了缓存目录与镜像规则。把公网 registry 换成内部镜像时,要同时处理 CA、代理 NO_PROXY 与镜像引用,关闭 TLS 校验只适合隔离实验,不能成为团队默认。
项目脚本要显式带 profile 和 context
项目接入可以保持下面的最小结构:
k8s/minikube/lab.yaml
k8s/minikube/ingress.yaml
k8s/minikube/impossible-cpu.yaml
Dockerfile.minikube-lab所有 minikube 命令都带 -p tooling-dev,所有 kubectl 命令都带 --context tooling-dev 和 namespace。不要依赖 minikube update-context 或某个终端恰好选中了本地集群。高危删除前先打印目标:
minikube -p tooling-dev status
kubectl config current-context
kubectl --context tooling-dev -n tooling-dev auth can-i delete deployments本地 profile 默认给开发者高权限,这种便利不能迁移到共享或生产集群。GUI、IDE 和 k9s 读取同一 kubeconfig 后也获得对应权限;生产 context 应使用独立、只读、短期凭证,不能因为 minikube 工作流方便就把管理员 kubeconfig 合并进开发机默认配置。
在 CI 中重建 profile,而不是复用开发机状态
minikube 官方提供 Continuous Integration 指南。CI 适合验证 addon、driver 差异或 minikube 特有访问方式,但它比 kind 启动更重;如果只需要快速验证 Kubernetes 清单,kind 往往成本更低。
下面的 Linux amd64 示例固定 minikube v1.38.1 和发布页 SHA-256,使用 Runner 已有 Docker daemon。版本升级时同时更新 URL、校验值和 Kubernetes 版本:
set -euo pipefail
curl -fsSLo minikube \
https://github.com/kubernetes/minikube/releases/download/v1.38.1/minikube-linux-amd64
echo '099477eaf248bcb5bcea8ce78a2898e93ac01461c35189da1848c3de82ecd22e minikube' \
| sha256sum -c -
install -m 0755 minikube "$HOME/.local/bin/minikube"
export PATH="$HOME/.local/bin:$PATH"
cleanup() {
status=$?
if [ "$status" -ne 0 ]; then
minikube -p ci logs --file=./minikube-ci.log || true
fi
minikube delete -p ci || true
exit "$status"
}
trap cleanup EXIT
minikube start -p ci \
--driver=docker \
--container-runtime=containerd \
--kubernetes-version=v1.35.1 \
--cpus=2 \
--memory=4096mb
minikube -p ci image build -f Dockerfile.minikube-lab \
-t local/minikube-lab:"$GIT_COMMIT" .
sed "s/dev-001/$GIT_COMMIT/g" k8s/minikube/lab.yaml \
| kubectl --context ci apply -f -
kubectl --context ci -n tooling-dev rollout status deploy/minikube-lab --timeout=90s
minikube -p ci service minikube-lab -n tooling-dev --urlCI 失败先保存 minikube logs,再删除 profile。日志 artifact 可能含宿主路径、代理和 registry 地址,只对需要排障的人可见并设置保留期。并行 Job 必须使用唯一 profile 名,否则 $MINIKUBE_HOME、容器名、网络与端口会冲突;更强的做法是每个 Job 使用隔离 Runner/VM。
停止、暂停、删除是三种不同动作
pause 默认只暂停 kube-system、kubernetes-dashboard、istio-operator 等系统 namespace,不会冻结全部业务 Pod;需要暂停整个开发 profile 时显式使用 -A。stop 停止节点但保留 profile;delete 才删除 profile 的虚拟机/容器和本地集群状态。开发者离开半天可全量暂停,切换项目可 stop,要求从零验证或更换关键 driver 参数时应 delete 后重建。
minikube -p tooling-dev pause -A
minikube -p tooling-dev unpause
minikube -p tooling-dev stop
minikube -p tooling-dev start删除业务对象前先保留事件和日志:
kubectl --context tooling-dev -n tooling-dev get events --sort-by=.lastTimestamp
kubectl --context tooling-dev -n tooling-dev logs deploy/minikube-lab --all-pods --tail=100
minikube -p tooling-dev logs --file=./artifacts/minikube-tooling-dev.log然后执行:
kubectl --context tooling-dev delete namespace tooling-dev --wait=true
minikube delete -p tooling-dev
minikube profile list
kubectl config get-contexts最后两条用于证明 profile 与 context 是否清理。独立保存的镜像 tar、日志、挂载目录和 Docker 构建缓存不一定随 profile 删除,按项目 owner 清单精确回收。不要在共享开发机上执行无差别 Docker prune。
团队选型与长期维护
minikube 适合希望在一台机器上保留命名 profile、需要 VM driver、addon、Dashboard、service/tunnel 和多种容器运行时实验的开发者。它对新手友好,也能模拟一些本地网络、Ingress、存储和多节点行为。代价是状态与驱动组合更多,冷启动、磁盘和 CI 时间通常高于 kind。
团队若选择 minikube,应固定一个主驱动和一个 Kubernetes 版本,另设少量兼容矩阵验证 Hyper-V/KVM2/VFKit 等差异,而不是允许每个人随意组合。升级 minikube 时,先在新 profile 重跑镜像缺失、资源拒绝、NodePort、Ingress、addon 与删除实验;验证通过后再修改项目默认版本。旧 profile 不承载不可替代数据,任何本地数据库、PV 和调试文件都应能从脚本或受控备份恢复。
本地成功只证明目标 Kubernetes API、控制器收敛、资源约束和所选 driver 路径在当前开发机成立。它不能证明生产云负载均衡、CSI、跨节点吞吐、真实 IAM、节点升级和故障切换。把这些结论写进团队测试说明,能避免“minikube 两节点跑过”被误读为生产高可用证明。
最后保留三个可观察不变量:同一提交能从空 profile 重建;故意换成缺失镜像时一定出现可解释事件;删除后 profile、context、临时 tunnel 和敏感日志按 owner 清空。做到这三点,minikube 才是可恢复的开发工作台,而不是越用越难重建的个人宠物集群。
