k8s 容器引擎介绍

1. docker与containerd对比

在 V1.24 版本以前 k8s 默认使用docker容器引擎

在 V1.24 版本以后 k8s 移除了dockershim,改为默认使用Containerd

1.1. 调用链路的区别

  • 使用docker作为容器引擎时需要通过dockershim对接docker再调用containerd。
  • 使用containerd作为容器引擎时kubelt可以通过CRI-containerd直接调用containerd。

1.2. 标准输出日志的区别

dockercontainerd
储存路径如果 Kubernetes 使用 Docker 作为容器运行时,容器日志的落盘由docker来完成, 日志通常存储在 /var/lib/docker/containers/<container-id>-json.log。如果 Kubernetes 使用 containerd 作为容器运行时,容器日志的落盘由kubelet来完成,路径 为/var/log/pods/<namespace>_<pod-name>_<pod-uid>/<container-name>/<container-id>,同时在/var/log/containers目录下创建软链接,指向日志文件。
日志轮转配置在docker配置文件中指定:
“log-driver”: “json-file”,
“log-opts”: {“max-size”: “100m”,”max-file”: “5”}
方法一:在 kubelet 启动时指定参数 –container-log-max-files=5 –container-log-max-size=”100Mi”
方法二:在配置文件KubeletConfiguration中指定 containerLogMaxFiles: 5, containerLogMaxSize: “100Mi”,配置文件路径/var/lib/kubelet/config.yaml

1.3. 配置文件路径

Containerd:

# containerd 配置文件路径
/etc/containerd/config.toml

# 默认配置中还有两个关于存储的配置路径:
# 1、保存持久化数据,包括 Snapshots, Content, Metadata 以及各种插件的数据
root = "/var/lib/containerd"  
# 2、保存运行时的临时数据的,包括 sockets、pid、挂载点、运行时状态以及不需要持久化的插件数据。
state = "/run/containerd"   
Bash

Docker:

/etc/docker/daemon.json
Bash

1.4. stream server

在 Kubernetes 和容器生态中,Stream Server 是容器运行时(如 containerd 或 CRI-O)提供的一个关键服务,主要用于处理容器 标准输入(stdin)、输出(stdout)和错误(stderr)流 的转发和管理。如 kubectl exec/logs 等命令需要在 apiserver 跟容器运行时之间建立流转发通道。

docker API 本身提供 stream 服务,kubelet 内部的 docker-shim 会通过 docker API 做流转发。而 containerd 或 CRI-O 容器运行时需要单独配置 Stream Server 服务。

Stream Server 配置:

# /etc/containerd/config.toml
...
[plugins."io.containerd.grpc.v1.cri"]
    ...
    stream_server_address = "127.0.0.1"
    stream_server_port = "0"
    ...

# stream_server_address = "127.0.0.1"
## 作用:指定 Stream Server 监听的网络地址。
## 127.0.0.1:仅允许本地(节点内部)访问 Stream Server,禁止外部直接连接。
## 若需允许远程访问(不推荐),可改为 0.0.0.0,但必须配合 TLS 加密。
## Kubernetes API Server 通过每个节点的 kubelet 代理访问 Stream Server,所以 Stream Server 无需对外暴露。

# stream_server_port = "0"
## 作用:指定 Stream Server 监听的端口。
## "0":表示由系统自动分配一个空闲端口(通常通过临时端口范围)。
Bash

2. containerd 客户端命令介绍

2.1. crictl、ctr 命令

更换 containerd 后,以往我们常用的 docker 命令也不再使用,取而代之的分别是 crictl 和 ctr 两个命令客户端。

  • crictl 命令(k8s提供):crictl 是遵循 CRI 接口规范的一个命令行工具,用于直接与 实现了 CRI 的容器运行时(如 containerd、CRI-O)交互,通常用它来检查和管理 k8s 节点上的容器运行时和镜像(不涉及非 CRI 管理的容器或镜像)。
  • ctr 命令(containerd提供):ctr 是 containerd 原生管理工具,管理所有由 containerd 托管的容器、镜像和快照(包括非 Kubernetes 容器)。

注意:

# 使用crictl命令之前,需要先配置/etc/crictl.yaml如下(不配置的话,你用该命令会一直报warn警告)
cat > /etc/crictl.yaml << 'EOF'
runtime-endpoint: unix:///run/containerd/containerd.sock
image-endpoint: unix:///run/containerd/containerd.sock
timeout: 10
debug: false
EOF

# 也可以通过命令进行设置(会自动生成/etc/crictl.yaml)
sudo crictl config runtime-endpoint unix:///run/containerd/containerd.sock
sudo crictl config image-endpoint unix:///run/containerd/containerd.sock
Bash

2.2. nerdctl 命令

