转载:https://zhuanlan.zhihu.com/p/388874530
前言
之前给大家介绍过几种在笔记本电脑上安装Kubernetes集群的工具,虽然安装起来不太繁琐但是多多少少还是需要花一些时间的,对于不想瞎倒腾,就想快速安装个本地集群开始学习和测试的同学,推荐你们试一试Docker桌面应用里自带的Kubernetes集群。其实我也是之前用Minikube安装的集群莫名其妙坏掉启动不起来后,偶然发现Docker桌面应用里内嵌了一个Kubernetes集群,试了试效果感觉还是挺不错的。下面我带大家简单过一下启用集群方法,全程几乎就是点点点,也不需要做啥。
启用Kubernetes
也不知道是什么时候开始(反正老早就有了,我这个是前年装的…一直没升级过),Docker的桌面应用除了提供Docker CLI集成外还内嵌了一个Kubernetes集群,默认是不开启的,启用后这个单点的Kubernetes集群会运行在本地的Docker实例中。
要启用这个集群只需要打开Docker应用的首选项(Preferences)界面,选择Kubernetes选项卡。

点击应用并重启,就可以去刷小视频了,再回来集群就安装好了。
除了启用Kubernetes集群外,如果电脑上之前没有安装过 kubectl(客户端命令工具)的话还会为你自动安装上kubectl,并配置连接到刚才启动的本地集群上。如果是本地之前安装过kubectl 和 存在其他Kubernetes集群,想要连接到Docker桌面应用内嵌的集群则需要切换一下 kubectl 的上下文。
$ kubectl config get-contexts $ kubectl config use-context docker-desktop
使用Kubernetes
集群启用完成后,在打开Docker桌面应用的选项卡在 UI 上会有些微的变化,证明Kubernetes
集群已经成功启动起来了。

让我们随便运行几个 kubctl 命令,试试效果。
➜ ~ kubectl get node NAME STATUS ROLES AGE VERSION docker-desktop Ready control-plane,master 13d v1.21.1
可以看到我们现在使用的是一个单节点,名字叫docker-desktop的集群(这个名没地方改)。
使用Docker桌面应用自带的Kubernetes集群还有一点方便的地方就是,集群外部通过 127.0.0.1 就能访问集群内部,也就是我们通过 NodePort类型的 Service 向集群外暴露的资源,通过 127.0.0.1:port 的形式就能访问到。
我们随便拿一个之前我们搭建MySQL开发环境的例子测试一下。搭建MySQL需要的YAML定义文件和步骤我就不再重复说了,忘记的同学之前访问上一篇文章:利用Kubernetes搭建便携式开发环境之MySQL和Redis
## 切到定义文件在的目录 kubectl apply -f mysql-configmap.yaml kubectl apply -f deployment-service.yaml -------------------------------------------------------- ## 可以看到下面的Pod和Service资源 kubectl get pod NAME READY STATUS RESTARTS AGE mysql-cc4479465-gwdj7 1/1 Running 0 13d -------------------------------------------------------- kubectl get svc mysql NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE mysql NodePort 10.104.123.151 <none> 3306:30306/TCP 13d
在电脑上只要通过127.0.0.1:30306就能访问到我们刚刚安装的MySQL啦,持久化之类的事情我也试过,只要我们不主动把MySQL这个Pod删掉数据就会一直在。
安装 dashboard
‼️重要:dashboard启动需要科学上网,原因是不科学上网有些镜像拉取不下来?
‼️重要:如果运行时发现dashboard 的相关服务起不来了,dashboard打不开,暂时解决方法是,挂vpn翻墙,然后重启 docker desktop服务。

