使用 Rootless Docker 运行 Minikube

实际上按照minikube官方文档完成安装很容易,但是选择以rootless docker作为驱动还是相对麻烦的,所以这篇博客不算是重复造轮子,主要是一份更加流畅的指南,需要结合官方文档使用。

基础环境

  • windows上安装virtualbox,并在vb上创建虚拟机ubuntu22.04
  • minikube v1.32.0

安装形式

参考官方文档minikube startdrivers,使用minikube一般来说需要容器运行时或者虚拟机管理器的支持,minikube将使用它们的API创建一个可用的集群,如果需要在自己创建的虚拟机中启动minikube,可以选择驱动为none或ssh,适合有明确需求的专业用户使用,我主要用它来做一些实验,再加上需要在vm中使用它,所以选择容器运行时的方式,又因为docker被广泛使用,所以这里选择docker作为驱动。

如果你使用rootfull docker,也就是drivers/docker文档中的“Standard Docker”形式,对于ubuntu来说几条命令就能搞定docker的安装,如果不把你平常使用的用户(比如我的用户ian)加入docker用户组,使用命令sudo minikube start启动时,将看到以下错误信息:

在这里插入图片描述
此时只需要参考Manage Docker as a non-root user文档,修改当前普通用户的用户组并使其生效就可以顺利执行命令minikube start了,但这只是将docker daemon创建的unix socket暴露给了属于docker组的用户,似乎并不符合这个错误提示:“The “docker” driver should not be used with root privileges.”

所以我这里选择以rootless的方式安装docker,虽然更繁琐,但是能够了解rootless目前的情况,docker文档Run the Docker daemon as a non-root user (Rootless mode)中给出了rootless模式的已知限制,并推荐使用ubuntu内核,一定要参考,不过这不能表明rootless与rootfull的全部差异,后面会提到。对于我们尝试它来说,主要有三方面限制:docker版本、cgroup版本、kernel版本,一一满足即可,这是一个绿地项目,不用顾虑什么。

部署架构是这样的,docker in docker的方式:

在这里插入图片描述
rootless docker是这样的:
在这里插入图片描述

安装步骤

安装rootless docker

首先参考drivers/docker中的“Rootless Docker”部分,检查以下项目:

  1. [重要]要安装的docker版本,20.10及以上才提供rootless支持
  2. cgroup版本为v2,如果存在/sys/fs/cgroup/cgroup.controllers文件说明已经启用了v2,在一些发行版中已经默认启用v2,比如这里的ubuntu22.04,但是并不代表non-root用户可以委托所有的控制器,需要启用对CPU、IO控制器的委托,对于云环境可能有特别的配置,详情参考[Optional] cgroup v2,文档建议修改systemd配置后重启,关于cgroup v2可以参考详解Cgroup V2
  3. kernel版本5.11及以上,推荐5.13及以上(更加安全),执行uname -a查看内核版本

然后参考Common steps (Read first!)做rootless docker安装前准备,可以理解为需要root权限来做的一些准备,分为几个部分:

  1. 登录
    1. 大多数rootless容器实现依赖XDG_RUNTIME_DIR环境变量,文档中描述了哪些情况下此环境变量应该被设置和不被设置,检查命令echo $XDG_RUNTIME_DIR
    2. 允许容器开机启动,也就是随系统启动用户实例,命令sudo loginctl enable-linger $(whoami),检查命令sudo loginctl show-user $(whoami)
    3. 为避免执行docker run命令出现错误:docker: Error response from daemon: OCI runtime create failed: ...: read unix @->/run/systemd/private: read: connection reset by peer: unknown.,需要启用dbus用户会话,ubuntu22.04默认已安装dbus-user-session包,执行命令systemctl --user status dbus可以看到此服务由dbus.socket触发,因此不用再按照文档中说明的步骤启动和配置开机启动(如果主动配置还会因为service unit文件没有install部分而报错)。关于用户服务可以参考systemd/用户
  2. /etc/subuid和/etc/subgid
    1. 检查是否存在/etc/subuid/etc/subgid文件,并被设置了合理的值,类似<username>:100000:65536,否则填写并创建正确的配置
    2. 安装uidmap,命令:sudo apt-get install -y uidmap,虽然文档说这个包通常是默认安装的,但在ubuntu22.04上并不是
    3. [跳过]这里主要说使用systemd-homed时的情况,不过似乎很少有发行版使用
  3. 关于cgroup v2的配置已在前文包含
  4. 配置sysctl
    1. [跳过,ubuntu不需要此设置]打开user namespace,创建包含kernel.unprivileged_userns_clone=1的配置文件/etc/sysctl.d/99-rootless.conf,并使其生效:sudo sysctl --system
    2. 开启ping命令,创建包含net.ipv4.ping_group_range = 0 2147483647的配置文件/etc/sysctl.d/99-rootless.conf,并使其生效:sudo sysctl --system,不过似乎只有在进入用户空间后才能ping通容器
    3. 允许非root用户监听1024以下的端口,创建包含net.ipv4.ip_unprivileged_port_start=0的配置文件/etc/sysctl.d/99-rootless.conf,并使其生效:sudo sysctl --system

至此配置部分已经完成,可以开始安装rootlees docker了:

mkdir /tmp/docker && cd $_
curl -o rootless-install.sh -fsSL https://get.docker.com/rootless
sh rootless-install.sh

命令执行成功后,可以从日志看到安装完成,并告诉我们后续在~/.bashrc中配置环境变量PATH和DOCKER_HOST:

在这里插入图片描述
对于ubuntu22.04来说,~/.profile已经包含了设置PATH的逻辑,即如果~/bin存在,就设置到PATH中,这里我们遵循docker的说明,所以需要屏蔽~/.profile中的相关逻辑,以保证PATH变量的值不会在这里产生重复的项。

此时docker cli会通过环境变量DOCKER_HOST获取到正确的context,所以可以省去指定context的步骤,如果你执行docker context use rootless命令,并不会修改默认配置,而是给你一个警告信息。记住,使用systemctl --user命令将dockerd作为用户进程管理。

如果此时探索rootless docker,会发现一些与rootfull安装的差异,比如命令docker info输出中会包含关于bridge的警告,类似WARNING: bridge-nf-call-iptables is disabled,操作系统/proc/sys/net/目录下没有bridge子目录,命令ip addr的输出中也没有docker0网桥,不过,从命令docker network ls的输出中可以看到,网桥是创建成功的。这些都是在用户空间运行dockerd带来的差异,参考Entering into dockerd namespaces,进入用户空间就可以看到docker0网桥:

nsenter -U --preserve-credentials -n -m -t $(cat $XDG_RUNTIME_DIR/docker.pid)

这个问题会引起minikube中pod dns异常,后面会提到并修复。

如果出现其他问题,可以参考docker提供的Troubleshooting

还有两个可选的优化:网络栈和端口转发方式,可以参考Tips中的说明,对于网络栈,仅仅需要安装slirp4netns(当前使用哪个网络栈可以在命令sysyemctl --user status docker输出中的rootlesskit进程参数中看到),docked会在启动时自动选择它。

然后是在~/.config/docker/daemon.json文件中配置日志滚动、仓库镜像之类的,重启dockerd后生效:

{
    "log-driver": "json-file",
    "log-opts": {
        "max-size": "3m",
        "max-file": "3"
    },
    "registry-mirrors": ["docker.m.daocloud.io"]
}

前面提到的执行命令docker info产生警告的问题会影响k8s相同node上的pod通过service通信,举个具体的例子,minikube安装单节点集群后,coredns与业务pod处于同一个节点,在业务pod中通过coredns service的cluster ip查询域名(例如使用kubectl run -it --rm --restart=Never busybox --image=m.daocloud.io/gcr.io/google-containers/busybox sh模拟业务pod,在其中执行nslookup kubernetes.default)时会超时失败,这主要是因为缺失内核模块br_netfilter造成的,node内的流量直接通过bridge转发从而使iptables(minikube安装的集群默认使用iptables)失效,也就使cluster ip失效了,细节可以参考博客k8s中为什么需要br_netfilter与net.bridge.bridge-nf-call-iptables=1

在rootfull docker安装过程中会自动完成此项配置,这也是前面说的,文档中没有的rootless与rootfull的不同,此时,首先需要确保内核模块br_netfilter生效,并且能够永久生效:

# 立即生效
modprobe br_netfilter
# 永久生效
echo "br_netfilter" | sudo tee -a /etc/modules-load.d/modules.conf

然后在/etc/sysctl.conf文件中增加以下配置:

net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1

最后执行sudo sysctl -p读入新加入的配置,重启dockerd后再执行docker info就看不到警告了。

安装minikube

接下来的步骤就比较简单了,如果没有代理,使用命令minikube start --image-repository='registry.cn-hangzhou.aliyuncs.com/google_containers'可以很快完成minikube的启动(经过测试,--image-mirror-country='cn'参数,也就是根据国家获取mirror不能有效工作,阿里云mirror可以参考k8s.gcr.io 镜像),执行命令minikube kubectl -- get pods -A可以看到所有的pod都进入Running状态了,很幸运。这里顺便给出提到的两个参数的说明:

--image-mirror-country='':
    Country code of the image mirror to be used. Leave empty to use the global one. For Chinese mainland users,
    set it to cn.

--image-repository='':
    Alternative image repository to pull docker images from. This can be used when you have limited access to
    gcr.io. Set it to "auto" to let minikube decide one for you. For Chinese mainland users, you may use local
    gcr.io mirrors such as registry.cn-hangzhou.aliyuncs.com/google_containers

但是会有一个问题,也就是不幸的状态,如果你要添加addons,以metrics-server举例,执行命令minikube addons enable metrics-server后会发现pod一直停留在ImagePullBackOff状态,执行命令minikube kubectl -- get deployment -n kube-system metrics-server -o yaml可以看到使用的镜像为registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server:v0.6.4@sha256:ee4304963fb035239bb5c5e8c10f2f38ee80efc16ecbdb9feb7213c17ae2e86e,如果手动去拉这个镜像,就会得到一个错误:“Error response from daemon: manifest for registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server@sha256:ee4304963fb035239bb5c5e8c10f2f38ee80efc16ecbdb9feb7213c17ae2e86e not found: manifest unknown: manifest unknown”,经过测试得知阿里mirror有registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server:v0.6.4镜像,但是哈希值不一样,这样就必须使用kc edit deployment -n kube-system metrics-server方式修改deployment中的image字段才能成功运行这个addons。实际上这种问题不光是使用addons的时候可能遇到,启用minikube也可能遇到,会出现各种镜像不一致导致不能拉取的问题,它们可能由阿里云mirror、minikube任意一方造成,总之官方不会测试添加--image-repository='registry.cn-hangzhou.aliyuncs.com/google_containers'参数的情况。还有一个有点可笑的问题,我不知道怎样在registry.cn-hangzhou.aliyuncs.com/google_containers仓库中搜索镜像,很多人跟我有一样的问题,但是阿里云社区中相关问题的答案没有任何价值。使用代理才能得到质量保证(可以参考Proxies and VPNs)。

还有一个好的国内镜像选择:DaoCloud/public-image-mirror项目,它列出了已经收录的镜像,参考此项目的文档,k8s.m.daocloud.ioregistry.k8s.io的镜像,在--image-repository选项中使用应该是没有问题的(未测试,但用在containerd中是没有任何问题的),本文档中已经多次使用了daocloud提供的镜像。

minikube start成功后,本地不安装kubectl的话,在~/.bashrc里设置一个别名就可以了:

alias kc="minikube kubectl --"

这里说明下如何使用dashboard:

# 启动dashboard但是不打开浏览器,此时将输出dashboard的url,是监听在127.0.0.1的,像这样:
# http://127.0.0.1:41997/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/
minikube dashboard --url

# 打开新终端,为了在windows的浏览器上访问,需要做代理
kc proxy --address=0.0.0.0 --accept-hosts='.*'

# 接下来就可以在默认的8001端口上访问dashboard的url,像这样:
# http://192.168.56.59:8001/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/

启用插件metrics-serverminikube addons enable metrics-server就可以在dashboard上看到基本的监控指标了,还有两点说明:

  1. 使用命令minikube ssh可以连接到部署k8s的容器minikube,它是在vm上运行的容器,其内部使用docker部署了k8s
  2. ~/.minikube/files路径下的文件可以覆盖容器minikube内的文件,可以使用这种方式修改容器内的文件,参考File Sync

好了,现在可以根据官方文档探索minikube了。

如果使用代理,minikube会把用于设置代理的环境变量传入minikube容器内的docker daemon:

ian@ian:~$ minikube ssh
docker@minikube:~$ docker info
 ...
 HTTP Proxy: http://192.168.56.1:10809
 HTTPS Proxy: http://192.168.56.1:10809
 No Proxy: control-plane.minikube.internal
 ...

这一般不会引起什么问题,如果外部的代理环境变量unset,在minikube容器重启后,内部的环境变量也会被取消。

变更记录

  • 修正错误和补充细节
    • 错误提示:“The “docker” driver should not be used with root privileges.”并不是指需要以rootless的方式运行docker,而是非root用户能够访问docker daemon创建的socket,即/run/docker.sock,感觉这个提示有点误导,但是不改变这篇博客的初衷
    • 对不使用代理的情况做了细化,问题依旧很大,官方似乎并不会针对指定mirror的情况做测试
  • 补充细节
    • 增加了关于内核模块br_netfilter的说明
    • 增加了daocloud提供的加速站
  • 补充细节
    • 为docker配置了daocloud提供的mirror
    • 为minikube mirror选项增加建议,使用daocloud mirror
  • 26
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值