当前位置:  首页>> 技术小册>> Kubernetes中文教程(五)

这个文档描述了怎样不使用 root 特权,而是通过使用
去运行 Kubernetes 节点组件(例如 kubelet、CRI、OCI、CNI)。

这种技术也叫做 rootless 模式(Rootless mode)

这个文档描述了怎么以非 root 用户身份运行 Kubernetes 节点组件以及 Pod。
如果你只是想了解如何以非 root 身份运行 Pod,请参阅 [SecurityContext]。

  • [启用 cgroup v2]
  • [在 systemd 中启用 user session]
  • [根据不同的 Linux 发行版,配置 sysctl 的值]
  • [确保你的非特权用户被列在 /etc/subuid/etc/subgid 文件中]
  • 启用 KubeletInUserNamespace [特性门控]

使用 Rootless 模式的 Docker/Podman 运行 Kubernetes

kind

[kind] 支持使用 Rootless 模式的 Docker 或者 Podman 运行 Kubernetes。

请参阅[使用 Rootless 模式的 Docker 运行 kind]。

minikube

[minikube] 也支持使用 Rootless 模式的 Docker 或 Podman 运行 Kubernetes。

请参阅 Minikube 文档:

  • [Rootless Docker]
  • [Rootless Podman]

在非特权容器内运行 Kubernetes

sysbox

[Sysbox] 是一个开源容器运行时
(类似于 “runc”),支持在 Linux 用户命名空间隔离的非特权容器内运行系统级工作负载,
比如 Docker 和 Kubernetes。

查看 [Sysbox 快速入门指南: Kubernetes-in-Docker]
了解更多细节。

Sysbox 支持在非特权容器内运行 Kubernetes,
而不需要 cgroup v2 和 “KubeletInUserNamespace” 特性门控。
Sysbox 通过在容器内暴露特定的 /proc/sys 文件系统,
以及其它一些先进的操作系统虚拟化技术来实现。

直接在主机上运行 Rootless 模式的 Kubernetes

K3s

[K3s] 实验性支持了 Rootless 模式。

请参阅[使用 Rootless 模式运行 K3s]
页面中的用法.

Usernetes

[Usernetes] 是 Kubernetes 的一个参考发行版,
它可以在不使用 root 特权的情况下安装在 $HOME 目录下。

Usernetes 支持使用 containerd 和 CRI-O 作为 CRI 运行时。
Usernetes 支持配置了 Flannel 的多节点集群。

关于用法,请参阅 [Usernetes 仓库]。

手动部署一个在用户命名空间运行 kubelet 的节点

本节提供在用户命名空间手动运行 Kubernetes 的注意事项。

本节是面向 Kubernetes 发行版的开发者,而不是最终用户。

创建用户命名空间

第一步是创建一个 。

如果你正在尝试使用用户命名空间的容器(例如 Rootless 模式的 Docker/Podman 或 LXC/LXD)
运行 Kubernetes,那么你已经准备就绪,可以直接跳到下一小节。

否则你需要通过传递参数 CLONE_NEWUSER 调用 unshare,自己创建一个命名空间。

用户命名空间也可以通过如下所示的命令行工具取消共享:

  • [unshare]
  • [RootlessKit]
  • [become-root]

在取消命名空间的共享之后,你也必须对其它的命名空间例如 mount 命名空间取消共享。

在取消 mount 命名空间的共享之后,你需要调用 chroot 或者 pivot_root
但是你必须在这个命名空间内挂载可写的文件系统到几个目录上。

请确保这个命名空间内至少以下几个目录是可写的:

  • /etc
  • /run
  • /var/logs
  • /var/lib/kubelet
  • /var/lib/cni
  • /var/lib/containerd
  • /var/lib/containers

创建委派 cgroup 树

除了用户命名空间,你也需要有一个版本为 cgroup v2 的可写 cgroup 树。

Kubernetes 需要 cgroup v2 才支持在用户命名空间运行节点组件。
cgroup v1 是不支持的。

如果你在一个采用 systemd 机制的主机上使用用户命名空间的容器(例如 Rootless 模式的 Docker/Podman
或 LXC/LXD)来运行 Kubernetes,那么你已经准备就绪。

否则你必须创建一个具有 Delegate=yes 属性的 systemd 单元,来委派一个具有可写权限的 cgroup 树。

在你的节点上,systemd 必须已经配置为允许委派。更多细节请参阅 Rootless 容器文档的
[cgroup v2] 部分。

配置网络

节点组件的网络命名空间必须有一个非本地回路的网卡。它可以使用
[slirp4netns]、
[VPNKit]、
[lxc-user-nic]
等工具进行配置。

Pod 的网络命名空间可以使用常规的 CNI 插件配置。对于多节点的网络,已知 Flannel 可以正常工作。

诸如 kubelet 端口(10250/TCP)和 NodePort 服务端口之类的端口必须通过外部端口转发器
(例如 RootlessKit、slirp4netns 或
[socat]) 从节点网络命名空间暴露给主机。

