使用containerd容器运行时的Kubernetes集群如何配置访问http私有仓库(insecure-registries)?

在使用docker容器运行时,配置访问http私有仓库的方法较为简单,类似如下即可:

shell 复制代码
#  cat /etc/docker/daemon.json 
{
  "insecure-registries": ["192.168.0.4:5500"]
}

而当Kubernetes使用containerd时,其配置文件就相对复杂了。总的来说,有两种方式可以实现http仓库的访问。

方法一:registry.configs

修改/etc/containerd/config.toml中如下位置,默认配置为:

复制代码
    [plugins."io.containerd.grpc.v1.cri".registry]
      config_path = ""

      [plugins."io.containerd.grpc.v1.cri".registry.auths]

      [plugins."io.containerd.grpc.v1.cri".registry.configs]

      [plugins."io.containerd.grpc.v1.cri".registry.headers]

      [plugins."io.containerd.grpc.v1.cri".registry.mirrors]

例如添加私有仓库http://192.168.0.4:5500,则添加如下配置:

复制代码
    [plugins."io.containerd.grpc.v1.cri".registry]
      config_path = ""

      [plugins."io.containerd.grpc.v1.cri".registry.auths]

      [plugins."io.containerd.grpc.v1.cri".registry.configs]
        [plugins."io.containerd.grpc.v1.cri".registry.configs."192.168.0.4:5500".tls]
          insecure_skip_verify = true
      [plugins."io.containerd.grpc.v1.cri".registry.headers]

      [plugins."io.containerd.grpc.v1.cri".registry.mirrors]
        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."192.168.0.4:5500"]
          endpoint = ["http://192.168.0.4:5500"]

修改完成后重启containerd

shell 复制代码
systemctl restart containerd

查看最新配置

shell 复制代码
containerd config dump

测试镜像拉取:

shell 复制代码
#  crictl pull 192.168.0.4:5500/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.3.0
Image is up to date for sha256:69547dffc18fcddd4f41b7696a046ad7252ceeabce944106da94fa4bfb3c6b24

如需配置仓库认证信息,可参考:https://github.com/containerd/containerd/blob/main/docs/cri/registry.md

按照文档的说法,这种配置方式只支持到v1.6,目前我们的生产环境最高版本也是1.6,因此尚未测试这种方式在v1.7是否可行。

方法二:hosts.toml

这种方式较为推荐,因为它可以做到不同仓库的配置文件分开管理,首先我们将默认配置文件修改为(即修改config_path):

复制代码
    [plugins."io.containerd.grpc.v1.cri".registry]
      config_path = "etc/containerd/certs.d"

      [plugins."io.containerd.grpc.v1.cri".registry.auths]

      [plugins."io.containerd.grpc.v1.cri".registry.configs]

      [plugins."io.containerd.grpc.v1.cri".registry.headers]

      [plugins."io.containerd.grpc.v1.cri".registry.mirrors]

接着创建配置文件夹:

shell 复制代码
cd /etc/containerd/
mkdir certs.d

然后创建仓库配置文件夹(以下也称主机命名空间namespace)及配置文件hosts.toml,文件夹名称为仓库域名或者[IP address][:port],本例中为:

复制代码
mkdir certs.d/192.168.0.4:5500
touch certs.d/192.168.0.4:5500/hosts.toml

创建完成后文件树如下:

shell 复制代码
#  tree /etc/containerd/certs.d
/etc/containerd/certs.d
└── 192.168.0.4:5500
    └── hosts.toml

hosts.toml写入如下配置:

复制代码
#  cat /etc/containerd/certs.d/192.168.0.4\:5500/hosts.toml 
server = "http://192.168.0.4:5500"

[host."http://192.168.0.4:5500"]
  capabilities = ["pull", "resolve", "push"]
  skip_verify = true

重启containerd,并测试镜像拉取:

shell 复制代码
#  systemctl restart containerd

#  crictl pull 192.168.0.4:5500/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.3.0
Image is up to date for sha256:69547dffc18fcddd4f41b7696a046ad7252ceeabce944106da94fa4bfb3c6b24

hosts.toml文件详解