- k8s集群启动以后,就可以用下面的命令确认集群是否ready
Mac-mini ~ % kubectl get node NAME STATUS ROLES AGE VERSION docker-desktop Ready control-plane 2d2h v1.32.2
- 接着运行以下命令来安装 Kubernetes Dashboard:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.7.0/aio/deploy/recommended.yaml
- 创建服务账户
admin-user.yaml apiVersion: v1 kind: ServiceAccount metadata: name: admin-user namespace: kubernetes-dashboard
kubectl apply -f admin-user.yaml 输出: serviceaccount/admin-user created
- 绑定服务账户集群角色
admin-user-role-binding.yaml apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: admin-user roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: admin-user namespace: kubernetes-dashboard
kubectl apply -f admin-user-role-binding.yaml 输出: clusterrolebinding.rbac.authorization.k8s.io/admin-user created
- 创建
admin-user
的 token(这个token好像会过期,如果过期的话,就用下面命令重新创建个)
Kubernetes 从 1.24 版本开始,默认启用ServiceAccount
令牌的自动管理,生成的 Token 默认有效期为1 小时(3600秒
)。
kubectl -n kubernetes-dashboard create token admin-user
- 创建永久 Token(不推荐,存在安全风险)
通过Secret手动创建不指定过期时间的 Token: apiVersion: v1 kind: Secret metadata: name: admin-user-permanent-token namespace: kubernetes-dashboard annotations: kubernetes.io/service-account.name: "admin-user" # 关联ServiceAccount type: kubernetes.io/service-account-token 应用该 Secret 后,通过以下命令获取 Token: 该 Token 无过期时间,需手动删除 Secret 才能失效。 生产环境中应避免使用永久 Token,建议通过 RBAC 控制权限并定期轮换短期 Token。 kubectl get secret admin-user-permanent-token -n kubernetes-dashboard -o jsonpath="{.data.token}" | base64 -d
- 用下面的命令启动 dashboard
kubectl proxy --port=8001
- 用下面的url访问 dashboard
http://localhost:8001/api/v1/namespaces/kubernetes-dashboard/services/https:kubernetes-dashboard:/proxy/#/login
- 输入刚刚创建的
admin-user
的 token, 然后登录就可以访问dashboard了


