目 录CONTENT

文章目录

containerd入门

简中仙
2023-01-18 / 0 评论 / 0 点赞 / 129 阅读 / 0 字 / 正在检测是否收录...
温馨提示:
本文最后更新于2024-02-07,若内容或图片失效,请留言反馈。 本文如有错误或者侵权的地方,欢迎您批评指正!

一、Containerd介绍

早在2016年3月,Docker 1.11的Docker Engine里就包含了containerd,而现在则是把containerd从Docker Engine里彻底剥离出来,作为一个独立的开源项目独立发展,目标是提供一个更加开放、稳定的容器运行基础设施。和原先包含在Docker Engine里containerd相比,独立的containerd将具有更多的功能,可以涵盖整个容器运行时管理的所有需求。

containerd并不是直接面向最终用户的,而是主要用于集成到更上层的系统里,比如Swarm, Kubernetes, Mesos等容器编排系统。

containerd以Daemon的形式运行在系统上,通过暴露底层的gRPC API,上层系统可以通过这些API管理机器上的容器。

每个containerd只负责一台机器,Pull镜像,对容器的操作(启动、停止等),网络,存储都是由containerd完成。具体运行容器由runC负责,实际上只要是符合OCI规范的容器都可以支持。

对于容器编排服务来说,运行时只需要使用containerd+runC,更加轻量,容易管理。

独立之后containerd的特性演进可以和Docker Engine分开,专注容器运行时管理,可以更稳定。

1、Containerd前世今生

2013年docker公司在推出docker产品后,由于其对全球技术产生了一定的影响力,Google公司明显感觉到自己公司内部所使用的Brog系统江湖地位受到的威胁,希望Docker公司能够与自己联合打造一款开源的容器运行时作为Docker核心依赖,但Docker公司拒绝了;接着Google公司联合RedHat、IBM等公司说服Docker公司把其容器核心技术libcontainer捐给中立社区(OCI,Open Container Intiative),并更名为runC。

为了进一步遏制Docker在未来技术市场影响力,避免在容器市场上Docker一家独大,Google公司带领导RedHat、IBM等成立了CNCF(Cloud Native Computing Fundation)基金会,即云原生计算基金会。CNCF的目标很明确,既然在容器应用领域无法与Docker相抗衡,那就做Google更有经验的技术市场------大规模容器编排应用场景,Google公司把自己内部使用的Brog系统开源------Kubernetes,也就是我们今天所说的云原生技术生态。

2016年Docker公司推出了Docker Swarm,意在一统Docker生态,让Docker既可以实现容器应用管理,也可以实现大规模容器编排,经过近1年左右时间的市场验证后,发现在容器编排方面无法独立抗衡kubernetes,所以Docker公司于2017年正式宣布原生支持Kubernetes,至此,Docker在大规模容器编排应用市场败下阵来,但是Docker依然不甘心失败,把Docker核心依赖Containerd捐给了CNCF,依此说明Docker依旧是一个PaaS平台。

2020年CNCF基金会宣布Kubernetes 1.20版本将不再仅支持Docker容器管理工具,此事的起因主要也与Docker捐给CNCF基金会的Containerd有关,早期为了实现Kubernetes能够使用Docker实现容器管理,专门在Kubernetes组件中集成一个shim(垫片)技术,用来将Kubernetes容器运行时接口(CRI,Container Runntime Interface)调用翻译成Docker的API,这样就可以很好地使用Docker了,但是随着Kubernetes在全球技术市场的广泛应用,有更多的容器管理工具的出现,它们都想能够借助于Kubernetes被用户所使用,所以就提出标准化容器运行时接口,只要适配了这个接口就可以集成到Kubernetes生态当中,所以Kubernetes取消了对shim的维护,并且由于Containerd技术的成功,可以实现无缝对接Kubernetes,所以接下来Kubernetes容器运行时的主角是Containerd。

2、Containerd内部架构

1、架构图

Containerd的定位是专注于容器生命周期的管理,相比于Docker来说Containerd的职能定位更加清晰,从架构上也更加精简。Containerd同样采用Daemon(守护进程)方式运行于操作系统中,通过unix domain docket对外暴露gRPC API。Containerd负责镜像的管理,但不包含镜像构建,除此之外还负责存储及网络方面的管理以及容器的创建,Containerd具体的运行仍然是底层的容器运行时来负责,例如runc。runc默认作为Containerd底层的容器运行时。下图是一个内部架构图。

容器架构图

Containerd 采用标准的 C/S 架构

  • 服务端通过 GRPC 协议提供稳定的 API
  • 客户端通过调用服务端的 API 进行高级的操作

为了实现解耦,Containerd 将不同的职责划分给不同的组件,每个组件就相当于一个子系统(subsystem)。连接不同子系统的组件被称为模块。

Containerd 两大子系统为:

  • Bundle : 在 Containerd 中,Bundle 包含了配置、元数据和根文件系统数据,你可以理解为容器的文件系统。而 Bundle 子系统允许用户从镜像中提取和打包 Bundles。
  • Runtime : Runtime 子系统用来执行 Bundles,比如创建容器。 其中,每一个子系统的行为都由一个或多个模块协作完成(架构图中的 Core 部分)。每一种类型的模块都以插件的形式集成到 Containerd 中,而且插件之间是相互依赖的。 例如,上图中的每一个长虚线的方框都表示一种类型的插件,包括 Service Plugin、Metadata Plugin、GC Plugin、Runtime Plugin 等,其中 Service Plugin 又会依赖 Metadata Plugin、GC Plugin 和 Runtime Plugin。每一个小方框都表示一个细分的插件,例如 Metadata Plugin 依赖 Containers Plugin、Content Plugin 等。

