containerd基本使用

containerd是一个容器运行时标准,也是k8s目前主流的运行时,本文介绍历史,存储方式,和oci

containerd历史

containerd是一个运行时,最开始集成在docker中拆解出来捐赠给cncf,同样被拆解出来的还有runc,以及根据docker镜像v2制定的oci镜像规范

  • 1.24版本之前k8s的kubelet内置了dokcer-shim插件负责和docker通讯,之后则只能通过cri
flowchart LR
  kubelet(kubelet)-->docker-shim(docker-shim)
  docker-shim(docker-shim)-->docker(docker)
  docker(docker)-->containers([containers])
  • 最开始cri是一个单独的进程,然后发现效率太差
flowchart LR
  kubelet(kubelet)--"grpc"-->cri-plugin(cri-plugin)

  cri-plugin(cri-plugin)--"grpc"-->containerd(containerd)

  containerd(containerd)--"exec"-->containerd-shim-runc(containerd-shim-runc)
  containerd-shim-runc(containerd-shim-runc)--"exec"-->runc(runc)
  runc(runc)--"exec"-->containers([containers])
  • 最后将cri已插件的形式集成到containerd中
flowchart LR
  kubelet(kubelet)--"grpc"-->cri-plugin(cri-plugin)

  subgraph containerd组件
  cri-plugin(cri-plugin)-->containerd(containerd)
  end

  containerd(containerd)--"exec"-->containerd-shim-runc(containerd-shim-runc)
  containerd-shim-runc(containerd-shim-runc)--"exec"-->runc(runc)
  runc(runc)--"exec"-->containers([containers])

架构

  • 全局架构

Alt text

  • containerd与kubelet

Alt text

  • 内部插件架构

Alt text

flowchart LR
  kubectl(kubctl)<-->api-server(api-server)

  subgraph master
  api-server(api-server)<-->etcd[(etcd)]
  api-server(api-server)<-->scheduler(scheduler)
  api-server(api-server)<-->controller-manage(controller-manage)
  end

  api-server(api-server)<-->kubelet(kubelet)
  kubelet(kubelet)<--"grpc"-->containerd(containerd)

  subgraph containerd组件
  containerd(containerd)<--"exec"-->containerd-shim-runc(containerd-shim-runc)
  containerd-shim-runc(containerd-shim-runc)<--"exec"-->runc(runc)
  runc(runc)<--"exec"-->containers(containers)
  end

  api-server(api-server)<-->kube-proxy(kube-proxy)
  kube-proxy(kube-proxy)<-->ipt(iptables/ipvs)

containerd下载安装

ctr使用

containerd可以使用的客户端有很多比如crictl,nerdctl命令

  • –address value, -a value 指定 containerd’s GRPC server,默认 /run/containerd/containerd.sock

  • 查看K8S命名空间下的镜像,-n指定namespace

1
ctr -n k8s.io images ls
  • 查看所有namespace
1
ctr ns ls
  • 下载镜像
1
ctr images pull docker.io/library/alpine:3.18.3
  • 创建 container
1
ctr c create docker.io/library/alpine:3.18.3 alpine
  • 查看
1
ctr c ls
  • 后台启动
1
ctr t start -d alpine
  • 查看container
1
ctr t ls
  • 查看 k8s 中正在运行的容器
1
ctr -n k8s.io task ls
  • 打tag
1
ctr images tag docker.io/library/alpine:3.18.3 <仓库>/alpine:3.18.3
  • push 上传镜像
1
ctr images push <镜像>
  • 查看插件
1
ctr plugin ls
  • 打印containerd默认配置
1
containerd config default

OCI镜像格式

  • 各个类型的关系

oci镜像格式的mediaType参考这里

Alt text

类型mediaType

所有例子基于alpine:3.18.3

index
  • 最顶级的类型主要存放各个操作系统和平台对应的manifest类型