前面我们介绍了可以使用 ctr 操作管理 containerd 镜像容器,但是大家都习惯了使用 docker cli,ctr 使用起来可能还是不太顺手,为了能够让大家更好的转到 containerd 上面来,社区提供了一个新的命令行工具:nerdctl。

nerdctl 是一个与 docker cli 风格兼容的 containerd 客户端工具,而且直接兼容 docker compose 的语法,这就大大提高了直接将 containerd 作为本地开发、测试或者单机容器部署使用的效率。

安装:

# 如果没有安装 nerdctl,则可以下载 nerdctl-full-<VERSION>-linux-amd64.tar.gz 包进行安装
wget https://github.com/containerd/nerdctl/releases/download/v1.7.6/nerdctl-1.7.6-linux-amd64.tar.gz

mkdir -p /usr/local/containerd/ && tar -zxvf nerdctl-1.7.6-linux-amd64.tar.gz nerdctl && mv nerdctl /usr/local/containerd/

ln -s /usr/local/containerd/nerdctl /usr/local/sbin/nerdctl
 
# 查看 nerdctl
nerdctl version # 报错warn,提示buildkit未安装

WARN[0000] unable to determine buildctl version: exec: "buildctl": executable file not found in $PATH 
Client:
 Version:	v1.7.6
 OS/Arch:	linux/amd64
 Git commit:	845e989f69d25b420ae325fedc8e70186243fd93
 buildctl:
  Version:	

Server:
 containerd:
  Version:	1.7.27
  GitCommit:	05044ec0a9a75232cad458027ca83437aae3f4da
 runc:
  Version:	1.2.5
  GitCommit:	v1.2.5-0-g59923ef

# BuildKit 是 Docker 官方推出的下一代镜像构建工具,旨在解决传统 Docker 构建(docker build)的性能、灵活性和安全性问题。自 Docker 18.09 起,BuildKit 成为默认构建引擎(需显式启用),它通过并行化构建、缓存优化和跨平台支持,显著提升了容器镜像的构建效率。
# 同时,新版本 k8s 弃用了 docker,默认使用 containerd,则不能使用 docker build 构建镜像,所以需要使用 BuildKit 工具来构建镜像。

# 安装 buildkit 见下文 nerdctl 镜像命令详解
# 参考文档:https://zhuanlan.zhihu.com/p/366671300
Bash

配置 nerdctl 命令补全:

# 安装 Bash 自动补全功能
sudo yum install bash-completion* -y
sudo apt install bash-completion* -y

# 生成补全脚本并保存到 ~/.nerdctl-completion.bash
nerdctl completion bash > ~/.nerdctl-completion.bash
echo "source '$HOME/.nerdctl-completion.bash'" >> $HOME/.bash_profile
# 立即生效
source $HOME/.bash_profile

# 全局配置,所有用户生效
nerdctl completion bash > /etc/bash_completion.d/nerdctl
Bash

2.3. 客户端命令 docker、ctr、crictl、nerdctl 详解

2.3.1. 名称空间

可以用 -n 指定名称空间,可以将镜像或者容器分散到不同的空间内,但并非所有命令都支持。

dockerctr (containerd)crictl(k8s)nerdctl
是否支持不支持支持不支持支持
示例ctr ns ls

ctr -n k8s.io image ls # 查看指定名称空间下的镜像

ctr -n k8s.io container ls # 查看指定名称空间下的容器

默认所有操作都在k8s.io名称空间下
nerdctl -n k8s.io image ls

nerdctl -n k8s.io
container ls

2.3.2. 镜像相关命令

工具对比
命令dockerctrcrictlnerdctl
查看本地镜像docker imagesctr image lscrictl images同docker命令
下载/拉取镜像docker pullctr image pullctictl pull同docker命令
给镜像打标签docker tagctr image tag同docker命令
上传/推送镜像docker pushctr image push同docker命令
删除本地镜像docker rmictr image rmcrictl rmi同docker命令
查看镜像详情docker inspectcrictl inspecti # 注意末尾是小写字母
i
同docker命令
导出镜像docker savectr image export同docker命令
导入镜像docker loadctr image import xx.tar docker.io/library/nginx:alpine同docker命令
登录镜像仓库docker login不支持,理由:ctr 工具主要是用于底层的容器操作和管
理,而不是直接与镜像仓库进行交互如推拉镜像等。
不支持,理由:主要用于管理 Pod
和容器,而非直接与镜像仓库交互。
支持
ctr(containerd)镜像命令详解
# 1、查看全部镜像
sudo ctr image ls      # 分字段展示
sudo ctr image ls -q   # 列出本地存储中的镜像(images)的 ID 列表,而不显示详细的镜像信息。
sudo ctr image check   # 检测default名称空间下所有镜像的可用性,主要看STATUS为complete代表可用

