Containerd-cri常用功能

本文致力于学习并梳理Containerd,信息来源均参考至官方Github,原文链接如下补充。

cri

工作架构

link: https://github.com/containerd/containerd/blob/main/docs/cri/architecture.md

img

  1. Kubelet 通过 CRI 运行时服务 API 调用 cri 插件来创建 pod;
  2. cri 创建 pod 的网络命名空间,然后使用 CNI 配置它;
  3. cri 使用containerd内部创建并启动一个特殊的暂停容器(沙箱容器),并将该容器放入pod的cgroup和命名空间中(为简洁起见,省略了步骤);
  4. Kubelet 随后通过 CRI 镜像服务 API 调用 cri 插件来拉取应用程序容器镜像;
  5. 如果节点上不存在镜像,cri 会进一步使用 containerd 来拉取镜像;
  6. 然后,Kubelet 通过 CRI 运行时服务 API 调用 cri,使用拉取的容器镜像在 pod 内创建并启动应用程序容器;
  7. cri最终使用containerd内部创建应用程序容器,将其放入pod的cgroup和命名空间中,然后启动pod的新应用程序容器。经过这些步骤,一个 pod 及其对应的应用程序容器就被创建并运行了。

Systemd Cgroup

link: https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/kubeadm/configure-cgroup-driver/
默认情况下containerdkubelet使用cgroupfs管理cgroup,但是仍然建议使用systemd管理。

开启方式

containerd开启systemd管理cgroup方式如下。

version = 2
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true

而在kubernetes中需要修正KubeletConfiguration的字段为cgroupDriver:"systemd";或者在版本 1.22 及更高版本中,如果用户没有在 KubeletConfiguration中设置cgroupDriver字段,kubeadm会将它设置为默认值 systemd;或者在Kubernetes v1.28中,启用KubeletCgroupDriverFromCRI特性门控结合支持RuntimeConfig CRI RPC的容器运行时,kubelet会自动从运行时检测适当的Cgroup 驱动程序,并忽略kubelet配置中的cgroupDriver设置。

多运行时

link: https://kubernetes.io/zh-cn/docs/concepts/containers/runtime-class/
基于外部灵活插件的特性,可以实现不同容器使用不同的容器运行时。首先需要containerd激活各种插件。

version = 2
[plugins."io.containerd.grpc.v1.cri".containerd]
default_runtime_name = "crun"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes]
# crun: https://github.com/containers/crun
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.crun]
runtime_type = "io.containerd.runc.v2"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.crun.options]
BinaryName = "/usr/local/bin/crun"
# gVisor: https://gvisor.dev/
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.gvisor]
runtime_type = "io.containerd.runsc.v1"
# Kata Containers: https://katacontainers.io/
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.kata]
runtime_type = "io.containerd.kata.v2"

然后kubernetes指定容器的runtime class即可。

apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: crun
handler: crun
---
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: gvisor
handler: gvisor
---
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: kata
handler: kata
apiVersion: v1
kind: Pod
spec:
runtimeClassName: crun

registry代理

link: https://github.com/containerd/containerd/blob/main/docs/hosts.md
link: https://github.com/containerd/containerd/blob/main/docs/cri/registry.md

配置镜像代理

镜像代理是指当下载某个镜像仓库的镜像时,如果有对应代理文件则轮训使用代理地址下载镜像,当代理地址均无法连接时则直链源镜像仓库。目前使用中发现,如果可以连接某个代理镜像地址,但发生了failed to read expected number of bytes: unexpected EOF错误时,不会切换下一个地址或直链源地址拉取镜像,而是会死磕当前代理地址导致镜像无法正常拉取、Pod无法启动。
指定镜像代理配置文件存放目录。

version = 2
[plugins."io.containerd.grpc.v1.cri".registry]
config_path = "/etc/containerd/certs.d"
version = 3
[plugins."io.containerd.cri.v1.images".registry]
config_path = "/etc/containerd/certs.d"

使用cri接口触发下载镜像会直接使用到镜像代理,而使用ctr时需要如下:ctr images pull --hosts-dir "/etc/containerd/certs.d" myregistry.io:5000/image_name:tag

镜像代理具体配置,其中文件夹命名规则需要满足[registry_host_name|IP address][:port];所有相关路径的配置可以是绝对路径,也可以是相对于hosts.toml的相对路径。

$ tree /etc/containerd/certs.d
/etc/containerd/certs.d
└── docker.io
└── hosts.toml

以下为hosts.toml

server = "https://docker.io"
[host."https://registry-1.docker.io"]
# 指定代理地址可执行的功能
## push只对于上游镜像地址,而非镜像源
## 解析名称为摘要(digst)的过程,必须由信任的主机完成
capabilities = ["pull", "resolve", "push"]
# 忽略主机名、tls验证
skip_verify = true
# 可以为一个或一组路径,用于与镜像仓库用户认证
ca = ["/etc/certs/test-1-ca.pem", "/etc/certs/special.pem"]
client = [["/etc/certs/client.cert", "/etc/certs/client.key"],["/etc/certs/client.pem", ""]]
# 如果代理镜像仓库不符合OCI规则,可以开启为true以解决请求路径问题
override_path = false
# 添加header
[host."https://registry-1.docker.io".header]
x-custom-2 = ["value1", "value2"]
x-custom-1-2 = "another custom header"

镜像密钥

对一个镜像仓库配置密钥有两种方式,一种是containerd本身的镜像密钥配置,一种是kubernetes使用cri接口的形式实现的。

registry.auth

首先,官方已将该方法指定为将废弃,但是直到新的密钥插件出现前该方式始终可用。

# explicitly use v2 config format
version = 2
# The registry host has to be a domain name or IP. Port number is also
# needed if the default HTTPS or HTTP port is not used.
[plugins."io.containerd.grpc.v1.cri".registry.configs."gcr.io".auth]
username = ""
password = ""
auth = ""
identitytoken = ""
# explicitly use v3 config format
version = 3
# The registry host has to be a domain name or IP. Port number is also
# needed if the default HTTPS or HTTP port is not used.
[plugins."io.containerd.cri.v1.images".registry.configs."gcr.io".auth]
username = ""
password = ""
auth = ""
identitytoken = ""

这种形式的字段与.docker/docker.json中的意义相同,但每次都需要systemctl restart containerd生效配置。

k8s imagePullSecrets

link: https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/pull-image-private-registry/
在k8s中可以创建存储了镜像仓库认证账户的secret,以imagePullSecrets功能挂载信息并使用该认证信息拉取镜像。
注意,imagePullSecrets要求匹配上镜像仓库,且只会使用提供的账户。假如建立了一个镜像仓库registry-a,该仓库以拉取式角色缓存(参见https://distribution.github.io/distribution/recipes/mirror/)docker.io镜像仓库运行,且配置了认证功能(registry-a账户与docker.io的账户不一样),K8s节点配置了前文的hosts.toml后,secrets应该存放registry-a的账户,而非docker.io的账户,否则认证不通过无法拉取镜像。

posted @   冰豆花  阅读(124)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示