例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
{
"manifests": [
{
"digest": "sha256:c5c5fda71656f28e49ac9c5416b3643eaa6a108a8093151d6d1afc9463be8e33",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "amd64",
"os": "linux"
},
"size": 528
},
{
"digest": "sha256:f748290eb66ad6f938e25dd348acfb3527a422e280b7547b1cdfaf38d4492c4b",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "arm",
"os": "linux",
"variant": "v6"
},
"size": 528
},
{
"digest": "sha256:16e86b2388774982fbdf230101a72201691b1f97cb0066c2099abf30dd7e6d59",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "arm",
"os": "linux",
"variant": "v7"
},
"size": 528
},
{
"digest": "sha256:b312e4b0e2c665d634602411fcb7c2699ba748c36f59324457bc17de485f36f6",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "arm64",
"os": "linux",
"variant": "v8"
},
"size": 528
},
{
"digest": "sha256:1fd62556954250bac80d601a196bb7fd480ceba7c10e94dd8fd4c6d1c08783d5",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "386",
"os": "linux"
},
"size": 528
},
{
"digest": "sha256:c75ede79e457d6454bca6fc51967a247a4b9daff9f31197cfbef69b1a651cada",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "ppc64le",
"os": "linux"
},
"size": 528
},
{
"digest": "sha256:5febc00b4d2a84af2a077bc34ea90659b6570110a54253f19c5dca8164b1dbf6",
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"platform": {
"architecture": "s390x",
"os": "linux"
},
"size": 528
}
],
"mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
"schemaVersion": 2
}
manifest
  • 主要定义镜像相关的清单,主要包含config类型和layers类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"schemaVersion": 2,
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"config": {
"mediaType": "application/vnd.docker.container.image.v1+json",
"size": 1471,
"digest": "sha256:7e01a0d0a1dcd9e539f8e9bbd80106d59efbdf97293b3d38f5d7a34501526cdb"
},
"layers": [
{
"mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip",
"size": 3401613,
"digest": "sha256:7264a8db6415046d36d16ba98b79778e18accee6ffa71850405994cffa9be7de"
}
]
}
config
  • 记录镜像的历史,启动参数环境变量以及最重要的解压后的层等信息
例子
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
{
"architecture": "amd64",
"config": {
"Hostname": "",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh"
],
"Image": "sha256:39dfd593e04b939e16d3a426af525cad29b8fc7410b06f4dbad8528b45e1e5a9",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": null
},
"container": "ba09fe2c8f99faad95871d467a22c96f4bc8166bd01ce0a7c28dd5472697bfd1",
"container_config": {
"Hostname": "ba09fe2c8f99",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"#(nop) ",
"CMD [\"/bin/sh\"]"
],
"Image": "sha256:39dfd593e04b939e16d3a426af525cad29b8fc7410b06f4dbad8528b45e1e5a9",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"created": "2023-08-07T19:20:20.894140623Z",
"docker_version": "20.10.23",
"history": [
{
"created": "2023-08-07T19:20:20.71894984Z",
"created_by": "/bin/sh -c #(nop) ADD file:32ff5e7a78b890996ee4681cc0a26185d3e9acdb4eb1e2aaccb2411f922fed6b in / "
},
{
"created": "2023-08-07T19:20:20.894140623Z",
"created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\"]",
"empty_layer": true
}
],
"os": "linux",
"rootfs": {
"type": "layers",
"diff_ids": [
"sha256:4693057ce2364720d39e57e85a5b8e0bd9ac3573716237736d6470ec5b7b7230"
]
}
}
layer
  • 记录压缩过后的层sha256信息,是真正层的内容一般采用tar.gz压缩
下载保存oci镜像格式

使用skopeo可以和方便的保存到本地,之前介绍过使用skopeo同步docker镜像

1
skopeo copy docker://docker.io/alpine:3.18.3 oci:alpine-oci --override-os linux --override-arch amd64
1
2
3
4
5
6
7
8
9
10
11
12
❯ tree                                                                   
.
├── blobs
│ └── sha256
│ ├── 7264a8db6415046d36d16ba98b79778e18accee6ffa71850405994cffa9be7de
│ ├── 913cf3a39d377faf89ed388ad913a318a390488c9f34c46e43424795cdabffe8
│ └── cf4e5bc0709f07284518b287f570c47bdb2afc14b8ae4f14077e9ff810a0120b
├── index.json
└── oci-layout

3 directories, 5 files

Containerd存储方式

目录结构
  • 其目录命名格式以类型.id的格式

  • 有些目录根据插件并没有显示

  • 默认数据存放在/var/lib/containerd/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
tree -L 2
.
├── io.containerd.content.v1.content # 存放从hub上下载的源文件
│   ├── blobs # 存放下载完毕的文件
│   └── ingest # 存放下载未完成的文件
├── io.containerd.grpc.v1.cri # cri插件存放的文件
│   ├── containers # cri创建的容器
│   └── sandboxes
├── io.containerd.metadata.v1.bolt # 存放containerd的数据文件
│   └── meta.db
├── io.containerd.runtime.v1.linux
├── io.containerd.runtime.v2.task # 运行的容器
│   └── k8s.io # namespace
├── io.containerd.snapshotter.v1.native
│   └── snapshots
├── io.containerd.snapshotter.v1.overlayfs # 存放解压过后的文件
│   ├── metadata.db # 解压数据库文件
│   └── snapshots # 解压的文件
└── tmpmounts # 临时挂载目录

15 directories, 2 files

参考

https://blog.frognew.com/2021/04/relearning-container-01.html