hosts.toml中指定的文件必须为绝对路径或相对于hosts.toml的相对路径

  • server字段
    该主机命名空间的默认服务器地址,也即Registry
  • host字段
    Mirror,镜像地址(serverhost的关系,就是Registrymirror的关系,例如Docker HubRegistry,而国内的镜像源如阿里镜像源则是Mirror),如果配置了host,当客户端试图拉取或推送镜像时,会根据配置文件中定义的顺序和能力去尝试这些镜像服务器。
  • capabilities字段
    表示该主机被信任执行的一系列操作集合。
  • skip_verify
    表示是否跳过证书链验证,默认为false,即不跳过验证。
  • ca字段
    指定ca证书路径或路径集合。
  • client字段
    指定客户端证书或证书集合。
  • header字段
    指定请求header,由一系列键值对组成
  • override_path字段
    表示主机的API根路径是在URL路径中定义的,而不是通过API规范定义的。这个参数主要用于与那些不遵循OCI(Open Container Initiative)标准、缺少/v2前缀的非合规Registry配合使用。在Docker或其他容器引擎与Registry交互时,默认情况下会按照OCI规范去访问Registry API,即请求通常以 /v2/ 开头,例如:https://registry.example.com/v2/<image>/<tag>。然而,某些非标准的Registry可能并未遵循这一规范,其API根路径可能直接是注册表名之后的某个自定义路径。在这种情况下,通过将 override_path 设置为 true 并提供相应的路径,客户端就可以正确地定位到这些非标准Registry的API根路径,以实现与它们的有效通信。例如,如果API根路径是 https://registry.example.com/custom/api,则可以通过配置 override_path 来适应这种特殊格式。

一个示例配置文件如下:

复制代码
server = "https://registry-1.docker.io"

[host."https://mirror.registry"]
  capabilities = ["pull"]
  ca = "/etc/certs/mirror.pem"
  skip_verify = false
  [host."https://mirror.registry".header]
    x-custom-2 = ["value1", "value2"]

[host."https://mirror-bak.registry/us"]
  capabilities = ["pull"]
  skip_verify = true

[host."http://mirror.registry"]
  capabilities = ["pull"]

[host."https://test-1.registry"]
  capabilities = ["pull", "resolve", "push"]
  ca = ["/etc/certs/test-1-ca.pem", "/etc/certs/special.pem"]
  client = [["/etc/certs/client.cert", "/etc/certs/client.key"],["/etc/certs/client.pem", ""]]

[host."https://test-2.registry"]
  client = "/etc/certs/client.pem"

[host."https://test-3.registry"]
  client = ["/etc/certs/client-1.pem", "/etc/certs/client-2.pem"]

[host."https://non-compliant-mirror.registry/v2/upstream"]
  capabilities = ["pull"]
  override_path = true

注意一:两种方法不能混用

笔者在撰文时使用的测试环境恰好碰到该问题,因此也顺手记录。当两者混用时,即有如下配置:

复制代码
    [plugins."io.containerd.grpc.v1.cri".registry]
      config_path = "etc/containerd/certs.d"

      [plugins."io.containerd.grpc.v1.cri".registry.auths]

      [plugins."io.containerd.grpc.v1.cri".registry.configs]
        [plugins."io.containerd.grpc.v1.cri".registry.configs."192.168.0.4:5500".tls]
          insecure_skip_verify = true
      [plugins."io.containerd.grpc.v1.cri".registry.headers]

      [plugins."io.containerd.grpc.v1.cri".registry.mirrors]
        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."192.168.0.4:5500"]
          endpoint = ["http://192.168.0.4:5500"]

此时systemctl restart containerd,然后测试拉取镜像,会有如下报错:

复制代码
#  crictl pull 192.168.0.4:5500/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.3.0
FATA[0000] validate service connection: validate CRI v1 image API for endpoint "unix:///run/containerd/containerd.sock": rpc error: code = Unimplemented desc = unknown service runtime.v1.ImageService 

对此问题进行排查,检查节点状态发现已NotReady

shell 复制代码
#  kubectl get node
NAME                  STATUS     ROLES           AGE   VERSION
kcs-zrjtest-m-c8ggl   NotReady   control-plane   29h   v1.25.7-eki.3.0.0
kcs-zrjtest-m-mqtb5   Ready      control-plane   29h   v1.25.7-eki.3.0.0
kcs-zrjtest-m-tbqmq   Ready      control-plane   29h   v1.25.7-eki.3.0.0
kcs-zrjtest-s-h8gvl   Ready      <none>          29h   v1.25.7-eki.3.0.0
kcs-zrjtest-s-k7n9f   Ready      <none>          29h   v1.25.7-eki.3.0.0
kcs-zrjtest-s-q6tbt   Ready      <none>          29h   v1.25.7-eki.3.0.0
kcs-zrjtest-s-sczsh   Ready      <none>          29h   v1.25.7-eki.3.0.0
kcs-zrjtest-s-v9svm   Ready      <none>          29h   v1.25.7-eki.3.0.0