dashboard 重启时 镜像拉取不了的解决办法
kubernetes-dashboard dashboard-metrics-scraper-5bd45c9dd6-q4wml 1/1 Running 22 (16m ago) 43d kubernetes-dashboard kubernetes-dashboard-79cbcf9fb6-bvj58 0/1 ImagePullBackOff 0 92s kubernetes-dashboard kubernetes-dashboard-api-7b6b887946-76ncg 1/1 Running 32 (16m ago) 43d kubernetes-dashboard kubernetes-dashboard-auth-769bf978b9-tnc8m 1/1 Running 22 (16m ago) 43d kubernetes-dashboard kubernetes-dashboard-kong-65548bdf66-drm48 0/1 Running 13 (5m9s ago) 5d5h kubernetes-dashboard kubernetes-dashboard-metrics-scraper-76df4956c4-k64r9 1/1 Running 22 (16m ago) 43d kubernetes-dashboard kubernetes-dashboard-web-56df7655d9-rx7hh 1/1 Running 22 (16m ago) 43d wechat-applet-services service-notification-deployment-54bdd8655c-45tpm 1/1 Running 8 (16m ago) 20d wechat-applet-services service-task-executor-deployment-698cd9547-wvbvs 1/1 Running 5 (16m ago) 7d7h wechat-applet-services service-thumbnail-deployment-59b4f4759d-8qjbd 1/1 Running 4 (16m ago) 6d wechat-applet-services service-wechat-deployment-7f497855df-6rg9v 1/1 Running 2 (16m ago) 5d21h kubectl logs kubernetes-dashboard-79cbcf9fb6-bvj58 -n kubernetes-dashboard Error from server (BadRequest): container "kubernetes-dashboard" in pod "kubernetes-dashboard-79cbcf9fb6-bvj58" is waiting to start: trying and failing to pull image
可以看到 kubernetes-dashboard-79cbcf9fb6-bvj58 这个pod起不来,镜像拉取失败。
执行以下命令查看该 Pod 的详细配置,重点关注镜像相关信息:
kubectl get pod kubernetes-dashboard-79cbcf9fb6-bvj58 -n kubernetes-dashboard -o yaml
kubectl get pod kubernetes-dashboard-79cbcf9fb6-bvj58 -n kubernetes-dashboard -o yaml apiVersion: v1 kind: Pod metadata: creationTimestamp: "2025-07-03T12:48:56Z" generateName: kubernetes-dashboard-79cbcf9fb6- labels: k8s-app: kubernetes-dashboard pod-template-hash: 79cbcf9fb6 name: kubernetes-dashboard-79cbcf9fb6-bvj58 namespace: kubernetes-dashboard ownerReferences: - apiVersion: apps/v1 blockOwnerDeletion: true controller: true kind: ReplicaSet name: kubernetes-dashboard-79cbcf9fb6 uid: 5d718a39-36d4-45ca-8f82-7e5b18c58cd0 resourceVersion: "5231806" uid: 42a3f595-2356-4a79-9010-60e3285e98e6 spec: containers: - args: - --auto-generate-certificates - --namespace=kubernetes-dashboard image: kubernetesui/dashboard:v2.7.0 imagePullPolicy: Always livenessProbe: failureThreshold: 3 httpGet: path: / port: 8443 scheme: HTTPS initialDelaySeconds: 30 periodSeconds: 10 successThreshold: 1 timeoutSeconds: 30 name: kubernetes-dashboard ports: - containerPort: 8443 protocol: TCP resources: {} securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true runAsGroup: 2001 runAsUser: 1001 terminationMessagePath: /dev/termination-log terminationMessagePolicy: File volumeMounts: - mountPath: /certs name: kubernetes-dashboard-certs - mountPath: /tmp name: tmp-volume - mountPath: /var/run/secrets/kubernetes.io/serviceaccount name: kube-api-access-7pk9w readOnly: true dnsPolicy: ClusterFirst enableServiceLinks: true nodeName: docker-desktop nodeSelector: kubernetes.io/os: linux preemptionPolicy: PreemptLowerPriority priority: 0 restartPolicy: Always schedulerName: default-scheduler securityContext: seccompProfile: type: RuntimeDefault serviceAccount: kubernetes-dashboard serviceAccountName: kubernetes-dashboard terminationGracePeriodSeconds: 30 tolerations: - effect: NoSchedule key: node-role.kubernetes.io/master - effect: NoExecute key: node.kubernetes.io/not-ready operator: Exists tolerationSeconds: 300 - effect: NoExecute key: node.kubernetes.io/unreachable operator: Exists tolerationSeconds: 300 volumes: - name: kubernetes-dashboard-certs secret: defaultMode: 420 secretName: kubernetes-dashboard-certs - emptyDir: {} name: tmp-volume - name: kube-api-access-7pk9w projected: defaultMode: 420 sources: - serviceAccountToken: expirationSeconds: 3607 path: token - configMap: items: - key: ca.crt path: ca.crt name: kube-root-ca.crt - downwardAPI: items: - fieldRef: apiVersion: v1 fieldPath: metadata.namespace path: namespace status: conditions: - lastProbeTime: null lastTransitionTime: "2025-07-03T12:49:26Z" status: "True" type: PodReadyToStartContainers - lastProbeTime: null lastTransitionTime: "2025-07-03T12:48:56Z" status: "True" type: Initialized - lastProbeTime: null lastTransitionTime: "2025-07-03T12:48:56Z" message: 'containers with unready status: [kubernetes-dashboard]' reason: ContainersNotReady status: "False" type: Ready - lastProbeTime: null lastTransitionTime: "2025-07-03T12:48:56Z" message: 'containers with unready status: [kubernetes-dashboard]' reason: ContainersNotReady status: "False" type: ContainersReady - lastProbeTime: null lastTransitionTime: "2025-07-03T12:48:56Z" status: "True" type: PodScheduled containerStatuses: - image: kubernetesui/dashboard:v2.7.0 imageID: "" lastState: {} name: kubernetes-dashboard ready: false restartCount: 0 started: false state: waiting: message: 'Error response from daemon: Get "https://registry-1.docker.io/v2/": net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)' reason: ErrImagePull volumeMounts: - mountPath: /certs name: kubernetes-dashboard-certs - mountPath: /tmp name: tmp-volume - mountPath: /var/run/secrets/kubernetes.io/serviceaccount name: kube-api-access-7pk9w readOnly: true recursiveReadOnly: Disabled hostIP: 192.168.65.3 hostIPs: - ip: 192.168.65.3 phase: Pending podIP: 10.1.1.124 podIPs: - ip: 10.1.1.124 qosClass: BestEffort startTime: "2025-07-03T12:48:56Z"
可以看到有 Error response from daemon: Get “https://registry-1.docker.io/v2/, 看来还是访问https://registry-1.docker.io/v2/镜像仓库有问题。
但是可以看到docker本地是有这个镜像的。

