# 通过 rkt 运行 k8s

本文档描述如何使用 rkt 作为容器运行时(runtime)来运行 k8s。

注意:本文档描述如何使用所谓的 “rktnetes”。在以后,k8s 将通过容器运行时接口(CRI)来支持 rkt 运行时(runtime)。目前 rkt shim for the CRI 仍处于实验阶段,不过如果需要使用仍然可以在 kubeadm reference 中找到教程。

# 前提

  • Systemd 必须安装并且启用。k8s V1.3 要求的 systemd 最低版本是 219。Systemd 是用来监控和管理 node 上的 pod 的。
  • 安装最新版的 rkt。要求的 rkt 最低版本是 v1.13.0。CoreOS Linux alpha channel 附带了一个最新的 rkt 发布版本,如果必要的话您可以通过 在 CoreOS 上更新 rkt 更新 rkt。
  • rkt API service 必须运行在 node 上。
  • 你需要安装 kubelet 在 node 上,并且建议运行 kube-proxy 在所有 node 上。本文档描述如何设置 kubelet 的参数使其能够使用 rkt 作为运行时(runtime)。

# rktnetes 中的 pod 网络

# k8s 的 CNI 网络

你可以通过适当地设置 kubelet 的 --network-plugin 和 --network-plugin-dir 参数来让 k8s pod 使用常用的 Container Network Interface(CNI)网络插件。通过这种方法,rkt 可以在不了解网络细节的情况下通过提供的子网来连接 pod。

# kubenet:Google Compute Engine(GCE)网络

您能够通过配置 kubelet 的参数 --network-plugin=kubenet 来选择使用 kubenet 插件。该插件目前只支持 GCE 环境。当使用 kubenet,k8s CNI 将会创建并且管理网络,同时提供一个网桥设备给 rkt 使其能够连接到 GCE 网络。

# rkt contained 网络

相对于将网络交给 k8s,rkt 也能通过其自身的 contained 网络 在一个网桥设备提供的子网上直接配置网络连接,如 flannel SDN,或者其它的 CNI 插件。以这种方式配置,rkt 通过查找它的 配置目录,通常位于 /etc/rkt/net.d,来发现 CNI 配置并且调用合适的插件来创建 pod 网络。

# 通过网桥实现 rkt contained 网络

rkt 默认使用 contained 网络,所以你可以把 kubelet 的 --network-plugin 参数置空让其使用这个默认网络。任意的 CNI 插件都能支持 contained 网络。通过 contained 网络,rkt 将尝试把 pod 连接到一个名为 rkt.kubernetes.io 的网络,所以提供支持的 CNI 配置必须使用这个名称。

如果使用 contained 网络,需要在 rkt 网络配置目录下创建一个网络配置文件,该文件定义如何在您的环境中创建 rkt.kubernetes.io 网络。如下示例展示如何通过 bridge CNI 插件创建一个网桥设备:

$ cat <<EOF >/etc/rkt/net.d/k8s_network_example.conf
{
  "name": "rkt.kubernetes.io",
  "type": "bridge",
  "bridge": "mybridge",
  "mtu": 1460,
  "addIf": "true",
  "isGateway": true,
  "ipMasq": true,
  "ipam": {
    "type": "host-local",
    "subnet": "10.22.0.0/16",
    "gateway": "10.22.0.1",
    "routes": [
      { "dst": "0.0.0.0/0" }
    ]
  }
}
EOF

# 通过 flannel 实现 rkt contained 网络

目前推荐通过 k8s CNI 的支持来操作 flannel,不过您也可以通过配置 flannel 插件目录来为 rkt 的 contained 网络提供子网。如下提供一个 CNI/flannel 配置文件的示例:

$ cat <<EOF >/etc/rkt/net.d/k8s_flannel_example.conf
{
    "name": "rkt.kubernetes.io",
    "type": "flannel",
    "delegate": {
        "isDefaultGateway": true
    }
}
EOF

如果需要查看更多关于 flannel 的配置信息,请参阅 CNI/flannel README。