检查节点kubelet日志,有如下报错:

shell 复制代码
#  journalctl -u kubelet -f
Apr 10 17:27:31 kcs-zrjtest-m-c8ggl kubelet[15698]: E0410 17:27:31.681528   15698 remote_runtime.go:391] "ListPodSandbox with filter from runtime service failed" err="rpc error: code = Unimplemented desc = unknown service runtime.v1.RuntimeService" filter="nil"
Apr 10 17:27:31 kcs-zrjtest-m-c8ggl kubelet[15698]: E0410 17:27:31.681561   15698 kuberuntime_sandbox.go:297] "Failed to list pod sandboxes" err="rpc error: code = Unimplemented desc = unknown service runtime.v1.RuntimeService"
Apr 10 17:27:31 kcs-zrjtest-m-c8ggl kubelet[15698]: E0410 17:27:31.681571   15698 generic.go:205] "GenericPLEG: Unable to retrieve pods" err="rpc error: code = Unimplemented desc = unknown service runtime.v1.RuntimeService"

问题指向容器运行时,检查containerd日志:

shell 复制代码
Apr 10 17:23:32 kcs-zrjtest-m-c8ggl containerd[116927]: time="2024-04-10T17:23:32.560557543+08:00" level=warning msg="failed to load plugin io.containerd.grpc.v1.cri" error="invalid plugin config: `mirrors` cannot be set when `config_path` is provided"

即当指定了config_path时,是不能再配置mirrors的([plugins."io.containerd.grpc.v1.cri".registry.mirrors])。

解决办法也即方法一和方法二只保留其一。

注意二:这两种方法是用来配置cri的,因此不适用于ctrnerdctl命令

有些同学在配置完成后,使用ctrnerdctl命令进行拉取测试,会发现测试无效:

shell 复制代码
#  ctr images pull 192.168.0.4:5500/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.3.0
INFO[0000] trying next host                              error="failed to do request: Head \"https://192.168.0.4:5500/v2/registry.k8s.io/ingress-nginx/kube-webhook-certgen/manifests/v1.3.0\": http: server gave HTTP response to HTTPS client" host="192.168.0.4:5500"
ctr: failed to resolve reference "192.168.0.4:5500/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.3.0": failed to do request: Head "https://192.168.0.4:5500/v2/registry.k8s.io/ingress-nginx/kube-webhook-certgen/manifests/v1.3.0": http: server gave HTTP response to HTTPS client

这是因为以上配置是为cri准备的( [plugins."io.containerd.grpc.v1.cri".registry]),因此只适用于cri客户端如crictlkubectl,上文中也是使用crictl进行的测试。

如果使用ctr测试,可以使用--hosts-dir指定配置文件:

复制代码
ctr images pull --hosts-dir "/etc/containerd/certs.d" 192.168.0.4:5500/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.3.0

或者直接使用--plain-http参数指定使用http

复制代码
ctr images pull --plain-http 192.168.0.4:5500/registry.k8s.io/ingress-nginx/kube-webhook-certgen:v1.3.0
相关推荐
duration~1 小时前
K8S自定义CRD
容器·贪心算法·kubernetes
程序员 小柴2 小时前
docker的与使用
java·docker·eureka
ghostwritten2 小时前
Docker Registry Clean
运维·docker·容器
宋冠巡3 小时前
Windows安装Docker(Docker Desktop)
windows·docker·容器
小马爱打代码4 小时前
Kubernetes 中部署 Ceph,构建高可用分布式存储服务
分布式·ceph·kubernetes
阿噜噜小栈4 小时前
最新国内可用的Docker镜像加速器地址收集
运维·笔记·docker·容器
云上艺旅4 小时前
K8S学习之基础六十八:Rancher创建deployments资源
学习·云原生·容器·kubernetes·rancher
rider1894 小时前
【4】搭建k8s集群系列(二进制部署)之安装master节点服务(kube-apiserver)
云原生·容器·kubernetes
海鸥816 小时前
podman和与docker的比较 及podman使用
docker·容器·podman
GreenMountainEcho12 小时前
Kubernetes 入门篇之 Node 安装与部署
云原生·容器·kubernetes