修改 Deployment 使用本地镜像:临时修改 Deployment,强制使用本地已导入的镜像(不通过网络拉取)
kubectl edit deployment kubernetes-dashboard -n kubernetes-dashboard
将 imagePullPolicy
改为 IfNotPresent
(如果本地有镜像,则不尝试拉取):
pec: containers: - name: kubernetes-dashboard image: kubernetesui/dashboard:v2.7.0 imagePullPolicy: IfNotPresent # 原为 Always
改完Deployment以后,Pod会重新部署,可以发现可以正常启动了。
安装 Metrics API
Metrics API(由 metrics-server
组件提供),该组件用于收集 Pod 和节点的资源使用数据(CPU、内存等)。
Metrics API 是 Kubernetes 中的核心监控组件,负责收集和暴露集群资源使用数据(如 CPU、内存、磁盘 I/O 等)。它作为标准化接口,为上层工具(如 kubectl top
、Horizontal Pod Autoscaler、Prometheus)提供统一的指标查询方式。以下是详细介绍:
1. 核心概念与架构
Metrics API 由两部分组成:
- API 服务(
metrics.k8s.io
):- 属于 Kubernetes API 体系的一部分,提供标准化的 REST API 接口。
- 版本:
v1beta1
(Kubernetes 1.8+),未来可能升级到v1
。
- 数据采集组件(默认由
metrics-server
实现):- 周期性从节点的 kubelet 收集容器和 Pod 的资源使用数据。
- 将数据聚合后存储在内存中(不支持历史数据持久化)。
2. 核心作用
Metrics API 是 Kubernetes 监控体系的基础组件,支撑以下功能:
- 命令行工具:
kubectl top nodes/pods
命令直接从 Metrics API 获取实时数据。 - 自动扩缩容:
Horizontal Pod Autoscaler(HPA)根据 Metrics API 的指标自动调整 Pod 数量。 - 调度决策:
Kubernetes 调度器根据节点资源使用情况(通过 Metrics API)选择最优节点。 - 可视化工具:
如 Dashboard、Grafana 等可通过 Metrics API 获取实时监控数据。
3. 安装(需要翻墙)❗️❗️
- 3.1 下载 最新版本 metrics-server 的 components.yaml
curl -O https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
- 3.2 修改配置文件
# 修改配置(解决证书和性能问题) vi components.yaml # 添加以下参数(在 spec.containers.args 中): - --kubelet-insecure-tls # 跳过 TLS 验证(测试环境使用) - --metric-resolution=30s # 设置指标采集频率(默认 15s,可调整)
❗️❗️ 因为需要从registry.k8s.io 拉取下面镜像,国内网络可能无法访问,所以需要翻墙。

