本文致力于学习并梳理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
标签:常用,Containerd,v1,registry,io,containerd,镜像,cri From: https://www.cnblogs.com/yulinor/p/18263510link: 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
的账户,否则认证不通过无法拉取镜像。