containerd 介绍 与 docker 总结

  |  

全部的 K8S学习笔记总目录,请点击查看。

本节主要介绍containerd的基本概念,以及docker的一些总结。

containerd

容器运行时(ContainerRuntime),运行于 kubernetes(k8s)集群的每个节点中,负责容器的整个生命周期,其中 docker 是目前应用最广的。

随着容器云的发展,越来越多的容器运行时涌现。为了解决这些容器运行时和 k8s 的集成问题,在 k8s 1.5 版本中,社区推出了
CRI(ContainerRuntimeInterface,容器运行时接口),以支持更多的容器运行时。

Kubelet 通过 CRI 和容器运行时进行通信,使得容器运行时能够像插件一样单独运行。可以说每个容器运行时都有自己的优势,这就允许用户更容易选择和替换自己的容器运行时。

cri-k8s

CRI & OCI

OCI(OpenContainerInitiative,开放容器计划)定义了创建容器的格式和运行时的开源行业标准,包括镜像规范(ImageSpecification)和运行时规范(
RuntimeSpecification)。

镜像规范定义了 OCI 镜像的标准。高层级运行时将会下载一个 OCI 镜像,并把它解压成 OCI 运行时文件系统包(filesystembundle)。

oci+cri

运行时规范则描述了如何从 OCI 运行时文件系统包运行容器程序,并且定义它的配置、运行环境和生命周期。如何为新容器设置命名空间(
namepsaces)和控制组(cgroups),以及挂载根文件系统等等操作,都是在这里定义的。它的一个参考实现是runC。我们称其为低层级运行时(Low-levelRuntime)。除
runC 以外,也有很多其他的运行时遵循 OCI 标准,例如 kata-runtime。

为什么弃用Docker

目前 docker 仍是 kubernetes 默认的容器运行时。那为什么会选择换掉 docker 呢?主要的原因是它的复杂性。

我们总结了 docker,containerd 以及 cri-o 的详细调用层级。Docker
的多层封装和调用,导致其在可维护性上略逊一筹,增加了线上问题的定位难度(貌似除了重启docker,我们就毫无他法了)。Containerd 和
cri-o 的方案比起 docker 简洁很多。因此我们更偏向于选用更加简单和纯粹的 containerd 和 cri-o 作为我们的容器运行时。

kubelet-cri

我们对 containerd 和 cri-o 进行了一组性能测试,包括创建、启动、停止和删除容器,以比较它们所耗的时间。containerd
在各个方面都表现良好,除了启动容器这项。从总用时来看,containerd 的用时还是要比 cri-o 要短的。

runcPerformance

从功能性来讲,containerd 和 cri-o 都符合 CRI 和 OCI 的标准。从稳定性来说,单独使用 containerd 和 cri-o
都没有足够的生产环境经验。但庆幸的是,containerd 一直在 docker 里使用,而 docker 的生产环境经验可以说比较充足。可见在稳定性上
containerd 略胜一筹。所以我们最终选用了 containerd

containerd操作

更换 containerd 后,常用的 docker 命令也不再有用,containerd 命令行客户端如下图所示:

containerd

  • ctr -v 输出的是 containerd 的版本,crictl -v 输出的是当前 k8s 的版本,从结果显而易见你可以认为 crictl 是用于 k8s 的。
  • 一般来说你某个主机安装了 k8s 后,命令行才会有 crictl 命令。而 ctr 是跟 k8s 无关的,你主机安装了 containerd 服务后就可以操作
    ctr 命令。
  • 用 crictl 运行 Pod 沙盒对容器运行时排错很有帮助。 在运行的 Kubernetes 集群中,沙盒会随机地被 kubelet 停止和删除。因此
    crictl 尽量不要在单独起容器的情况下使用,因为容器会被停止和删除。

先提前放出docker/ctr/crictl之间命令的对比,后面会详细介绍。