# 应用配置 kubectl apply -f components.yaml
- 3.3 验证metrics-server是否启动
# 检查 metrics-server Pod 状态 kubectl get pods -n kube-system -l k8s-app=metrics-server 输出如下: NAME READY STATUS RESTARTS AGE metrics-server-8467fcc7b7-j7rl9 1/1 Running 0 34m
- 3.4 验证Metrics API是否可用
# 检查 Metrics API 是否可用 kubectl get --raw "/apis/metrics.k8s.io/v1beta1" 输出如下: {"kind":"APIResourceList","apiVersion":"v1","groupVersion":"metrics.k8s.io/v1beta1","resources":[{"name":"nodes","singularName":"","namespaced":false,"kind":"NodeMetrics","verbs":["get","list"]},{"name":"pods","singularName":"","namespaced":true,"kind":"PodMetrics","verbs":["get","list"]}]}
- 3.5 用kubectl命令 查询 Node集群 和 Pod 的 内存 CPU等指标
# 检查 Node 指标 kubectl top nodes 输出: NAME CPU(cores) CPU(%) MEMORY(bytes) MEMORY(%) docker-desktop 187m 1% 5398Mi 69% # 检查 所有命名空间的 Pod指标 kubectl top pods -A 输出: NAMESPACE NAME CPU(cores) MEMORY(bytes) kube-system coredns-668d6bf9bc-7chdd 3m 48Mi kube-system coredns-668d6bf9bc-tnx27 3m 34Mi kube-system etcd-docker-desktop 20m 310Mi kube-system kube-apiserver-docker-desktop 27m 323Mi kube-system kube-controller-manager-docker-desktop 14m 138Mi kube-system kube-proxy-w8mq6 1m 78Mi kube-system kube-scheduler-docker-desktop 10m 82Mi kube-system metrics-server-8467fcc7b7-j7rl9 4m 24Mi kube-system storage-provisioner 2m 20Mi kube-system vpnkit-controller 0m 38Mi kubernetes-dashboard dashboard-metrics-scraper-5bd45c9dd6-q4wml 1m 40Mi kubernetes-dashboard kubernetes-dashboard-79cbcf9fb6-cp4px 1m 68Mi kubernetes-dashboard kubernetes-dashboard-api-7b6b887946-76ncg 1m 51Mi kubernetes-dashboard kubernetes-dashboard-auth-769bf978b9-tnc8m 1m 36Mi kubernetes-dashboard kubernetes-dashboard-kong-79867c9c48-5sx4b 4m 161Mi kubernetes-dashboard kubernetes-dashboard-metrics-scraper-76df4956c4-k64r9 1m 36Mi kubernetes-dashboard kubernetes-dashboard-web-56df7655d9-rx7hh 1m 36Mi wechat-applet-services service-notification-deployment-7dc7db69d9-hbcn8 0m 79Mi wechat-applet-services service-task-executor-deployment-74c7dbd875-xn5t8 2m 132Mi wechat-applet-services service-thumbnail-deployment-77cfbbf8fd-9gq9v 0m 120Mi
- 3.6 dashboard 上也能看到集群和Pod的指标图形了

k8s部署一个简单完整的示例
我们使用 httpd
(Apache) 镜像 来创建一个完整的示例,包括 Deployment、Service,并将服务暴露到集群外部。
- 创建示例的namespace
kubectl create namespace k8s-study 显示: namespace/k8s-study created
- 创建 Deployment
# httpd-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: httpd-deployment labels: app: httpd spec: replicas: 3 # 创建3个Pod副本 selector: matchLabels: app: httpd template: metadata: labels: app: httpd spec: containers: - name: httpd image: httpd:alpine # 使用docker hub 官方httpd镜像(Alpine轻量版) ports: - containerPort: 80 # Apache默认端口 resources: limits: memory: "128Mi" cpu: "100m"
应用 Deployment: kubectl apply -f httpd-deployment.yaml -n k8s-study 显示: deployment.apps/httpd-deployment created
- 创建 Service
创建一个 NodePort 类型的 Service 来暴露 Apache 服务:
# httpd-service.yaml apiVersion: v1 kind: Service metadata: name: httpd-service spec: selector: app: httpd # 匹配Deployment中的label ports: - protocol: TCP port: 80 # Service端口 targetPort: 80 # Pod端口 type: NodePort # 暴露到集群外部
应用 Service: kubectl apply -f httpd-service.yaml -n k8s-study 显示: service/httpd-service created
- 验证部署
检查 Deployment 和 Pod 状态:
kubectl get deployments -n k8s-study kubectl get pods -n k8s-study
- 检查 Service 状态并获取分配的 NodePort
kubectl get services httpd-service -n k8s-study 显示: NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE httpd-service NodePort 10.101.194.247 <none> 80:32636/TCP 2m37s 这里的 32636 就是随机分配的 NodePort(范围 30000-32767)。
- 从集群外部访问服务
curl http://localhost:32636

- 通过dashboard也能查看pod状态


通过Docker桌面应用在电脑上安装Kubernetes集群可以说是把我们学习K8s的起步依赖降到了最低,让我们能快速跳过工具安装步骤开始正题的学习,想学K8s的同学们赶紧动手试试吧。