最近本人在 Mac OS X 下安装的 Docker Desktop 经常蹦出要升级的窗口,Skip this update PRO
不能用,Install & Restart
也总是失败,所以每次只能 SNOOZE
。原来觉得事有蹊跷,后来才知道这或许与近日吵得沸沸扬扬的 Docker Desktop 收费计划有关。Docker Desktop 是专门为 Windows 和 Mac OS X 定制的,Mac OS X 和 Windows 都是开发人员用的平台。Linux 下可以不用 Docker Desktop,Linux 下 Docker 之间甚至一层窗户纸都没有,实际部署的 Docker 服务也是运行在 Linux 下的。
墙里边微信正在谋划着对聊天记录的云存储收年费,外边是 Docker 在向大公司和开发人员下手,这难道是美国加州版的共同富裕?
查看一下当前 Docker Subscription Service Agreement, 将来可不被收费的对象包括个人用户,教育行业和非商业的开源项目,小企业不收费的门槛是雇员少于 250 并且年收入少于 1 千万美金。还给出一个开始有效日为 2021 年 8 月 31 日,再加一个慷慨的最后宽限日期为 2022 年 1 月 31 日,这其间大家自愿。
对于一个公司人数不少,且日常使用公司配发 Mac 笔记本的开发人员,只能等着被收费了,除非不计法律的风险。
不过,也别急着发慌,还是有替换方案,这里是 Docker Desktop 收费,Docker 仍然是免费的。这儿有两个 Docker Desktop 的替代方案:
- hyperkit + minikube
- Podman
原文见 Replacing Docker Desktop with hyperkit + minikube
未雨绸缪,况且本人几乎不用 Docker Desktop 提供的 UI, 更不愿用 Docker Desktop 提供的 Kubernetes。先在 Mac 下尝试一番没有 Docker Desktop 的日子,第一步把 Docker Desktop 痛痛快快的卸载掉,这时候连 docker 命令都没有了。
方案 一: hyperkit + minikube
首先要依次安装 docker cli,hyperkit, 和 minikube
安装 Docker CLI
$ brew install docker
$ brew install docker-compose # 有必要的话把它装了
这时候应该就能执行 docker
和 docker-compose
这两个命令了, 但是 docker ps 等命令还无法执行, 因为还没有 DOCKER_HOST, 用 docker --version
看下版本还是可以的。
如果还不见 docker, 可以尝试下面的命令
$ brew install docker-toolbox
安装 hyperkit 和 minikube 前启动
$ brew install hyperkit
$ brew install minikube
$ minikube start
Minikube 实际上是启动了一个 Kubernetes 集群,这里是本人写的一篇 几种简单安装 Kubernetes 集群的方法, 其中就介绍到了如何用 Minikube 来体验 Kubernetes。
这里的 minikube 默认使用的 driver 是 hyperkit,相当于是 minikube start --driver=hyperkit
, 也可以指定 virtualbox,命令为 minikube start --driver=virtualbox
, 或通过 minikube config set driver virtualbox
来修改。minikube 推荐使用 hyperkit
, 坚持使用 virtualbox 的话就可不用安装 hyperkit
, 而需安装 virtualbox
。使用 virtualbox 为 driver 就会看到在 VirtualBox 中会创建一个虚拟机,
Minikube 启动后可用 Kubernetes 的命令 kubectl get service
查看它所有启动的服务。假如提示 kubectl
命令找不到的话,即用下方命令安装它
$ brew install kubernetes-cli
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 88m $ kubectl get pods --namespace kube-system kubectl NAME READY STATUS RESTARTS AGE coredns-78fcd69978-ghntt 1/1 Running 1 (77m ago) 88m etcd-minikube 1/1 Running 1 (77m ago) 88m kube-apiserver-minikube 1/1 Running 1 (3m4s ago) 89m kube-controller-manager-minikube 1/1 Running 1 (77m ago) 88m kube-proxy-7bsc2 1/1 Running 1 (77m ago) 88m kube-scheduler-minikube 1/1 Running 1 (3m4s ago) 88m storage-provisioner 1/1 Running 2 (2m17s ago) 88m |
执行 docker 相关命令
即将到来的有小激动人心的时刻,现在立马执行像 docker ps
的命令会出现不能连接 Docker daemon 的错误
Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
需先执行下面一条命令
eval $(minikube docker-env)
它其实是帮我们设置了四个环境变量,直接执行 minikube docker-env
就能看到它的输出
$ minikube docker-env
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.64.2:2376"
export DOCKER_CERT_PATH="/Users/yanbin/.minikube/certs"
export MINIKUBE_ACTIVE_DOCKERD="minikube"
# To point your shell to minikube's docker-daemon, run:
# eval $(minikube -p minikube docker-env)
至此,我们就能做我们之前用 docker 做的所有事情了,像
docker build .
docker ps
docker push
等等
如果在每一个会话中都需要上面的环境变量,那么就把 eval $(minikube docker-env)
加到相应 shell 的初始化配置文件中去,如 Zsh 的 .zshrc
文件。
Minikube 的配置
这种方式又仿佛让我们回到了没有 Docker Desktop 之前用 boot2docker 的时代,回看之前 2014 年时写的 Mac 下通过 boot2docker 来使用 Docker 的日志 Mac OS X 下安装使用 Docker,都是被逼的, 轮回来得太快。
前面看到的 DOCKER_HOST 是 192.168.64.2 这个主机,实际上 Docker 要做的事情都是它干的,docker 命令不过是个皮。我们一路下来,显示 192.168.64.2 就是 Minikube 启动的一个虚拟机,minikube ssh
就能进到里面去
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
yanbin $ minikube ssh _ _ _ _ ( ) ( ) ___ ___ (_) ___ (_)| |/') _ _ | |_ __ /' _ ` _ `\| |/' _ `\| || , < ( ) ( )| '_`\ /'__`\ | ( ) ( ) || || ( ) || || |`\ | (_) || |_) )( ___/ (_) (_) (_)(_)(_) (_)(_)(_) (_)`\___/'(_,__/'`\____) $ hostname minikube $ ifconfig | grep 192 inet addr:192.168.64.2 Bcast:192.168.64.255 Mask:255.255.255.0 $ cat /proc/cpuinfo | grep processor processor : 0 processor : 1 $ cat /proc/meminfo | grep MemTotal MemTotal: 3935188 kB |
进到该虚拟机,我们列出相关的信息,CPU 2 个,内存 4 G。该虚拟机的 CPU 和内存可以进行配置
$ minikube config set cpus 2
$ minikube config set memory 2048
需要在 minikube stop|start 后重新生效,还能在 minikube start
时指定配置参数
$ minikube start --memory=8192 --cpus=4 --disk-size=50g
更多的 minikube 命令用 minikube --help
查看,比如 minikube ip
直接查看到该虚拟机的 IP 地址。
$ minikube dashboard --url
上面命令让我们直接在浏览器中打开一个 Kubernetes Dashboard,想在其中看什么 Kubernetes 的信息都方便,绝对可以把 Docker Desktop 内置的 Kubernetes 比下去。
可能的一个问题,Mac 连了 VPN 之后 minikube 启动会有问题, 既然在无 VPN 情况下启动了 minikube, 一旦连接上了 VPN 后,还是不能用,原因是启动 minikube 的 bridge 的网络在连上 VPN 后不通。具体点讲就是连接了 VPN 之后,VPN 把到原本应该经过 xboxnetX 网络进到虚拟机(如 192.168.99.101) 的路由换成了走 VNP 的网络设备(如 utun2),而且用 route
还删不掉,在 Cisco AnyConnect 中把 All local (LAN) access when using VPN (if configured)
勾选上也不行。
方案二:Podman
我们看到目前 Docker CLI 还是用 Apache 2.0 授权的,可自由使用,万一这也被 Docker 的后台公司看上商机了呢?不用慌张,我们还有一个后招,那就是 Docker CLI 的替代品 Podman
。要是将来 Podman 也参于围剿,那会更热闹了。
在 Mac OS 下 Podman 的安装(无论什么都可以 brew 一下)
$ brew install podman
安装的 Podman 当前版本 为 3.3.1.
Podman 可独自挑大梁,它提供了兼容 Docker CLI 的 podman,以及 Mac OS 与 Docker 容器间的媒介虚拟机。在用 podman 之前需用 machine
命令创建并启动那个虚拟机
$ podman machine init
$ podman machine start
既然是一个 Linux 虚拟机就能 ssh 进去探个究竟,下面是那几个命令一并的输出信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
$ podman machine init Downloading VM image: fedora-coreos-34.20210904.1.0-qemu.x86_64.qcow2.xz: done Extracting compressed file $ podman machine start INFO[0000] waiting for clients... INFO[0000] listening tcp://0.0.0.0:7777 INFO[0000] new connection from to /var/folders/hm/t_nnzqw55g17fqwhf2rgtx3r0000gp/T/podman/qemu_podman-machine-default.sock Waiting for VM ... qemu-system-x86_64: warning: host doesn't support requested feature: CPUID.80000001H:ECX.svm [bit 2] Downloads git:(:|) podman machine ssh Connecting to vm podman-machine-default. To close connection, use `~.` or `exit` Fedora CoreOS 34.20210904.1.0 Tracker: https://github.com/coreos/fedora-coreos-tracker Discuss: https://discussion.fedoraproject.org/c/server/coreos/ [core@localhost ~]$ cat /proc/cpuinfo | grep processor processor : 0 [core@localhost ~]$ cat /proc/meminfo | grep MemTotal MemTotal: 2013528 kB |
上面的信息告诉我们 podman 初始化并启动了一个 Qemu 的 fecora-coreos 虚拟机,一个 CPU, 内存为 2Gb。
如果我们需要调整该虚拟机的 CPU 和内存,在 podman machine init
时,可指定 --cpus, --memory 参数,用 podman machine init --help
查看帮助信息
$ podman machine init --help
Initialize a virtual machine
Description:
initialize a virtual machine
Usage:
podman machine init [options] [NAME]
Examples:
podman machine init myvm
Options:
--cpus uint Number of CPUs. The default is 1. (default 1)
--disk-size uint Disk size in GB (default 10)
--ignition-path string Path to ignition file
--image-path string Path to qcow image
-m, --memory uint Memory (in MB) (default 2048)
或用 podman info
, podman system info
也能查看到 podman
系统的信息。
podman 可替代 Docker CLI, 所以先前的 docker build
, docker ps
之类的命令可以用 podman build
,podman ps
等,因此我们可创建一个别名
$ alias docker=podman
现在来试一下 podman pull busybox
试图拉取一个镜像
$ podman pull busybox
Error: failed to parse "X-Registry-Auth" header for /v3.3.1/libpod/images/pull?alltags=false&arch=&authfile=&os=&password=&policy=always&quiet=false&reference=busybox&username=&variant=: error storing credentials in temporary auth file (server: "https://index.docker.io/v1/", user: ""): key https://index.docker.io/v1/ contains http[s]:// prefix
原因是之前的 Docker Desktop 创建了 ~/.docker/config.json
文件,不能被 podman 所用,把它删除了(参考:podman: Error: failed to parse "X-Registry-Auth" header),再试就没问题了。
如果一切顺利的话就可以用 podman
来替代 docker 去构建镜像等操作了。
可是在我的本地仍然是 podman build .
构建不了,也许是因为原来安装过 Docker Desktop, hyperkit, 和 minikube 的缘故,也可能是当前 podman
的 bug。
接着来构建一个镜像,Dockerfile 内容写成
1 |
FROM busybox |
或是
1 |
FROM docker.io/busybox |
执行
$ podman --log-level=debug build .
会看到两种类型的错误
Error: failed Request: Unable to copy tar file from request body /v3.3.1/libpod/build?dockerfile=%5B%22Dockerfile%22%5D&forcerm=1&isolation=1&jobs=1&layers=1&networkmode=0&nsoptions=%5B%7B%22Name%22%3A%22user%22%2C%22Host%22%3Atrue%2C%22Path%22%3A%22%22%7D%2C%7B%22Name%22%3A%22network%22%2C%22Host%22%3Atrue%2C%22Path%22%3A%22%22%7D%5D&outputformat=application%2Fvnd.oci.image.manifest.v1%2Bjson&pullpolicy=missing&rm=1&shmsize=67108864&t=
或是
Error: mkdir /var/tmp/libpod_builder721137603: no space left on device
用 podman machine ssh
进到虚拟机果然看到
[core@localhost ~]$ mkdir /var/tmp/libpod_builder721137603
mkdir: cannot create directory ‘/var/tmp/libpod_builder721137603’: No space left on device
删除了 ~/.config/containers
和 ~/.local/share/containers
也无济于事。
后来发现 No space left on device
是因为把 Dockerfile
放在了 ~/Downloads
目录中,在构建 Docker 镜像时把该目录中的所有文件都发向了 podman machine, 把 Dockerfile 挪出到一个新建目录中就行。
后来重启后,又瞎折腾了一翻,发现 podman build .
又能工作了,不知所以。
至于 Dockerfile
中的 FROM
要不是加上 docker.io
前缀,这是无所谓的,用 podman info
可查看 podman
搜寻 Docker 镜像的顺序是
registries:
search:
- registry.fedoraproject.org
- registry.access.redhat.com
- docker.io
- quay.io
podman login docker.io
按提示输入用户名和密码就能创建 docker hub, 能往其中 push 自己的镜像。
AWS 的 ECR 登陆,用
$ aws ecr get-login-password --region us-east-1 | podman login --username AWS --password-stdin <1234567890>.dkr.ecr.us-east-1.amazonaws.com
也可以登陆成功,之后就能 podman pull <1234567890>.dkr.ecr.us-east-1.amazonaws.com/abc:latest,或者是 podman pull AWS ECR 上的 image 了.
方案三:原始的 Docker Machine
再不济我们还可以再回到重新,用 docker-machine 的办法
$ brew install docker-machine
$ docker-machine create --driver virtualbox default
$ eval $(docker-machine env)
$ docker ps
前面的 Minikube + hyperkit 和这里的 Docker Machine 最终都是用的 Docker Daemon, docker 命令连接到 Docker Machine 来操作的。则 podman 是 Daemonless 的,所以也就只有它不怕 VPN 连接的干扰。
我本人目前的使用的就是 docker-machine,创建的是 VirtualBox 虚拟机,具体步骤是
$ docker-machine create --driver virtualbox --engine-env DOCKER_TLS=no --engine-opt host=tcp://0.0.0.:2375 default
$ docker-machine stop
$ VBoxManage modifyvm "default" --natpf1 "docker,tcp,127.0.0.1,2375,,2375
$ docker-machine start
$ export DOCKER_HOST=tcp://localhost:2375
$ docker ps
通过本地的端口映射就不会受连接 VPN 之后路由的影响,同时在 docker-machine 里还能访问外面(包括 VPN 的资源)
如果在使用 AWS ECR 时出现类似下面的错误
$ aws ecr get-login-password --region us-east-1 | \docker login --username AWS --password-stdin 123456789077.dkr.ecr.us-east-1.amazonaws.comError saving credentials: error storing credentials - err: exec: "docker-credential-desktop": executable file not found in $PATH, out:
~/.docker/config.json
,把其中的 credsStore
改成 credStore
就行了,现在什么都能解决了,IntelliJ IDEA 中如何要使用 Docker 的话,可配置用 TCP socket
, Engine API URL:
中填上 tcp://localhost:2375
。总结
其实在 Mac 下通过 minikube 来使用 docker 与 Docker Desktop 的方式是差不多的,用 Docker Desktop 来运行容器也是在它的一个虚拟机中运行,Docker Desktop 给出的虚拟机内存默认为 2 G, 需要更大内存来运行像 Java 容器同样需要修改 Docker Desktop 的配置。
最后重新罗列基本的命令
$ brew install docker
$ brew install hyperkit
$ brew install minikube
$ minikube start
$ eval $(minikube docker-env)
$ docker ......................
podman 一个 Docker Desktop 的完全替代方案,它管理自己的中间虚拟机,podman 命令可作为 docker 命令的别名使用。
用回 Docker Machine 也没问题,只有 podman 在连接了 VPN 后还能正常使用,而其他要配置 DOCKER_HOST
的方式会受到 VPN 连接的影响,需手工加 route, 或更难做。Docker Desktop 也没有这个 VPN 的问题。
最后还发现一个 Docker Desktop 的替代品 Lima, 见 Lima:Docker Desktop for Mac 的免费开源且自由的替代品,尝试了一下,没有前两种方式那么友好。再有 Canonical 的 MicroK8s, 没有 Docker Desktop 的日子会更热闹了。
[…] 摆脱 Docker Desktop 即将到来的收费 进一步找到符合自己需求的 Docker Desktop 替代品,前面试用过 hyperkit + […]
研究下怎么用 RH 系的工具
RH 系的什么工具?
podman
在 Replacing Docker Desktop with hyperkit + minikube 也提及了 podman, 用来替代 Docker CLI(暂时完全免费) 的.
brew install podman
然后 alias docker=podman, 像 docker 一样使用 podman.
并直接用 podman machine init|start 自启中间虚拟机