我使用Docker Desktop在Mac中启用Docker和Kubernetes已经有一段时间了。尽管它疯狂地吞噬着CPU和内存,让粉丝们疯狂。但随着“当面”弹出强制升级Docker的弹窗和软件许可的变更,是时候为本地Kubernetes开发寻找其他替代品了。

这篇文章只会专注于Mac平台。如果你在Linux上尝试过,请告诉我情况如何。

卸载Docker Desktop

Docker Desktop 汉化补丁 docker desktop设置中文_kubernetes

让我们先从删除Docker Desktop开始。

brew uninstall docker

这不仅会摆脱Docker,还会摆脱Hyperkit以及Docker守护进程。Docker守护进程允许我们构建镜像并适用交互式的Docker CLI与之对话。当然还包括Kubernetes集群和kubectl二进制(除非你有单独部署)。如果你没有使用Homebrew,那么就需要相应地卸载这些工具。

然后,让我们把这些工具逐一找回来。

安装Hyperkit

Docker Desktop 汉化补丁 docker desktop设置中文_Docker Desktop 汉化补丁_02

Hyperkit仍然是在Mac上本地运行Kubernetes集群的一个可行的选择,我们先来安装它。

brew install hyperkit

确认安装正确。

❯ hyperkit -v
hyperkit: 0.20200908Homepage:https://github.com/docker/hyperkit
License: BSD

安装Docker CLI

Docker Desktop 汉化补丁 docker desktop设置中文_Docker Desktop 汉化补丁_03

我们是想摆脱Docker Desktop,但并不是Docker本身。Docker仍然是一个很有用的、开源的容器管理工具,如果你有一堆Dockerfiles需要处理,Docker CLI会很有用。

brew install docker

注意:千万不要运行brew install --cask docker。这会安装Docker Desktop集成版本,我们又要重头来过。

这仅仅会安装Docker CLI,但不会安装Docker守护程序dockerd。你可以通过运行docker info看到这一点。

❯ docker info
Client:
 Context:    default
 Debug Mode: falseServer:
ERROR: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?

安装Kubectl

Docker Desktop 汉化补丁 docker desktop设置中文_docker_04

brew install kubectl

这一点没什么可说的。

安装Minikube(和Docker守护进程)

Docker Desktop 汉化补丁 docker desktop设置中文_linux_05

随着Hyperkit的部署,我们已经准备好部署Kubernetes集群了。并且,在这个过程中启动了一个Docker守护程序。

brew install minikube

在我们开始使用Kubernetes集群之前,这里有一些小知识需要了解。

使用哪一种驱动?

换句话说,我们是将Kubernetes部署在虚拟机、容器还是直接部署在裸金属服务器上?根据操作系统的不同,这里有多种选择[1]。我们将使用Mac的Hyperkit驱动。

使用哪一种容器运行时?

可用的选项:Docker、containerd和cri-o。鉴于Kubernetes本身正在远离Docker而转向Containerd,Containerd是一个不错的选择。但由于我们希望Docker守护程序能够构建Docker镜像,所以我们还是使用Docker吧。

设定CPU和内存限制

和Docker Desktop一样,设置正确的CPU和内存限制总是明智,特别是如果你打算运行许多Pod。

minikube config set cpus 6
minikube config set memory 12g

最后,启动Kubernetes集群。

❯ minikube start --kubernetes-version=v1.19.14 --driver=hyperkit --container-runtime=docker

使用命令行选项-kubernetes-version来部署特定版本的Kubernetes。不用这个标志的话,默认部署最新的版本。我需要部署一个较早的版本来满足我的需要。

以下是上述命令的输出。

😄  minikube v1.23.0 on Darwin 11.5.2
    ▪ MINIKUBE_ACTIVE_DOCKERD=minikube
✨  Using the hyperkit driver based on user configuration
👍  Starting control plane node minikube in cluster minikube
💾  Downloading Kubernetes v1.19.14 preload ...     
    > preloaded-images-k8s-v12-v1...: 470.78 MiB / 470.78 MiB  100.00% 6.17 MiB