那么Containerd在监控或者说是可观测性方面,是通过metrics接口直接提供各组件的性能指标,可被Promethues直接采集,符合其数据格式。

Containerd还支持对namespace的直接操纵,以不同namespace划分容器,不同的namespace中可以存在相同的容器名称。如果你是安装Docker CE那么默认为安装Containerd的,困为Docker是依赖Containerd的。那么此时会创建一个默认的namespace叫moby。这个名称是不是很熟悉,moby就是我们之前的故事中的由开源的docker更名后的项目名称。那么此时所创建的容器都属于这个moby的namespace中。

img

架构缩略图

Containerd 被分为三个大块:Storage、Metadata 和 Runtime

img

2、CRI支持

Containerd作为CNCF孵化项目,已经从CNCF宣布毕业。CNCF的存在主要目的是打造一个以kubernetes为中心的云原生生态,在kubernetes成为业界的事实标准后,为了使得更具扩展与灵活性,也为了促进生态建设,使得kubernetes更加的易于集成,就推出了一系列规范,如CRI(容器运行时接口)、CSI(容器存储接口)、CNI(容器网络接口)。那么要想与kubernetes对接,那么就必须遵循这些规范来实现这些接口。Docker本身是不支持CRI的那么前期的kubernetes一直在kubelet中增加的一个docker-shim的东西,用于来将CRI调用翻译成适用于dockerd的API调用,也就是说kubernetes一直用docker-shim来适配docker。那么Containerd开源进入CNCF后,就实现的CRI,可以被docker直接调用。减少了调用链的复杂度。

我们先来看一下kubelet在使用不同的容器管理器时,对底层oci运行时的调用链,比如对runc的调用,如下所示。

img

如上图所示,在使用docker管理容器时,调用链最长,这即降低了性能也增加了问题排查的复杂度。

而在使用containerd时,对于cri的实现,是基于插件化的,使用cri-containerd以插件方式集成在containerd内部,减少了调用链的长度。

那么这里你可能会问还有一cri-o是什么,好像更轻量。cri-o是轻量级的容器管理器,专门为kubernetes而设计的,站在cri-o的角度来说,用户如果使用kubernetes那么就不需要单独去操作主机中的容器,一切都交由kubernetes,那么对于具体容器的管理,就由cri-o来负责,因此cri-o没有为用户留有太多的交互式功能,而是以API形式接受kubernetes的调用。

3、常用插件

Content Plugin : 提供对镜像中可寻址内容的访问,所有不可变的内容都被存储在这里。

Snapshot Plugin : 用来管理容器镜像的文件系统快照。镜像中的每一个 layer 都会被解压成文件系统快照,类似于 Docker 中的 graphdriver。

Metrics : 暴露各个组件的监控指标。

二、安装Containerd

操作系统环境为centos7.9

1、YUM方式安装

1、获取YUM源

获取阿里云YUM源

# wget -O /etc/yum.repos.d/docker-ce.repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

查看YUM源中Containerd软件

# yum list | grep containerd
containerd.io.x86_64                     1.6.15-3.1.el7                @docker-ce-stable

2、使用yum命令安装

安装Containerd.io软件,即可安装Containerd

# yum install docker-ce-20.10.* docker-ce-cli-20.10.* containerd -y
# yum -y install containerd				# 或者单独安装

3、验证安装及启动服务

使用rpm -qa命令查看是否安装

# rpm -qa | grep containerd
containerd.io-1.6.15-3.1.el7.x86_64

设置containerd服务启动及开机自启动

# systemctl enable containerd
# systemctl start containerd

查看containerd服务启动状态

# systemctl status containerd
● containerd.service - containerd container runtime
   Loaded: loaded (/usr/lib/systemd/system/containerd.service; disabled; vendor preset: disabled)
   Active: active (running) since Sun 2023-01-29 16:54:02 CST; 1 weeks 0 days ago		# 此行第二列及第三列表示其正在运行状态
     Docs: https://containerd.io
 Main PID: 924 (containerd)
    Tasks: 38
   Memory: 94.5M
   CGroup: /system.slice/containerd.service
           ├─  924 /usr/bin/containerd
           ├─23168 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 252adcb68b692999c3ae3d4bee0f4d079c7d054e2228ff5add07172dbaab607d -address /run/containerd/containerd.sock
           └─23192 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 1edad37e41585df010068ccb4216c7b543aa2b665e6d18a57b6f452b63536395 -address /run/containerd/containerd.sock
		......

4、验证可用性

安装Containerd时ctr命令亦可使用,ctr命令主要用于管理容器及容器镜像等。

使用ctr命令查看Containerd客户端及服务端相关信息。

# ctr version
Client:
  Version:  1.6.15
  Revision: 5b842e528e99d4d4c1686467debf2bd4b88ecd86
  Go version: go1.18.9

Server:
  Version:  1.6.15
  Revision: 5b842e528e99d4d4c1686467debf2bd4b88ecd86
  UUID: 4c7ced0b-a969-4652-a836-4c8bcbc42554

2、二进制方式安装

1、获取安装包

Containerd的Github地址:https://github.com/containerd/containerd

在GitHub上发布了两个包containerd-1.6.16-linux-amd64.tar.gz这个包只包含Containerd核心组件,不包含Runc以及cri、cni等,需要提前安装。如果是单独安装的话,建议使用第二个包cri-containerd-cni-1.6.16-linux-amd64.tar.gz,包含runc和k8s里的所需要的相关文件,k8s集群里需要用到此包。虽然包含runC,但是依赖系统中的seccomp(安全计算模式,是一种限制容器调用系统资源的模式。)