命令 docker ctr(containerd) crictl(kubernetes)
查看运行的容器 docker ps ctr task ls/ctr container ls crictl ps
查看镜像 docker images ctr image ls crictl images
查看容器日志 docker logs crictl logs
查看容器数据信息 docker inspect ctr container info crictl inspect
查看容器资源 docker stats crictl stats
启动/关闭已有的容器 docker start/stop ctr task start/kill crictl start/stop
运行一个新的容器 docker run ctr run 无(最小单元为pod)
打标签 docker tag ctr image tag
创建一个新的容器 docker create ctr container create crictl create
导入镜像 docker load ctr image import
导出镜像 docker save ctr image export
删除容器 docker rm ctr container rm crictl rm
删除镜像 docker rmi ctr image rm crictl rmi
拉取镜像 docker pull ctr image pull ctictl pull
推送镜像 docker push ctr image push
登录或在容器内部执行命令 docker exec crictl exec
清空不用的容器 docker image prune crictl rmi –prune

更多命令操作,可以直接在命令行输入命令查看帮助。

1
2
3
docker --help
ctr --help
crictl --help

以下是各种客户端操作 containerd 的命令,因为之后会安装 k8s,很多操作通过 k8s 直接就完成了,所以对应命令可以先做了解即可。

containerd 客户端 ctr

ctr 是 containerd 项目的一部分提供的命令行客户端。如果一台机器上运行了 containerd,那么ctr二进制文件也一般会进行安装。

由于 containerd 有 namespaces 的概念,对于上层编排系统的支持,ctr 客户端主要区分了3个命名空间分别是k8s.io、moby和default,以上我们用
crictl 操作的均在 k8s.io 命名空间,使用 ctr 看镜像列表就需要加上 -n 参数。crictl 只有一个 k8s.io 命名空间,但是没有 -n 参数。

我们知道 Docker 也是默认调用的 containerd, Docker 使用的命名空间默认是 moby,而不是 default,所以假如我们用 docker
启动容器,那么我们也可以通过 ctr -n moby 来定位容器信息。

【温馨提示】ctr images pull 拉取的镜像默认放在default,而 crictl pull 和 kubelet 默认拉取的镜像都在 k8s.io 命名空间下。所以通过
ctr 导入镜像的时候特别注意一点,最好指定命名空间。

命令示例

1
2
3
4
5
6
# 注意 -n 不能放在命令最后面,下面查看的镜像是一样的
ctr -n=k8s.io image ls
ctr -n k8s.io image ls

# 使用ctr命令指定命名空间导入镜像
ctr -n=k8s.io image import dashboard.tar

ctr 命令

ctr 命令的参数和全局参数如下。

参数命令的格式为:ctr [global options] command [command options] [arguments...]

全局参数可以在任何命令后面使用,并且可以多个参数组合使用。

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
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
  1. 查看版本

    1
    2
    ctr -v
    ctr --version
  2. 指定空间

    1
    ctr -n k8s.io image ls

namespace 相关操作

ctr 所有的命令都支持 -n 参数,用于指定命名空间,如果不指定命名空间,默认为default命名空间。命名空间的概念类似于 docker
的仓库,但是不同的是,docker 的仓库是一个集中的仓库,而 ctr 的命名空间是分布式的,每个命名空间都是一个独立的仓库。

命令 ctr namespace 用于管理命名空间,包括查看、创建和删除命名空间。可以简化为 ctr ns

  1. 查看命名空间

    1
    ctr namespace ls
  2. 创建命名空间

    1
    ctr namespace create k8s.io
  3. 删除命名空间

    1
    ctr namespace rm k8s.io

镜像相关操作

镜像相关命令如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# ctr image -h
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
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
  1. 拉取推送镜像

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # 拉取镜像
    # docker默认是docker.io官网去找镜像,所以docker拉去镜像可以这样写:docker pull nginx:alpine,而containerd没有默认仓库,所以必须写完整的镜像名字才能拉去镜像
    ctr i pull docker.io/library/nginx:alpine

    # 推送镜像到harbor
    #
    # --namespace=k8s.io 指定命名空间,不是必须,根据环境而定
    # --skip-verify 跳过认证
    # --user 指定harbor用户名及密码
    ctr --namespace=k8s.io images push harbor.mydomain.com/k8s/pause:1.25.1 --skip-verify --user admin:Harbor12345

    # 不想 -u user:password 可以在配置文件进行配置,也可以使用 nerdctl ,下面有介绍

    # 拉取带认证的镜像
    ctr images pull --user admin:Harbor12345 --tlscacert=/etc/containerd/harbor.mydomain.com/ca.crt harbor.mydomain.com/k8s/pause:1.25.1
  2. 检查镜像列表,确认镜像是否存在以及镜像的完整性,主要查看其中的 STATUScomplete 表示镜像是完整可用的状态。

    1
    2
    ctr image check
    ctr i check
  3. 导入/导出镜像

    1
    2
    ctr i export nginx.tar.gz docker.io/library/nginx:alpine
    ctr i import nginx.tar.gz
  4. 查看镜像列表

    1
    2
    3
    4
    ctr i ls
    ctr i list
    # 只查看镜像名称
    ctr i ls -q
  5. 挂载/卸载镜像

    1
    2
    3
    # ctr 支持将镜像挂载到指定目录,这样就可以直接访问镜像中的文件了,而不需要启动容器,可以确认镜像中的文件是否正确
    ctr i mount docker.io/library/nginx:alpine /tmp/nginx
    ctr i unmount /tmp/nginx
  6. 删除镜像

    1
    2
    ctr i rm nginx:alpine
    ctr i remove nginx:alpine
  7. 打标签

    1
    2
    # crictl 没有 tag 命令,只能使用 nerdctl 和 ctr,必须指定命名空间,要不然 kubelet 无法使用。
    ctr -n k8s.io i tag my-nginx:v1 harbor.mydomain.com/my-nginx:v1
  8. 镜像转换

    1
    2
    3
    4
    # ctr 支持将镜像转换为 OCI 格式,这样就可以使用其他容器运行时运行镜像了,比如 runc
    ctr i convert --oci nginx:alpine nginx:alpine-oci
    # 也支持将 OCI 格式的镜像转换为 docker 格式
    ctr i convert nginx:alpine nginx:alpine-docker
  9. 镜像构建

    containerd 不提供开箱即用的镜像构建支持。一般使用更高级别的工具用来构建镜像,比如 docker。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    cat > Dockerfile <<EOF
    FROM nginx:alpine
    RUN echo 'Build Image From Containerd' > /usr/share/nginx/html/index.html
    EOF

    # 可以使用docker构建镜像,然后导出到本地,再使用ctr导入到containerd
    docker build -t my-nginx:v1 .
    docker save -o my-nginx.tar my-nginx:v1

    ctr images import my-nginx.tar

    # 或者使用nerdctl进行构建,与docker功能一样
    # 不加-n指定命名空间,crictl看不到,kubelet也不能使用它,默认在default命名空间下
    nerdctl -n k8s.io build -t nginx:nerctl -f ./Dockerfile .

    # 参数解释:(下一节会有 nerctl 介绍)
    # -t:指定镜像名称
    # . :当前目录Dockerfile
    # -f:指定Dockerfile路径
    # --no-cache:不缓存

容器相关操作

容器相关操作,包括创建、启动、停止、删除等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
:~# ctr container --help
NAME:
ctr containers - manage containers

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

COMMANDS:
create create container
delete, del, 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
  1. 创建容器

    1
    2
    # container 只是创建了静态容器,此时容器还未启动运行。如果要启动容器,需要使用 task start 命令。
    ctr c create docker.io/library/nginx:alpine my-nginx
  2. 删除容器

    1
    2
    3
    ctr c rm my-nginx
    ctr c delete my-nginx
    ctr c del my-nginx
  3. 查看指定容器的信息

    1
    ctr c info my-nginx
  4. 查看所有容器

    1
    2
    ctr c ls
    ctr c list
  5. 容器标签

    1
    2
    # 容器标签可以用来标记容器,方便管理(只能通过 ctr c info 查看, ctr ls 不会显示)
    ctr c label my-nginx mylabel=nginx
  6. 容器检查点

    1
    2
    3
    # 容器检查点可以用来备份容器,方便恢复 (没有测试)
    ctr c checkpoint my-nginx mycheckpoint
    ctr c restore my-nginx mycheckpoint

管理任务

管理任务,包括创建、启动、停止、删除等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# ctr task --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, 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
  1. 启动已经创建的容器

    1
    2
    ctr t start my-nginx
    ctr t start -d my-nginx
  2. 查看任务

    1
    2
    ctr t ls
    ctr t list
  3. 查看任务中的进程

    1
    2
    # 注意:这里的进程是指容器中进程在宿主机上的进程号。
    ctr t ps my-nginx
  4. 任务中执行命令

    1
    2
    3
    ctr t exec my-nginx ls /
    # 进入容器内部终端,997,是随便指定的,只要不重复就行
    ctr t exec --exec-id 997 -t my-nginx /bin/sh
  5. 暂停/回复任务

    1
    2
    ctr t pause my-nginx
    ctr t resume my-nginx
  6. 杀死/删除任务

    1
    2
    3
    4
    5
    6
    7
    8
    # 只是给任务发送了 SIGTERM 信号,任务还是存在的,状态为 stopped
    ctr t kill my-nginx
    # 删除任务,任务必须是 stopped 状态
    ctr t rm my-nginx
    ctr t delete my-nginx

    # 给特定进程发送信号,这里是把刚刚创建的进程强制杀死
    ctr t kill --exec-id 999 -s SIGTERM my-nginx

    关于信号量相关的内容,可以参考这篇文章 Linux 信号量详解

  7. 获取任务的指标

    1
    2
    # 我们可以通过metric命令获取容器关于cgroup相关的信息,包括CPU、内存、PID的限额和使用情况等。
    ctr t metric my-nginx

运行容器

容器运行需要进行两步,第一步是创建容器,第二步是启动容器。

使用 ctr run 命令可以一步到位,创建并启动容器。

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
# 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
--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)
--cni enable cni networking for the container
--snapshotter value snapshotter name. Empty value stands for the default value. [$CONTAINERD_SNAPSHOTTER]
--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)
--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 (default: 0)
--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
--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
--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)

创建并启动容器

1
ctr run -d -t --net-host docker.io/library/nginx:alpine my-nginx

containerd 客户端 nerdctl

推荐使用 nerdctl,使用效果与 docker 命令的语法一致
二进制包的 github 下载链接:https://github.com/containerd/nerdctl/releases

  • 精简 (nerdctl-{version}-linux-amd64.tar.gz): 只包含nerdctl
  • 完整 (nerdctl-full-{version}-linux-amd64.tar.gz): 包含 containerd, runc, and CNI等依赖

nerdctl 的目标并不是单纯地复制 docker 的功能,它还实现了很多 docker 不具备的功能,例如延迟拉取镜像(lazy-pulling)、镜像加密(imgcrypt)等。

nerdctl

安装 nerdctl

精简版只包含nerdctl,完整版包含nerdctl和CNI插件等依赖,k8s的网络插件会在/opt/cni/bin/下会生成cni插件目录。这里选择完整版进行安装,因为启动容器的时候配置网络需要cni网络插件的支持。

  1. 精简版 nerdctl 安装

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    wget https://github.com/containerd/nerdctl/releases/download/v0.22.2/nerdctl-0.22.2-linux-amd64.tar.gz
    # 解压
    tar -xf nerdctl-0.22.2-linux-amd64.tar.gz

    # 查看解压后的文件,可以看见除了nerdctl还有containerd-rootless-setuptool.sh、containerd-rootless.sh,另外两个文件是用来在非root用户下使用nerdctl的
    ls -l

    total 37624
    -rwxr-xr-x 1 root root 21562 Aug 1 2022 containerd-rootless-setuptool.sh
    -rwxr-xr-x 1 root root 7032 Aug 1 2022 containerd-rootless.sh
    -rwxr-xr-x 1 root root 27807744 Aug 1 2022 nerdctl
    -rw-r--r-- 1 root root 10685899 Aug 1 2022 nerdctl-0.22.2-linux-amd64.tar.gz

    # 将nerdctl复制到/usr/local/bin/目录下,这样就可以直接使用nerdctl命令了。具体目录根据机器上的PATH环境变量来定。
    cp nerdctl /usr/local/bin/
  2. 完整版 nerdctl 安装

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    wget https://github.com/containerd/nerdctl/releases/download/v0.22.2/nerdctl-full-0.22.2-linux-amd64.tar.gz
    # 解压后还有如下4个目录
    # 1. bin(二进制模式,包括 nerdctl buildkitd runc tini等)
    # 2. lib(systemctl 的 service 文件)
    # 3. libexec(cni组件)
    # 4. share(说明文档)
    tar -xf nerdctl-full-0.22.2-linux-amd64.tar.gz -C /usr/local/

    # 将service文件复制到/etc/systemd/system/目录下
    cp /usr/local/lib/systemd/system/*.service /etc/systemd/system/

    # 启动服务buildkit
    systemctl enable buildkit containerd --now
    systemctl status buildkit containerd
  3. 安装 buildkit 支持构建镜像

    buildkit GitHub地址: https://github.com/moby/buildkit

    使用精简版 nerdctl 无法直接通过 containerd 构建镜像,需要与 buildkit 组全使用以实现镜像构建。当然你也可以安装上面的完整
    nerdctl,完整版可以直接使用 nerdctl build 命令构建镜像,是因为完整版已经有现成的 buildkit.service 服务了。

    buildkit项目是Docker公司开源出来的一个构建工具包,支持OCI标准的镜像构建。它主要包含以下部分:

    • 服务端buildkitd,当前支持runc和containerd作为worker,默认是runc;
    • 客户端buildctl,负责解析Dockerfile,并向服务端buildkitd发出构建请求。
    • buildkit是典型的C/S架构,client和server可以不在一台服务器上。而nerdctl在构建镜像方面也可以作为buildkitd的客户端。
    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
    # 下载地址 https://github.com/moby/buildkit/releases
    wget https://github.com/moby/buildkit/releases/download/v0.10.4/buildkit-v0.10.4.linux-amd64.tar.gz

    # 解压之后只有一个bin目录,里面有buildkit所需要的二进制文件
    # 以下的命令会将buildkit的二进制文件合并到/usr/local/bin/目录下
    tar -xf buildkit-v0.10.4.linux-amd64.tar.gz -C /usr/local/

    # buildkit需要配置两个文件:
    # 1. /usr/lib/systemd/system/buildkit.socket
    # 2. /usr/lib/systemd/system/buildkit.service

    cat > /etc/systemd/system/buildkit.socket <<EOF
    [Unit]
    Description=BuildKit
    Documentation=https://github.com/moby/buildkit
    [Socket]
    ListenStream=%t/buildkit/buildkitd.sock
    SocketMode=0660
    [Install]
    WantedBy=sockets.target
    EOF

    cat > /etc/systemd/system/buildkit.service << EOF
    [Unit]
    Description=BuildKit
    Requires=buildkit.socket
    After=buildkit.socket
    Documentation=https://github.com/moby/buildkit
    [Service]
    # Replace runc builds with containerd builds
    ExecStart=/usr/local/bin/buildkitd --addr fd://
    [Install]
    WantedBy=multi-user.target
    EOF

    # 启动buildkit
    systemctl daemon-reload
    systemctl enable buildkit --now
  4. 设置nerdctl自动补全

    1
    2
    3
    4
    5
    # 编辑文件
    vim /etc/profile
    source <(nerdctl completion bash)
    # 让其生效
    source /etc/profile

namespace 相关操作

  1. 创建 namespace

    1
    nerdctl namespace create mynamespace
  2. 列出 namespace

    1
    nerdctl namespace ls
  3. 删除 namespace

    1
    nerdctl namespace rm mynamespace

镜像相关操作

  1. 拉取镜像

    1
    nerdctl pull nginx:alpine
  2. 列出镜像

    1
    nerdctl image ls
  3. 删除镜像

    1
    nerdctl image rm nginx:alpine
  4. 拉取推送镜像

    1
    2
    3
    4
    5
    6
    # 拉取镜像
    nerdctl pull nginx:alpine
    # 重命名镜像
    nerdctl image tag nginx:alpine harbor.mydomain.com/library/nginx:alpine
    # 推送镜像
    nerdctl push harbor.mydomain.com/library/nginx:alpine

    更详细的镜像拉取操作请参考下面的内容:

    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
    # http方式,配置如下:
    mkdir -p /etc/containerd/harbor.mydomain.com
    cat > /etc/containerd/certs.d/harbor.mydomain.com/hosts.toml <<EOF
    server = "https://docker.io"

    [host."http://myharbor-minio.com"]
    capabilities = ["pull", "resolve","push"]
    # skip_verify = true
    # ca = "ca.crt" #相对路径
    # ca = "/opt/auth/ca.crt" #绝对路径
    # ca = ["/opt/auth/ca.crt"]
    # ca = ["ca.crt"]
    # client = [["/opt/auth/nginx.cclinux.cn.crt", "/opt/auth/nginx.cclinux.cn.key"]]
    EOF

    # https方式,配置如下:
    mkdir -p /etc/containerd/certs.d/harbor.secure.mydomain.com:443

    cat > /etc/containerd/certs.d/harbor.secure.mydomain.com\:443/hosts.toml <<EOF
    server = "https://docker.io"

    [host."https://harbor.secure.mydomain.com:443"]
    capabilities = ["pull", "resolve","push"]
    skip_verify = true
    # ca = "ca.crt" #相对路径
    # ca = "/opt/auth/ca.crt" #绝对路径
    # ca = ["/opt/auth/ca.crt"]
    ca = ["/etc/containerd/harbor.secure.mydomain.com/ca.crt"]
    # client = [["/opt/auth/nginx.cclinux.cn.crt", "/opt/auth/nginx.cclinux.cn.key"]]
    EOF

    # 可以通过 nerdctl 登录
    echo Harbor12345 | nerdctl login --username "admin" --password-stdin harbor.secure.mydomain.com:443

    # 登出命令
    # nerdctl logout harbor.secure.mydomain.com:443

    # 推送到私有仓库
    nerdctl --insecure-registry --namespace=k8s.io push harbor.secure.mydomain.com:443/k8s/pause:1.25.1
  5. 镜像构建

    1
    2
    3
    4
    # 从Dockerfile构建镜像
    nerdctl build -t nginx:my-alpine -f Dockerfile .
    # 从Dockerfile构建镜像并推送到私有仓库
    nerdctl build -t harbor.secure.mydomain.com:443/k8s/nginx:alpine -f Dockerfile .

容器相关操作

  1. 创建容器

    1
    nerdctl run -d --name mynginx -p 80:80 nginx:alpine
  2. 列出容器

    1
    2
    nerdctl ps -a
    nerdctl container ls -a
  3. 删除容器(停止容器后才能删除)

    1
    2
    3
    4
    5
    nerdctl stop mynginx
    nerdctl rm mynginx

    nerdctl container stop mynginx
    nerdctl container rm mynginx
  4. 进入容器

    1
    2
    3
    nerdctl exec -it mynginx sh

    nerdcrl container exec -it mynginx sh
  5. 查看容器日志

    1
    2
    3
    nerdctl logs mynginx

    nerdctl container logs mynginx
  6. 查看容器详细信息

    1
    2
    3
    nerdctl inspect mynginx

    nerdctl container inspect mynginx
  7. 查看容器内进程

    1
    nerdctl top mynginx

k8s 操作 containerd 的客户端 crictl

crictl 命令

这里我使用的是 crictl v1.26.0 版本,命令里面有些是与 pod 相关的,暂时略过,这里只介绍与 container 相关的命令。

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
crictl -h
NAME:
crictl - client for CRI

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

VERSION:
v1.26.0

COMMANDS:
attach Attach to a running container
create Create a new container
exec Run a command in a running container
version Display runtime version information
images, image, img List images
inspect Display the status of one or more containers
inspecti Return the status of one or more images
imagefsinfo Return image filesystem info
inspectp Display the status of one or more pods
logs Fetch the logs of a container
port-forward Forward local port to a pod
ps List containers
pull Pull an image from a registry
run Run a new container inside a sandbox
runp Run a new pod
rm Remove one or more containers
rmi Remove one or more images
rmp Remove one or more pods
pods List pods
start Start one or more created containers
info Display information of the container runtime
stop Stop one or more running containers
stopp Stop one or more running pods
update Update one or more running containers
config Get and set crictl client configuration options
stats List container(s) resource usage statistics
statsp List pod resource usage statistics
completion Output shell completion code
checkpoint Checkpoint one or more running containers
help, h Shows a list of commands or help for one command

GLOBAL OPTIONS:
--config value, -c value Location of the client config file. If not specified and the default does not exist, the program's directory is searched as well (default: "/etc/crictl.yaml") [$CRI_CONFIG_FILE]
--debug, -D Enable debug mode (default: false)
--image-endpoint value, -i value Endpoint of CRI image manager service (default: uses 'runtime-endpoint' setting) [$IMAGE_SERVICE_ENDPOINT]
--runtime-endpoint value, -r value Endpoint of CRI container runtime service (default: uses in order the first successful one of [unix:///var/run/dockershim.sock unix:///run/containerd/containerd.sock unix:///run/crio/crio.sock unix:///var/run/cri-dockerd.sock]). Default is now deprecated and the endpoint should be set instead. [$CONTAINER_RUNTIME_ENDPOINT]
--timeout value, -t value Timeout of connecting to the server in seconds (e.g. 2s, 20s.). 0 or less is set to default (default: 2s)
--help, -h show help (default: false)
--version, -v print the version (default: false)

命令示例

使用 crictl 命令之前,需要先配置 /etc/crictl.yaml 如下:

1
2
3
4
5
6
7
8
9
10
vim /etc/crictl.yaml

runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false

# 也可以通过命令进行设置
crictl config runtime-endpoint unix:///run/containerd/containerd.sock
crictl config image-endpoint unix:///run/containerd/containerd.sock

命令行示例:

1
2
3
4
5
6
7
# crictl 没有 -n 参数,操作都在 k8s.io 命名空间下。
crictl image ls
crictl images
# crictl image list = ctr -n k8s.io image list
# crictl image ls = ctr -n k8s.io image ls
# crictl images = ctr -n k8s.io image list
# crictl images = ctr -n k8s.io image ls

image 相关操作

1
2
3
4
5
6
7
# 查看所有的 image
crictl image list
# 拉取 image
# 注意:回车之后屏幕会卡住,不要着急,正常现象。crictl 没有进度条,拉取镜像的过程中,会一直卡在这里,直到拉取完成,只能耐心等待完成。
crictl pull nginx:1.25
# 删除 image
crictl rmi nginx:1.25

container 相关操作

1
2
# 查看所有的 container
crictl ps -a
crictl 运行一个容器比较复杂,需要书写两个 json 文件 比如以下两个文件,一个是 pod-config.json,一个是 container-config.json,其中 pod-config.json 是 pod 的配置,container-config.json 是 container 的配置。 pod 的概念是 k8s 中有的,这里先知道即可。
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
$ cat pod-config.json
{
"metadata": {
"name": "nginx-sandbox",
"namespace": "default",
"attempt": 1,
"uid": "hdishd83djaidwnduwk28bcsb"
},
"log_directory": "/tmp",
"linux": {
}
}

$ cat container-config.json
{
"metadata": {
"name": "busybox"
},
"image":{
"image": "busybox"
},
"command": [
"top"
],
"log_path":"busybox.0.log",
"linux": {
}
}
1
2
3
4
5
6
7
8
9
10
# 根据以上两个文件创建 container, 注意如果 k8s 没有安装好可能会报错,因为 crictl 是 k8s 的客户端,需要 k8s 的环境。
crictl run container-config.json pod-config.json
# 删除 container
crictl rm mynginx
# 进入 container,注意这里的 container id 是 crictl ps -a 查看到的
crictl exec -it <container id> sh
# 查看 container 日志
crictl logs <container id>
# 查看 container 详细信息
crictl inspect <container id>

总结

  • 使用 k8s 后,对于容器的操作,基本上都是通过 kubelet 完成,这个之后会使用到。
  • 镜像的构建推荐使用 docker build 等方式,推送到镜像仓库后,再通过 containerd 进行使用。
  • 查看容器中的日志,使用 crictl logs 命令。
  • 常规的对于 containerd 的操作,推荐使用 nerdctl 命令,使用效果与 docker 命令的语法一致。

docker 总结

实用技巧

  1. 清理主机上所有退出的容器

    1
    $ docker rm  $(docker ps -aq)
  2. 调试或者排查容器启动错误

    1
    2
    3
    ## 若有时遇到容器启动失败的情况,可以先使用相同的镜像启动一个临时容器,先进入容器
    $ docker run --rm -ti <image_id> sh
    ## 进入容器后,手动执行该容器对应的ENTRYPOINT或者CMD命令,这样即使出错,容器也不会退出,因为bash作为1号进程,我们只要不退出容器,该容器就不会自动退出

docker总结

Docker

  1. 为了解决软件交付过程中的环境依赖,同时提供一种更加轻量的虚拟化技术,Docker出现了。
  2. 2013年诞生,15年开始迅速发展,从17.03月开始,使用时间日期管理版本,稳定版以每季度为准。
  3. Docker是一种CS架构的软件产品,可以把代码及依赖打包成镜像,作为交付介质,并且把镜像启动成为容器,提供容器生命周期的管理。
  4. 使用yum部署docker,启动后通过操作docker这个命令行,自动调用docker daemon完成容器相关操作。
  5. 常用操作,围绕镜像|容器|仓库三大核心要素
    • systemctl start|stop|restart docker
    • docker build | pull -> docker tag -> docker push
    • docker run –name my-demo -d -p 8080:80 -v /opt/data:/data demo:v20200327 ping xx.com
    • docker cp /path/a.txt mycontainer:/opt
    • docker exec -ti mycontainer /bin/sh
    • docker logs -f –tail=100 mycontainer
  6. 通过dockerfile构建业务镜像,先使用基础镜像,然后通过一系列的指令把我们的业务应用所需要的运行环境和依赖都打包到镜像中,然后通过CMD或者ENTRYPOINT指令把镜像启动时的入口制定好,完成封装即可。有点类似于,先找来一个集装箱模板(
    基础镜像),然后把项目依赖的服务都扔到集装箱中,然后设置好服务的启动入口,关闭箱门,即完成了业务镜像的制作。
  7. 容器的实现依赖于内核模块提供的namespace和control-group的功能,通过namespace创建一块虚拟空间,空间内实现了各类资源(
    进程、网络、文件系统)的隔离,提供control-group实现了对隔离的空间的资源使用的限制。
  8. docker镜像使用分层的方式进行存储,根据主机的存储驱动的不同,实现方式会不同,kernel在3.10.0-514以上自动支持overlay2存储驱动,也是目前Docker推荐的方式。
  9. 得益于分层存储的模式,多个容器可以通过copy-on-write的策略,在镜像的最上层加一个可写层,同时利用存储驱动的UnionFS的能力,实现一个镜像快速启动多个容器的场景。
  10. docker的网络模式分为4种,最常用的为bridge和host模式。bridge模式通过docker0网桥,启动容器的时候通过创建一对虚拟网卡,将容器连接在桥上,同时维护了虚拟网卡与网桥端口的关系,实现容器间的通信。容器与宿主机之间的通信通过iptables端口映射的方式,docker利用iptables的PREROUTING和POSTROUTING的nat功能,实现了SNAT与DNAT,使得容器内部的服务被完美的保护起来。
  11. 本章重点内容是docker的核心要素及基础的操作,实现原理以及docker的网络模式为选修包,目的为了帮助有docker基础及经验的同学更好的进一步理解docker。
文章目录
  1. 1. containerd
    1. 1.1. CRI & OCI
    2. 1.2. 为什么弃用Docker
  2. 2. containerd操作
    1. 2.1. containerd 客户端 ctr
      1. 2.1.1. 命令示例
      2. 2.1.2. ctr 命令
      3. 2.1.3. namespace 相关操作
      4. 2.1.4. 镜像相关操作
      5. 2.1.5. 容器相关操作
      6. 2.1.6. 管理任务
      7. 2.1.7. 运行容器
    2. 2.2. containerd 客户端 nerdctl
      1. 2.2.1. 安装 nerdctl
      2. 2.2.2. namespace 相关操作
      3. 2.2.3. 镜像相关操作
      4. 2.2.4. 容器相关操作
    3. 2.3. k8s 操作 containerd 的客户端 crictl
      1. 2.3.1. crictl 命令
      2. 2.3.2. 命令示例
      3. 2.3.3. image 相关操作
      4. 2.3.4. container 相关操作
    4. 2.4. 总结
  3. 3. docker 总结
    1. 3.1. 实用技巧
    2. 3.2. docker总结