你可以使用 K3s 的端口转发器。更多细节请参阅
[在 Rootless 模式下运行 K3s]。
该实现可以在 k3s 的 [pkg/rootlessports 包]中找到。

配置 CRI

kubelet 依赖于容器运行时。你需要部署一个容器运行时(例如 containerd 或 CRI-O),
并确保它在 kubelet 启动之前已经在用户命名空间内运行。

containerd 1.4 开始支持在用户命名空间运行 containerd 的 CRI 插件。

在用户命名空间运行 containerd 必须进行如下配置:

  1. version = 2
  2. [plugins."io.containerd.grpc.v1.cri"]
  3. # 禁用 AppArmor
  4. disable_apparmor = true
  5. # 忽略配置 oom_score_adj 时的错误
  6. restrict_oom_score_adj = true
  7. # 禁用 hugetlb cgroup v2 控制器(因为 systemd 不支持委派 hugetlb controller)
  8. disable_hugetlb_controller = true
  9. [plugins."io.containerd.grpc.v1.cri".containerd]
  10. # 如果内核 >= 5.11 , 也可以使用 non-fuse overlayfs, 但需要禁用 SELinux
  11. snapshotter = "fuse-overlayfs"
  12. [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
  13. # 我们使用的 cgroupfs 已经被 systemd 委派,所以我们不使用 SystemdCgroup 驱动
  14. #
  15. SystemdCgroup = false

配置文件的默认路径是 /etc/containerd/config.toml
可以用 containerd -c /path/to/containerd/config.toml 来指定该路径。

CRI-O 1.22 开始支持在用户命名空间运行 CRI-O。

CRI-O 必须配置一个环境变量 _CRIO_ROOTLESS=1

也推荐使用以下配置:

  1. [crio]
  2. storage_driver = "overlay"
  3. # 如果内核 >= 5.11 , 也可以使用 non-fuse overlayfs, 但需要禁用 SELinux
  4. storage_option = ["overlay.mount_program=/usr/local/bin/fuse-overlayfs"]
  5. [crio.runtime]
  6. # 我们使用的 cgroupfs 已经被 systemd 委派,所以我们不使用 "systemd" 驱动
  7. #
  8. cgroup_manager = "cgroupfs"

配置文件的默认路径是 /etc/containerd/config.toml
可以用 containerd -c /path/to/containerd/config.toml 来指定该路径。

配置 kubelet

在用户命名空间运行 kubelet 必须进行如下配置:

  1. apiVersion: kubelet.config.k8s.io/v1beta1
  2. kind: KubeletConfiguration
  3. featureGates:
  4. KubeletInUserNamespace: true
  5. # 我们使用的 cgroupfs 已经被 systemd 委派,所以我们不使用 "systemd" 驱动
  6. #
  7. cgroupDriver: "cgroupfs"

KubeletInUserNamespace 特性门控被启用时, kubelet 会忽略节点内由于配置如下几个 sysctl
参数值而可能产生的错误。

  • vm.overcommit_memory
  • vm.panic_on_oom
  • kernel.panic
  • kernel.panic_on_oops
  • kernel.keys.root_maxkeys
  • kernel.keys.root_maxbytes.

在用户命名空间内, kubelet 也会忽略任何由于打开 /dev/kmsg 而产生的错误。
这个特性门控也允许 kube-proxy 忽略由于配置 RLIMIT_NOFILE 而产生的一个错误。

KubeletInUserNamespace 特性门控从 Kubernetes v1.22 被引入, 标记为 “alpha” 状态。

通过挂载特制的 proc 文件系统 (比如 [Sysbox]),
也可以在不使用这个特性门控的情况下在用户命名空间运行 kubelet,但这不受官方支持。

配置 kube-proxy

在用户命名空间运行 kube-proxy 需要进行以下配置:

  1. apiVersion: kubeproxy.config.k8s.io/v1alpha1
  2. kind: KubeProxyConfiguration
  3. mode: "iptables" # or "userspace"
  4. conntrack:
  5. # 跳过配置 sysctl 的值 "net.netfilter.nf_conntrack_max"
  6. maxPerCore: 0
  7. # 跳过配置 "net.netfilter.nf_conntrack_tcp_timeout_established"
  8. tcpEstablishedTimeout: 0s
  9. # 跳过配置 "net.netfilter.nf_conntrack_tcp_timeout_close"
  10. tcpCloseWaitTimeout: 0s

注意事项

  • 大部分“非本地”的卷驱动(例如 nfsiscsi)不能正常工作。
    已知诸如 localhostPathemptyDirconfigMapsecretdownwardAPI
    这些本地卷是能正常工作的。

  • 一些 CNI 插件可能不正常工作。已知 Flannel 是能正常工作的。

更多细节请参阅 rootlesscontaine.rs 站点的 [Caveats and Future work] 页面。

  • [rootlesscontaine.rs]
  • [Rootless Containers 2020 ]
  • [使用 Rootless 模式的 Docker 运行 kind]
  • [Usernetes]
  • [使用 Rootless 模式运行 K3s]
  • [KEP-2033: Kubelet-in-UserNS ]

该分类下的相关小册推荐: