Containerd-cri常用功能
本文致力于学习并梳理Containerd,信息来源均参考至官方Github,原文链接如下补充。
cri
工作架构
link: https://github.com/containerd/containerd/blob/main/docs/cri/architecture.md
- Kubelet 通过 CRI 运行时服务 API 调用 cri 插件来创建 pod;
- cri 创建 pod 的网络命名空间,然后使用 CNI 配置它;
- cri 使用containerd内部创建并启动一个特殊的暂停容器(沙箱容器),并将该容器放入pod的cgroup和命名空间中(为简洁起见,省略了步骤);
- Kubelet 随后通过 CRI 镜像服务 API 调用 cri 插件来拉取应用程序容器镜像;
- 如果节点上不存在镜像,cri 会进一步使用 containerd 来拉取镜像;
- 然后,Kubelet 通过 CRI 运行时服务 API 调用 cri,使用拉取的容器镜像在 pod 内创建并启动应用程序容器;
- cri最终使用containerd内部创建应用程序容器,将其放入pod的cgroup和命名空间中,然后启动pod的新应用程序容器。经过这些步骤,一个 pod 及其对应的应用程序容器就被创建并运行了。
Systemd Cgroup
link: https://kubernetes.io/zh-cn/docs/tasks/administer-cluster/kubeadm/configure-cgroup-driver/
默认情况下containerd
,kubelet
使用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
的账户,否则认证不通过无法拉取镜像。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!