containerd介绍
- 早在2016年3月,Docker 1.11的Docker Engine里就包合了containerd,而现在则是把containerd从Docker Engine里彻底剥离出来, 为一个独立的开源项目独立发展,目标是提供一个更加开放、稳定的容器运行基础没施。和原先包合在Docker Engine里containerd相比,独立的containerd将具有更多的功能,可以涵盖整个容品运行时管理的所有需求。
- containerd并不是直接面向最终用户的,而是主要用于集成到更上层的系统里,比如Swarm, Kubernetes, Mesos等容器编排系统。
- 每个containerd只负责一台机器,Pul镜像,对容器的操作(启动、停止等),网络,存储都是由containerd完成。具体运行容器由runC 负责,实际上只要是符合OCI规范的容器都可以支持。
- containerd以Daemon的形式运行在系统上,通过暴露底层的gRPC API,上层系统可以通过
这些AP/管理机器上的容器。- 对于容器编排服务来说,运行时只需要使用containerd+runC,更加轻量,容易管理
- 独立之后containerd的特性演进可以和Docker Ergine分开,专注容器运行时管理,可以更稳定,containerd是由Docker开发的容器运行时,已经在生产环境中得到了广泛的验证和应用。它经过长时间的发展和优化,可以满足大规模集群的运行需求。
- 13年docker把核心技术 libcontainer捐献给OCI 并改名为runC
- 15年docker把核心依赖containerd 捐献给CNCF
- 20年k8s1.20之后不再支持docker,因为还需要维护一套docker-shim(垫片)去从k8s容器运行时接口(CRI)转化翻译为docker的API
- 很多的容器管理工具都希望能被k8s用到,所以k8s制定了标准化的CRI,只要符合都能用
- containerd可以无缝衔接k8s,所以k8s之后的容器运行时(CRI)就是containerd
- containerd 采用C/S架构
- containerd 从容器启动 停止 删除的时间都很快于其他
YUM方式安装
wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum install -y containerd.io
配置containerd
containerd config default > /etc/containerd/config.toml
vi /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc]
...
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
SystemdCgroup = true #改这
[plugins."io.containerd.grpc.v1.cri"]
sandbox_image = "registry.cn-shanghai.aliyuncs.com/yanghl/pause:3.2"
配置crictl(crictl 工具需要知道如何连接到后台的容器运行时)
cat > /etc/crictl.yaml <<EOF
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
EOF
启动containerd
systemctl enable containerd --now
#验证
ctr version
ctr images ls
ctr containerd ls
二进制安装(找名字长的cri-containerd-cni-xxx)
1.下载安装包
Containerd有两种安装包:
第一种是 containerd-xxx,这种包用于单机测试没问题,不包含runC,需要提前安装。
第二种是 cri-containerd-cni-xxxx,包含runc和k8s里的所需要的相关文件。k8s集群里需要用到此包。虽然包含runC,但是依赖系统中的seccomp(安全计算模式,是一种限制容器调用系统资源的模式。)
wget https://gh.rainbond.cc/https://github.com/containerd/containerd/releases/download/v1.6.27/cri-containerd-cni-1.6.27-linux-amd64.tar.gz
tar -xzvf cri-containerd-cni-1.6.27-linux-amd64.tar.gz
1.1解压如下所示三个目录
查看etc目录,主要为containerd服务管理配置文件及cni虚拟网卡配置文件
查看opt目录,主要为gce环境中使用containerd配置文件及cni插件
查看usr目录,主要为containerd运行时文件,包含runc
2.移动下载的二进制到指定位置
2.1 containerd
cp usr/local/bin/containerd /usr/local/bin/
cp etc/systemd/system/containerd.service /usr/lib/systemd/system/containerd.service
#建议usr/local/bin/* 都复制到/usr/local/bin/ ,不然容器启动的时候会找不到containerd-shim- runc-v2(垫片),这也就是为什么下面说runC真正的去运行容器
/etc/systemd/system/ 目录中的服务文件通常是管理员自定义的或者针对特定需求定制的服务,而
/usr/lib/systemd/system/ 目录中的服务文件则是由软件包提供的默认服务文件。
2.2生成containerd配置文件
这个配置文件中注意沙箱的镜像和镜像仓库
containerd --help
mkdir /etc/containerd
containerd config default > /etc/containerd/config.toml
systemctl enable containerd --now
单独安装RUNC
真正的去运行容器的是runC
由于二进制包中提供的runC默认需要系统中安装seccomp支持,需要单独安装,且不同版本runC对seccomp版本要求一致,所以建议单独下载runC 二进制包进行安装,里面包含了seccomp模块支持。
wget https://gh.rainbond.cc/https://github.com/opencontainers/runc/releases/download/v1.1.12/runc.amd64
#install: 这是一个Unix命令,用于复制文件并设置其属性
install -m 755 runc.amd64 /usr/local/sbin/runc
runc -v
复制ctr命令
cp usr/local/bin/ctr /usr/bin/
#查看containerd版本
ctr version
containerd容器镜像管理
- docker使用docker images命令管理镜像
- 单机containerd使用ctr images命令管理镜像,containerd本身的CLI工具
- k8s中containerd使用crictl images命令管理镜像Kubernetes社区的专用CLI工具
ctr i ls
# 引用地址REF 类型TYPE DIGEST描述哈希值 大小SIZE 支持的平台PLATFROMS 标签LABELS
ctr i pull --all-platforms docker.io/library/nginx:alpine
#因为containerd没有像Docker CLI那样的默认仓库设置,下载镜像需要指定完整---仓库地址/命令空间/镜像名:tag
ctr i pull --platforms linux/amd64 docker.io/library/nginx:alpine
ctr i rm/remove/delete/del 仓库地址/命令空间/镜像名:tag
- –all-platforms 所有平台, 不加根据当前系统CPU架构来下载
镜像挂载查看镜像内容
mkdir /mnt/mount1
ctr i mount 仓库地址/命令空间/镜像名:tag /mnt/mount1
ls /mnt/mount1
umount /mnt/mount1
镜像导出/入
ctr i export [--all-platforms] 导出名 仓库地址/命令空间/镜像名:tag
ctr i import 导出名
镜像tag
ctr i tag 仓库地址/命令空间/镜像名:tag 仓库地址/命令空间/镜像名:tag
ctr i check 仓库地址/命令空间/镜像名:tag
containerd容器管理
#创建静态容器,并没有运行
ctr c create 仓库地址/命令空间/镜像名:tag 容器名称
ctr c ls
ctr taks/t/tasks ls
ctr c info 容器名称
#动态容器
ctr run --net-host 仓库地址/命令空间/镜像名:tag 容器名称
#复制安装时候的垫片
cp usr/local/bin/containerd-shim-runc-v1 /usr/bin/
ctr task start -d 容器名称
ctr taks/t/tasks ls
进入容器
ctr task exec --exec-id $RANDOM(或者手动指定) -t 容器名称 /bin/bash
暂停/恢复容器
ctr task pause 容器名称
ctr task ls
ctr task resume 容器名称
停止/删除/启动容器
ctr task kill 容器名称
ctr task rm 容器名称
ctr task start -d 容器名称
删除容器
先停止动态容器变为静态的,在删除tasks,最后删除容器
ctr task ls
ctr task kill 容器名称
ctr c rm 容器名称
containerd私有仓库
修改/etc/containerd/config.toml后重启containerd
vim /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".registry]
[plugins."io.containerd.grpc.v1.cri".registry.configs]
[plugins."io.containerd.grpc.v1.cri".registry.configs."your-private-registry.com".auth]
username = "your-username"
password = "your-password"
[plugins."io.containerd.grpc.v1.cri".registry.configs."your-private-registry.com".tls]
ca_file = "/path/to/ca.pem"
推送到镜像仓库
ctr i tag 旧的镜像名称 新的的镜像名称
#告诉使用http协议
ctr i pull --plain-http 新的的镜像名称
containerd Namespace管理
containerd中namespace的作用是隔离运行的容器,实现运行多个容器
Docker的namespace和containerd的namespace在原理上是相似的,因为两者都基于Linux内核的namespace技术来实现容器的隔离性。但是,在Docker和containerd这两个不同的容器运行时环境中,namespace的具体实现和使用方式可能存在一些差异。
在Docker中,namespace用于隔离容器内部进程对系统资源的访问,包括进程ID(PID)、网络栈、挂载的文件系统、主机名等1。Docker会自动为每个容器创建和管理这些namespace,使得容器内部的进程只能看到与其相关的资源,而无法看到主机或其他容器的资源2。
在containerd中,namespace的概念同样用于隔离容器,但containerd更加专注于底层的容器运行时管理。它提供了更底层的API和工具,使得用户可以更直接地管理Linux的namespace和其他容器化功能2。containerd中的namespace允许用户为每个容器或容器组创建一个独立的命名空间,以实现更好的隔离性和管理性2。
在Kubernetes(k8s)中,使用Docker和containerd作为容器运行时在调用链和组件数量上存在差异。当使用Docker时,调用链较长,涉及到多个组件(如dockershim、dockerd、containerd等)2。而使用containerd时,调用链更短,组件更少,因此更加稳定且占用节点资源更少2。此外,containerd在Kubernetes中引入了命名空间(namespace)的概念,使得每个镜像和容器都在各自的命名空间下可见,提供了更好的隔离性和管理性2。
总的来说,Docker和containerd都使用Linux内核的namespace技术来实现容器的隔离性,但在具体实现和使用方式上可能存在差异。这些差异主要体现在对namespace的管理方式、调用链的长度和组件数量、以及与其他工具的集成方式等方面
namespace 命令
ctr --help
ctr namespace/ns ls
ctr namespace/ns create xxx
ctr ns rm xxx
ctr -n xxx image ls
ctr -n xxx image pull 镜像名称
ctr -n xxx c create 镜像名称
ctr -n xxx c ls
containerd 网络管理
默认containerd 管理的容器没有外网 只有lo网卡,需添加网络插件,使用容器可以连接外网(CNI)
CNI源码下载安装
plugins源码下载安装
下载
mkdir -p ncontainerd/cni-plugins && cd ncontainerd
wget https://gh.rainbond.cc/https://github.com/containernetworking/cni/archive/refs/tags/v1.1.1.tar.gz
tar -xvf v1.1.1.tar.gz
wget https://gh.rainbond.cc/https://github.com/containernetworking/plugins/releases/download/v1.1.1/cni-plugins-linux-amd64-v1.1.1.tgz
tar -xvf cni-plugins-linux-amd64-v1.1.1.tgz -C cni-plugins
CNI网络配置
/etc/cni/net.d/xxx.conf
cat > /etc/cni/net.d/10-mynet.conf <<EOF
{
"cniVersion": "1.0.0",
"name": "mynet",
"type": "bridge",
"bridge": "cni0",
"isGateway": true,
"ipMasq": true,
"ipam": {
"type": "host-local",
"subnet": "10.66.0.0/16",
"routes": [ { "dst": "0.0.0.0/0" }]
}
}
EOF
cat > /etc/cni/net.d/99-loopback.conf <<EOF
{
"cniVersion": "1.0.0",
"name": "lo",
"type": "loopback"
}
EOF
生成CNI网络
jq命令下载
wget https://gh.rainbond.cc/https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-amd64
install -m 755 jq-linux-amd64 /usr/bin/jq
必须在scripts目录中执行,需要依赖exec-plugins.sh文件,再次进入scripts目录
执行脚本文件,基于/etc/cni/net.d/目录中的*.conf配置文件生成容器网络
注意下面的cni-plugins的位置路径要写对
cd cni-1.1.1/script
CNI_PATH=/root/containerd/ncontainerd/cni-plugins ./priv-net-run.sh echo "okokok"
#ip a 看到cni0网桥生成
#有了这个网桥 所有containerd管理的容器都可以连接到这个cni0上来,来实现与主机或之外的网络通信
#ip route 可以看到路由也出现了
配置containerd容器配置网络功能
ctr ns create yhl
ctr -n yhl run -d docker.io/library/busybox:latest test1
ctr -n yhl task ls
ctr -n yhl task exec --exec-id $RANDOM -t test1 sh
#此时 ip a 看到的没有ip 也没有路由
获取容器进程ID及网络命名空间
ctr -n yhl task ls
#/proc/pid/ns/net 就是下面的$netpaht PID就是下面的$pid
为指定的容器添加网络配置
CNI_PATH=/root/containerd/ncontainerd/cni-plugins ./exec-plugins.sh add $pid $netpath
ctr -n yhl task exec --exec-id $RANDOM -t test1 sh
# ip a 就可以看到给分配了网络地址 也有了路由
echo 123>/tmp/index.html
wget -O - -q 127.0.0.1
#或者退出到容器外访问也是可以的
wget -O - -q 10.66.0.3
与其他containerd容器共享命名空间
ctr -n yhl c create --with-ns "pid:/proc/12870/ns/pid" docker.io/library/busybox:latest test3
ctr -n yhl task start -d test3
ctr -n yhl task exec --exec-id $RANDOM -t test3 sh
#ps 可以看到多了一个sh进程
containerd容器持久化存储
scr为宿主机所在目录
dst为容器所在目录
bind模式 它的主要作用是将一个已存在的目录树挂载到另一个挂载点,目录的重复挂载,修改只读文件内容
ctr -n yhl c create docker.io/library/busybox:latest test4 --mount type=bind,src=/tmp,dst=/hostdir,options=rbind:rw
ctr -n yhl task exec --exec-id $RANDOM -t test4 sh
#通过写文件到这两任意目录看另一个目录是否也有