下载完成之后呢,上传至主机中,然后将压缩包内文件解压至系统各目录中,命令如下

# wget https://mirror.ghproxy.com/https://github.com/containerd/containerd/releases/download/v1.6.16/cri-containerd-cni-1.6.16-linux-amd64.tar.gz
# tar Cxf / cri-containerd-cni-1.6.16-linux-amd64.tar.gz

2、安装并测试可用性

1、升级软件依赖

系统默认安装的 libseccomp 是 2.3.1 版本,该版本已经不能满足我们这里的版本的 Containerd 了(从 1.5.7 版本开始就不兼容了),需要 2.4 以上的版本,所以我们需要重新安装一个高版本的 libseccomp。

方法一:单独升级libseccomp版本

注意:因为chrony 依赖 libseccomp,卸载 libseccomp 时候,需要先卸载 chrony 在去卸载 libseccomp,然后再去安装chrony。

# rpm -e libseccomp-2.3.1-4.el7.x86_64 --nodeps			# centos7 默认版本
# wget http://rpmfind.net/linux/centos/8-stream/BaseOS/x86_64/os/Packages/libseccomp-2.5.1-1.el8.x86_64.rpm
# rpm -e chrony-3.4-1.el7.x86_64						# 卸载 chrony
# rpm -ivh libseccomp-2.5.1-1.el8.x86_64.rpm 
# yum install chrony -y
# systemctl enable chronyd && systemctl start chronyd

方法二:安装runC(推荐)

由于二进制包中提供的runC默认需要系统中安装seccomp支持,需要单独安装,且不同版本runC对seccomp版本要求一致,所以建议单独下载runC 二进制包进行安装,里面包含了seccomp模块支持。

# wget https://mirror.ghproxy.com/https://github.com/opencontainers/runc/releases/download/v1.1.4/runc.amd64
# mv runc.amd64 /usr/sbin/runc
# chmod +x /usr/sbin/runc
# runc -v
runc version 1.1.4
commit: v1.1.4-0-g5fd4c4d1
spec: 1.0.2-dev
go: go1.17.10
libseccomp: 2.5.4
2、生成默认配置文件

生成containerd默认配置文件,配置文件默认存放位置在/etc/containerd,命令如下

# mkdir /etc/containerd
# containerd config default | tee /etc/containerd/config.toml

执行以下命令启动containerd守护进程

# systemctl enable containerd --now

可以使用ctr这个自带的CLI工具检查一下版本信息

# ctr version

3、配置优化

1、镜像加速及私有仓库

我们在使用docker时通常需要配置一个镜像加速地址,一般是通过/etc/docker/daemon.json来更改,那么在使用Containerd时,怎么更改呢?这里不用担心Containerd也是支持镜像加速的,而且是可以支持对多个仓库分别配置加速地址,这一点比docker要强大。

Containerd的默认配置在/etc/containerd/config.toml中如果你是安装docker-ce时做为依赖安装的的Contaierd那么这个配置只是非常简单的一些值,那么你可以通过以下命令来查看完整的默认配置

containerd config default

从输出中找到如下字段,在registry.mirors处就是镜像加速的配置,现在默认只有一个加速的仓库地址是默认的docker.io,该仓库对应的加速地址在endpoint中配置。

[plugins."io.containerd.grpc.v1.cri".registry]
      [plugins."io.containerd.grpc.v1.cri".registry.mirrors]
        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
          endpoint = ["https://registry-1.docker.io"]

然后找到上面字段中所说的registry.mirrors字段,将docker.io的endpoint更改为你的阿里云或者其他平台商提供镜像加速地址。当然你可以增加其他的镜像仓库并为它们配置加速,例如k8s.gcr.io,更改如下所示

[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."harbor.example.com".tls]
          insecure_skip_verify = true							# 跳过证书认证
 [plugins."io.containerd.grpc.v1.cri".registry.configs."harbor.example.com".auth]
          username = "admin"
          password = "Harbor12345"
      [plugins."io.containerd.grpc.v1.cri".registry.headers]

      [plugins."io.containerd.grpc.v1.cri".registry.mirrors]
        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
            endpoint = ["https://docker.mirrors.ustc.edu.cn","http://hub-mirror.c.163.com"]
        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."gcr.io"]
            endpoint = ["https://gcr.mirrors.ustc.edu.cn"]
        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."k8s.gcr.io"]
            endpoint = ["https://gcr.mirrors.ustc.edu.cn/google-containers"]
        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."quay.io"]
            endpoint = ["https://quay.mirrors.ustc.edu.cn"]
        [plugins."io.containerd.grpc.v1.cri".registry.mirrors."harbor.example.com"]
            endpoint = ["https://harbor.example.com"]

registry.mirrors."xxx":表示需要配置 mirror 的镜像仓库。例如,registry.mirrors."docker.io" 表示配置 docker.io 的 mirror。

endpoint : 表示提供 mirror 的镜像加速服务地址。

推送容器镜像至Harbor

# ctr images tag docker.io/library/nginx:latest
# ctr images push --platform linux/amd64 --plain-http harbor.example.com/library/nginx:latest

说明:

  • 先tag再push
  • 因为我们harbor是http协议,不是https协议,所以需要加上--plain-http

2、配置Containerd所需的内核

# cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-cri.conf
net.bridge.bridge-nf-call-iptables  = 1
net.ipv4.ip_forward                 = 1
net.bridge.bridge-nf-call-ip6tables = 1
EOF

3、配置Containerd所需的模块

此操作是为了解决:使用containerd管理容器生命周期

# cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf
overlay
br_netfilter
EOF

加载模块

# modprobe -- overlay
# modprobe -- br_netfilter

4、将Containerd的Cgroup改为Systemd

找到containerd.runtimes.runc.options,添加SystemdCgroup = true(如果已存在直接修改,否则会报错)

# vim /etc/containerd/config.toml
114           [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]
115             BinaryName = ""
116             CriuImagePath = ""
117             CriuPath = ""
118             CriuWorkPath = ""
119             IoGid = 0
120             IoUid = 0
121             NoNewKeyring = false
122             NoPivotRoot = false
123             Root = ""
124             ShimCgroup = ""
125             SystemdCgroup = true				# false 改为 true

5、将sandbox_image的Pause镜像改成符合自己版本的地址

61     sandbox_image = "registry.cn-hangzhou.aliyuncs.com/google_containers/pause:3.6"			# 根据实际修改

6、配置crictl客户端连接的运行时位置

# cat > /etc/crictl.yaml <<EOF
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
pull-image-on-create: false
EOF

三、Containerd命令

docker使用docker images命令管理镜像

单机containerd使用ctr images命令管理镜像,containerd本身的CLI,images简称i

k8s中containerd使用crictl images命令管理镜像,Kubernetes社区的专用CLI工具

1、ctr 命令

1、Containerd镜像管理命令

获取命令帮助

# ctr --help
NAME:
   ctr -
        __
  _____/ /______
 / ___/ __/ ___/
/ /__/ /_/ /
\___/\__/_/

containerd CLI


USAGE:
   ctr [global options] command [command options] [arguments...]

VERSION:
   1.6.15

DESCRIPTION:

ctr is an unsupported debug and administrative client for interacting
with the containerd daemon. Because it is unsupported, the commands,
options, and operations are not guaranteed to be backward compatible or
stable from release to release of the containerd project.

COMMANDS:
   plugins, plugin            provides information about containerd plugins
   version                    print the client and server versions
   containers, c, container   manage containers
   content                    manage content
   events, event              display containerd events
   images, image, i           manage images
   leases                     manage leases
   namespaces, namespace, ns  manage namespaces
   pprof                      provide golang pprof outputs for containerd
   run                        run a container
   snapshots, snapshot        manage snapshots
   tasks, t, task             manage tasks
   install                    install a new package
   oci                        OCI tools
   shim                       interact with a shim directly
   help, h                    Shows a list of commands or help for one command

GLOBAL OPTIONS:
   --debug                      enable debug output in logs
   --address value, -a value    address for containerd's GRPC server (default: "/run/containerd/containerd.sock") [$CONTAINERD_ADDRESS]
   --timeout value              total timeout for ctr commands (default: 0s)
   --connect-timeout value      timeout for connecting to containerd (default: 0s)
   --namespace value, -n value  namespace to use with commands (default: "default") [$CONTAINERD_NAMESPACE]
   --help, -h                   show help
   --version, -v                print the version

获取命令帮助

# ctr i
NAME:
   ctr images - manage images

USAGE:
   ctr images command [command options] [arguments...]

COMMANDS:
   check                    check existing images to ensure all content is available locally
   export                   export images
   import                   import images
   list, ls                 list images known to containerd
   mount                    mount an image to a target path
   unmount                  unmount the image from the target
   pull                     pull an image from a remote
   push                     push an image to a remote
   delete, del, remove, rm  remove one or more images by reference
   tag                      tag an image
   label                    set and clear labels for an image
   convert                  convert an image

OPTIONS:
   --help, -h  show help
2、查看镜像
# ctr i ls
REF TYPE DIGEST SIZE PLATFORMS LABELS
3、下载镜像

containerd支持oci标准的镜像,所以可以直接使用docker官方或dockerfile构建的镜像

# ctr i pull --all-platforms docker.io/library/nginx:alpine			#  --platform 选项指定对应平台的镜像(推荐)

说明:这里ctr命令pull镜像时,不能直接把镜像名字写成nginx:alpine

查看已下载容器镜像

# ctr i ls
REF                            TYPE                                                      DIGEST                                                                  SIZE     PLATFORMS                                                                                LABELS
docker.io/library/nginx:alpine application/vnd.docker.distribution.manifest.list.v2+json sha256:659610aadb34b7967dea7686926fdcf08d588a71c5121edb094ce0e4cdbc45e6 15.9 MiB linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x -
4、镜像挂载

方便查看镜像中包含的内容,把已下载的容器镜像挂载至当前文件系统

# ctr i mount docker.io/library/nginx:alpine /mnt
sha256:a71c46316a83c0ac8c2122376a89b305936df99fa354c265f5ad2c1825e94167
/mnt
# ls /mnt
bin  dev  docker-entrypoint.d  docker-entrypoint.sh  etc  home  lib  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var
# ctr i unmount /mnt						# 卸载
5、镜像导出

把容器镜像导出

# ctr i export --all-platforms nginx.img docker.io/library/nginx:alpine

说明:

--all-platforms,导出所有平台镜像,本版本为1.6版本,1.4版本不需要添加此选项。

查看已导出容器镜像

# ls -lh nginx.img
-rw-r--r-- 1 root root 105M Feb  6 14:51 nginx.img

注意:如果拉取镜像使用的是以下命令,导出时可能会出现错误

# ctr i pull docker.io/library/nginx:alpine
# ctr i export --all-platforms nginx.img docker.io/library/nginx:alpine
ctr: content digest sha256:91a6fa58c8700c7dbf9bf2d64540f1d529caab5e3f1b850c27c0a65782c07c36: not found
6、镜像删除

删除指定容器镜像

# ctr i rm docker.io/library/nginx:alpine
docker.io/library/nginx:alpine
# ctr i ls
REF TYPE DIGEST SIZE PLATFORMS LABELS
7、镜像导入

导入容器镜像

# ctr i import nginx.img
unpacking docker.io/library/nginx:alpine 
(sha256:da9c94bec1da829ebd52431a84502ec471c8e548ffb2cedbf36260fd9bd1d4d3)...done
8、修改镜像tag

把docker.io/library/nginx:alpine 修改为 nginx:alpine

# ctr i tag docker.io/library/nginx:alpine nginx:alpine
nginx:alpine

查看修改后的容器镜像

# ctr i ls
REF                            TYPE                                                      DIGEST                                                                  SIZE     PLATFORMS                                                                                LABELS
docker.io/library/nginx:alpine application/vnd.docker.distribution.manifest.list.v2+json sha256:659610aadb34b7967dea7686926fdcf08d588a71c5121edb094ce0e4cdbc45e6 15.9 MiB linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x -
nginx:alpine                   application/vnd.docker.distribution.manifest.list.v2+json sha256:659610aadb34b7967dea7686926fdcf08d588a71c5121edb094ce0e4cdbc45e6 15.9 MiB linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x -

修改后对容器镜像做检查比对

# ctr i check
REF                            TYPE                                                      DIGEST                                                                  STATUS         SIZE              UNPACKED
docker.io/library/nginx:alpine application/vnd.docker.distribution.manifest.list.v2+json sha256:659610aadb34b7967dea7686926fdcf08d588a71c5121edb094ce0e4cdbc45e6 complete (8/8) 15.9 MiB/15.9 MiB true
nginx:alpine                   application/vnd.docker.distribution.manifest.list.v2+json sha256:659610aadb34b7967dea7686926fdcf08d588a71c5121edb094ce0e4cdbc45e6 complete (8/8) 15.9 MiB/15.9 MiB true

2、Containerd容器管理

1、获取命令帮助
1、获取创建静态容器命令帮助
# ctr container --help
NAME:
   ctr containers - manage containers

USAGE:
   ctr containers command [command options] [arguments...]

COMMANDS:
   create                   create container
   delete, del, remove, rm  delete one or more existing containers
   info                     get info about a container
   list, ls                 list containers
   label                    set and clear labels for a container
   checkpoint               checkpoint a container
   restore                  restore a container from checkpoint

OPTIONS:
   --help, -h  show help

说明:

使用ctr container create 命令创建容器后,容器并没有处于运行状态,其只是一个静态的容器。这个 container 对象只是包含了运行一个容器所需的资源及配置的数据结构,例如: namespaces、rootfs 和容器的配置都已经初始化成功了,只是用户进程(本案例为nginx)还没有启动。需要使用ctr tasks命令才能获取一个动态容器。

2、获取动态容器命令帮助
# ctr run --help
NAME:
   ctr run - run a container

USAGE:
   ctr run [command options] [flags] Image|RootFS ID [COMMAND] [ARG...]

OPTIONS:
   --rm                                    remove the container after running
   --null-io                               send all IO to /dev/null
   --log-uri value                         log uri
   --detach, -d                            detach from the task after it has started execution
   --fifo-dir value                        directory used for storing IO FIFOs
   --cgroup value                          cgroup path (To disable use of cgroup, set to "" explicitly)
   --platform value                        run image for specific platform
   --cni                                   enable cni networking for the container
   --runc-binary value                     specify runc-compatible binary
   --runc-root value                       specify runc-compatible root
   --runc-systemd-cgroup                   start runc with systemd cgroup manager
   --uidmap container-uid:host-uid:length  run inside a user namespace with the specified UID mapping range; specified with the format container-uid:host-uid:length
   --gidmap container-gid:host-gid:length  run inside a user namespace with the specified GID mapping range; specified with the format container-gid:host-gid:length
   --remap-labels                          provide the user namespace ID remapping to the snapshotter via label options; requires snapshotter support
   --cpus value                            set the CFS cpu quota (default: 0)
   --cpu-shares value                      set the cpu shares (default: 1024)
   --snapshotter value                     snapshotter name. Empty value stands for the default value. [$CONTAINERD_SNAPSHOTTER]
   --snapshotter-label value               labels added to the new snapshot for this container.
   --config value, -c value                path to the runtime-specific spec config file
   --cwd value                             specify the working directory of the process
   --env value                             specify additional container environment variables (e.g. FOO=bar)
   --env-file value                        specify additional container environment variables in a file(e.g. FOO=bar, one per line)
   --label value                           specify additional labels (e.g. foo=bar)
   --annotation value                      specify additional OCI annotations (e.g. foo=bar)
   --mount value                           specify additional container mount (e.g. type=bind,src=/tmp,dst=/host,options=rbind:ro)
   --net-host                              enable host networking for the container
   --privileged                            run privileged container
   --read-only                             set the containers filesystem as readonly
   --runtime value                         runtime name (default: "io.containerd.runc.v2")
   --runtime-config-path value             optional runtime config path
   --tty, -t                               allocate a TTY for the container
   --with-ns value                         specify existing Linux namespaces to join at container runtime (format '<nstype>:<path>')
   --pid-file value                        file path to write the task's pid
   --gpus value                            add gpus to the container
   --allow-new-privs                       turn off OCI spec's NoNewPrivileges feature flag
   --memory-limit value                    memory limit (in bytes) for the container (default: 0)
   --device value                          file path to a device to add to the container; or a path to a directory tree of devices to add to the container
   --cap-add value                         add Linux capabilities (Set capabilities with 'CAP_' prefix)
   --cap-drop value                        drop Linux capabilities (Set capabilities with 'CAP_' prefix)
   --seccomp                               enable the default seccomp profile
   --seccomp-profile value                 file path to custom seccomp profile. seccomp must be set to true, before using seccomp-profile
   --apparmor-default-profile value        enable AppArmor with the default profile with the specified name, e.g. "cri-containerd.apparmor.d"
   --apparmor-profile value                enable AppArmor with an existing custom profile
   --rdt-class value                       name of the RDT class to associate the container with. Specifies a Class of Service (CLOS) for cache and memory bandwidth management.
   --rootfs                                use custom rootfs that is not managed by containerd snapshotter
   --no-pivot                              disable use of pivot-root (linux only)
   --cpu-quota value                       Limit CPU CFS quota (default: -1)
   --cpu-period value                      Limit CPU CFS period (default: 0)
   --rootfs-propagation value              set the propagation of the container rootfs

说明:

使用ctr run命令可以创建一个静态容器并使其运行。一步到位运行容器。

2、查看容器

container表示静态容器,可用c缩写代表container

# ctr container ls
CONTAINER    IMAGE    RUNTIME
3、查看任务

task表示容器里跑的进程, 可用t缩写代表task

# ctr task ls
TASK    PID    STATUS
4、创建静态容器
# ctr c create docker.io/library/nginx:alpine nginx1
# ctr c ls
CONTAINER    IMAGE                             RUNTIME
nginx1       docker.io/library/nginx:alpine    io.containerd.runc.v2

查看容器详细信息

# ctr c info nginx1
5、静态容器启动为动态容器

启动task,即表时在容器中运行了进程,即为动态容器。

# ctr task start -d nginx1
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/

说明:

-d表示daemon或者后台的意思,否则会卡住终端

查看容器所在宿主机进程,是以宿主机进程的方式存在的

# ctr task ls
TASK      PID      STATUS
nginx1    61641    RUNNING

查看容器的进程(都是物理机的进程)

# ctr task ps nginx1
PID      INFO
61641    -
61676    -
61677    -

物理机查看到相应的进程

# ps -ef | grep 61641
root     61641 61620  0 15:39 ?        00:00:00 nginx: master process nginx -g daemon off;
101      61676 61641  0 15:39 ?        00:00:00 nginx: worker process
101      61677 61641  0 15:39 ?        00:00:00 nginx: worker process
root     61856 58177  0 15:43 pts/0    00:00:00 grep --color=auto 61641
6、进入容器操作
# ctr task exec --exec-id 1 nginx1 /bin/sh
ifconfig
lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

curl 127.0.0.1					# 访问本地提供的web服务
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>
100   615  100   615    0     0  1026k      0 --:--:-- --:--:-- --:--:--  600k

说明:

为exec进程设定一个id,可以随意输入,只要保证唯一即可,也可使用$RANDOM变量。

7、直接运行一个动态容器
# ctr run -d --net-host docker.io/library/nginx:alpine nginx2
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh

说明:

  • -d 代表dameon,后台运行
  • --net-host 代表容器的IP就是宿主机的IP(相当于docker里的host类型网络)

查看已运行容器

# ctr c ls
CONTAINER    IMAGE                             RUNTIME
nginx2       docker.io/library/nginx:alpine    io.containerd.runc.v2

查看已运行容器中运行的进程,既tasks

# ctr tasks ls
TASK      PID      STATUS
nginx2    62836    RUNNING

进入容器

# ctr task exec --exec-id 1 -t nginx2 /bin/sh
/ # ifconfig
br-be72c0dee4b1 Link encap:Ethernet  HWaddr 02:42:6A:DF:E5:79
          inet addr:172.19.0.1  Bcast:172.19.255.255  Mask:255.255.0.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:9107 errors:0 dropped:0 overruns:0 frame:0
          TX packets:14856 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:4171681 (3.9 MiB)  TX bytes:1183127 (1.1 MiB)

docker0   Link encap:Ethernet  HWaddr 02:42:F6:FE:F3:D9
          inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0
          UP BROADCAST MULTICAST  MTU:1500  Metric:1
          RX packets:69518 errors:0 dropped:0 overruns:0 frame:0
          TX packets:75565 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:3142249 (2.9 MiB)  TX bytes:738654677 (704.4 MiB)

eth0      Link encap:Ethernet  HWaddr 00:16:3E:0D:3E:45
          inet addr:192.168.0.174  Bcast:192.168.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:3171915 errors:0 dropped:0 overruns:0 frame:0
          TX packets:2795891 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:1964872517 (1.8 GiB)  TX bytes:2815022583 (2.6 GiB)

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:17966 errors:0 dropped:0 overruns:0 frame:0
          TX packets:17966 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:61339427 (58.4 MiB)  TX bytes:61339427 (58.4 MiB)

vethf9e4a99 Link encap:Ethernet  HWaddr CA:7A:39:59:01:05
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:9107 errors:0 dropped:0 overruns:0 frame:0
          TX packets:14856 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:4299179 (4.0 MiB)  TX bytes:1183127 (1.1 MiB)

/ # echo "nginx2" > /usr/share/nginx/html/index.html					# 为容器中运行的网站添加网站文件
/ # exit
# curl 127.0.0.1														# 在宿主机上访问网站
nginx2
8、暂停容器

查看容器状态

# ctr tasks ls
TASK      PID      STATUS
nginx2    62836    RUNNING

暂停容器

# ctr tasks pause nginx2

再次查看容器状态,看到其状态为PAUSED,表示停止

# ctr tasks ls
TASK      PID      STATUS
nginx2    62836    PAUSED
9、恢复容器

使用resume命令恢复容器

# ctr tasks resume nginx2
# ctr tasks ls
TASK      PID      STATUS
nginx2    62836    RUNNING
10、停止容器
# ctr tasks --help
NAME:
   ctr tasks - manage tasks

USAGE:
   ctr tasks command [command options] [arguments...]

COMMANDS:
   attach                   attach to the IO of a running container
   checkpoint               checkpoint a container
   delete, del, remove, rm  delete one or more tasks
   exec                     execute additional processes in an existing container
   list, ls                 list tasks
   kill                     signal a container (default: SIGTERM)
   pause                    pause an existing container
   ps                       list processes for container
   resume                   resume a paused container
   start                    start a container that has been created
   metrics, metric          get a single data point of metrics for a task with the built-in Linux runtime

OPTIONS:
   --help, -h  show help

使用kill命令停止容器中运行的进程,既为停止容器

# ctr tasks kill nginx2

查看容器停止后状态,STATUS为STOPPED

# ctr tasks ls
TASK      PID      STATUS
nginx1    61641    RUNNING
nginx2    62836    STOPPED
11、删除容器

必须先停止tasks或先删除task,再删除容器

# ctr tasks delete nginx2

查看静态容器,确认其还存在于系统中

# ctr c ls
CONTAINER    IMAGE                             RUNTIME
nginx2       docker.io/library/nginx:alpine    io.containerd.runc.v2

删除容器

# ctr c delete nginx2
12、监控容器资源消耗情况
# ctr task metrics nginx1
ID        TIMESTAMP
nginx1    2023-02-06 08:51:45.230533687 +0000 UTC

METRIC                   VALUE
memory.usage_in_bytes    3497984
memory.limit_in_bytes    9223372036854771712
memory.stat.cache        0
cpuacct.usage            45130196
cpuacct.usage_percpu     [22352586 22777610]
pids.current             3
pids.limit               0

2、nerdctl

Containerd由于面向的是上层的编排系统,而在与用户的直接交互上并不是很友好,其自带的ctr为一个CLI工具,类似使用docker命令,但是该ctr工具并不友好,单单是创建一个容器都异常复杂,那么除此之外还有一个crictl,这个工具其实也并不友好,这就造成人们在切换到Containerd后,在进行单机调试时,可能一时间无法适应,找不到合适的CLI工具来与Containerd进行交互,那么为了解决这个问题,官方又推出了一个新的CLI,该工具比以往都要强大,它的使用方式与docker几乎无差别,甚至还扩展了一些Docker不具备的功能,这个工具就是nerdctl。你甚至可以将它取个别名alias nerdctl=’docker’就直接把它当docker来使用。

nerdctl在github上的地址:https://github.com/containerd/nerdctl

你可以从上面找到最新的release版本,官方提供了两个版本,一个是只包含nerdctl这个工具,而另一个full(完整版)版本,包含了containerd、runc、cni、BuildKit等。如果在你的环境中已经有Containerd了那么你只需安装nerdctl这个工具也可以。

如果你是只安装nerdctl这个工具,那么命令如下

wget https://mirror.ghproxy.com/https://github.com/containerd/nerdctl/releases/download/v1.2.0/nerdctl-1.2.0-linux-amd64.tar.gz
tar Cxf /usr/local/bin nerdctl-1.2.0-linux-amd64.tar.gz

如果你选择完整版安装,那么命令如下

wget https://mirror.ghproxy.com/https://github.com/containerd/nerdctl/releases/download/v1.2.0/nerdctl-full-1.2.0-linux-amd64.tar.gz
tar Cxf /usr/local nerdctl-full-1.2.0-linux-amd64.tar.gz

安装完成之后,可以尝试着查看一下该工具的帮助信息,命令如下

nerdctl --help

1、nerdctl管理

查看namespace

nerdctl namespace ls

查看network信息

nerdctl network ls

这里需要说明的是,Containerd是使用cni来进行网络管理的,因此如果在没有安装cni情况下执行该命令会报cni未安装的错误提示。

你可以从完整版的数据包中找到这些cni介质,当然你也可以单独下载。

假如,你从完整版中获取cni,那么你需要将安装包解压至一个目录,例如/tmp/nerdctl,然后将cni复制到/opt/cni/bin目录中即可

tar -xf nerdctl-full-1.2.0-linux-amd64.tar.gz -C /tmp/nerdctl
cp /tmp/nerdctl/libexec/cni/* /opt/cni/bin/

2、运行容器

nerdctl run -d --name nginx -p 8080:80 nginx:1.19.6

你可基于namespace来创建容器,例如在test命名空间中创建一个nginx容器

ctr ns create test
nerdctl -n test run -d --name nginx -p 8080:80 nginx:1.19.6

镜像也是基于namespace,也就是说假设你的默认namespace是moby,那么你在这个空间中查看的镜像,与test空间中可能会不同,如果你在test中pull了一个新镜像,那么在moby空间将不可见,除非使用-n test声明查看的命名空间。

3、构建镜像

实际上一般构建镜像,与运行容器的可能会分别处于不同的环境中,这样在职能上的划分,可避免混合任务带来的风险。那么nerdctl这个工具并不具备构建镜像的能力,而需要借助其他服务来完成,如果你需要构建镜像,那么可以使用buildkit来完成。

buildkit可以从nerdctl-full的包中获得,也可以单独下载安装,例如,我这里直接从nerdctl-full这个包中获取。安装命令如下

cd /tmp/nerdctl
cp build* /usr/local/bin/
cp lib/systemd/system/buildkit.service /usr/lib/systemd/system/
systemctl enable buildkit --now

那么你可以像使用docker时一样来构建自己的镜像,执行命令只过是将docker换成nerdctl即可。

准备Dockerfile文件,内容如下

FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP=app.py
ENV FLASK_RUN_HOST=0.0.0.0
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
    && apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]

然后执行构建,命令如下

nerdctl build -t python-web:latest .

构建完成后,可以查看镜像,命令如下

nerdctl images

另外nerdctl 还可以直接像compose一样来读取docker-compose文件完成容器的部署

nerdctl compose -d -f docker-compose.yaml

总体而言,nerdctl让人又仿佛回到了使用docker命令时,那样熟悉而又流畅的操作容器的感觉。弥补了ctr命令在交互上的不足。

3、Containerd NameSpace管理

containerd中namespace的作用为:隔离运行的容器,可以实现运行多个容器。

查看命令帮助

# ctr namespace --help
NAME:
   ctr namespaces - manage namespaces

USAGE:
   ctr namespaces command [command options] [arguments...]

COMMANDS:
   create, c   create a new namespace
   list, ls    list namespaces
   remove, rm  remove one or more namespaces
   label       set and clear labels for a namespace

OPTIONS:
   --help, -h  show help

列出已有namespace

# ctr ns ls
NAME    LABELS
default
moby

创建namespace

# ctr ns create nginx
# ctr ns ls
NAME    LABELS
default
moby
nginx			# 此命名空间为新添加的

删除namespace

# ctr ns rm nginx
nginx
# ctr ns ls
NAME    LABELS
default
moby

在指定namespace中下载容器镜像

# ctr -n web images pull docker.io/library/nginx:latest

在指定namespace中创建静态容器

# ctr -n web container create docker.io/library/nginx:latest nginxapp

查看在指定namespace中创建的容器

# ctr -n web c ls
CONTAINER    IMAGE                             RUNTIME
nginxapp     docker.io/library/nginx:latest    io.containerd.runc.v2

四、Containerd Network管理

默认Containerd管理的容器仅有lo网络,无法访问容器之外的网络,可以为其添加网络插件,使用容器可以连接外网。CNI(Container Network Interface)

Containerd默认是使用cni插件来建立容器网络的,因此需要额外配置cni,首先需要先创建一个cni网络默认配置,cni网络默认配置文件位于/etc/cni/net.d/

cat > /etc/cni/net.d/10-cni-net.conflist << EOF
{
  "cniVersion": "0.4.0",
  "name": "cni-net",
  "plugins": [
    {
      "type": "bridge",
      "bridge": "cni0",
      "isGateway": true,
      "ipMasq": true,
      "promiscMode": true,
      "ipam": {
        "type": "host-local",
        "ranges": [
          [{
            "subnet": "172.18.1.0/24"
          }]
        ],
        "routes": [
          { "dst": "0.0.0.0/0" }
        ]
      }
    },
    {
      "type": "portmap",
      "capabilities": {"portMappings": true}
    }
  ]
}
EOF

1、创建CNI网络

1、获取CNI工具源码

# wget https://mirror.ghproxy.com/https://github.com/containernetworking/cni/archive/refs/tags/v1.1.2.tar.gz

查看已下载cni工具源码包

# tar zxf v1.1.2.tar.gz
# mv cni-1.1.2 cni
# cd cni/
# ls
cnitool  CODE-OF-CONDUCT.md  CONTRIBUTING.md  CONVENTIONS.md  DCO  Documentation  go.mod  go.sum  GOVERNANCE.md  libcni  LICENSE  logo.png  MAINTAINERS  pkg  plugins  README.md  RELEASING.md  ROADMAP.md  scripts  SPEC.md  test.sh

2、获取CNI Plugins(CNI插件)

准备容器网络配置文件,用于为容器提供网关、IP地址等。

创建名为mynet的网络,其中包含名为cni0的网桥

# vim /etc/cni/net.d/10-mynet.conf
{
  "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" }
   ]
  }
}
# vim /etc/cni/net.d/99-loopback.conf
{
  "cniVerion": "1.0.0",
  "name": "lo",
  "type": "loopback"
}

3、生成CNI网络

安装jq

# wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
# yum -y install jq
# cd cni/scripts/
# ls
docker-run.sh  exec-plugins.sh  priv-net-run.sh  release.sh

执行脚本文件,基于/etc/cni/net.d/目录中的*.conf配置文件生成容器网络

# CNI_PATH=/home/cni-plugins ./priv-net-run.sh echo "Hello World"

在宿主机上查看是否生成容器网络名为cni0的网桥

# ip a s
......
5: cni0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state 
DOWN group default qlen 1000
    link/ether 36:af:7a:4a:d6:12 brd ff:ff:ff:ff:ff:ff
    inet 10.66.0.1/16 brd 10.66.255.255 scope global cni0
       valid_lft forever preferred_lft forever
    inet6 fe80::34af:7aff:fe4a:d612/64 scope link
       valid_lft forever preferred_lft forever

在宿主机上查看其路由表情况

# ip route
default via 192.168.10.2 dev ens33 proto dhcp metric 100
10.66.0.0/16 dev cni0 proto kernel scope link src 10.66.0.1
192.168.10.0/24 dev ens33 proto kernel scope link src 192.168.10.164 metric 
100
192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1

五、Containerd容器数据持久化存储

实现把宿主机目录挂载至Containerd容器中,实现容器数据持久化存储

# ctr container create docker.io/library/busybox:latest busybox3 --mount type=bind,src=/tmp,dst=/hostdir,options=rbind:rw

说明:

创建一个静态容器,实现宿主机目录与容器挂载

src=/tmp 为宿主机目录

dst=/hostdir 为容器中目录

0

评论区