🔥  Creating hyperkit VM (CPUs=6, Memory=12288MB, Disk=20000MB) ...
❗  This VM is having trouble accessing https://k8s.gcr.io
💡  To pull new external images, you may need to configure a proxy: https://minikube.sigs.k8s.io/docs/reference/networking/proxy/
🐳  Preparing Kubernetes v1.19.14 on Docker 20.10.8 ...
    ▪ Generating certificates and keys ...
    ▪ Booting up control plane ...
    ▪ Configuring RBAC rules ...
🔎  Verifying Kubernetes components...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟  Enabled addons: storage-provisioner, default-storageclass
❗  /usr/local/bin/kubectl is version 1.22.1, which may have incompatibilites with Kubernetes 1.19.14.
    ▪ Want kubectl v1.19.14? Try 'minikube kubectl -- get pods -A'
🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default

如果你在本地运行dnsmasq,在集群中可能会出现DNS解析失败。你可以卸载它或者在dnsmasq.conf中添加listen-address=192.168.64.1。更多信息可以在这里[2]找到。

Kube Config的上下文已经设置好了。我们可以用 kubectl来检查集群,如下所示。

❯ minikube kubectl get nodes
NAME       STATUS   ROLES    AGE    VERSION
minikube   Ready    master   7m6s   v1.19.14

由于我们已经安装了kubectl二进制程序,我们可以直接使用它。

此时,我们已经有了一个Kubernetes集群,由于我们使用了Docker驱动,Docker守护程序也在运行。所以在我们使用守护进程之前,让我们先设置环境变量。

eval $(minikube docker-env)

确认Docker守护进程是正常工作的。

❯ docker info
Client:
 Context:    default
 Debug Mode: falseServer:
 Containers: 14
  Running: 14
  Paused: 0
  Stopped: 0
 Images: 10
 Server Version: 20.10.8
 Storage Driver: overlay2
  Backing Filesystem: extfs
 ...

下面是我们的Minikube集群在K9S中的样子。

Docker Desktop 汉化补丁 docker desktop设置中文_linux_06

新安装的Minikube集群的K9S截图

需要Docker Compose?

Docker Desktop 汉化补丁 docker desktop设置中文_linux_07

用以下命令安装Docker-Compose。

brew install docker-compose

暴露Services到Minikube外部

Docker Desktop 汉化补丁 docker desktop设置中文_kubernetes_08

对于本地开发,通常是通过浏览器或CLI从电脑访问服务。端口转发总是一个选择,但有时Ingress或负载均衡器也是有用的。让我们看看它们是如何与Minikube一起工作的。

处理Ingress资源

我们现在有了一个Kubernetes集群,也可以在上面部署应用程序。但我们如何访问Ingress资源呢?Minikube有一个答案,就是addons(附加组件)。

❯ minikube addons enable ingress
    ▪ Using image k8s.gcr.io/ingress-nginx/controller:v1.0.0-beta.3
    ▪ Using image k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0
    ▪ Using image k8s.gcr.io/ingress-nginx/kube-webhook-certgen:v1.0
🔎  Verifying ingress addon...

这会部署Nginx Ingress控制器。更重要的是,它会把Nginx服务部署以 NodePort的形式部署,并将Minikube的IP直接指向Ingress。让我们先找到这个IP。

❯ minikube ip
192.168.64.12

我们在80端口调用上述IP,我们应该可以从Nginx得到响应。

❯ curl http://192.168.64.12
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx</center>
</body>
</html>

记住,Ingress依赖于DNS工作,它应该被解析到Minikube的IP上。如果后端服务之一调用该DNS,除非明确配置了,否则会解析失败。这个时候,另一个附加组件可以来拯救你。

❯ minikube addons enable ingress-dns
    ▪ Using image cryptexlabs/minikube-ingress-dns:0.3.0

这将在Kubernetes集群内启动一个DNS服务器,监听在Minikube的IP上。此外,还需要一个自定义的解析器,以强制自定义顶级域名(如.test,不要使用.local)的DNS解析被重定向到上面启动的DNS服务器。Minikube Ingress DNS[3]文档很好地解释了这一点。按照文档里描述的步骤操作,你将会部署成功一个带有自定义DNS的Ingress。

负载均衡类型的Service

部署负载均衡器类型的服务,并从主机上访问它,就像你在云端部署时一样,这不是很好吗?多亏了metalb插件,让这变得很简单。

