本文参考自:Using the CRI-O Container Engine

CRI-O 是一个开源的、社区驱动的容器引擎。 其主要目标是取代 Docker 服务作为 Kubernetes 实施的容器引擎。随着 Kubernetes v1.24 对 dockershim 的弃用,CRI-O 将成为 Kubernetes 容器引擎的不二之选。
CRI-O 容器引擎为运行与开放容器标准 (OCI) 兼容的运行时提供了一个稳定、更安全和高性能的平台。使用 CRI-O 容器引擎可以借助使用符合 OCI 的运行时(如 runc、默认 OCI 运行时或 Kata Containers)来启动容器和 Pod。

CRI-O 的稳定性来自于它是与 Kubernetes 的主要和次要版本同步开发、测试和发布的,而且它遵循 OCI 标准。例如,CRI-O 1.24 与 Kubernetes 1.24 保持一致。CRI-O 的适用范围与容器运行时接口(CRI)相关联(参见:What is the scope of CRI-O?)。CRI 准确地提取和标准化了 Kubernetes 服务(kubelet)从其容器引擎中所需的支撑。随着多种容器引擎开始被相继开发,CRI 团队这样做是为了帮助稳定 Kubernetes 容器引擎的要求。

操控 CRI-O 的常用命令行工具包括:

crictl - 用于排除故障和直接与 CRI-O 容器引擎一起工作(需安装 cri-tools,较常用)

runc - 用于运行容器镜像(CRI-O 自带,几乎不用)