# 2、拉取 Docker Hub 官方镜像 nginx:alpine,需要注意的是镜像地址需要加上 docker.io Host 地址
sudo ctr images pull docker.io/library/nginx:alpine 

# 3、重新打标签
sudo ctr image tag docker.io/library/nginx:alpine harbor.k8s.local/course/nginx:alpine

# 4、上传镜像
sudo ctr images push docker.io/library/nginx:alpine --user xxx 

# 5、删除镜像
sudo ctr image rm harbor.k8s.local/course/nginx:alpine

# 6、查看镜像详情


# 7、将镜像导出为压缩包
sudo ctr image export nginx.tar.gz docker.io/library/nginx:alpine
sudo ctr -n k8s.io image export  a.tar.gz registry.cn-hangzhou.aliyuncs.com/google_containers/coredns:v1.11.1

# 8、从压缩包导入镜像
sudo ctr image import nginx.tar.gz
sudo ctr -n default image import a.tar.gz
# 直接导入可能会出现类似于 ctr: content digest sha256:xxxxxx not found 的错误,要解决这个办法需要 pull 可以通用/适用所有平台的镜像:
sudo ctr i pull --all-platforms docker.io/library/nginx:alpine
sudo ctr i export --all-platforms nginx.tar.gz docker.io/library/nginx:alpine
sudo ctr i rm docker.io/library/nginx:alpine
sudo ctr i import nginx.tar.gz

# 9、将镜像挂载到主机目录
sudo ctr image mount docker.io/library/nginx:alpine /mnt
sudo ctr image unmount /mnt

# 10、命名空间:Containerd 也有 namespaces 的概念,镜像或容器可以分散到不同的空间,对于多租户的场景十分有用
sudo ctr ns ls 
sudo ctr ns create test
sudo ctr ns rm test
sudo ctr -n test image ls
# 说明:
# 1、Docker 其实也是默认调用的 containerd,事实上 Docker 使用的 containerd 下面的命名空间默认是 moby,而不是 default
# 2、Kubernetes 下使用的 containerd 默认命名空间是 k8s.io
Bash
crictl(kubernetes)镜像命令详解
# crictl 没有-n参数,操作都在`k8s.io`命名空间下。
# sudo crictl image list 等同于 sudo ctr -n=k8s.io image list
# sudo crictl image ls   等同于 sudo ctr -n=k8s.io image ls

# 注意:
# sudo ctr images pull 拉取的镜像默认放在 default 而 sudo crictl pull 和 kubelet 默认拉取的镜像都在 k8s.io 命名空间下。所以通过 ctr 导入镜像的时候特别注意一点,最好指定命名空间。
Bash
nerdctl 镜像命令详解
# 镜像管理
nerdctl images
nerdctl pull docker.io/library/busybox:latest
nerdctl login --username=xxx --password yyy registry.cn-shanghai.aliyuncs.com
nerdctl tag centos:7 registry.cn-shanghai.aliyuncs.com/egon/test:v1.0
nerdctl push registry.cn-shanghai.aliyuncs.com/egon/test:v1.0
nerdctl save -o busybox.tar.gz busybox:latest
nerdctl load -i busybox.tar.gz
nerdctl rmi busybox
 
# ctr不能 build 镜像,我们可以用 nerdctl
# 1、Containerfile文件如下
FROM ubuntu
CMD sleep 1000

# 2、构建镜像
nerdctl build -t test:v1.0 -f Containerfile .
# 可以看到有一个错误提示,需要我们安装 `buildctl` 并运行 `buildkitd`,这是因为 `nerdctl build` 需要依赖 `buildkit` 工具。
# buildkit 项目也是 Docker 公司开源的一个构建工具包,支持 OCI 标准的镜像构建。它主要包含以下部分:
# 1、服务端 `buildkitd`:当前支持 runc 和 containerd 作为 worker,默认是 runc,我们这里使用 containerd
# 2、客户端 `buildctl`:负责解析 Dockerfile,并向服务端 buildkitd 发出构建请求
# buildkit 是典型的 C/S 架构,客户端和服务端是可以不在一台服务器上,而 `nerdctl` 在构建镜像的时候也作为 `buildkitd` 的客户端,所以需要我们安装并运行 `buildkitd`。

# 安装 buildkit
wget https://github.com/moby/buildkit/releases/download/v0.13.2/buildkit-v0.13.2.linux-amd64.tar.gz

tar -zxvf buildkit-v0.13.2.linux-amd64.tar.gz -C /usr/local/containerd/
ln -s /usr/local/containerd/bin/buildkitd /usr/local/sbin/buildkitd
ln -s /usr/local/containerd/bin/buildctl /usr/local/sbin/buildctl

cat > /etc/systemd/system/buildkit.service << "EOF"
[Unit]
Description=BuildKit
Documentation=https://github.com/moby/buildkit
[Service]
ExecStart=/usr/local/sbin/buildkitd --oci-worker=false --containerd-worker=true
[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable buildkit --now
systemctl status buildkit.service


# 如果 containerd 服务使用了代理,那么在使用 BuildKit 构建镜像时,仅配置 containerd 的代理是不够的,因为 BuildKit 服务 (buildkitd) 是一个独立的服务进程,需要单独配置代理。
# containerd 代理:仅影响 nerdctl pull 等镜像拉取操作。
# BuildKit 代理:影响镜像构建时的基础镜像拉取和层下载。
# 创建代理配置文件
mkdir -p /etc/systemd/system/buildkit.service.d/
tee /etc/systemd/system/buildkit.service.d/proxy.conf <<'EOF'
[Service]
Environment="HTTP_PROXY=http://hypervisor-01:20172"
Environment="HTTPS_PROXY=http://hypervisor-01:20172"
Environment="NO_PROXY=localhost,127.0.0.1,.internal,192.168.2.0/24"
EOF

# 重载配置
sudo systemctl daemon-reload
sudo systemctl restart buildkit


# 重新构建镜像
nerdctl build -t test:v1.0 -f Containerfile .
nerdctl images 
REPOSITORY    TAG       IMAGE ID        CREATED           PLATFORM       SIZE        BLOB SIZE
test          v1.0      2c93d0cc2e4b    10 seconds ago    linux/amd64    81.1 MiB    28.3 MiB
ubuntu        latest    a08e551cb338    18 minutes ago    linux/amd64    81.1 MiB    28.4 MiB

# 启动测试
nerdctl run -d --name=test test:v1.0
nerdctl container ls
nerdctl exec -ti test sh
Bash

2.3.2. 容器相关命令

工具对比
命令dockerctrcrictlnerdctl
显示本地运行的容器docker ps ctr task ls/ctr container lscrictl ps同docker命令
创建一个新容器docker createctr container createcrictl create同docker命令
运行一个新容器docker runctr run无(最小单元为 pod)同docker命令
启动容器docker startctr task startcrictl start同docker命令
关闭容器docker stop ctr task killcrictl stop同docker命令
删除容器docker rmctr container rmcrictl rm同docker命令
查看容器详情docker inspectctr container infocrictl inspect同docker命令
查看容器日志docker logscrictl logs同docker命令
查看容器资源docker statscrictl stats同docker命令
进入容器内部docker execcrictl exec同docker命令
清空不用的容器docker image prunecrictl rmi –prune同docker命令
ctr(containerd)容器命令详解
# 容器操作
## 创建容器
ctr image pull docker.io/library/nginx:alpine --hosts-dir=/etc/containerd/certs.d
ctr container create docker.io/library/nginx:alpine nginx

## 查看容器
ctr container ls
ctr container ls -q
ctr container info nginx
## 删除容器
ctr container rm nginx


# 任务
## (1)任务介绍
# 上面用container create只是创建了一个静态的容器对象,把运行容器需要的资源及配置数据例如namespaces、rootfs和容器的配置都初始化完毕了,但是容器内的进程还没有启动,即容器尚未处于运行状态

## (2) 启动任务(激活容器)
ctr task start -d nginx # nginx是你创建的容器名字

## (3)查看
ctr task ls

## (4)进入容器
# 注意必须要指定 --exec-id 参数,这个 id 可以随便写,只要唯一就行。
ctr task exec --exec-id 0 -t nginx sh

## (5)暂停容器
ctr task pause nginx  # 可以查看容器ctr task ls发现状态变成PAUSED

## (6)恢复容器
ctr task resume nginx 

## (7)ctr无法stop容器,只能暂停或杀死
ctr task kill nginx  # 可以查看容器ctr task ls发现状态变成STOPPED

## (8)删掉
ctr task rm nginx

## (9)获取容器cgroup相关信息(内存、CPU 和 PID 的限额与使用量。)
ctr task metrics nginx # 记得要先启动才能看:ctr task start -d nginx

## (10)看容器中所有进程在宿主机中的 PID
ctr task ps nginx  # 第一行的就对应容器内的1号进程
ShellScript
nerdctl 容器命令详解
# 容器管理
nerdctl run -d -p 80:80 --name=nginx --restart=always nginx:alpine
nerdctl exec -it nginx /bin/sh
nerdctl ps 
nerdctl ps -a
nerdctl inspect nginx
nerdctl logs
nerdctl logs -f
nerdctl stop nginx
nerdctl rm nginx
nerdctl rm -f nginx


# 更多命令操作,可以直接在命令行输入命令查看帮助。
docker --help
ctr --help
crictl --help
ShellScript
上一篇
下一篇