minikube addons enable metallb

这将部署另外两个Pod,负责为负载均衡器类型的Service分配一个外部IP。如果不这样做,这些服务的外部IP将始终处于“pending”状态。

在使用metallb之前,还有一个步骤。默认情况下,metallb没有办法知道哪个范围的IP可以分配给负载均衡器的服务。运行下面的命令来提供一个范围。

❯ minikube addons configure metallb
-- Enter Load Balancer Start IP: 192.168.64.5
-- Enter Load Balancer End IP: 192.168.64.15
    ▪ Using image metallb/speaker:v0.9.6
    ▪ Using image metallb/controller:v0.9.6
✅  metallb was successfully configured

基于你的Minikube IP,分配一个小范围的IP,包括Minikube IP。现在,每当你部署一个负载均衡器服务时,这个范围内的一个IP将被分配。

其他问题

Docker Desktop 汉化补丁 docker desktop设置中文_Docker Desktop 汉化补丁_09

登录到远程镜像仓库

你可能仍然有旧的~/.docker/config.json,其中credsStore设置为osxkeychain或desktop。这在新的配置中不会起作用。为了解决这个问题,我们来安装Docker Credential Helper。

brew install docker-credential-helper

密钥凭证还是会像以前一样存储在MacOS Keychain中。如果这不起作用,一个快速的解决方法是删除~/.docker/config.json文件,然后再次登录到镜像仓库。

保留Docker镜像和持久化存储卷声明

Added 7th Sept 2021

Docker Desktop的一个好处是,你可以关闭Kubernetes集群,以后再启动它,用相同的Docker镜像和持久化卷运行你的Pod。例如,在Kubernetes中运行本地数据库时,这就很有用。能够在多次重启中仍然保持有效的持久化卷是很方便的。

在Minikube中,如果我用minikube stop关闭集群(和Hyperkit虚拟机),它会删除Docker镜像和所有持久化卷,这很麻烦。但幸运的是,Minikube提供了一种防止删除的方法。我们可以暂停Kubernetes集群和Hyperkit VM,而不是停止它。

minikube pause

该命令会终止Kubernetes集群,但不会删除Hyperkit虚拟机。这就释放了更多的CPU,同时仍然保留了所有的Docker镜像和持久化卷。但是,等一下,它变得更好!它不会停止dockerd守护进程。所以你可以继续使用Docker CLI,只是别忘了用eval $(minikube docker-env)设置一下docker环境。

当你想恢复在Kubernetes集群上的工作时,可以运行以下命令。

minikube unpause

而你将拥有所有的系统Pod,包括附加组件Addons。这甚至在笔记本电脑重新启动后,也能正常工作!

在Docker容器中绑定挂载

Added 7th Sept 2021

一些在Reddit[4]上的好心人指出,Docker容器中的绑定挂载(-v)在Minikube和Docker的配置中并不能工作。这是Docker容器的一个常见操作,他理论上应该可以正常工作。

由于存在Hyperkit作为中间层,挂载一个卷其实是分成两步操作的。首先,让我们把笔记本上的磁盘挂载到Hyperkit VM上。

minikube mount /myvolume:/test

这将把本地文件夹/myvolume挂载到Hyperkit VM的/test路径下。这个进程仍然是活跃的,所以你不应该关闭这个终端。

在另一个终端上,运行Docker容器,并将/test卷绑定到容器内的一个路径上。

docker run --rm -it -v /test:/inside busybox /bin/sh

这将在容器内的Hyperkit VM上挂载/test卷,路径为/inside。实际上,这会使得笔记本电脑上/myvolume下的所有处在容器内的文件和文件夹处于读写模式。很好!

总结

Docker Desktop 汉化补丁 docker desktop设置中文_kubernetes_10

在周日下午花了几个小时后,我对这个新的配置相当满意。我们摆脱了Docker Desktop,用Hyperkit和Minikube取代了它。我们仍然可以使用Docker API来管理Docker文件,并在本地Kubernetes集群中部署应用程序。最重要的是,我的笔记本可以愉快地运行,额外的资源可以用来运行Slack、Notion和其他Electron应用程序;-)