podman - 用于在容器引擎之外管理 pod 和容器镜像(run, stop, start, ps, attach, exec 等,需安装 podman,经常用。podman 的详细使用方式见:Podman构建和管理容器

一些 Docker 功能被包含在其他工具中,而不是 CRI-O 中。例如,podman提供了与许多 docker 命令功能完全兼容的命令行,并将这些功能也扩展到管理 pod 上。使用 podman 运行容器或 pod 不需要容器引擎。

不支持 CRI-O 作为独立的容器引擎运行。必须使用 CRI-O 作为 Kubernetes 安装的容器引擎,要在没有 Kubernetes 的情况下运行容器,请使用 podman。

安装 CRI - O(参考:容器运行时 | Kubernetes

说明:如果 Kubernetes 的网络代理组件(如 calico)使用的是 eBPF 模式,则不要依照 Kubernetes 官方文档在 /etc/modules-load.d/crio.conf 中配置 br_netfilter 内核模块,只需保留其中的 overlay 模块。还可以直接删除用于转发桥接流量到 iptables 链的配置文件 /etc/sysctl.d/99-kubernetes-cri.conf

要查询和调试 CRI-O 容器运行时,请运行 crictl 命令直接与 CRI-O 通信。crictl 使用的 CRI-O 实例在 /etc/crictl.yaml 文件中标识。

说明:旧版 /etc/crictl.yaml 中的 image-endpoint 已从 v1.21.0 移除。

详见:fix: Don't set `image-endpoint` in crictl config · cri-o/cri-o@4bca0bb · GitHub

cat /etc/crictl.yaml
# 显示如下内容
runtime-endpoint: "unix:///var/run/crio/crio.sock"

默认情况下,crictl.yaml 文件使 crictl 指向本地系统上的 CRI-O socket。要查看 crictl 可用的选项,请不带参数直接运行 crictl。要获得特定选项的帮助,请添加 --help。例如:

crictl run --help
# 显示如下内容
NAME:
   crictl run - Run a new container inside a sandbox

USAGE:
   crictl run [command options] container-config.[json|yaml] pod-config.[json|yaml]

OPTIONS:
   --auth AUTH_STRING           Use AUTH_STRING for accessing the registry. AUTH_STRING is a base64 encoded 'USERNAME[:PASSWORD]'
   --creds USERNAME[:PASSWORD]  Use USERNAME[:PASSWORD] for accessing the registry
   --no-pull                    Do not pull the image (overrides disable-pull-on-run=false in config) (default: false)
   --runtime value, -r value    Runtime handler to use. Available options are defined by the container runtime.
   --timeout value, -t value    Seconds to wait for a container create request before cancelling the request (default: 0s)
   --with-pull                  Pull the image (overrides disable-pull-on-run=true in config) (default: false)
   --help, -h                   show help (default: false)

配置国内容器镜像加速器,执行以下命令。

vi /etc/containers/registries.conf

说明:registries.conf 现已全部使用 V2 配置格式,如果你的文件中混合了 V1 和 V2 的配置格式,请将 V1 版的配置格式全部删除,只保留 V2 版配置格式。

详见:image/containers-registries.conf.5.md at main · containers/image · GitHub

删除 registries.conf 中的默认配置,替换为以下内容。

注:mirror.ccs.tencentyun.com 镜像加速器只有在腾讯云上才能使用。请根据实际环境配置。

unqualified-search-registries = ["docker.io", "k8s.gcr.io", "registry.fedoraproject.org", "registry.access.redhat.com", "registry.centos.org"]

[[registry]]
prefix = "docker.io"
location = "mirror.ccs.tencentyun.com"

[[registry]]
prefix = "k8s.gcr.io/coredns/coredns"
location = "registry.aliyuncs.com/google_containers/coredns"

[[registry]]
prefix = "*.gcr.io"
location = "registry.aliyuncs.com/google_containers"

各配置项解释如下:

unqualified-search-registries: 按顺序拉取不匹配的镜像时需要尝试的 host[:port] 镜像注册表数组。

[[registry]]: 镜像注册表,用于反向代理到国内镜像。

insecure: true 或 false。默认 false,表示容器运行时在从镜像注册表检索镜像时需要 TLS 连接。
如果将 insecure 设置为 true,则允许使用未加密的 HTTP 以及具有不受信任的证书的 TLS 连接。

blocked true 或 false。默认 false。如果为 true,则表示阻止本地系统 pull、search 自 [[registry]] 块中已定义的 prefix、location 镜像地址。

prefix 镜像名称前缀,可以是具体的镜像注册表,如 docker.io。还可以包含格式为 *.example.com 的通配符子域。
通配符应仅出现在开头第一个字符,其他格式将不起作用(甚至会导致 crio 无法启动)。
例如:*.example.com 有效,但 example.*.com、*.example.com/foo 和 *.example.com:5000/foo/bar:baz 都无效。
请注意:* 匹配任意数量的子域。*.example.com 将匹配 bar.example.com、foo.bar.example.com 等。

location: 接受与 prefix 字段相同的格式,但不能用通配符。配合 prefix 使用时表示将所有以 prefix 为根命名空间的镜像都反向代理到指定的 location 镜像。

检查 crio.service 日志,执行如下命令。

journalctl -xeu crio

列出其中一个容器的日志,执行如下命令。

crictl logs $(container_id)

开启 CRI-O 调试,编辑 /etc/crio/crio.conf 修改如下。

# 可选日志级别:fatal, panic, error, warn, info (default), debug, trace
[crio.runtime]
log_level = "debug"

重新加载配置文件,并重新启动服务,命令如下。

systemctl daemon-reload
systemctl restart crio

通过 crictl 命令,你可以直接与 CRI-O 容器引擎对接,检查和操作与该容器引擎相关的容器、镜像和 pod。runc 容器运行时是与 CRI-O 交互的另一种方式。如果你想在 CRI-O 容器引擎之外运行容器,例如在一个节点上运行支持工具,你可以使用 podman 命令。

首先,你可以使用 crictl info 和 crictl version 命令检查 CRI-O 服务的一般状态。

crictl info
# 显示如下内容
{
  "status": {
    "conditions": [
      {
        "type": "RuntimeReady",
        "status": true,
        "reason": "",
        "message": ""
      },
      {
        "type": "NetworkReady",
        "status": true,
        "reason": "",
        "message": ""
      }
    ]
  }
}
crictl version
# 显示如下内容
Version:  0.1.0
RuntimeName:  cri-o
RuntimeVersion:  1.23.2
RuntimeApiVersion:  v1alpha2

查看已经拉取到本地 CRI-O 节点的镜像。

crictl images

查看当前在CRI-O环境中已激活的(Ready)pod。

crictl pods

查看当前正在运行的容器。

crictl ps

查看所有容器,包括正在运行、已停止和已退出的容器。

crictl ps -a

如果你的 CRI-O 服务被停止或出现故障,你可以使用 runc 命令列出在 CRI-O 中运行的容器。这个例子搜索了一个 CRI-O 运行和不运行的容器的存在。然后它显示你可以用 runc 来调查那个容器,即使是在 CRI-O 停止的时候。

crictl ps | grep d36a99a9a40ec
d36a99a9a40ec       062cd20609d3895658e54e5f367b9d70f42db4f86ca14bae7309512c7e0777fd
    11 hours ago        CONTAINER_RUNNING   sync                 2
sudo systemctl stop crio
sudo crictl ps | grep d36a99a9a40ec
2022/04/14 11:22:16 grpc: addrConn.resetTransport failed to create client transport:
   connection error: desc = "transport: dial unix /var/run/crio/crio.sock: connect:
   no such file or directory"; Reconnecting to {/var/run/crio/crio.sock <nil>}
   FATA[0000] listing containers failed: rpc error: code = Unavailable desc = grpc:
   the connection is unavailable
sudo runc list | grep d36a99a9a40ec
d36a99a9a40ecc4c830f10ed2d5bb3ce1c6deadcb1a4879ff342e315051a71ed   19477       running
  /run/containers/storage/overlay-containers/d36a99a9a40ecc4c830f10ed2d5bb3ce1c6deadcb1a4879ff342e315051a71ed/userdata
  2022-04-14T04:44:29.47950187Z    root
ls /run/containers/storage/overlay-containers/d36*/userdata/
attach  config.json  ctl  pidfile  run
less /run/containers/storage/overlay-containers/d36*/userdata/config.json
{
	"ociVersion": "1.0.0",
	"process": {
		"user": {
			"uid": 0,
			"gid": 0
		},
		"args": [
			"/bin/bash",
			"-c",
			"#!/bin/bash\nset -euo pipefail\n\n# set by the node
                        image\nunset KUBECONFIG\n\ntrap 'kill $(jobs -p);
                        exit 0' TERM\n\n# track the current state of the ...
sudo systemctl start crio

如你所见,即使关闭了 CRI-O 服务,runc 也会显示容器的存在和它在文件系统中的位置,以备进一步调查。

进入容器内并查看容器的操作系统名称和版本

crictl exec bcaee950b412 cat /etc/os-release
# 显示如下内容
NAME="Anolis OS"
VERSION="8.4"

查看在容器内运行的进程列表,运行如下命令。

crictl exec -ti bcaee950b412 ps -ef
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 07:36 ?        00:00:00 /usr/sbin/init
root          20       1  0 07:36 ?        00:00:00 /usr/lib/systemd/systemd-journald
root          21       1  0 07:36 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache        22      21  0 07:36 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache        23      21  0 07:36 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache        24      21  0 07:36 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
apache        25      21  0 07:36 ?        00:00:00 /usr/sbin/httpd -DFOREGROUND
dbus          26       1  0 07:36 ?        00:00:00 /usr/bin/dbus-daemon --system --address=systemd: --nofork --n
root         244       0  0 08:32 pts/1    00:00:00 ps -ef

作为一种选择,你还可以使用 runc 命令 "exec" 进入一个容器。

runc exec -t e47b3a837aa3023c748c4c31a090266f014afba641a8ab9cfca31b065b4f2ddd ps -ef
UID        PID  PPID  C STIME TTY          TIME CMD
1000130+     1     0  0 Oct17 ?        00:38:16 /usr/bin/origin-web-console --audit-log-path=- -v=0 --config=/var/webconsole-config/webc
1000130+ 16541     0  0 15:48 pts/0    00:00:00 ps -ef
1000130+ 17518     1  0 Oct23 ?        00:00:00 [curl] <defunct>

如果容器内没有 ps 命令,runc 有 ps 选项,它具有显示容器内运行的进程的相同效果。

sudo runc ps e47b3a837aa3023c748c4c31a090266f014afba641a8ab9cfca31b065b4f2ddd

注意,runc 需要完整的容器 ID,而 crictl 只需要开头的几个唯一字符。

有了pod sandbox (沙箱) ID(从 crictl pods 输出),运行crictl inspectp来显示该pod沙箱的信息。

sudo crictl pods | grep 5a60ac777aaa0
5a60ac777aaa0  8 days ago  SANDBOX_READY registry-console-1-vktl6  default  0
sudo crictl inspectp 5a60ac777aaa0
{
  "status": {
    "id": "5a60ac777aaa055f14b998a9f2ced3e146b3cddbe270154abb75decd583bf879",
    "metadata": {
      "attempt": 0,
      "name": "registry-console-1-vktl6",
      "namespace": "default",
      "uid": "6af860cc-d20b-11e8-b094-525400535ba1"
    },
    "state": "SANDBOX_READY",
    "createdAt": "2022-04-14T08:53:22.828511516-04:00",
    "network": {
      "ip": "10.128.0.6"

要查看本地系统上 CRI-O 可用的镜像状态信息,请运行 crictl inspecti

crictl inspecti 25f8c7f3da61c
{
  "status": {
    "id": "25f8c7f3da61c2a810effe5fa779cf80ca171afb0adf94c7cb51eb9a8546629d",
    "repoTags": [
      "k8s.gcr.io/etcd:3.5.1-0"
    ],
    "repoDigests": [
      "k8s.gcr.io/etcd@sha256:05c1a3be66823dcaca55ebe17c3c9a60de7ceb948047da3e95308348325ddd5a",
      "k8s.gcr.io/etcd@sha256:64b9ea357325d5db9f8a723dcf503b5a449177b17ac87d69481e126bb724c263"
    ],
    "size": "293920249",
    "uid": {
      "value": "0"
    },
    "username": "",
    "spec": null
  }
}