# Contained 网络的注意事项:

  • 对于创建的 CNI 配置文件,其中的网络名称必须为 rkt.kubernetes.io。
  • 向下兼容的 API 和环境变量替换将不包含 pod IP 地址。
  • 尽管提供了 /etc/hostname,但是 /etc/hosts 文件将不会包含 pod 自己的 hostname。

# 运行 rktnetes

# 通过 rkt 运行时(runtime)来运行一个本地的 k8s 集群

如果需要使用 rkt 来作为本地 k8s 集群的容器运行时(container runtime),需要为 kubelet 设置如下参数:

  • --container-runtime=rkt 设置 node 的容器运行时(container runtime)为 rkt。
  • --rkt-api-endpoint=HOST:PORT 设置 rkt API service 的 endpoint。默认为:localhost:15441。
  • --rkt-path=PATH_TO_RKT_BINARY 设置 rkt 二进制的目录。非必填项。如果不设置该参数,则在 $PATH 中查找 rkt。
  • –rkt-stage1-image=STAGE1 设置 stage1 镜像的名字,例如 coreos.com/rkt/stage1-coreos。非必填项。如果不设置,则使用默认的 Linux 内核软件隔离器 stage1。

如果您是使用 hack/local-up-cluster.sh 脚本来启动集群,您可以通过编辑 CONTAINER_RUNTIME,RKT_PATH,和 RKT_STAGE1_IMAGE 环境变量来设置上面这些参数。如果 rkt 已经正确的配置在您的 $PATH 中,那么 RKT_PATH 和 RKT_STAGE1_IMAGE` 就都不是必填项。

$ export CONTAINER_RUNTIME=rkt
$ export RKT_PATH=<rkt_binary_path>
$ export RKT_STAGE1_IMAGE=<stage1-name>

现在可以使用 local-up-cluster.sh 脚本来启动集群了:

$ hack/local-up-cluster.sh

同时,我们也尝试在 minikube 中将 rkt 作为容器运行时(container runtime)。

# 在 Google Compute Engine(GCE)上启动 rktnetes 集群

本节概述如何使用 kube-up 脚本在 GCE 上启动 CoreOS/rkt 集群。

首先需要指定 OS distribution,GCE distributor 的 master project,和 k8s 的 master 和 node 的示例镜像。然后设置 KUBE_CONTAINER_RUNTIME 为 rkt:

$ export KUBE_OS_DISTRIBUTION=coreos
$ export KUBE_GCE_MASTER_PROJECT=coreos-cloud
$ export KUBE_GCE_MASTER_IMAGE=<image_id>
$ export KUBE_GCE_NODE_PROJECT=coreos-cloud
$ export KUBE_GCE_NODE_IMAGE=<image_id>
$ export KUBE_CONTAINER_RUNTIME=rkt

或者,通过设置 KUBE_RKT_VERSION 来指定 rkt 版本:

$ export KUBE_RKT_VERSION=1.13.0

或者,通过设置 KUBE_RKT_STAGE1_IMAGE 来为容器运行时(container runtime)选择另一个 stage1 isolator

$ export KUBE_RKT_STAGE1_IMAGE=<stage1-name>

然后您就可以通过以下命令启动集群:

$ cluster/kube-up.sh

# 在 AWS 上启动一个 rktnetes 集群

在 AWS 上目前还不支持 kube-up 脚本。不过,我们建议遵循 k8s on AWS guide 在 AWS 上启动一个 CoreOS k8s 集群,然后按照上述配置来设置 kubelet 的选项。

# 在集群中部署应用

创建集群之后,您就可以开始部署应用了。您可以在 deploy a simple nginx web server 找到一个介绍示例。请注意,您并不需要修改该示例来让其运行在 “rktnetes” 集群上。更多示例可以参阅 k8s examples directory。

# 通过可互换的 stage1 镜像实现模块化隔离

rkt 在一个可互换的隔离环境中运行容器。这个功能被称作 stage1 镜像。目前支持三种 rkt stage1 镜像:

  • 默认使用 systemd-nspawn stage1。通过 Linux kernel namespaces 和 cgroups 来隔离运行态的容器,该行为类似于默认的容器运行时(container runtime)。
  • KVM stage1,在一个 KVM hypervisor-managed 的虚拟机中运行容器。在 k8s v1.3 版本中仍处于实验状态。
  • fly stage1,仅通过 chroot 来隔离容器,从而为需要特殊权限的应用程序提供主机级别的 mount 和网络命名空间权限。

除了上述的三个 stage1 镜像,您也可以根据您自己特定的隔离需求来创建您自己的镜像。如果不配置,那么将默认使用 default stage1。目前有两种方法来选择不同的 stage1;通过 node 或者通过 pod:

  • 设置 kubelet 的 --rkt-stage1-image 参数来告知 kubelet 为其 node 上的所有 pod 使用哪个 stage1 镜像。例如,--rkt-stage1-image=coreos/rkt/stage1-coreos 将会选择默认的 systemd-nspawn stage1。
  • 设置 rkt.alpha.kubernetes.io/stage1-name-override 注解来覆盖 stage1,stage1 用来执行一个指定的容器。这将允许在同一个集群或者节点上混合使用不同的容器隔离机制。例如,以下的 pod manifest (缩减版)将使用 fly stage1 来运行 pod,从而让它的应用 – 这里就是 kubelet – 能够访问宿主机的命名空间:
apiVersion: v1
kind: Pod
metadata:
  name: kubelet
  namespace: kube-system
  labels:
    k8s-app: kubelet
  annotations:
    rkt.alpha.kubernetes.io/stage1-name-override: coreos.com/rkt/stage1-fly
spec:
  containers:
  - name: kubelet
    image: quay.io/coreos/hyperkube:v1.3.0-beta.2_coreos.0
    command:
    - kubelet
    - --api-servers=127.0.0.1:8080
    - --config=/etc/kubernetes/manifests
    - --allow-privileged
    - --kubeconfig=/etc/kubernetes/kubeconfig
    securityContext:
      privileged: true
[...]

# 使用不同 stage1 镜像的注意事项

设置 stage1 注解将会潜在的赋予 pod 以 root 权限。所以,pod 的 securityContext 中的 privileged 必须设置为 true。

使用 KVM stage1 时需要配套使用 rkt 的 contained network,因为 CNI 插件驱动目前还没完全支持 hypervisor-based 运行时(runtime)。

# rkt 和 Docker 之间已知的问题和差异

rkt 和默认节点容器引擎具有非常不同的设计,就像 rkt 的本地 ACI 和 Docker 的容器镜像格式一样。从一个容器引擎切换到另一个时,用户可能会遇到不同的行为。更多信息请参阅 in the k8s rkt notes。

# 故障排除

以下是一些基于 rkt 容器引擎的 k8s 的故障排除的提示:

# 检查 rkt 的 pod 状态

如果想要检查正在运行的 pod 的状态,可以使用 rkt 的子命令 rkt list,rkt status,和 rkt image list。更多关于 rkt 子命令的信息可参阅 rkt commands documentation。

# 检查 journal 日志

可以在 node 上使用 journalctl 命令来检查 pod 的日志。Pod 是作为 systemd 单元来进行管理和命名的。Pod 的单元名称是通过把 k8s_ 前缀和 pod 的 UUID 串联起来形成的,格式类似于 k8s_${RKT_UUID}。用 rkt list 命令找到 pod 的 UUID 来组成它的服务名,然后使用 journalctl 命令查看日志:

$ sudo journalctl -u k8s_ad623346

# 日志输出级别

默认情况下,日志级别为 2。如果想要查看更多和 rkt 相关的日志信息,可以设置级别为 4 或更高级别。对于一个本地集群,设置环境变量:LOG_LEVEL=4 即可。

检查 k8s 的事件和日志。

k8s 提供了多种工具以进行问题排查和检测。

Last Updated: 4/15/2023, 8:33:17 PM